Source Code file: castlemaster2-annotated.asm
AddressPosition in BinarySizeTimingAssembledCode
#0000#0000
; --------------------------------
#0000#0000
; "Castle Master 2: The Crypt" by Incentive Software Ltd., 1990
#0000#0000
; Disassembled by Santiago Ontañón in 2023
#0000#0000
;
#0000#0000
; Disclaimer: All the comments, label and constant names in this disassembly are my best interpretation of what the
#0000#0000
;   code actually does. Fully annotating a disassembly like this one requires a large amount of work (this one took
#0000#0000
;   me over a month, dedicating 2-3 hours every day). Therefore, it might contain errors or misunderstandings.
#0000#0000
;   Please report if you find something that is incorrect. When I am very unsure of what some code does, I added
#0000#0000
;   a note, but I might have missed many.
#0000#0000
; 
#0000#0000
; Notes and curiosities from the codebase:
#0000#0000
; - There are two identical functions:
#0000#0000
;   - La9de_hl_eq_h_times_64
#0000#0000
;   - Lcb6d_hl_eq_h_times_64
#0000#0000
; - There are two implemented versions of the same multiplication operation "(de,hl) = de * hl":
#0000#0000
;   - La15e_de_times_hl_signed
#0000#0000
;   - L8ab4_de_times_hl_signed
#0000#0000
;   - Interestingly: the first is redundant, since the second is smaller and faster. However, it is the
#0000#0000
;     first that is the most commonly used in the code!!!
#0000#0000
; - There is self-modifying code
#0000#0000
; - The 3d rendering engine is quite advanced for the year it was written:
#0000#0000
;   - It contains all basic elements of later 3d engines
#0000#0000
;   - It only considers 2 rotation angles (pitch and yaw), but it would be trivial to add a third, if it
#0000#0000
;       wasn't because of the skybox (which would have to rotate if we added "roll").
#0000#0000
;   - It contains skybox rendering code for outdoor areas (and even a "lightning" animation over the skybox!)
#0000#0000
;   - It supports textured shapes
#0000#0000
;   - Objects can be lines, triangles, quads or pentagons
#0000#0000
;   - It implements many levels of culling (quick rendering cube, rendering frustum/pyramid)
#0000#0000
;   - It implements polygon clipping for those that are only partly within the screen
#0000#0000
;   - Different stages of rendering are "cached" in memory, so that we do not need to repeat them. For example,
#0000#0000
;     when entering a menu, and going back to the game, all the 3d -> 2d projection does not need to be redone,
#0000#0000
;     as positions have not changed. So, this is skipped. Similarly, when player does not move, rotation matrices
#0000#0000
;     are not recalculated.
#0000#0000
;   - All in all, even if the individual functions are not very optimized (things can be done significantly faster),
#0000#0000
;     the overall structure is very nice (and some of the low-level functions are indeed quite optimized, such as
#0000#0000
;     the one that renders textured horizontal lines).
#0000#0000
; - All the computations are done with fixed point arithmetic. Even line and polygon drawing uses this fixed-point
#0000#0000
;   calculations, rather than the more optimized Bresenham routines. This makes the code simpler, even if
#0000#0000
;   slower than it could be.
#0000#0000
; - Sorting of objects for rendering is quite curious, as it happens in coordinates *before* they are projected to
#0000#0000
;   camera coordinates (just distance from player in each separate axis). I am sure this causes many issues in corner
#0000#0000
;   cases. 
#0000#0000
; - I think the code has a couple of bugs, I marked them with "BUG?" tags. Of course, I am not 100% sure, but I
#0000#0000
;   think they are bugs.
#0000#0000
; 
#0000#0000
; Potential optimization of the code:
#0000#0000
; - The code seems more functional than optimized. The lowest level drawing routines seem to be optimized well, but most
#0000#0000
;   of the math routines are not. So, there is a lot of opportunity to make the engine faster.
#0000#0000
; - I have added "OPTIMIZATION" tags in places where small things could be optimized. I only added those that
#0000#0000
;   an automatic optimizer (in this case MDL: https://github.com/santiontanon/mdlz80optimizer) would not already
#0000#0000
;   detect automatically. Basically, these are notes for an potential optimized version. Only small things are noted
#0000#0000
;   large architectural changes (like moving from fixed-point arithmetic line-drawing to Bresenham-style, are not
#0000#0000
;   annotated in the code).
#0000#0000
;
#0000#0000
; Related work:
#0000#0000
; - See Phantasma, a reimplementation of the Freescape engine: https://github.com/TomHarte/Phantasma
#0000#0000
; - See the information on the Freescape reimplementation in SCUMMVM: https://wiki.scummvm.org/index.php?title=Freescape
#0000#0000
;
#0000#0000
#0000#0000
; --------------------------------
#0000#0000
; BIOS Functions and constants:
#0000#0000
; - Information obtained from "The Spectrum Machine Code Reference Guide" book.
#0000#0000
#0000#0000
; Saves a collection of bytes to tape
#0000#0000
; Input:
#0000#0000
; - ix: address to save
#0000#0000
; - de: byte count
#0000#0000
L04c6_BIOS_CASSETTE_SAVE_NO_BREAK_TEST: equ #04c6
#0000#0000
#0000#0000
; Saves a collection of bytes to tape
#0000#0000
; Input:
#0000#0000
; - ix: address where to load
#0000#0000
; - de: byte count
#0000#0000
L0562_BIOS_READ_FROM_TAPE_SKIP_TESTS: equ #0562
#0000#0000
#0000#0000
ULA_PORT: equ #fe  ; Writing to this port ignores the high 8bits.
#0000#0000
                   ; The 8 bit value written is used as follows:
#0000#0000
                   ; - bits 0, 1, 2: border color
#0000#0000
                   ; - bit 3: MIC (tape output)
#0000#0000
                   ; - bit 4: speaker output
#0000#0000
#0000#0000
#0000#0000
; --------------------------------
#0000#0000
; Video memory constants:
#0000#0000
; - Information obtained from: http://www.breakintoprogram.co.uk/hardware/computers/zx-spectrum/screen-memory-layout
#0000#0000
L4000_VIDEOMEM_PATTERNS: equ #4000
#0000#0000
L5800_VIDEOMEM_ATTRIBUTES: equ #5800
#0000#0000
#0000#0000
SCREEN_WIDTH: equ 24
#0000#0000
SCREEN_HEIGHT: equ 14
#0000#0000
SCREEN_WIDTH_IN_PIXELS: equ SCREEN_WIDTH * 8  ; 192  ; mdl: SCREEN_WIDTH_IN_PIXELS = 192 (#00c0)
#0000#0000
SCREEN_HEIGHT_IN_PIXELS: equ SCREEN_HEIGHT * 8  ; 112  ; mdl: SCREEN_HEIGHT_IN_PIXELS = 112 (#0070)
#0000#0000
#0000#0000
; --------------------------------
#0000#0000
; Game constants:
#0000#0000
CONTROL_MODE_KEYBOARD: equ 0
#0000#0000
CONTROL_MODE_SINCLAIR_JOYSTICK: equ 1
#0000#0000
CONTROL_MODE_KEMPSTON_JOYSTICK: equ 2
#0000#0000
CONTROL_MODE_CURSOR_JOYSTICK: equ 3
#0000#0000
#0000#0000
MAX_COORDINATE: equ 127 * 64  ; mdl: MAX_COORDINATE = 8128 (#1fc0)
#0000#0000
#0000#0000
MAX_PRESSED_KEYS: equ 5
#0000#0000
FILENAME_BUFFER_SIZE: equ 12
#0000#0000
#0000#0000
SPIRIT_METER_MAX: equ 64
#0000#0000
MAX_STRENGTH: equ 24
#0000#0000
#0000#0000
GAME_OVER_REASON_OVERPOWERED: equ 1
#0000#0000
GAME_OVER_REASON_YOU_COLLAPSE: equ 2
#0000#0000
GAME_OVER_REASON_CRUSHED: equ 3
#0000#0000
GAME_OVER_REASON_FATAL_FALL: equ 4
#0000#0000
GAME_OVER_REASON_ESCAPED: equ 5
#0000#0000
#0000#0000
; Sound FX:
#0000#0000
SFX_MENU_SELECT: equ 3  ; Also used for when player collides with an object
#0000#0000
SFX_THROW_ROCK_OR_LAND: equ 5
#0000#0000
SFX_FALLING: equ 6
#0000#0000
SFX_GAME_START: equ 7
#0000#0000
SFX_LIGHTNING: equ 8
#0000#0000
SFX_GATE_CLOSE: equ 9
#0000#0000
SFX_PICK_UP_ITEM: equ 10
#0000#0000
SFX_OPEN_CHEST: equ 11
#0000#0000
SFX_CLIMB_DROP: equ 12
#0000#0000
SFX_OPEN_ESCAPED: equ 13
#0000#0000
; There are other SFX defined, but only used in the game scripts:
#0000#0000
; 1  ; sounds like if you die / get hit / error
#0000#0000
; 2  ; sounds like game over
#0000#0000
; 4  ; short high -> higher pitch beep
#0000#0000
; 14  ; low-pitch repeated sound, not sure what
#0000#0000
; 15  ; tiny short SFX
#0000#0000
#0000#0000
INPUT_FORWARD: equ 3
#0000#0000
INPUT_BACKWARD: equ 4
#0000#0000
INPUT_TURN_LEFT: equ 5
#0000#0000
INPUT_TURN_RIGHT: equ 6
#0000#0000
INPUT_LOOK_UP: equ 7
#0000#0000
INPUT_LOOK_DOWN: equ 8
#0000#0000
INPUT_CRAWL: equ 9
#0000#0000
INPUT_WALK: equ 10
#0000#0000
INPUT_RUN: equ 11
#0000#0000
INPUT_FACE_FORWARD: equ 12
#0000#0000
INPUT_U_TURN: equ 13
#0000#0000
#0000#0000
INPUT_MOVEMENT_POINTER_ON_OFF: equ 21
#0000#0000
INPUT_THROW_ROCK: equ 22
#0000#0000
INPUT_MOVE_POINTER_RIGHT: equ 23
#0000#0000
INPUT_MOVE_POINTER_LEFT: equ 24
#0000#0000
INPUT_MOVE_POINTER_DOWN: equ 25
#0000#0000
INPUT_MOVE_POINTER_UP: equ 26
#0000#0000
INPUT_ACTION: equ 27
#0000#0000
#0000#0000
INPUT_SWITCH_BETWEEN_MOVEMENT_AND_POINTER: equ 30
#0000#0000
#0000#0000
INPUT_INFO_MENU: equ 41
#0000#0000
#0000#0000
; How many degrees is a full circle:
#0000#0000
FULL_ROTATION_DEGREES: equ 72
#0000#0000
#0000#0000
; Datablock structures:
#0000#0000
AREA_HEADER_SIZE: equ 8
#0000#0000
#0000#0000
; Area struct:
#0000#0000
AREA_FLAGS: equ 0
#0000#0000
AREA_N_OBJECTS: equ 1
#0000#0000
AREA_ID: equ 2
#0000#0000
AREA_RULES_OFFSET: equ 3  ; 2 bytes
#0000#0000
AREA_SCALE: equ 5
#0000#0000
AREA_ATTRIBUTE: equ 6
#0000#0000
AREA_NAME: equ 7
#0000#0000
#0000#0000
; Object struct:
#0000#0000
OBJECT_TYPE_AND_FLAGS: equ 0
#0000#0000
OBJECT_X: equ 1
#0000#0000
OBJECT_Y: equ 2
#0000#0000
OBJECT_Z: equ 3
#0000#0000
OBJECT_SIZE_X: equ 4
#0000#0000
OBJECT_SIZE_Y: equ 5
#0000#0000
OBJECT_SIZE_Z: equ 6
#0000#0000
OBJECT_ID: equ 7
#0000#0000
OBJECT_SIZE: equ 8
#0000#0000
OBJECT_ADDITIONAL_DATA: equ 9
#0000#0000
#0000#0000
; Object types:
#0000#0000
OBJECT_TYPE_ENTRANCE: equ 0
#0000#0000
OBJECT_TYPE_CUBE: equ 1
#0000#0000
OBJECT_TYPE_SPIRIT: equ 2
#0000#0000
OBJECT_TYPE_RECTANGLE: equ 3
#0000#0000
; - Object types in between 4 and 9 are different solids, like pyramids,
#0000#0000
; hourglasses, wedges, etc. that are synthesized on the fly.
#0000#0000
; - I believe the object ID here just indicates their orientation (one of
#0000#0000
; the 6 possible cardinal directions in 3d), and their additional data
#0000#0000
; is used to determine their exact shape (via some checks in at the bedinning of
#0000#0000
; function "L97bb_project_other_solids").
#0000#0000
OBJECT_TYPE_LINE: equ 10
#0000#0000
OBJECT_TYPE_TRIANGLE: equ 11
#0000#0000
OBJECT_TYPE_QUAD: equ 12
#0000#0000
OBJECT_TYPE_PENTAGON: equ 13
#0000#0000
OBJECT_TYPE_HEXAGON: equ 14
#0000#0000
#0000#0000
; Rule types:
#0000#0000
RULE_TYPE_ADD_TO_SCORE: equ 1
#0000#0000
RULE_TYPE_TOGGLE_OBJECT_VISIBILITY: equ 3
#0000#0000
RULE_TYPE_MAKE_OBJECT_VISIBILE: equ 4
#0000#0000
RULE_TYPE_MAKE_OBJECT_INVISIBILE: equ 5
#0000#0000
RULE_TYPE_TOGGLE_OBJECT_FROM_AREA_VISIBILITY: equ 6
#0000#0000
RULE_TYPE_MAKE_OBJECT_FROM_AREA_VISIBILE: equ 7
#0000#0000
RULE_TYPE_MAKE_OBJECT_FROM_AREA_INVISIBILE: equ 8
#0000#0000
RULE_TYPE_INCREMENT_VARIABLE: equ 9
#0000#0000
RULE_TYPE_DECREMENT_VARIABLE: equ 10
#0000#0000
RULE_TYPE_END_RULE_IF_VARIABLE_DIFFERENT: equ 11
#0000#0000
RULE_TYPE_SET_BOOLEAN_TRUE: equ 12
#0000#0000
RULE_TYPE_SET_BOOLEAN_FALSE: equ 13
#0000#0000
RULE_TYPE_END_RULE_IF_BOOLEAN_DIFFERENT: equ 14
#0000#0000
RULE_TYPE_PLAY_SFX: equ 15
#0000#0000
RULE_TYPE_DESTROY_OBJECT: equ 16
#0000#0000
RULE_TYPE_DESTROY_OBJECT_FROM_AREA: equ 17
#0000#0000
RULE_TYPE_TELEPORT: equ 18
#0000#0000
RULE_TYPE_STRENGTH_UPDATE: equ 19
#0000#0000
RULE_TYPE_SET_VARIABLE: equ 20
#0000#0000
RULE_TYPE_REDRAW: equ 26
#0000#0000
RULE_TYPE_PAUSE: equ 27
#0000#0000
RULE_TYPE_REQUEST_SFX_NEXT_FRAME: equ 28
#0000#0000
RULE_TYPE_TOGGLE_BOOLEAN: equ 29
#0000#0000
RULE_TYPE_END_RULE_IF_OBJECT_INVISIBLE: equ 30
#0000#0000
RULE_TYPE_END_RULE_IF_OBJECT_VISIBLE: equ 31
#0000#0000
RULE_TYPE_END_RULE_IF_OBJECT_FROM_AREA_INVISIBLE: equ 32
#0000#0000
RULE_TYPE_END_RULE_IF_OBJECT_FROM_AREA_VISIBLE: equ 33
#0000#0000
RULE_TYPE_SHOW_MESSAGE: equ 34
#0000#0000
RULE_TYPE_RENDER_EFFECT: equ 35
#0000#0000
RULE_TYPE_FLIP_SKIP_RULE: equ 44
#0000#0000
RULE_TYPE_UNSET_SKIP_RULE: equ 45
#0000#0000
RULE_TYPE_END_RULE_IF_VARIABLE_LARGER: equ 46
#0000#0000
RULE_TYPE_END_RULE_IF_VARIABLE_LOWER: equ 47
#0000#0000
RULE_TYPE_SELECT_OBJECT: equ 48
#0000#0000
#0000#0000
#0000#0000
; --------------------------------
#0000#0000
; RAM Variables before the game data:
#0000#0000
L5cbc_render_buffer: equ #5cbc  ; 2712 bytes ((SCREEN_HEIGHT * 8 + 1) * SCREEN_WIDTH)
#0000#0000
#0000#0000
; Variables that overlap with the render buffer, these are used when projecting
#0000#0000
; the 3d vertices into 2d, so, they are discarded and not needed when using the 
#0000#0000
; render buffer.
#0000#0000
L5e4c_pitch_rotation_matrix: equ #5e4c
#0000#0000
L5e55_rotation_matrix: equ #5e55
#0000#0000
L5e5e_at_least_one_vertex_outside_rendering_frustum: equ #5e5e
#0000#0000
L5e5f_add_to_projected_objects_flag: equ #5e5f  ; If this is 1, the current object being projected from 3d to 2d, will be added to the list of objects to draw.
#0000#0000
L5e60_projection_pre_work_type: equ #5e60  ; Indicates whether we need to do additional computations before projecting each face.
#0000#0000
L5e61_object_currently_being_processed_type: equ #5e61
#0000#0000
L5e62_player_collision_with_object_flags: equ #5e62
#0000#0000
L5e63_3d_vertex_coordinates_relative_to_player: equ #5e63
#0000#0000
L5e75_48_bit_accumulator: equ #5e75
#0000#0000
L5e7b_48bitmul_tmp1: equ #5e7b
#0000#0000
L5e7d_48bitmul_tmp2: equ #5e7d
#0000#0000
#0000#0000
L5e9f_3d_vertex_coordinates_after_rotation_matrix: equ #5e9f  ; 16 bit representation.
#0000#0000
#0000#0000
L5edc_vertex_rendering_frustum_checks: equ #5edc  ; 5 bits per vertex, indicating if they passed or not each of the 5 culling tests for the rendering frustum.
#0000#0000
#0000#0000
L5ee8_already_projected_vertex_coordinates: equ #5ee8
#0000#0000
#0000#0000
L5f24_shape_edges_ptr: equ #5f24  ; Pointer to the array with the order of edges to use for projection.
#0000#0000
L5f26_alternative_shape_edges_ptr: equ #5f26  ; Alternative edges pointer (for when object is seen from below, this is only needed for flat shapes).
#0000#0000
L5f28_cull_face_when_no_projected_vertices: equ #5f28
#0000#0000
L5f29_extra_solid_dimensions: equ #5f29  ; stores 4 additional dimensions used temporarily to synthesize solids like pyramids, hourglasses, etc. on the fly. (4 16bit numbers).
#0000#0000
L5f31_sorting_comparison_result: equ #5f31  ; result of comparing the coordinates of two objects to see if they should be flipped for rendering.
#0000#0000
L5f32_sorting_any_change: equ #5f32
#0000#0000
L5f33_sorting_boundingbox_ptr1: equ #5f33
#0000#0000
L5f35_sorting_boundingbox_ptr2: equ #5f35
#0000#0000
L5f37_sorting_bbox1_c1: equ #5f37  ; These four variables hold the values of the min/max coordinates for the current axis of the two bounding boxes being compared for sorting.
#0000#0000
L5f39_sorting_bbox2_c1: equ #5f39
#0000#0000
L5f3b_sorting_bbox1_c2: equ #5f3b
#0000#0000
L5f3d_sorting_bbox2_c2: equ #5f3d
#0000#0000
L5f3f_n_objects_covering_the_whole_screen_left: equ #5f3f
#0000#0000
L5f40_16_bit_tmp_matrix: equ #5f40  ; Used internally to save the results of matrix multiplication.
#0000#0000
L5f52_16_bit_tmp_matrix_ptr: equ #5f52  ; Used to keep track of the elements in the matrix above.
#0000#0000
#0000#0000
L5fa2_3d_object_bounding_boxes_relative_to_player: equ #5fa2  ; in 16 bit precision: x1, x2, y1, y2, z1, z2
#0000#0000
#0000#0000
L6664_row_pointers: equ #6664  ; Pointers to each row of pixels in the buffer.
#0000#0000
L6754_end_of_render_buffer: equ #6754
#0000#0000
#0000#0000
; This contains the current room objects, already projected to 2d coordinates:
#0000#0000
; - Each entry has 2 pointers:
#0000#0000
;   - One pointer to the "L67f4_projected_vertex_data" (with the projected vertices)
#0000#0000
;   - One pointer to the "L5fa2_3d_object_bounding_boxes_relative_to_player"
#0000#0000
L6754_current_room_object_projected_data: equ #6754
#0000#0000
#0000#0000
; For each projected object, the data is organized as follows:
#0000#0000
; - 1 byte: object ID
#0000#0000
; - 1 byte: number of primitives/faces:
#0000#0000
;   - If the most significant bit is set, it means this object covers the whole screen.
#0000#0000
; - face data:
#0000#0000
;   - 1 byte (texture / # vertices),
#0000#0000
;   - and then 2 bytes per vertex screen x, screen y (screen y is reversed, 0 = bottom).
#0000#0000
L67f4_projected_vertex_data: equ #67f4
#0000#0000
#0000#0000
#0000#0000
    org #6a00
#6a00#0000
#6a00#0000
; --------------------------------
#6a00#0000
; Program start
#6a00#0000
L6a00_start:
#6a00#0000311
c3 2f 6a 
    jp L6a2f_game_init
#6a03#0003
#6a03#0003
#6a03#0003
; --------------------------------
#6a03#0003
; Set up the interrupt routine to "Lbe66_interrupt_routine".
#6a03#0003
L6a03_setup_interrupts:
#6a03#000315
f3 
    di
#6a04#0004112
e5 
    push hl
#6a05#0005112
d5 
    push de
#6a06#0006112
c5 
    push bc
#6a07#0007112
f5 
    push af
#6a08#000815
af 
        xor a
#6a09#0009314
32 7c 74 
        ld (L747c_within_interrupt_flag), a
#6a0c#000c311
21 00 fe 
        ld hl, Lfe00_interrupt_vector_table
#6a0f#000f15
7c 
        ld a, h
#6a10#0010211
ed 47 
        ld i, a
#6a12#001215
54 
        ld d, h
#6a13#001315
5d 
        ld e, l
#6a14#001415
1c 
        inc e
#6a15#0015211
36 fd 
        ld (hl), #fd
#6a17#0017311
01 00 01 
        ld bc, 256
#6a1a#001a223/18
ed b0 
        ldir
#6a1c#001c28
3e c3 
        ld a, #c3  ; jp opcode
#6a1e#001e311
21 66 be 
        ld hl, Lbe66_interrupt_routine
#6a21#0021314
32 fd fd 
        ld (Lfdfd_interrupt_jp), a
#6a24#0024317
22 fe fd 
        ld (Lfdfe_interrupt_pointer), hl
#6a27#0027210
ed 5e 
        im 2
#6a29#0029111
f1 
    pop af
#6a2a#002a111
c1 
    pop bc
#6a2b#002b111
d1 
    pop de
#6a2c#002c111
e1 
    pop hl
#6a2d#002d15
fb 
    ei
#6a2e#002e111
c9 
    ret
#6a2f#002f
#6a2f#002f
#6a2f#002f
; --------------------------------
#6a2f#002f
; Initializes the game the very first time.
#6a2f#002f
L6a2f_game_init:
#6a2f#002f311
31 f8 ff 
    ld sp, #fff8  ; initialize the stack
#6a32#003215
f3 
    di
#6a33#003315
af 
    xor a  ; Set control mode to keyboard
#6a34#0034314
32 83 76 
    ld (L7683_control_mode), a
#6a37#0037422
fd 22 7d 74 
    ld (L747d), iy  ; Note: This instruction is very strange, as at this point "iy" is undefined.
#6a3b#003b318
cd c9 a4 
    call La4c9_init_game_state
#6a3e#003e318
cd 03 6a 
    call L6a03_setup_interrupts
#6a41#0041311
c3 7e 6a 
    jp L6a7e_main_application_loop
#6a44#0044
#6a44#0044
#6a44#0044
; --------------------------------
#6a44#0044
; Unused?
#6a44#004416
    db #00, #00, #00, #00, #00, #00, #00, #00, #00, #00, #00, #00, #00, #00, #00, #00
#6a54#005416
    db #00, #00, #00, #00, #00, #00, #00, #00, #00, #00, #00, #00, #00, #00, #00, #00
#6a64#006416
    db #00, #00, #00, #00, #00, #00, #00, #00, #00, #00, #00, #00, #00, #00, #00, #00
#6a74#007410
    db #00, #00, #00, #00, #00, #00, #00, #00, #00, #00
#6a7e#007e
#6a7e#007e
#6a7e#007e
; --------------------------------
#6a7e#007e
; Main application loop: calls title screen, starts game, restarts title screen, etc.
#6a7e#007e
; I think this is a game loop
#6a7e#007e
L6a7e_main_application_loop:
#6a7e#007e311
21 fd ff 
    ld hl, #fffd
#6a81#0081317
22 6c 74 
    ld (L746c_game_flags), hl
#6a84#008428
3e 02 
    ld a, 2
#6a86#0086314
32 77 74 
    ld (L7477_render_buffer_effect), a  ; Request gate opening effect
#6a89#0089318
cd 2e c7 
    call Lc72e_title_screen_loop
#6a8c#008c318
cd aa 83 
    call L83aa_redraw_whole_screen
#6a8f#008f15
af 
    xor a
#6a90#0090314
32 79 74 
    ld (L7479_current_game_state), a
#6a93#0093311
c3 99 6a 
    jp L6a99
#6a96#0096
L6a96_game_loop:
#6a96#0096318
cd aa 83 
    call L83aa_redraw_whole_screen
#6a99#0099
L6a99:
#6a99#0099318
cd ec 9d 
    call L9dec_game_tick
#6a9c#009c318
cd 05 a0 
    call La005_check_rules
#6a9f#009f317
2a 6c 74 
    ld hl, (L746c_game_flags)
#6aa2#00a2210
cb 4d 
    bit 1, l  ; check the "game over" flag
#6aa4#00a4311
ca 96 6a 
    jp z, L6a96_game_loop
#6aa7#00a7318
cd c9 a4 
    call La4c9_init_game_state
#6aaa#00aa311
c3 7e 6a 
    jp L6a7e_main_application_loop
#6aad#00ad
#6aad#00ad
#6aad#00ad
; --------------------------------
#6aad#00ad
; Game state variables:
#6aad#00ad
; Saving game saves data starting from here:
#6aad#00ad
L6aad_savegame_data_start:
#6aad#00ad
L6aad_player_current_x:
#6aad#00ad2
    dw #00a0
#6aaf#00af
L6aaf_player_current_y:
#6aaf#00af2
    dw #09e0
#6ab1#00b1
L6ab1_player_current_z:
#6ab1#00b12
    dw #1b60
#6ab3#00b3
L6ab3_current_speed_in_this_room:
#6ab3#00b32
    dw #11d0
#6ab5#00b5
L6ab5_current_speed:  ; This is a value form the Ld0c8_speed_when_crawling array, depending on L6b0b_selected_movement_mode.
#6ab5#00b51
    db #f0
#6ab6#00b6
L6ab6_player_pitch_angle:  ; from 18 to -18 (54)
#6ab6#00b61
    db #00
#6ab7#00b7
L6ab7_player_yaw_angle:  ; from 0 - 71
#6ab7#00b71
    db #1a
#6ab8#00b8
L6ab8_player_crawling:  ; 2 when standing up, 1 when crawling.
#6ab8#00b81
    db 2
#6ab9#00b9
L6ab9_player_height:  ; player height * room scale
#6ab9#00b91
    db #26
#6aba#00ba
L6aba_max_falling_height_without_damage:  ; 2 * room scale
#6aba#00ba1
    db #26
#6abb#00bb
L6abb_max_climbable_height:
#6abb#00bb1
    db #13
#6abc#00bc
L6abc_current_room_scale:
#6abc#00bc1
    db #13
#6abd#00bd
L6abd_cull_by_rendering_volume_flag:
#6abd#00bd1
    db #00
#6abe#00be
L6abe_use_eye_player_coordinate:  ; When this is 0, we will use "feet" coordinates for collision checks, when 1, we will use "eye" coordinates.
#6abe#00be1
    db #00
#6abf#00bf
L6abf_current_area_name_string:
#6abf#00bf16
    db 0, "   THE CRYPT   "
#6acf#00cf
L6acf_current_area_id:
#6acf#00cf1
    db #02
#6ad0#00d0
L6ad0_current_area_n_objects:
#6ad0#00d01
    db #18
#6ad1#00d1
L6ad1_current_area_objects:
#6ad1#00d12
    dw #d6ca
#6ad3#00d3
#6ad3#00d32
    db #00, #00  ; unused?
#6ad5#00d5
L6ad5_current_area_rules:
#6ad5#00d52
    dw #d8ce
#6ad7#00d7
L6ad7_current_border_color:
#6ad7#00d72
    db #14, #00
#6ad9#00d9
L6ad9_current_attribute_color:
#6ad9#00d92
    db #16, #0b
#6adb#00db
L6adb_desired_border_color:
#6adb#00db2
    db #14, #00
#6add#00dd
L6add_desired_attribute_color:
#6add#00dd2
    db #47, #0b
#6adf#00df
L6adf_game_boolean_variables:
#6adf#00df
    ; One bit corresponding to each variable. 
#6adf#00df
    ; The first few correspond to collected keys.
#6adf#00df4
    db #00, #00, #00, #00
#6ae3#00e3
L6ae3_visited_areas:  ; one bit per area (keeps track of which areas the player has already visited).
#6ae3#00e38
    db #00, #00, #00, #00, #00, #00, #00, #00
#6aeb#00eb
L6aeb_score:  ; 3 bytes
#6aeb#00eb3
    db #00, #00, #00
#6aee#00ee
L6aee_game_variables:  ; These can be accessed by the game scripts.
#6aee#00ee8
    db #00, #00, #00, #00, #00, #00, #00, #00
#6af6#00f68
    db #00, #00, #00, #00, #00, #00, #00, #00
#6afe#00fe8
    db #00, #00, #00, #00, #00, #00, #00, #00
#6b06#01063
    db #00, #00, #00
#6b09#0109
L6b09_number_of_spirits_destroyed:
#6b09#01091
    db 0
#6b0a#010a
L6b0a_current_strength:
#6b0a#010a1
    db 16
#6b0b#010b
L6b0b_selected_movement_mode:  ; 0: crawl, 1: walk, 2: run
#6b0b#010b1
    db 2
#6b0c#010c
L6b0c_num_collected_keys:
#6b0c#010c1
    db 0
#6b0d#010d
L6b0d_new_key_taken:
#6b0d#010d1
    db 0  ; Contains the ID of a key just picked up, before being added to the inventory.
#6b0e#010e
L6b0e_lightning_time_seconds_countdown:
#6b0e#010e1
    db #14
#6b0f#010f
L6b0f_collected_keys:
#6b0f#010f
    ; Different from "L6adf_game_boolean_variables", this array has the keys in
#6b0f#010f
    ; the order the player picked them, directly as a list of IDs.
#6b0f#010f10
    db #00, #00, #00, #00, #00, #00, #00, #00, #00, #00
#6b19#0119
L6b19_current_area_flags:
#6b19#01191
    db #00
#6b1a#011a
L6b1a_pointer_x:
#6b1a#011a1
    db 0
#6b1b#011b
L6b1b_pointer_y:
#6b1b#011b1
    db 0
#6b1c#011c
L6b1c_movement_or_pointer:
#6b1c#011c1
    db 0  ; 0: movement, otherwise: pointer
#6b1d#011d
L6b1d_time_interrupts:
#6b1d#011d1
    db #01
#6b1e#011e
L6b1e_time_unit5:  ; Changes once per second, counting from 10 to 1
#6b1e#011e1
    db #00
#6b1f#011f
L6b1f_current_spirit_meter:  ; Increments in 1 each time Lbe65_time_unit3 wraps around (each 120 seconds).
#6b1f#011f1
    db #20
#6b20#0120
L6b20_display_movement_pointer_flag:  ; Whether to draw a small cross in the center of the screen when in movement mode.
#6b20#01201
    db #ff
#6b21#0121
L6b21_time_unit6_previous:  ; to keep track of when L6b22_time_unit6 changes.
#6b21#01211
    db #00
#6b22#0122
L6b22_time_unit6:  ; Increments by one each time L6b1e_time_unit5 cycles.
#6b22#01221
    db #00
#6b23#0123
L6b23_set_bit7_byte_3_flag_at_start:  ; If this is != 0, when starting a game, bit 7 of the 3rd byte of the boolean variables is set to 1 (not sure of the effect of this).
#6b23#01231
    db #00
#6b24#0124
L6b24_savegame_data_end:
#6b24#0124
#6b24#01244
    db #00, #00, #07, #00  ; Unused?
#6b28#0128
L6b28_player_radius:
#6b28#01282
    dw #000a
#6b2a#012a
L6b2a_spirit_in_room:  ; 0: no spirit, 1: spirit
#6b2a#012a1
    db 0
#6b2b#012b
L6b2b_desired_eye_compass_frame:
#6b2b#012b1
    db #00
#6b2c#012c
#6b2c#012c
; If an object definition has more bytes than this, it means there are rule effects associated with it:
#6b2c#012c
L6b2c_expected_object_size_by_type:
#6b2c#012c16
    db #09, #0c, #0e, #0a, #10, #10, #10, #10, #10, #10, #10, #13, #16, #19, #1c, #00
#6b3c#013c
#6b3c#013c
L6b3c_rule_size_by_type:  ; Assuming there are only 49 rule types (maximum type if 48).
#6b3c#013c16
    db #01, #04, #02, #02, #02, #02, #03, #03, #03, #02, #02, #03, #02, #02, #03, #02
#6b4c#014c16
    db #02, #03, #03, #02, #03, #00, #00, #00, #00, #02, #01, #02, #02, #02, #02, #02
#6b5c#015c16
    db #03, #03, #02, #02, #00, #00, #00, #00, #00, #02, #01, #00, #01, #01, #03, #03
#6b6c#016c1
    db #02
#6b6d#016d
#6b6d#016d
; Edges for cubes:
#6b6d#016d
L6b6d_cube_edges:
#6b6d#016d1
    db #0c
#6b6e#016e8
    db #00, #01, #01, #02, #02, #03, #03, #00
#6b76#01768
    db #04, #05, #05, #06, #06, #07, #07, #04
#6b7e#017e8
    db #00, #04, #01, #05, #02, #06, #03, #07
#6b86#0186
#6b86#0186
; byte 0: number of faces
#6b86#0186
; Each face then:
#6b86#0186
; - byte: texture
#6b86#0186
; - byte: number of vertices/edges
#6b86#0186
; - bytes 2+: edge indexes from where to get the vertices
#6b86#0186
; - the msb in the index indicates if we need to flip the vertexes in the edge in question.
#6b86#0186
L6b86_face_definition_for_cubes:
#6b86#01861
    db #06
#6b87#01876
    db #00, #04, #83, #0b, #07, #88
#6b8d#018d6
    db #00, #04, #05, #8a, #81, #09
#6b93#01936
    db #00, #04, #08, #04, #89, #80
#6b99#01996
    db #00, #04, #0a, #06, #8b, #82
#6b9f#019f6
    db #00, #04, #00, #01, #02, #03
#6ba5#01a56
    db #00, #04, #84, #87, #86, #85
#6bab#01ab
#6bab#01ab
; Edges for pyramids:
#6bab#01ab
L6bab_pyramid_edges:
#6bab#01ab1
    db #08
#6bac#01ac8
    db #00, #01, #01, #02, #02, #03, #03, #00
#6bb4#01b48
    db #00, #04, #01, #04, #02, #04, #03, #04
#6bbc#01bc
#6bbc#01bc
L6bbc_face_definition_for_pyramids:
#6bbc#01bc1
    db #05
#6bbd#01bd5
    db #00, #03, #83, #07, #84
#6bc2#01c25
    db #00, #03, #82, #06, #87
#6bc7#01c75
    db #00, #03, #81, #05, #86
#6bcc#01cc5
    db #00, #03, #80, #04, #85
#6bd1#01d16
    db #00, #04, #00, #01, #02, #03
#6bd7#01d7
#6bd7#01d7
L6bd7_wedge_edges:
#6bd7#01d71
    db #09
#6bd8#01d86
    db #00, #01, #01, #02, #02, #03
#6bde#01de6
    db #03, #00, #00, #04, #01, #04
#6be4#01e46
    db #02, #05, #03, #05, #04, #05
#6bea#01ea
#6bea#01ea
L6bea_face_definition_for_wedges:
#6bea#01ea1
    db #05
#6beb#01eb6
    db #00, #04, #83, #07, #88, #84
#6bf1#01f15
    db #00, #03, #82, #06, #87
#6bf6#01f66
    db #00, #04, #81, #05, #08, #86
#6bfc#01fc5
    db #00, #03, #80, #04, #85
#6c01#02016
    db #00, #04, #00, #01, #02, #03
#6c07#0207
#6c07#0207
L6c07_triangle_houglass_edges:
#6c07#02071
    db #09
#6c08#02086
    db #00, #01, #01, #02, #02, #03
#6c0e#020e6
    db #03, #00, #00, #04, #01, #05
#6c14#02146
    db #02, #05, #03, #04, #04, #05
#6c1a#021a
#6c1a#021a
L6c1a_face_definition_for_triangle_hourglasses:
#6c1a#021a1
    db #05
#6c1b#021b5
    db #00, #03, #83, #07, #84
#6c20#02206
    db #00, #04, #82, #06, #88, #87
#6c26#02265
    db #00, #03, #81, #05, #86
#6c2b#022b6
    db #00, #04, #80, #04, #08, #85
#6c31#02316
    db #00, #04, #00, #01, #02, #03
#6c37#0237
#6c37#0237
L6c37_hourglass_edges:
#6c37#02371
    db #0c
#6c38#02388
    db #00, #01, #01, #02, #02, #03, #03, #00
#6c40#02408
    db #04, #07, #07, #05, #05, #06, #06, #04
#6c48#02488
    db #00, #04, #01, #06, #02, #05, #03, #07
#6c50#0250
#6c50#0250
L6c50_face_definition_for_hourglasses:
#6c50#02501
    db #06
#6c51#02516
    db #00, #04, #83, #0b, #84, #88
#6c57#02576
    db #00, #04, #82, #0a, #85, #8b
#6c5d#025d6
    db #00, #04, #81, #09, #86, #8a
#6c63#02636
    db #00, #04, #80, #08, #87, #89
#6c69#02696
    db #00, #04, #00, #01, #02, #03
#6c6f#026f6
    db #00, #04, #04, #05, #06, #07
#6c75#0275
#6c75#0275
; Edge definition for different shapes (lines, triangles, rectangles and pentagons),
#6c75#0275
; - the first byte is the # of edges
#6c75#0275
; - after that, each pair of bytes defines an edge.
#6c75#0275
L6c75_line_edges:
#6c75#02755
    db #02, #00, #01, #01, #00
#6c7a#027a
#6c7a#027a
; Edges for triangles:
#6c7a#027a
L6c7a_triangle_edges_top:
#6c7a#027a7
    db #03, #00, #01, #01, #02, #02, #00
#6c81#0281
L6c81_triangle_edges_bottom:
#6c81#02817
    db #03, #00, #02, #02, #01, #01, #00
#6c88#0288
#6c88#0288
; Edges for rectangles:
#6c88#0288
L6c88_rectangle_edges_top:
#6c88#02889
    db #04, #00, #01, #01, #02, #02, #03, #03, #00
#6c91#0291
L6c91_rectangle_edges_bottom:
#6c91#02919
    db #04, #00, #03, #03, #02, #02, #01, #01, #00
#6c9a#029a
#6c9a#029a
; Edges for pentagons:
#6c9a#029a
L6c9a_pentagon_edges_top:
#6c9a#029a11
    db #05, #00, #01, #01, #02, #02, #03, #03, #04, #04, #00
#6ca5#02a5
L6ca5_pentagon_edges_bottom:
#6ca5#02a511
    db #05, #00, #04, #04, #03, #03, #02, #02, #01, #01, #00
#6cb0#02b0
#6cb0#02b0
L6cb0_face_definition_for_flat_objects:
#6cb0#02b01
    db #01
#6cb1#02b18
    db #00, #06, #00, #01, #02, #03, #04, #05
#6cb9#02b9
#6cb9#02b9
#6cb9#02b9
; --------------------------------
#6cb9#02b9
L6cb9_game_text:
#6cb9#02b916
    db 0, " PRESS ANY KEY "
#6cc9#02c9
L6cc9_text_overpowered:
#6cc9#02c916
    db 0, "  OVERPOWERED  "
#6cd9#02d916
    db 1, " YOU COLLAPSE  "
#6ce9#02e916
    db 0, "    CRUSHED    "
#6cf9#02f916
    db 1, "  FATAL FALL   "
#6d09#030916
    db 0, "   ESCAPE !!   "
#6d19#031916
    db 0, "   THE CRYPT   "
#6d29#0329
L6d29_text_out_of_reach:
#6d29#032916
    db 1, " OUT OF REACH  "
#6d39#0339
L6d39_text_no_effect:
#6d39#033916
    db 0, "   NO EFFECT   "
#6d49#034916
    db 1, "   NO ENTRY    "
#6d59#035916
    db 0, "  WAY BLOCKED  "
#6d69#0369
L6d69_text_not_enough_room:
#6d69#036916
    db 0, "NOT ENOUGH ROOM"
#6d79#0379
L6d79_text_too_weak:
#6d79#037916
    db 1, "   TOO WEAK    "
#6d89#0389
L6d89_text_crawl:
#6d89#038916
    db 1, "CRAWL SELECTED "
#6d99#0399
L6d99_text_walk:
#6d99#039916
    db 0, " WALK SELECTED "
#6da9#03a9
L6da9_text_run:
#6da9#03a916
    db 1, " RUN SELECTED  "
#6db9#03b916
    db 1, " AAAAAARRRGH!  "
#6dc9#03c916
    db 0, " KEY COLLECTED "
#6dd9#03d916
    db 0, " NO KEYS FOUND "
#6de9#03e916
    db 1, "NEED RIGHT KEY "
#6df9#03f916
    db 0, "  IT IS EMPTY  "
#6e09#040916
    db 1, "  DOOR TO...   "
#6e19#041916
    db 0, "IN CASE OF FIRE"
#6e29#042916
    db 0, "CHOMP CHOMP AHH"
#6e39#043916
    db 1, "   OOOOFFF!    "
#6e49#044916
    db 1, "TREASURE FOUND "
#6e59#045916
    db 1, "THE DOOR OPENS "
#6e69#046916
    db 0, "THE DOOR CLOSES"
#6e79#047916
    db 0, "   PADLOCKED   "
#6e89#048916
    db 0, "IT'S VERY HEAVY"
#6e99#049916
    db 0, "    SMASH !    "
#6ea9#04a916
    db 0, "SHOWS LEVEL NO."
#6eb9#04b916
    db 0, "   PADLOCKED   "
#6ec9#04c916
    db 0, "HMM, NEED A BIT"
#6ed9#04d916
    db 1, "MORE SPRING IN "
#6ee9#04e916
    db 1, "YOUR STEP HERE "
#6ef9#04f916
    db 0, " THE LID OPENS "
#6f09#050916
    db 1, "THE LID CLOSES "
#6f19#051916
    db 1, "GLUG GLUG GLUG "
#6f29#052916
    db 0, "RETRY THE CHEST"
#6f39#053916
    db 1, "REVITALISATION "
#6f49#0549
L6f49_area_names:
#6f49#054916
    db 1, "  WILDERNESS   "
#6f59#055916
    db 0, "   THE CRYPT   "
#6f69#056916
    db 1, "CRYPT CORRIDOR "
#6f79#057916
    db 0, " THE MOUSETRAP "
#6f89#058916
    db 0, " LAST TREASURE "
#6f99#059916
    db 1, "   TANTALUS    "
#6fa9#05a916
    db 0, "    BELENUS    "
#6fb9#05b916
    db 0, "    POTHOLE    "
#6fc9#05c916
    db 0, "   THE STEPS   "
#6fd9#05d916
    db 1, " LOOKOUT POST  "
#6fe9#05e916
    db 1, "   KERBEROS    "
#6ff9#05f916
    db 0, "   CRYPT KEY   "
#7009#060916
    db 0, "   GATEHOUSE   "
#7019#061916
    db 0, "  BELENUS KEY  "
#7029#062916
    db 1, "SPIRITS' ABODE "
#7039#063916
    db 1, "    RAVINE     "
#7049#064916
    db 1, "  LIFT SHAFT   "
#7059#065916
    db 0, "  LEVEL 2 KEY  "
#7069#066916
    db 0, "LIFT ENTRANCE 6"
#7079#067916
    db 1, "    TUNNEL     "
#7089#068916
    db 0, "  LEVEL 3 KEY  "
#7099#069916
    db 1, "   THE TUBE    "
#70a9#06a916
    db 0, "LIFT ENTRANCE 5"
#70b9#06b916
    db 0, "     EPONA     "
#70c9#06c916
    db 0, "  LEVEL 4 KEY  "
#70d9#06d916
    db 0, "LIFT ENTRANCE 4"
#70e9#06e916
    db 0, "  NANTOSUELTA  "
#70f9#06f916
    db 0, "  STALACTITES  "
#7109#070916
    db 0, "    NO ROOM    "
#7119#071916
    db 0, "  THE TRAPEZE  "
#7129#072916
    db 1, "TREASURE CHEST "
#7139#073916
    db 0, "LIFT ENTRANCE 3"
#7149#074916
    db 1, "  THE SWITCH   "
#7159#075916
    db 1, "  THE PILLAR   "
#7169#076916
    db 1, " GROUND FLOOR  "
#7179#077916
    db 1, " THE RAT TRAP  "
#7189#078916
    db 0, "    YIN KEY    "
#7199#079916
    db 1, "     LIFT      "
#71a9#07a916
    db 0, "  TRAPEZE KEY  "
#71b9#07b916
    db 1, "   YANG KEY    "
#71c9#07c9
#71c9#07c9
#71c9#07c9
; --------------------------------
#71c9#07c9
L71c9_text_status_array:
#71c9#07c911
    db 0, "FEEBLE    "
#71d4#07d411
    db 0, "WEAK      "
#71df#07df11
    db 0, "HEALTHY   "
#71ea#07ea11
    db 0, "STRONG    "
#71f5#07f511
    db 0, "MIGHTY    "
#7200#080011
    db 0, "HERCULEAN "
#720b#080b
#720b#080b
; --------------------------------
#720b#080b
; Used to store the filename the user inputs in the load/save menu.
#720b#080b
L720b_text_input_buffer:
#720b#080b14
    db 0, "             "
#7219#08191
    db 19  ; Unused?
#721a#081a
#721a#081a
L721a_text_asterisks:
#721a#081a22
    db 0, "*********************"
#7230#0830
#7230#083013
    db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
#723d#083d16
    db #00, #00, #00, #00, #00, #00, #00, #00, #00, #00, #00, #30, #72, #30, #72, #30
#724d#084d15
    db #72, #30, #72, #30, #72, #30, #72, #30, #72, #30, #72, #30, #72, #30, #72
#725c#085c
#725c#085c
#725c#085c
; --------------------------------
#725c#085c
L725c_videomem_row_pointers:
#725c#085c16
    dw #4084, #4184, #4284, #4384, #4484, #4584, #4684, #4784
#726c#086c16
    dw #40a4, #41a4, #42a4, #43a4, #44a4, #45a4, #46a4, #47a4
#727c#087c16
    dw #40c4, #41c4, #42c4, #43c4, #44c4, #45c4, #46c4, #47c4
#728c#088c16
    dw #40e4, #41e4, #42e4, #43e4, #44e4, #45e4, #46e4, #47e4
#729c#089c16
    dw #4804, #4904, #4a04, #4b04, #4c04, #4d04, #4e04, #4f04
#72ac#08ac16
    dw #4824, #4924, #4a24, #4b24, #4c24, #4d24, #4e24, #4f24
#72bc#08bc16
    dw #4844, #4944, #4a44, #4b44, #4c44, #4d44, #4e44, #4f44
#72cc#08cc16
    dw #4864, #4964, #4a64, #4b64, #4c64, #4d64, #4e64, #4f64
#72dc#08dc16
    dw #4884, #4984, #4a84, #4b84, #4c84, #4d84, #4e84, #4f84
#72ec#08ec16
    dw #48a4, #49a4, #4aa4, #4ba4, #4ca4, #4da4, #4ea4, #4fa4
#72fc#08fc16
    dw #48c4, #49c4, #4ac4, #4bc4, #4cc4, #4dc4, #4ec4, #4fc4
#730c#090c16
    dw #48e4, #49e4, #4ae4, #4be4, #4ce4, #4de4, #4ee4, #4fe4
#731c#091c16
    dw #5004, #5104, #5204, #5304, #5404, #5504, #5604, #5704
#732c#092c16
    dw #5024, #5124, #5224, #5324, #5424, #5524, #5624, #5724
#733c#093c
#733c#093c
#733c#093c
; --------------------------------
#733c#093c
; Unused?
#733c#093c
L733c:
#733c#093c10
    db #30, #72, #30, #72, #30, #72, #30, #72, #30, #72
#7346#094610
    db #30, #72, #30, #72, #30, #72, #30, #72, #30, #72
#7350#0950
#7350#0950
L7350_compass_eye_ui_row_pointers:
#7350#0950
    ; from (25, 158) to (25, 162)    
#7350#095010
    dw #5679, #5779, #5099, #5199, #5299
#735a#095a
#735a#095a
L735a_ui_message_row_pointers:
#735a#095a
    ; from (11, 176) to (11, 183)
#735a#095a8
    dw #50cb, #51cb, #52cb, #53cb
#7362#09628
    dw #54cb, #55cb, #56cb, #57cb
#736a#096a
#736a#096a
L736a_spirit_count_ui_row_pointers:
#736a#096a
    ; from (14, 152) to (14, 159)
#736a#096a8
    dw #506e, #516e, #526e, #536e
#7372#09728
    dw #546e, #556e, #566e, #576e
#737a#097a
#737a#097a
L737a_strength_ui_row_pointers:
#737a#097a
    ; from (4, 151) to (4, 165)
#737a#097a8
    dw #5744, #5064, #5164, #5264
#7382#09828
    dw #5364, #5464, #5564, #5664
#738a#098a8
    dw #5764, #5084, #5184, #5284
#7392#09926
    dw #5384, #5484, #5584
#7398#0998
#7398#0998
L7398_key_count_ui_row_pointers:
#7398#0998
    ; from (4, 173) to (4, 186)
#7398#09988
    dw #55a4, #56a4, #57a4, #50c4
#73a0#09a08
    dw #51c4, #52c4, #53c4, #54c4
#73a8#09a88
    dw #55c4, #56c4, #57c4, #50e4
#73b0#09b04
    dw #51e4, #52e4
#73b4#09b4
#73b4#09b4
L73b4_waving_flag_row_pointers:
#73b4#09b48
    dw #451d, #461d, #471d, #403d
#73bc#09bc8
    dw #413d, #423d, #433d, #443d
#73c4#09c42
    dw #453d
#73c6#09c6
#73c6#09c6
L73c6_cosine_sine_table:
#73c6#09c6
    ; Each "dw" contains (cos, sin) (one byte each):
#73c6#09c6
    ; [-64, 64]
#73c6#09c6
    ; 72 steps is a whole turn.
#73c6#09c68
    dw #4000, #4006, #3f0b, #3e11
#73ce#09ce8
    dw #3c16, #3a1b, #3720, #3425
#73d6#09d68
    dw #3129, #2d2d, #2931, #2534
#73de#09de8
    dw #2037, #1b3a, #163c, #113e
#73e6#09e68
    dw #0b3f, #0640, #0040, #fa40
#73ee#09ee8
    dw #f53f, #ef3e, #ea3c, #e53a
#73f6#09f68
    dw #e037, #db34, #d731, #d32d
#73fe#09fe8
    dw #cf29, #cc25, #c920, #c61b
#7406#0a068
    dw #c416, #c211, #c10b, #c006
#740e#0a0e8
    dw #c000, #c0fa, #c1f5, #c2ef
#7416#0a168
    dw #c4ea, #c6e5, #c9e0, #ccdb
#741e#0a1e8
    dw #cfd7, #d3d3, #d7cf, #dbcc
#7426#0a268
    dw #e0c9, #e5c6, #eac4, #efc2
#742e#0a2e8
    dw #f5c1, #fac0, #00c0, #06c0
#7436#0a368
    dw #0bc1, #11c2, #16c4, #1bc6
#743e#0a3e8
    dw #20c9, #25cc, #29cf, #2dd3
#7446#0a468
    dw #31d7, #34db, #37e0, #3ae5
#744e#0a4e8
    dw #3cea, #3eef, #3ff5, #40fa
#7456#0a56
#7456#0a56
L7456_player_desired_x:
#7456#0a562
    dw 0
#7458#0a58
L7458_player_desired_y:
#7458#0a582
    dw 0
#745a#0a5a
L745a_player_desired_z:
#745a#0a5a2
    dw 0
#745c#0a5c1
    db #00  ; Unused?
#745d#0a5d
L745d_rendering_cube_volume:  ; max/min x, max/min y, max/min z (objects outside this will not be rendered).
#745d#0a5d6
    db #00, #00, #00, #00, #00, #00
#7463#0a63
L7463_global_area_objects:
#7463#0a632
    dw #d2c6
#7465#0a65
L7465_global_area_n_objects:
#7465#0a651
    db #4b
#7466#0a66
#7466#0a66
L7466_need_attribute_refresh_flag:
#7466#0a661
    db 1
#7467#0a67
L7467_player_starting_position_object_id:
#7467#0a671
    db #01
#7468#0a68
L7468_focus_object_id:
#7468#0a681
    db #01
#7469#0a69
L7469_n_spirits_found_in_current_area:
#7469#0a691
    db #00
#746a#0a6a
L746a_current_drawing_texture_id:
#746a#0a6a1
    db #00
#746b#0a6b
L746b_n_objects_to_draw:
#746b#0a6b1
    db #00
#746c#0a6c
L746c_game_flags:
#746c#0a6c2
    db #fd, #ff  ; 1st byte :
#746e#0a6e
                ; - bit 0: ????
#746e#0a6e
                ; - bit 1: game over indicator.
#746e#0a6e
                ; - bit 2: indicates that we need to "reproject" 3d objects to the 2d viewport.
#746e#0a6e
                ; - bit 3: ????
#746e#0a6e
                ; - bit 4/5: trigger redraw of compass eye.
#746e#0a6e
                ; - bit 6: ????
#746e#0a6e
                ; - bit 7: ????
#746e#0a6e
                ; 2nd byte: 
#746e#0a6e
                ; - bit 0: ????
#746e#0a6e
                ; - bit 1: ????
#746e#0a6e
                ; - bit 2: ????
#746e#0a6e
                ; - bit 3: trigger a re-render.
#746e#0a6e
                ; - bit 4: flag to refresh spirit meter.
#746e#0a6e
                ; - bit 5: in the update function, it triggers waiting until interrupt timer is 0, and then reprints the current room name.
#746e#0a6e
                ; - bit 6: flag to refresh # of keys in UI.
#746e#0a6e
                ; - bit 7: flag to redraw keys in the UI.
#746e#0a6e
L746e_global_rules_ptr:
#746e#0a6e2
    dw #d11f
#7470#0a70
L7470_previous_area_id:  ; Set when a RULE_TYPE_TELEPORT is triggered, but it is unused.
#7470#0a701
    db #00
#7471#0a71
L7471_event_rule_found:  ; 1 indicates that a rule for the corresponding event was found (0 otherwise).
#7471#0a711
    db #00
#7472#0a72
L7472_symbol_shift_pressed:
#7472#0a721
    db 0  ; 0 = not pressed, 1 = pressed.
#7473#0a73
L7473_timer_event:  ; every time L6b22_time_unit6 changes, this is set to 8.
#7473#0a731
    db #00
#7474#0a74
L7474_check_if_object_crushed_player_flag:
#7474#0a741
    db #00
#7475#0a75
L7475_call_Lcba4_check_for_player_falling_flag:  ; Indicates whether we should call Lcba4_check_for_player_falling this game cycle.
#7475#0a751
    db #01
#7476#0a76
L7476_trigger_collision_event_flag:  ; If this is "1" after the player has tried to move, it means we collided with an object.
#7476#0a761
    db #00
#7477#0a77
L7477_render_buffer_effect:
#7477#0a771
    db #02
#7478#0a78
L7478_interrupt_executed_flag:  ; some methods use this to wait for the interrupt to be executed.
#7478#0a781
    db #01
#7479#0a79
L7479_current_game_state:
#7479#0a79
    ; This is:
#7479#0a79
    ; - 0: for when player is controlling
#7479#0a79
    ; - 1: some times game state is 1 even not at game over (e.g. before game starts).
#7479#0a79
    ; - 1-5: when game is over (and number identifies the reason, including successful escape!)
#7479#0a79
    ; - 6: for when in the load/save/quit menu
#7479#0a791
    db #01
#747a#0a7a
L747a_requested_SFX:
#747a#0a7a1
    db #00
#747b#0a7b
L747b:  ; Unused, set to 63 at game start, unused afterwards.
#747b#0a7b1
    db #3f
#747c#0a7c
L747c_within_interrupt_flag:
#747c#0a7c1
    db 0  ; This is changed to #80 when we are inside the interrupt.
#747d#0a7d
#747d#0a7d
L747d:  ; Note: This saves the value of "iy" at game start, and restores it each time tape is accessed.
#747d#0a7d
        ; But it makes no sense, as the tape load/save functions do not make use of iy. Very strange!
#747d#0a7d2
    dw #5c3a
#747f#0a7f
L747f_player_event:  ; player events (they can be "or-ed"): 1: moving, 2: interact, 4: trow rock
#747f#0a7f1
    db #00
#7480#0a80
L7480_under_pointer_object_ID:  ; stores the ID of the object under the player pointer.
#7480#0a801
    db #00
#7481#0a81
L7481_n_objects_covering_the_whole_screen:
#7481#0a811
    db 0
#7482#0a82
; Copy of the projected vertex coordinates used by the Lb607_find_object_under_pointer
#7482#0a82
; function:
#7482#0a82
L7482_object_under_pointer__current_face_vertices:
#7482#0a8210
    db #00, #00, #00, #00, #00, #00, #00, #00, #00, #00
#748c#0a8c10
    db #00, #00, #00, #00, #00, #00, #00, #00, #00, #00
#7496#0a96
L7496_current_drawing_primitive_n_vertices:
#7496#0a961
    db #00
#7497#0a97
L7497_next_projected_vertex_ptr:  ; initialized at 'L67f4_projected_vertex_data', and keeps increasing as we project objects from 3d to 2d.
#7497#0a972
    dw #0000
#7499#0a99
L7499_3d_object_bounding_box_relative_to_player_ptr:
#7499#0a992
    dw #0000
#749b#0a9b
L749b_next_object_projected_data_ptr:
#749b#0a9b2
    dw #0000
#749d#0a9d
L749d_object_currently_being_processed_ptr:
#749d#0a9d2
    dw #0000
#749f#0a9f
L749f_number_of_pressed_keys:
#749f#0a9f1
    db #00
#74a0#0aa0
L74a0_pressed_keys_buffer:
#74a0#0aa05
    db #ef, #4e, #cd, #77, #66
#74a5#0aa5
L74a5_interrupt_timer:
#74a5#0aa51
    db #00  ; Decreases by 1 at each interrupt until reaching 0. It is used by the game to create pauses.
#74a6#0aa6
L74a6_player_movement_delta:
#74a6#0aa66
    dw #0000, #0000, #0000
#74ac#0aac
; These two sets of coordinates are used to define the volume the player will traverse when moving.
#74ac#0aac
; It is used because, due to the low frame rate, the player moves in very large steps, and we need
#74ac#0aac
; to ensure small objects are not skipped.
#74ac#0aac
L74ac_movement_volume_max_coordinate:
#74ac#0aac6
    dw #0000, #0000, #0000
#74b2#0ab2
L74b2_movement_volume_min_coordinate:
#74b2#0ab26
    dw #0000, #0000, #0000
#74b8#0ab8
; These 3 sets of coordinates are used in the "Lab6d_correct_player_movement_if_collision_internal"
#74b8#0ab8
; function to store the target movement position after correcting them in case there is a
#74b8#0ab8
; collision with an object.
#74b8#0ab8
L74b8_collision_corrected_coordinates_2:
#74b8#0ab86
    dw #0000, #0000, #0000
#74be#0abe
L74be_collision_corrected_climb_coordinates:
#74be#0abe6
    dw #0000, #0000, #0000
#74c4#0ac4
L74c4_collision_corrected_coordinates_1:
#74c4#0ac46
    dw #0000, #0000, #0000
#74ca#0aca
L74ca_movement_target_coordinates_2:  ; used when there is falling involved in movement
#74ca#0aca6
    dw #0000, #0000, #0000
#74d0#0ad0
L74d0_target_object_climb_coordinates:
#74d0#0ad02
    dw #0000  ; x
#74d2#0ad22
    dw #0000  ; y
#74d4#0ad42
    dw #0000  ; z
#74d6#0ad6
L74d6_movement_target_coordinates_1:  ; used when there is no falling involved in movement
#74d6#0ad66
    dw #0000, #0000, #0000
#74dc#0adc
L74dc_falling_reference_coordinates:
#74dc#0adc6
    dw #0000, #0000, #0000
#74e2#0ae2
L74e2_movement_direction_bits:
#74e2#0ae2
    ; bit 0 means negative movement on x, bit 1 means positive movement on y
#74e2#0ae2
    ; bits 2, 3 the same for y, and 4, 5 the same for z.
#74e2#0ae21
    db #00
#74e3#0ae3
L74e3_player_height_16bits:  ; (L6ab9_player_height) * 64
#74e3#0ae32
    dw #0000
#74e5#0ae5
L74e5_collision_correction_object_shape_type:  ; the game prefers 3d shapes to 2d shapes when correcting movement upon collisions. This variable is used to implemetn such preference.
#74e5#0ae51
    db #00
#74e6#0ae6
L74e6_movement_involves_falling_flag:  ; 0: no falling, 1: we fell
#74e6#0ae61
    db #00
#74e7#0ae7
L74e7_closest_object_below_distance:
#74e7#0ae72
    dw #0000
#74e9#0ae9
L74e9_closest_object_below_ptr:
#74e9#0ae92
    dw #0000
#74eb#0aeb
L74eb_closest_object_below_ID:
#74eb#0aeb1
    db #00
#74ec#0aec
L74ec_previous_pressed_keys_buffer:
#74ec#0aec5
    db #16, #5e, #3a, #d6, #1f
#74f1#0af1
L74f1:  ; Note: I believe this is unused (written, but never read)
#74f1#0af11
    db #0e
#74f2#0af2
L74f2_keyboard_input:  ; 8 bytes, one per keyboard half row
#74f2#0af28
    db #00, #00, #00, #00, #00, #00, #00, #00
#74fa#0afa
#74fa#0afa
L74fa_object_under_pointer__current_face:  ; saves the pointer to the current face we are checking when trying to find which object is under the pointer.
#74fa#0afa2
    dw #0c67
#74fc#0afc
#74fc#0afc
L74fc_object_under_pointer__projected_xs_at_pointer_y:
#74fc#0afc1
    db #18  ; number of points in the lsit below
#74fd#0afd5
    db #f5, #c6, #30, #23, #77  ; screen x coordinates of face edges at the y coordinate of the pointer.
#7502#0b02
                                ; Used by the "Lb607_find_object_under_pointer" function, to determine
#7502#0b02
                                ; which object is under the player pointer.
#7502#0b02
#7502#0b02
; --------------------------------
#7502#0b02
; Rendering variables:
#7502#0b02
L7502_sp_tmp:  ; Used to temporarily save the 'sp' register.
#7502#0b022
    dw 0
#7504#0b04
L7504_line_drawing_slope:  ; Amount we need to move in the X axis each time we move one pixel in the Y axis.
#7504#0b042
    dw #0000  ; Uses fixed point arithmetic (with 8 bits of decimal part).
#7506#0b06
L7506_polygon_drawing_second_slope:  ; When drawing polygons, we calculate two lines at once, and draw 
#7506#0b062
    dw #0000  ; horizontal lines between them. This is the slopw of the second line.
#7508#0b08
L7508_current_drawing_row:
#7508#0b081
    db #00
#7509#0b09
L7509_line_drawing_thinning_direction:
#7509#0b091
    db #00
#750a#0b0a
L750a_first_loop_flags:  ; Used to indicate if we have drawn at least one pixel when drawing polygons.
#750a#0b0a1
    db #00
#750b#0b0b
L750b_current_drawing_n_vertices_left:  ; How many vertices are there to draw in the current primitive.
#750b#0b0b1
    db 0
#750c#0b0c
L750c_current_drawing_row_ptr:
#750c#0b0c2
    dw 0
#750e#0b0e
L750e_current_drawing_texture_ptr:
#750e#0b0e2
    dw 0
#7510#0b10
L7510_current_drawing_2d_vertex_buffer:
#7510#0b108
    db #00, #00, #00, #00, #00, #00, #00, #00
#7518#0b188
    db #00, #00, #00, #00, #00, #00, #00, #00
#7520#0b208
    db #00, #00, #00, #00, #00, #00, #00, #00
#7528#0b288
    db #00, #00, #00, #00, #00, #00, #00, #00
#7530#0b308
    db #00, #00, #00, #00, #00, #00, #00, #00
#7538#0b38
#7538#0b38
; --------------------------------
#7538#0b38
L7538_text_spaces:
#7538#0b3815
    db 0, "              "
#7547#0b47
L7547_text_play_record:
#7547#0b4715
    db 0, "PLAY & RECORD,"
#7556#0b56
L7556_text_invalid_file:
#7556#0b5615
    db 0, "INVALID FILE  "
#7565#0b65
L7565_text_loading_error:
#7565#0b6515
    db 0, "LOADING ERROR "
#7574#0b74
L7574_text_loading:
#7574#0b7415
    db 0, "LOADING :     "
#7583#0b83
L7583_text_then_any_key:
#7583#0b8315
    db 0, "THEN ANY KEY  "
#7592#0b92
L7592_text_saving_file:
#7592#0b9215
    db 0, "SAVING FILE   "
#75a1#0ba1
L75a1_text_found:
#75a1#0ba115
    db 0, "FOUND :       "
#75b0#0bb0
L75b0_text_searching:
#75b0#0bb015
    db 0, "SEARCHING     "
#75bf#0bbf
#75bf#0bbf
; --------------------------------
#75bf#0bbf
L75bf_SFX_table:
#75bf#0bbf4
    db 30, #59, #00, #01  ; 30,  89 (dw), 1
#75c3#0bc34
    db 18, #47, #00, #01  ; 18,  71 (dw), 1
#75c7#0bc74
    db 1, #ef, #00, #01  ;  1, 239 (dw), 1
#75cb#0bcb4
    db 9, #00, #03, #01  ;  9, 768 (dw), 1
#75cf#0bcf4
    db 2, #00, #00, #01  ;  2,   0 (dw), 1
#75d3#0bd34
    db 8, #50, #00, #01  ;  8,  90 (dw), 1
#75d7#0bd74
    db 26, #00, #03, #03  ; 26, 768 (dw), 3
#75db#0bdb4
    db 11, #02, #00, #01  ; 11,   2 (dw), 1
#75df#0bdf4
    db 30, #59, #00, #01  ; ...
#75e3#0be34
    db 13, #43, #00, #0c
#75e7#0be74
    db 22, #f7, #09, #01
#75eb#0beb4
    db 0, #77, #00, #01
#75ef#0bef4
    db 4, #52, #01, #01
#75f3#0bf34
    db 28, #96, #00, #08
#75f7#0bf74
    db 16, #00, #00, #09
#75fb#0bfb
L75fb_SFX_data:
#75fb#0bfb4
    db #01, #17, #01, #01
#75ff#0bff4
    db #01, #02, #81, #04
#7603#0c034
    db #81, #2e, #00, #01
#7607#0c074
    db #00, #14, #00, #00
#760b#0c0b4
    db #04, #02, #81, #10
#760f#0c0f4
    db #07, #ff, #0a, #34
#7613#0c134
    db #ff, #01, #06, #00
#7617#0c174
    db #02, #00, #00, #00
#761b#0c1b4
    db #01, #7f, #01, #03
#761f#0c1f4
    db #81, #4c, #00, #01
#7623#0c234
    db #00, #f6, #ff, #00
#7627#0c274
    db #81, #20, #00, #02
#762b#0c2b4
    db #00, #30, #00, #00
#762f#0c2f4
    db #03, #06, #00, #01
#7633#0c334
    db #04, #01, #02, #08
#7637#0c374
    db #ff, #01, #00, #00
#763b#0c3b4
    db #80, #07, #02, #00
#763f#0c3f4
    db #00, #00, #00, #00
#7643#0c434
    db #05, #02, #7f, #04
#7647#0c474
    db #02, #7f, #0a, #03
#764b#0c4b4
    db #7f, #0f, #06, #7f
#764f#0c4f4
    db #10, #06, #7f, #22
#7653#0c534
    db #04, #02, #81, #43
#7657#0c574
    db #04, #81, #0a, #08
#765b#0c5b4
    db #81, #0a, #05, #81
#765f#0c5f4
    db #09, #00, #00, #00
#7663#0c634
    db #81, #4c, #00, #01
#7667#0c674
    db #00, #fa, #ff, #00
#766b#0c6b4
    db #02, #04, #7f, #02
#766f#0c6f4
    db #04, #81, #04, #00
#7673#0c734
    db #04, #03, #7f, #03
#7677#0c774
    db #04, #7f, #05, #07
#767b#0c7b4
    db #7f, #06, #06, #00
#767f#0c7f4
    db #04, #00, #00, #00
#7683#0c83
#7683#0c83
L7683_control_mode:
#7683#0c831
    db #00  ; Current control mode:
#7684#0c84
            ; 0: keyboard
#7684#0c84
            ; 1: sinclair joystick
#7684#0c84
            ; 2: kempston joystick
#7684#0c84
            ; 3: cursor joystick
#7684#0c84
#7684#0c84
#7684#0c84
; --------------------------------
#7684#0c84
; Input mapping (table that assigns keys to game functions).
#7684#0c84
L7684_input_mapping:
#7684#0c84
    ; Each row has 3 values: (key, game function while in movement, game function while in pointer)
#7684#0c843
    db "7", INPUT_FORWARD, INPUT_MOVE_POINTER_UP
#7687#0c873
    db "O", INPUT_FORWARD, INPUT_MOVE_POINTER_UP
#768a#0c8a3
    db #91, INPUT_FORWARD, INPUT_MOVE_POINTER_UP
#768d#0c8d3
    db "6", INPUT_BACKWARD, INPUT_MOVE_POINTER_DOWN
#7690#0c903
    db "K", INPUT_BACKWARD, INPUT_MOVE_POINTER_DOWN
#7693#0c933
    db #92, INPUT_BACKWARD, INPUT_MOVE_POINTER_DOWN
#7696#0c963
    db "5", INPUT_TURN_LEFT, INPUT_MOVE_POINTER_LEFT
#7699#0c993
    db "Z", INPUT_TURN_LEFT, INPUT_MOVE_POINTER_LEFT
#769c#0c9c3
    db #93, INPUT_TURN_LEFT, INPUT_MOVE_POINTER_LEFT
#769f#0c9f3
    db "8", INPUT_TURN_RIGHT, INPUT_MOVE_POINTER_RIGHT
#76a2#0ca23
    db "X", INPUT_TURN_RIGHT, INPUT_MOVE_POINTER_RIGHT
#76a5#0ca53
    db #94, INPUT_TURN_RIGHT, INPUT_MOVE_POINTER_RIGHT
#76a8#0ca8
    ; Each row has 2 values: (key, game function)
#76a8#0ca82
    db "0", INPUT_THROW_ROCK
#76aa#0caa2
    db #95, INPUT_THROW_ROCK
#76ac#0cac2
    db "B", INPUT_MOVEMENT_POINTER_ON_OFF
#76ae#0cae2
    db "C", INPUT_CRAWL
#76b0#0cb02
    db "W", INPUT_WALK
#76b2#0cb22
    db "R", INPUT_RUN
#76b4#0cb42
    db " ", INPUT_SWITCH_BETWEEN_MOVEMENT_AND_POINTER
#76b6#0cb62
    db "A", INPUT_ACTION
#76b8#0cb82
    db "U", INPUT_U_TURN
#76ba#0cba2
    db "F", INPUT_FACE_FORWARD
#76bc#0cbc2
    db "P", INPUT_LOOK_UP
#76be#0cbe2
    db "L", INPUT_LOOK_DOWN
#76c0#0cc02
    db "I", INPUT_INFO_MENU
#76c2#0cc2
#76c2#0cc2
; Temporary sprite attribute buffer for method Lcc19_draw_viewport_sprite_with_offset:
#76c2#0cc2
L76c2_buffer_sprite_x:
#76c2#0cc21
    db 0
#76c3#0cc3
L76c3_buffer_sprite_y:
#76c3#0cc31
    db 0
#76c4#0cc4
L76c4_buffer_sprite_width:
#76c4#0cc41
    db 0
#76c5#0cc5
L76c5_buffer_sprite_height:
#76c5#0cc51
    db 0
#76c6#0cc6
L76c6_buffer_sprite_ptr:
#76c6#0cc62
    dw #0000
#76c8#0cc8
L76c8_buffer_sprite_bytes_to_skip_at_start:
#76c8#0cc81
    db #00
#76c9#0cc91
    db #00  ; unused
#76ca#0cca
L76ca_bytes_to_skip_after_row:
#76ca#0cca1
    db #00
#76cb#0ccb1
    db #00  ; unused
#76cc#0ccc
#76cc#0ccc
L76cc_ui_key_bg_sprite:
#76cc#0ccc3
    db 6, 14, #ff  ; width, height, and-mask
#76cf#0ccf2
    dw 84  ; frame size
#76d1#0cd16
    db #63, #ff, #ff, #ff, #ff, #f8
#76d7#0cd76
    db #41, #ff, #ff, #ff, #ff, #f0
#76dd#0cdd6
    db #41, #ff, #ff, #ff, #ff, #f0
#76e3#0ce36
    db #54, #00, #00, #00, #00, #05
#76e9#0ce96
    db #40, #00, #00, #00, #00, #00
#76ef#0cef6
    db #55, #55, #55, #55, #55, #55
#76f5#0cf56
    db #41, #ff, #ff, #ff, #ff, #f0
#76fb#0cfb6
    db #41, #ff, #ff, #ff, #ff, #f0
#7701#0d016
    db #63, #ff, #ff, #ff, #ff, #f8
#7707#0d076
    db #7f, #ff, #ff, #ff, #ff, #ff
#770d#0d0d6
    db #bf, #ff, #ff, #ff, #ff, #ff
#7713#0d136
    db #aa, #ba, #aa, #af, #ba, #a8
#7719#0d196
    db #27, #47, #7e, #aa, #aa, #aa
#771f#0d1f6
    db #55, #55, #75, #55, #55, #55  ; MDL bitmap visualization
#7725#0d25
#7725#0d25
L7725_ui_key_sprite:
#7725#0d253
    db 1, 14, #fc  ; width, height, and-mask
#7728#0d282
    dw 14  ; frame size
#772a#0d2a14
    db #fc, #80, #b8, #08, #08, #f8, #80, #ec, #ec, #ec, #ec, #74, #34, #74  ; MDL bitmap visualization
#7738#0d38
#7738#0d38
L7738_ui_spirit_meter_bg_sprite:
#7738#0d383
    db 8, 8, #ff  ; width, height, and-mask
#773b#0d3b2
    dw 72  ; frame size
#773d#0d3d
           ; Note: this value is wrong, it should be 64, but it does not matter, as there is only one frame in this sprite.
#773d#0d3d8
    db #ff, #ff, #ff, #ff, #ff, #ff, #ff, #ff
#7745#0d458
    db #ff, #ff, #ff, #ff, #ff, #ff, #ff, #ff
#774d#0d4d8
    db #ff, #ff, #ff, #ff, #ff, #ff, #ff, #ff
#7755#0d558
    db #fb, #ff, #ff, #ff, #ff, #ff, #fd, #ff
#775d#0d5d8
    db #ff, #ff, #ff, #ff, #ff, #ff, #df, #ff
#7765#0d658
    db #ff, #ef, #ff, #bf, #ef, #ff, #ff, #bb
#776d#0d6d8
    db #ff, #7f, #f7, #ff, #ff, #fe, #ff, #ff
#7775#0d758
    db #ff, #ff, #ff, #ff, #ff, #ff, #ff, #ff  ; MDL bitmap visualization
#777d#0d7d
#777d#0d7d
L777d_ui_spirit_meter_indicator_sprite:
#777d#0d7d3
    db 2, 8, #fc  ; width, height, and-mask
#7780#0d802
    dw 16  ; frame size
#7782#0d828
    db #f0, #3f, #c0, #0f, #82, #87, #01, #43
#778a#0d8a8
    db #00, #03, #80, #07, #c0, #0f, #f0, #3f  ; MDL bitmap visualization
#7792#0d92
#7792#0d92
L7792_ui_compass_eye_sprites:
#7792#0d923
    db 2, 5, #ff
#7795#0d952
    dw 10
#7797#0d9710
    db #00, #fc, #43, #df, #73, #87, #43, #cf, #00, #fc  ; MDL bitmap visualization
#77a1#0da110
    db #00, #dc, #43, #87, #73, #cf, #43, #ff, #00, #fc  ; MDL bitmap visualization
#77ab#0dab10
    db #00, #fc, #43, #ff, #73, #df, #43, #87, #00, #cc  ; MDL bitmap visualization
#77b5#0db510
    db #00, #fc, #43, #7f, #72, #1f, #43, #3f, #01, #fc  ; MDL bitmap visualization
#77bf#0dbf10
    db #00, #fc, #43, #f7, #73, #e1, #43, #f3, #00, #fc  ; MDL bitmap visualization
#77c9#0dc910
    db #00, #00, #40, #d8, #73, #87, #43, #cf, #00, #fc  ; MDL bitmap visualization
#77d3#0dd310
    db #00, #00, #40, #00, #71, #8c, #43, #cf, #00, #fc  ; MDL bitmap visualization
#77dd#0ddd10
    db #00, #00, #40, #00, #70, #00, #43, #ce, #00, #fc  ; MDL bitmap visualization
#77e7#0de710
    db #00, #00, #40, #00, #70, #00, #40, #00, #00, #00  ; MDL bitmap visualization
#77f1#0df110
    db #00, #fc, #43, #cf, #73, #87, #43, #cf, #00, #fc  ; MDL bitmap visualization
#77fb#0dfb10
    db #00, #fc, #43, #ff, #73, #cf, #43, #cf, #00, #fc  ; MDL bitmap visualization
#7805#0e05
#7805#0e05
L7805_ui_strength_bg_sprite:
#7805#0e053
    db 9, 15, #ff  ; width, height, and-mask
#7808#0e082
    dw 135  ; frame size
#780a#0e0a9
    db #00, #00, #00, #00, #00, #00, #00, #00, #00
#7813#0e139
    db #00, #00, #00, #00, #00, #00, #00, #00, #00
#781c#0e1c9
    db #00, #00, #00, #00, #00, #00, #00, #00, #00
#7825#0e259
    db #00, #00, #00, #00, #00, #00, #00, #00, #00
#782e#0e2e9
    db #00, #00, #00, #00, #00, #00, #00, #00, #00
#7837#0e379
    db #00, #00, #00, #00, #00, #00, #00, #00, #00
#7840#0e409
    db #00, #00, #00, #00, #00, #00, #00, #00, #00
#7849#0e499
    db #00, #00, #00, #00, #00, #00, #00, #00, #00
#7852#0e529
    db #00, #00, #00, #00, #00, #00, #00, #00, #00
#785b#0e5b9
    db #00, #00, #00, #00, #00, #00, #00, #00, #00
#7864#0e649
    db #00, #00, #00, #00, #00, #00, #00, #00, #00
#786d#0e6d9
    db #00, #00, #15, #55, #55, #55, #50, #00, #00
#7876#0e769
    db #0a, #aa, #aa, #aa, #aa, #aa, #aa, #aa, #a0
#787f#0e7f9
    db #1f, #ff, #ff, #ff, #ff, #ff, #ff, #ff, #f8
#7888#0e889
    db #3f, #ff, #ff, #ff, #ff, #ff, #ff, #ff, #fc  ; MDL bitmap visualization
#7891#0e91
#7891#0e91
L7891_ui_strength_bar_sprite:
#7891#0e913
    db 9, 3, #ff
#7894#0e942
    dw 27
#7896#0e969
    db #1f, #ff, #ff, #ff, #ff, #ff, #ff, #ff, #f8
#789f#0e9f9
    db #1f, #ff, #ff, #ff, #ff, #ff, #ff, #ff, #f8
#78a8#0ea89
    db #0a, #aa, #aa, #aa, #aa, #aa, #aa, #aa, #a8  ; MDL bitmap visualization
#78b1#0eb1
#78b1#0eb1
L78b1_ui_strength_weight_sprite:
#78b1#0eb13
    db #01, #0f, #f0
#78b4#0eb42
    dw #000f
#78b6#0eb615
    db #60, #60, #60, #60, #60, #60, #60, #60, #60, #60, #60, #60, #60, #40, #20  ; MDL bitmap visualization
#78c5#0ec515
    db #00, #60, #60, #60, #60, #60, #60, #60, #60, #60, #60, #60, #40, #20, #f0  ; MDL bitmap visualization
#78d4#0ed415
    db #00, #00, #60, #60, #60, #60, #60, #60, #60, #60, #60, #40, #20, #f0, #f0  ; MDL bitmap visualization
#78e3#0ee315
    db #00, #00, #00, #60, #60, #60, #60, #60, #60, #60, #40, #20, #f0, #f0, #f0  ; MDL bitmap visualization
#78f2#0ef2
#78f2#0ef2
L78f2_background_mountains_gfx:
#78f2#0ef216
    db #06, #00, #00, #10, #00, #00, #00, #00, #00, #00, #0c, #00, #00, #00, #00, #00
#7902#0f0216
    db #0b, #00, #00, #38, #01, #a0, #00, #00, #00, #00, #1e, #30, #00, #00, #00, #00
#7912#0f1216
    db #17, #80, #00, #7c, #03, #d0, #00, #00, #01, #00, #3f, #5c, #80, #00, #18, #00
#7922#0f2216
    db #23, #c0, #00, #fe, #0d, #fe, #06, #00, #02, #80, #7e, #be, #c0, #00, #3c, #00
#7932#0f3216
    db #47, #e0, #01, #57, #56, #ff, #0f, #80, #05, #40, #f5, #fb, #40, #00, #76, #00
#7942#0f4216
    db #93, #d0, #0a, #ab, #ab, #ff, #af, #c3, #2a, #a1, #eb, #fe, #a8, #00, #de, #00
#7952#0f5216
    db #21, #a8, #75, #55, #41, #ff, #d6, #ef, #d5, #53, #57, #fc, #14, #01, #b7, #07
#7962#0f6216
    db #42, #d5, #ea, #aa, #92, #fb, #eb, #ab, #ea, #aa, #ae, #fa, #4a, #82, #ea, #be
#7972#0f7216
    db #97, #ab, #d5, #55, #25, #dd, #75, #45, #f5, #55, #7d, #dd, #25, #55, #d5, #54
#7982#0f8216
    db #2f, #f7, #aa, #aa, #53, #ea, #a8, #13, #fa, #aa, #ea, #be, #42, #ab, #aa, #a9
#7992#0f9216
    db #5f, #dd, #d5, #55, #07, #55, #02, #45, #fd, #51, #55, #57, #15, #57, #d5, #52
#79a2#0fa216
    db #af, #ee, #fa, #aa, #2b, #aa, #80, #8b, #fe, #aa, #aa, #ae, #aa, #be, #aa, #a4
#79b2#0fb216
    db #5a, #b5, #5d, #5c, #56, #d5, #29, #1f, #ff, #55, #55, #5b, #55, #7d, #55, #09
#79c2#0fc216
    db #b5, #5a, #af, #ba, #ad, #aa, #92, #3e, #bf, #ea, #aa, #af, #ab, #ea, #aa, #02
#79d2#0fd216
    db #5a, #f5, #55, #fd, #57, #55, #05, #5f, #57, #fd, #55, #55, #57, #55, #50, #15
#79e2#0fe216
    db #af, #ba, #aa, #fe, #ae, #fa, #aa, #be, #aa, #bf, #aa, #aa, #aa, #aa, #82, #aa
#79f2#0ff216
    db #55, #55, #55, #5f, #d5, #fd, #55, #55, #55, #5f, #fd, #55, #55, #55, #55, #55
#7a02#100216
    db #ea, #aa, #aa, #aa, #aa, #aa, #aa, #aa, #aa, #aa, #ff, #ff, #ff, #ff, #ff, #ff  ; MDL bitmap visualization
#7a12#1012
#7a12#1012
L7a12_waving_flag_gfx_properties:
#7a12#10123
    db 3, 9, #ff  ; width (in bytes), height, and-mask of last byte
#7a15#10152
    dw 27  ; 3 * 9 (bytes of each frame)
#7a17#1017
    ; Waving flag frame 1:
#7a17#10173
    db #00, #03, #f6
#7a1a#101a3
    db #00, #07, #fe
#7a1d#101d3
    db #07, #ff, #f6
#7a20#10203
    db #01, #ff, #f6
#7a23#10233
    db #00, #7f, #f6
#7a26#10263
    db #00, #1f, #f6
#7a29#10293
    db #01, #ff, #f6
#7a2c#102c3
    db #03, #ff, #7e
#7a2f#102f3
    db #03, #9f, #06  ; MDL bitmap visualization
#7a32#1032
    ; Waving flag frame 2:
#7a32#10323
    db #00, #1f, #06
#7a35#10353
    db #00, #3f, #fe
#7a38#10383
    db #0f, #ff, #f6
#7a3b#103b3
    db #01, #ff, #f6
#7a3e#103e3
    db #00, #7f, #f6
#7a41#10413
    db #00, #3f, #f6
#7a44#10443
    db #01, #ff, #f6
#7a47#10473
    db #03, #f9, #fe
#7a4a#104a3
    db #0f, #f0, #06  ; MDL bitmap visualization
#7a4d#104d
    ; Waving flag frame 3:
#7a4d#104d3
    db #00, #7e, #06
#7a50#10503
    db #01, #ff, #1e
#7a53#10533
    db #07, #ff, #f6
#7a56#10563
    db #00, #ff, #f6
#7a59#10593
    db #00, #3f, #f6
#7a5c#105c3
    db #01, #ff, #f6
#7a5f#105f3
    db #07, #ff, #f6
#7a62#10623
    db #0f, #87, #fe
#7a65#10653
    db #00, #01, #e6  ; MDL bitmap visualization
#7a68#1068
    ; Waving flag frame 4:    
#7a68#10683
    db #00, #00, #7e
#7a6b#106b3
    db #01, #fd, #f6
#7a6e#106e3
    db #07, #ff, #f6
#7a71#10713
    db #00, #7f, #f6
#7a74#10743
    db #00, #1f, #f6
#7a77#10773
    db #00, #3f, #f6
#7a7a#107a3
    db #00, #ff, #f6
#7a7d#107d3
    db #07, #ff, #fe
#7a80#10803
    db #0f, #1f, #06  ; MDL bitmap visualization
#7a83#1083
#7a83#1083
; --------------------------------
#7a83#1083
; Unused graphics?
#7a83#1083
L7a83:
#7a83#10833
    db #0f, #ff, #f0
#7a86#10863
    db #08, #00, #10
#7a89#10893
    db #09, #ff, #90
#7a8c#108c3
    db #09, #00, #90  ; MDL bitmap visualization
#7a8f#108f
#7a8f#108f
L7a8f:
#7a8f#108f5
    db #01, #07, #ff, #07, #00  ; MDL bitmap visualization
#7a94#1094
L7a94:
#7a94#10947
    db #7e, #c3, #81, #81, #81, #c3, #7e  ; MDL bitmap visualization
#7a9b#109b
#7a9b#109b
; --------------------------------
#7a9b#109b
L7a9b_lightning_gfx:
#7a9b#109b4
    db #00, #40, #00, #40
#7a9f#109f4
    db #00, #40, #00, #40
#7aa3#10a34
    db #00, #40, #00, #40
#7aa7#10a74
    db #00, #40, #00, #80
#7aab#10ab4
    db #01, #80, #01, #00
#7aaf#10af4
    db #01, #00, #02, #00
#7ab3#10b34
    db #04, #00, #08, #00
#7ab7#10b74
    db #18, #00, #10, #00
#7abb#10bb4
    db #30, #00, #20, #00
#7abf#10bf4
    db #20, #00, #20, #00
#7ac3#10c34
    db #70, #00, #50, #00
#7ac7#10c74
    db #50, #00, #88, #00
#7acb#10cb4
    db #08, #00, #04, #00
#7acf#10cf4
    db #02, #00, #02, #00
#7ad3#10d34
    db #01, #00, #01, #00
#7ad7#10d74
    db #01, #00, #00, #80
#7adb#10db4
    db #00, #c0, #00, #40
#7adf#10df4
    db #00, #20, #00, #10
#7ae3#10e34
    db #00, #08, #00, #0c
#7ae7#10e74
    db #00, #1c, #00, #32
#7aeb#10eb4
    db #00, #22, #00, #c2
#7aef#10ef4
    db #01, #81, #02, #01
#7af3#10f34
    db #02, #00, #02, #00
#7af7#10f74
    db #02, #00, #02, #00
#7afb#10fb4
    db #02, #00, #02, #00
#7aff#10ff4
    db #06, #00, #04, #00
#7b03#11034
    db #04, #00, #0c, #00
#7b07#11074
    db #18, #00, #30, #00
#7b0b#110b4
    db #20, #00, #20, #00
#7b0f#110f4
    db #70, #00, #4c, #00
#7b13#11134
    db #86, #00, #02, #00
#7b17#11174
    db #01, #00, #01, #00
#7b1b#111b4
    db #00, #80, #00, #80
#7b1f#111f4
    db #00, #80, #00, #80
#7b23#11234
    db #00, #80, #00, #80
#7b27#11274
    db #00, #80, #00, #60
#7b2b#112b4
    db #00, #30, #00, #08
#7b2f#112f4
    db #00, #08, #00, #06
#7b33#11334
    db #00, #02, #00, #02
#7b37#11374
    db #00, #02, #00, #02
#7b3b#113b4
    db #00, #02, #00, #02
#7b3f#113f4
    db #00, #03, #00, #01
#7b43#11434
    db #00, #01, #00, #00  ; MDL bitmap visualization
#7b47#1147
#7b47#1147
#7b47#1147
; --------------------------------
#7b47#1147
; Each block of 8 bytes correspods to a character. So, this includes
#7b47#1147
; a definition of the font being used, the first character is ' ':
#7b47#1147
; these tags inside comments are used to visualize the gfx using MDL with the "-mdl-asm+:html" flag.
#7b47#1147
L7b47_font:
#7b47#11478
    db #00, #00, #00, #00, #00, #00, #00, #00  ; MDL bitmap visualization
#7b4f#114f8
    db #1c, #1c, #1c, #18, #18, #00, #18, #18  ; MDL bitmap visualization
#7b57#11578
    db #66, #66, #44, #22, #00, #00, #00, #00  ; MDL bitmap visualization
#7b5f#115f8
    db #00, #7f, #7f, #7f, #7f, #7f, #7f, #00  ; MDL bitmap visualization
#7b67#11678
    db #10, #54, #38, #fe, #38, #54, #10, #00  ; MDL bitmap visualization
#7b6f#116f8
    db #3c, #42, #9d, #b1, #b1, #9d, #42, #3c  ; MDL bitmap visualization
#7b77#11778
    db #78, #cc, #cc, #78, #db, #cf, #ce, #7b  ; MDL bitmap visualization
#7b7f#117f8
    db #30, #30, #10, #20, #00, #00, #00, #00  ; MDL bitmap visualization
#7b87#11878
    db #10, #20, #40, #40, #40, #40, #20, #10  ; MDL bitmap visualization
#7b8f#118f8
    db #10, #08, #04, #04, #04, #04, #08, #10  ; MDL bitmap visualization
#7b97#11978
    db #10, #54, #38, #fe, #38, #54, #10, #00  ; MDL bitmap visualization
#7b9f#119f8
    db #00, #00, #10, #10, #7c, #10, #10, #00  ; MDL bitmap visualization
#7ba7#11a78
    db #00, #00, #00, #00, #18, #18, #08, #10  ; MDL bitmap visualization
#7baf#11af8
    db #00, #00, #00, #00, #3c, #00, #00, #00  ; MDL bitmap visualization
#7bb7#11b78
    db #00, #00, #00, #00, #00, #00, #18, #18  ; MDL bitmap visualization
#7bbf#11bf8
    db #01, #02, #04, #08, #10, #20, #40, #80  ; MDL bitmap visualization
#7bc7#11c78
    db #18, #66, #c3, #c3, #c3, #c3, #66, #18  ; MDL bitmap visualization
#7bcf#11cf8
    db #18, #38, #18, #18, #18, #18, #18, #18  ; MDL bitmap visualization
#7bd7#11d78
    db #9e, #61, #01, #7e, #e0, #c6, #e3, #fe  ; MDL bitmap visualization
#7bdf#11df8
    db #ee, #73, #03, #3e, #03, #01, #7f, #e6  ; MDL bitmap visualization
#7be7#11e78
    db #0e, #1c, #38, #71, #fd, #e6, #0c, #0c  ; MDL bitmap visualization
#7bef#11ef8
    db #fd, #86, #80, #7e, #07, #63, #c7, #7c  ; MDL bitmap visualization
#7bf7#11f78
    db #3d, #66, #c0, #f0, #fc, #c6, #66, #3c  ; MDL bitmap visualization
#7bff#11ff8
    db #b3, #4e, #06, #0c, #0c, #18, #18, #3c  ; MDL bitmap visualization
#7c07#12078
    db #7c, #c6, #c6, #7c, #c6, #c2, #fe, #4c  ; MDL bitmap visualization
#7c0f#120f8
    db #3c, #4e, #c6, #c6, #4e, #36, #46, #3c  ; MDL bitmap visualization
#7c17#12178
    db #00, #18, #18, #00, #00, #18, #18, #00  ; MDL bitmap visualization
#7c1f#121f8
    db #00, #18, #18, #00, #00, #18, #08, #10  ; MDL bitmap visualization
#7c27#12278
    db #03, #0c, #30, #c0, #30, #0c, #03, #00  ; MDL bitmap visualization
#7c2f#122f8
    db #00, #00, #ff, #00, #ff, #00, #00, #00  ; MDL bitmap visualization
#7c37#12378
    db #c0, #30, #0c, #03, #0c, #30, #c0, #00  ; MDL bitmap visualization
#7c3f#123f8
    db #7c, #c6, #06, #0c, #30, #30, #00, #30  ; MDL bitmap visualization
#7c47#12478
    db #00, #08, #0c, #fe, #ff, #fe, #0c, #08  ; MDL bitmap visualization
#7c4f#124f8
    db #1e, #1c, #1e, #66, #be, #26, #43, #e3  ; MDL bitmap visualization
#7c57#12578
    db #ee, #73, #23, #3e, #23, #21, #7f, #e6  ; MDL bitmap visualization
#7c5f#125f8
    db #39, #6e, #c6, #c0, #c0, #c2, #63, #3e  ; MDL bitmap visualization
#7c67#12678
    db #ec, #72, #23, #23, #23, #23, #72, #ec  ; MDL bitmap visualization
#7c6f#126f8
    db #ce, #7f, #61, #6c, #78, #61, #7f, #ce  ; MDL bitmap visualization
#7c77#12778
    db #ce, #7f, #61, #6c, #78, #60, #60, #f0  ; MDL bitmap visualization
#7c7f#127f8
    db #3d, #66, #c0, #c1, #ce, #c6, #66, #3c  ; MDL bitmap visualization
#7c87#12878
    db #e7, #66, #66, #6e, #76, #66, #66, #e7  ; MDL bitmap visualization
#7c8f#128f8
    db #66, #3c, #18, #18, #18, #18, #3c, #66  ; MDL bitmap visualization
#7c97#12978
    db #33, #1e, #0c, #8c, #4c, #cc, #dc, #78  ; MDL bitmap visualization
#7c9f#129f8
    db #f2, #67, #64, #68, #7e, #66, #66, #f3  ; MDL bitmap visualization
#7ca7#12a78
    db #d8, #70, #60, #60, #66, #61, #f3, #7e  ; MDL bitmap visualization
#7caf#12af8
    db #c3, #66, #6e, #76, #56, #46, #46, #ef  ; MDL bitmap visualization
#7cb7#12b78
    db #87, #62, #72, #7a, #5e, #4e, #46, #e1  ; MDL bitmap visualization
#7cbf#12bf8
    db #18, #66, #c3, #c3, #c3, #c3, #66, #18  ; MDL bitmap visualization
#7cc7#12c78
    db #ec, #72, #63, #63, #72, #6c, #60, #f0  ; MDL bitmap visualization
#7ccf#12cf8
    db #3c, #66, #c3, #c3, #66, #3c, #31, #1e  ; MDL bitmap visualization
#7cd7#12d78
    db #ec, #72, #63, #63, #76, #6c, #66, #f1  ; MDL bitmap visualization
#7cdf#12df8
    db #79, #86, #80, #7e, #07, #63, #c7, #7c  ; MDL bitmap visualization
#7ce7#12e78
    db #01, #7f, #fe, #98, #58, #18, #18, #3c  ; MDL bitmap visualization
#7cef#12ef8
    db #f7, #62, #62, #62, #62, #62, #f2, #3c  ; MDL bitmap visualization
#7cf7#12f78
    db #f3, #61, #72, #72, #32, #32, #1c, #3e  ; MDL bitmap visualization
#7cff#12ff8
    db #c3, #62, #62, #6a, #6e, #76, #66, #c3  ; MDL bitmap visualization
#7d07#13078
    db #f3, #72, #3c, #38, #1c, #3c, #4e, #cf  ; MDL bitmap visualization
#7d0f#130f8
    db #e3, #72, #34, #38, #18, #18, #18, #3c  ; MDL bitmap visualization
#7d17#13178
    db #7f, #87, #0e, #1c, #38, #71, #fd, #e6  ; MDL bitmap visualization
#7d1f#131f
#7d1f#131f
#7d1f#131f
; --------------------------------
#7d1f#131f
L7d1f_text_save_load_quit:
#7d1f#131f21
    db 0, "S-SAVE L-LOAD Q-QUIT"
#7d34#1334
L7d34_text_keys:
#7d34#13345
    db 0, "KEYS"
#7d39#1339
L7d39_text_spirits:
#7d39#13398
    db 0, "SPIRITS"
#7d41#1341
L7d41_text_strength:
#7d41#13419
    db 0, "STRENGTH"
#7d4a#134a
L7d4a_text_collected:
#7d4a#134a16
    db 0, " XX COLLECTED  "
#7d5a#135a
L7d5a_text_destroyed:
#7d5a#135a16
    db 0, " XX DESTROYED  "
#7d6a#136a
L7d6a_text_score:
#7d6a#136a16
    db 1, "SCORE  XXXXXXX "
#7d7a#137a
L7d7a_text_filename:
#7d7a#137a14
    db 0, "FILENAME :   "
#7d88#1388
#7d88#1388
L7d88_action_pointer_viewport_sprite:
#7d88#13884
    db 0, 0, 2, 9
#7d8c#138c2
    dw L7e3e  ; empty buffer
#7d8e#138e8
    dw L7dae, L7dc0, L7dd2, L7de4  ; pointer mask
#7d96#13968
    dw L7df6, L7e08, L7e1a, L7e2c
#7d9e#139e8
    dw L7e50, L7e62, L7e74, L7e86  ; action/throw pointer
#7da6#13a68
    dw L7e98, L7eaa, L7ebc, L7ece
#7dae#13ae
L7dae:
#7dae#13ae6
    db #e3, #ff, #e3, #ff, #e3, #ff
#7db4#13b46
    db #1c, #7f, #1c, #7f, #1c, #7f
#7dba#13ba6
    db #e3, #ff, #e3, #ff, #e3, #ff  ; MDL bitmap visualization 
#7dc0#13c0
L7dc0:
#7dc0#13c06
    db #f1, #ff, #f1, #ff, #f1, #ff
#7dc6#13c66
    db #8e, #3f, #8e, #3f, #8e, #3f
#7dcc#13cc6
    db #f1, #ff, #f1, #ff, #f1, #ff  ; MDL bitmap visualization 
#7dd2#13d2
L7dd2:
#7dd2#13d26
    db #f8, #ff, #f8, #ff, #f8, #ff
#7dd8#13d86
    db #c7, #1f, #c7, #1f, #c7, #1f
#7dde#13de6
    db #f8, #ff, #f8, #ff, #f8, #ff  ; MDL bitmap visualization 
#7de4#13e4
L7de4:
#7de4#13e46
    db #fc, #7f, #fc, #7f, #fc, #7f
#7dea#13ea6
    db #e3, #8f, #e3, #8f, #e3, #8f
#7df0#13f06
    db #fc, #7f, #fc, #7f, #fc, #7f  ; MDL bitmap visualization 
#7df6#13f6
L7df6:
#7df6#13f66
    db #fe, #3f, #fe, #3f, #fe, #3f
#7dfc#13fc6
    db #f1, #c7, #f1, #c7, #f1, #c7
#7e02#14026
    db #fe, #3f, #fe, #3f, #fe, #3f  ; MDL bitmap visualization 
#7e08#1408
L7e08:
#7e08#14086
    db #ff, #1f, #ff, #1f, #ff, #1f
#7e0e#140e6
    db #f8, #e3, #f8, #e3, #f8, #e3
#7e14#14146
    db #ff, #1f, #ff, #1f, #ff, #1f  ; MDL bitmap visualization 
#7e1a#141a
L7e1a:
#7e1a#141a6
    db #ff, #8f, #ff, #8f, #ff, #8f
#7e20#14206
    db #fc, #71, #fc, #71, #fc, #71
#7e26#14266
    db #ff, #8f, #ff, #8f, #ff, #8f  ; MDL bitmap visualization 
#7e2c#142c
L7e2c:
#7e2c#142c6
    db #ff, #c7, #ff, #c7, #ff, #c7
#7e32#14326
    db #fe, #38, #fe, #38, #fe, #38
#7e38#14386
    db #ff, #c7, #ff, #c7, #ff, #c7  ; MDL bitmap visualization 
#7e3e#143e
L7e3e:
#7e3e#143e6
    db #00, #00, #00, #00, #00, #00
#7e44#14446
    db #00, #00, #00, #00, #00, #00
#7e4a#144a6
    db #00, #00, #00, #00, #00, #00  ; MDL bitmap visualization 
#7e50#1450
L7e50:
#7e50#14506
    db #14, #00, #14, #00, #14, #00
#7e56#14566
    db #00, #00, #e3, #80, #00, #00
#7e5c#145c6
    db #14, #00, #14, #00, #14, #00  ; MDL bitmap visualization 
#7e62#1462
L7e62:
#7e62#14626
    db #0a, #00, #0a, #00, #0a, #00
#7e68#14686
    db #00, #00, #71, #c0, #00, #00
#7e6e#146e6
    db #0a, #00, #0a, #00, #0a, #00  ; MDL bitmap visualization 
#7e74#1474
L7e74:
#7e74#14746
    db #05, #00, #05, #00, #05, #00
#7e7a#147a6
    db #00, #00, #38, #e0, #00, #00
#7e80#14806
    db #05, #00, #05, #00, #05, #00  ; MDL bitmap visualization 
#7e86#1486
L7e86:
#7e86#14866
    db #02, #80, #02, #80, #02, #80
#7e8c#148c6
    db #00, #00, #1c, #70, #00, #00
#7e92#14926
    db #02, #80, #02, #80, #02, #80  ; MDL bitmap visualization 
#7e98#1498
L7e98:
#7e98#14986
    db #01, #40, #01, #40, #01, #40
#7e9e#149e6
    db #00, #00, #0e, #38, #00, #00
#7ea4#14a46
    db #01, #40, #01, #40, #01, #40  ; MDL bitmap visualization 
#7eaa#14aa
L7eaa:
#7eaa#14aa6
    db #00, #a0, #00, #a0, #00, #a0
#7eb0#14b06
    db #00, #00, #07, #1c, #00, #00
#7eb6#14b66
    db #00, #a0, #00, #a0, #00, #a0  ; MDL bitmap visualization 
#7ebc#14bc
L7ebc:
#7ebc#14bc6
    db #00, #50, #00, #50, #00, #50
#7ec2#14c26
    db #00, #00, #03, #8e, #00, #00
#7ec8#14c86
    db #00, #50, #00, #50, #00, #50  ; MDL bitmap visualization 
#7ece#14ce
L7ece:
#7ece#14ce6
    db #00, #28, #00, #28, #00, #28
#7ed4#14d46
    db #00, #00, #01, #c7, #00, #00
#7eda#14da6
    db #00, #28, #00, #28, #00, #28  ; MDL bitmap visualization 
#7ee0#14e0
#7ee0#14e0
#7ee0#14e0
L7ee0_stone_viewport_sprite_size1:
#7ee0#14e04
    db 0, 0, 2, 4
#7ee4#14e42
    dw L7f16  ; empty buffer
#7ee6#14e68
    dw L7f06, L7f06, L7f06, L7f06
#7eee#14ee8
    dw L7f06, L7f06, L7f06, L7f06
#7ef6#14f68
    dw L7f0e, L7f0e, L7f0e, L7f0e
#7efe#14fe8
    dw L7f0e, L7f0e, L7f0e, L7f0e
#7f06#1506
L7f06:
#7f06#15068
    db #00, #3f, #00, #3f, #80, #7f, #c0, #ff  ; MDL bitmap visualization 
#7f0e#150e
L7f0e:
#7f0e#150e8
    db #ff, #80, #ff, #80, #7f, #00, #3e, #00  ; MDL bitmap visualization 
#7f16#1516
L7f16:
#7f16#15168
    db #00, #00, #00, #00, #00, #00, #00, #00  ; MDL bitmap visualization 
#7f1e#151e
#7f1e#151e
#7f1e#151e
L7f1e_stone_viewport_sprite_size2:
#7f1e#151e4
    db 0, 0, 2, 5
#7f22#15222
    dw L7fe4  ; empty buffer
#7f24#15248
    dw L7f44, L7f4e, L7f58, L7f62
#7f2c#152c8
    dw L7f6c, L7f76, L7f80, L7f8a
#7f34#15348
    dw L7f94, L7f9e, L7fa8, L7fb2
#7f3c#153c8
    dw L7fbc, L7fc6, L7fd0, L7fda
#7f44#1544
L7f44:
#7f44#154410
    db #c1, #ff, #80, #ff, #00, #7f, #80, #ff, #c1, #ff  ; MDL bitmap visualization 
#7f4e#154e
L7f4e:
#7f4e#154e10
    db #e0, #ff, #c0, #7f, #80, #3f, #c0, #7f, #e0, #ff  ; MDL bitmap visualization 
#7f58#1558
L7f58:
#7f58#155810
    db #f0, #7f, #e0, #3f, #c0, #1f, #e0, #3f, #f0, #7f  ; MDL bitmap visualization 
#7f62#1562
L7f62:
#7f62#156210
    db #f8, #3f, #f0, #1f, #e0, #0f, #f0, #1f, #f8, #3f  ; MDL bitmap visualization 
#7f6c#156c
L7f6c:
#7f6c#156c10
    db #fc, #1f, #f8, #0f, #f0, #07, #f8, #0f, #fc, #1f  ; MDL bitmap visualization 
#7f76#1576
L7f76:
#7f76#157610
    db #fe, #0f, #fc, #07, #f8, #03, #fc, #07, #fe, #0f  ; MDL bitmap visualization 
#7f80#1580
L7f80:
#7f80#158010
    db #ff, #07, #fe, #03, #fc, #01, #fe, #03, #ff, #07  ; MDL bitmap visualization 
#7f8a#158a
L7f8a:
#7f8a#158a10
    db #ff, #83, #ff, #01, #fe, #00, #ff, #01, #ff, #83  ; MDL bitmap visualization 
#7f94#1594
L7f94:
#7f94#159410
    db #3c, #00, #7e, #00, #ff, #00, #7e, #00, #3c, #00  ; MDL bitmap visualization 
#7f9e#159e
L7f9e:
#7f9e#159e10
    db #1e, #00, #3f, #00, #7f, #80, #3f, #00, #1e, #00  ; MDL bitmap visualization 
#7fa8#15a8
L7fa8:
#7fa8#15a810
    db #0f, #00, #1f, #80, #3f, #c0, #1f, #80, #0f, #00  ; MDL bitmap visualization 
#7fb2#15b2
L7fb2:
#7fb2#15b210
    db #07, #80, #0f, #c0, #1f, #e0, #0f, #c0, #07, #80  ; MDL bitmap visualization 
#7fbc#15bc
L7fbc:
#7fbc#15bc10
    db #03, #c0, #07, #e0, #0f, #f0, #07, #e0, #03, #c0  ; MDL bitmap visualization 
#7fc6#15c6
L7fc6:
#7fc6#15c610
    db #01, #e0, #03, #f0, #07, #f8, #03, #f0, #01, #e0  ; MDL bitmap visualization 
#7fd0#15d0
L7fd0:
#7fd0#15d010
    db #00, #f0, #01, #f8, #03, #fc, #01, #f8, #00, #f0  ; MDL bitmap visualization 
#7fda#15da
L7fda:
#7fda#15da10
    db #00, #78, #00, #fc, #01, #fe, #00, #fc, #00, #78  ; MDL bitmap visualization 
#7fe4#15e4
L7fe4:
#7fe4#15e410
    db #00, #00, #00, #00, #00, #00, #00, #00, #00, #00  ; MDL bitmap visualization 
#7fee#15ee
#7fee#15ee
L7fee_stone_viewport_sprite_size3:
#7fee#15ee4
    db 0, 0, 2, 4
#7ff2#15f22
    dw L8094  ; empty buffer
#7ff4#15f48
    dw L8014, L801c, L8024, L802c
#7ffc#15fc8
    dw L8034, L803c, L8044, L804c
#8004#16048
    dw L8054, L805c, L8064, L806c
#800c#160c8
    dw L8074, L807c, L8084, L808c
#8014#1614
L8014:
#8014#16148
    db #87, #ff, #03, #ff, #03, #ff, #87, #ff  ; MDL bitmap visualization 
#801c#161c
L801c:
#801c#161c8
    db #c3, #ff, #81, #ff, #81, #ff, #c3, #ff  ; MDL bitmap visualization 
#8024#1624
L8024:
#8024#16248
    db #e1, #ff, #c0, #ff, #c0, #ff, #e1, #ff  ; MDL bitmap visualization 
#802c#162c
L802c:
#802c#162c8
    db #f0, #ff, #e0, #7f, #e0, #7f, #f0, #ff  ; MDL bitmap visualization 
#8034#1634
L8034:
#8034#16348
    db #f8, #7f, #f0, #3f, #f0, #3f, #f8, #7f  ; MDL bitmap visualization 
#803c#163c
L803c:
#803c#163c8
    db #fc, #3f, #f8, #1f, #f8, #1f, #fc, #3f  ; MDL bitmap visualization 
#8044#1644
L8044:
#8044#16448
    db #fe, #1f, #fc, #0f, #fc, #0f, #fe, #1f  ; MDL bitmap visualization 
#804c#164c
L804c:
#804c#164c8
    db #ff, #0f, #fe, #07, #fe, #07, #ff, #0f  ; MDL bitmap visualization 
#8054#1654
L8054:
#8054#16548
    db #70, #00, #f8, #00, #f8, #00, #70, #00  ; MDL bitmap visualization 
#805c#165c
L805c:
#805c#165c8
    db #38, #00, #7c, #00, #7c, #00, #38, #00  ; MDL bitmap visualization 
#8064#1664
L8064:
#8064#16648
    db #1c, #00, #3e, #00, #3e, #00, #1c, #00  ; MDL bitmap visualization 
#806c#166c
L806c:
#806c#166c8
    db #0e, #00, #1f, #00, #1f, #00, #0e, #00  ; MDL bitmap visualization 
#8074#1674
L8074:
#8074#16748
    db #07, #00, #0f, #80, #0f, #80, #07, #00  ; MDL bitmap visualization 
#807c#167c
L807c:
#807c#167c8
    db #03, #80, #07, #c0, #07, #c0, #03, #80  ; MDL bitmap visualization 
#8084#1684
L8084:
#8084#16848
    db #01, #c0, #03, #e0, #03, #e0, #01, #c0  ; MDL bitmap visualization 
#808c#168c
L808c:
#808c#168c8
    db #00, #e0, #01, #f0, #01, #f0, #00, #e0  ; MDL bitmap visualization 
#8094#1694
L8094:
#8094#16948
    db #00, #00, #00, #00, #00, #00, #00, #00  ; MDL bitmap visualization 
#809c#169c
#809c#169c
L909c_stone_viewport_sprite_size4:
#809c#169c4
    db 0, 0, 2, 3
#80a0#16a02
    dw L8122  ; empty buffer
#80a2#16a28
    dw L80c2, L80c8, L80ce, L80d4
#80aa#16aa8
    dw L80da, L80e0, L80e6, L80ec
#80b2#16b28
    dw L80f2, L80f8, L80fe, L8104
#80ba#16ba8
    dw L810a, L8110, L8116, L811c
#80c2#16c2
L80c2:
#80c2#16c26
    db #8f, #ff, #07, #ff, #8f, #ff  ; MDL bitmap visualization 
#80c8#16c8
L80c8:
#80c8#16c86
    db #c7, #ff, #83, #ff, #c7, #ff  ; MDL bitmap visualization 
#80ce#16ce
L80ce:
#80ce#16ce6
    db #e3, #ff, #c1, #ff, #e3, #ff  ; MDL bitmap visualization 
#80d4#16d4
L80d4:
#80d4#16d46
    db #f1, #ff, #e0, #ff, #f1, #ff  ; MDL bitmap visualization 
#80da#16da
L80da:
#80da#16da6
    db #f8, #ff, #f0, #7f, #f8, #ff  ; MDL bitmap visualization 
#80e0#16e0
L80e0:
#80e0#16e06
    db #fc, #7f, #f8, #3f, #fc, #7f  ; MDL bitmap visualization 
#80e6#16e6
L80e6:
#80e6#16e66
    db #fe, #3f, #fc, #1f, #fe, #3f  ; MDL bitmap visualization 
#80ec#16ec
L80ec:
#80ec#16ec6
    db #ff, #1f, #fe, #0f, #ff, #1f  ; MDL bitmap visualization 
#80f2#16f2
L80f2:
#80f2#16f26
    db #60, #00, #f0, #00, #60, #00  ; MDL bitmap visualization 
#80f8#16f8
L80f8:
#80f8#16f86
    db #30, #00, #78, #00, #30, #00  ; MDL bitmap visualization 
#80fe#16fe
L80fe:
#80fe#16fe6
    db #18, #00, #3c, #00, #18, #00  ; MDL bitmap visualization 
#8104#1704
L8104:
#8104#17046
    db #0c, #00, #1e, #00, #0c, #00  ; MDL bitmap visualization 
#810a#170a
L810a:
#810a#170a6
    db #06, #00, #0f, #00, #06, #00  ; MDL bitmap visualization 
#8110#1710
L8110:
#8110#17106
    db #03, #00, #07, #80, #03, #00  ; MDL bitmap visualization 
#8116#1716
L8116:
#8116#17166
    db #01, #80, #03, #c0, #01, #80  ; MDL bitmap visualization 
#811c#171c
L811c:
#811c#171c6
    db #00, #c0, #01, #e0, #00, #c0  ; MDL bitmap visualization 
#8122#1722
L8122:
#8122#17226
    db #00, #00, #00, #00, #00, #00  ; MDL bitmap visualization 
#8128#1728
#8128#1728
#8128#1728
; --------------------------------
#8128#1728
; Temporary data for function 'L8132_load_or_save_to_tape'
#8128#1728
L8128_initial_pressed_key:
#8128#17281
    db #c0
#8129#1729
L8129_filename_length:
#8129#17291
    db #01
#812a#172a
L812a_filename_ptr:
#812a#172a2
    dw #0080
#812c#172c
l812c_savegame_data_size:
#812c#172c2
    dw #01c0
#812e#172e
L812e_savegame_data_end_ptr:
#812e#172e2
    dw #00e0
#8130#1730
L8130_checksum:
#8130#17302
    dw #00c0
#8132#1732
#8132#1732
#8132#1732
; --------------------------------
#8132#1732
; Asks the player to type a savegame name, and load/ssaves a game.
#8132#1732
L8132_load_or_save_to_tape:
#8132#1732314
32 28 81 
    ld (L8128_initial_pressed_key), a  ; Remember whether we had pressed 'S' or 'L'.
#8135#1735318
cd f4 c3 
    call Lc3f4_read_filename
#8138#1738314
32 29 81 
    ld (L8129_filename_length), a
#813b#173b317
22 2a 81 
    ld (L812a_filename_ptr), hl
#813e#173e314
3a 28 81 
    ld a, (L8128_initial_pressed_key)  ; Restore which key was pressed to get to this menu.
#8141#174128
fe 53 
    cp "S"  ; Check if we wanted to save or load:
#8143#1743311
c2 19 82 
    jp nz, L8219_load
#8146#1746
#8146#1746
    ; Save game:
#8146#1746
    ; Copy the game data to save to the buffer:
#8146#1746311
11 bc 5c 
    ld de, L5cbc_render_buffer
#8149#1749311
21 ad 6a 
    ld hl, L6aad_player_current_x
#814c#174c311
01 77 00 
    ld bc, L6b24_savegame_data_end - L6aad_savegame_data_start
#814f#174f223/18
ed b0 
    ldir
#8151#1751
#8151#1751
    ; Add area object states:
#8151#1751314
3a 82 d0 
    ld a, (Ld082_n_areas)
#8154#175415
4f 
    ld c, a
#8155#1755416
fd 21 d1 d0 
    ld iy, Ld0d1_area_offsets
#8159#175915
eb 
    ex de, hl  ; hl = ptr to the next position in the save game data
#815a#175a
L815a_save_game_area_loop:
#815a#175a321
fd 5e 00 
    ld e, (iy)
#815d#175d321
fd 56 01 
    ld d, (iy + 1)  ; Get area pointer offset
#8160#1760212
fd 23 
    inc iy
#8162#1762212
fd 23 
    inc iy
#8164#1764416
dd 21 82 d0 
    ld ix, Ld082_area_reference_start
#8168#1768217
dd 19 
    add ix, de
#816a#176a321
dd 46 01 
    ld b, (ix + AREA_N_OBJECTS)
#816d#176d311
11 08 00 
    ld de, 8
#8170#1770217
dd 19 
    add ix, de  ; skip the header
#8172#1772
L8172_save_game_next_object_loop:
#8172#1772321
dd 7e 00 
    ld a, (ix + OBJECT_TYPE_AND_FLAGS)  ; save the object state
#8175#177518
77 
    ld (hl), a
#8176#177617
23 
    inc hl
#8177#1777321
dd 5e 08 
    ld e, (ix + OBJECT_SIZE)
#817a#177a217
dd 19 
    add ix, de  ; next object
#817c#177c214/9
10 f4 
    djnz L8172_save_game_next_object_loop
#817e#177e15
0d 
    dec c
#817f#177f213/8
20 d9 
    jr nz, L815a_save_game_area_loop
#8181#1781
#8181#1781317
22 2e 81 
    ld (L812e_savegame_data_end_ptr), hl
#8184#1784311
11 bc 5c 
    ld de, L5cbc_render_buffer
#8187#178715
b7 
    or a
#8188#1788217
ed 52 
    sbc hl, de
#818a#178a317
22 2c 81 
    ld (l812c_savegame_data_size), hl
#818d#178d318
cd 8c 83 
    call L838c_checksum
#8190#1790422
ed 43 30 81 
    ld (L8130_checksum), bc
#8194#1794
#8194#1794422
ed 5b 2e 81 
    ld de, (L812e_savegame_data_end_ptr)
#8198#1798
#8198#1798
    ; Generate the savegame header (19 bytes):
#8198#1798
    ; - 1 byte: 30
#8198#1798
    ; - 12 bytes: filename
#8198#1798
    ; - 2 bytes: savegame size
#8198#1798
    ; - 2 bytes: (Ld083_game_version)
#8198#1798
    ; - 2 bytes: checksum
#8198#179828
3e 1e 
    ld a, 30  ; Header start
#819a#179a18
12 
    ld (de), a
#819b#179b17
13 
    inc de
#819c#179c317
2a 2a 81 
    ld hl, (L812a_filename_ptr)
#819f#179f311
01 0c 00 
    ld bc, 12
#81a2#17a2223/18
ed b0 
    ldir  ; Append the filename to the savegame data.
#81a4#17a4
#81a4#17a4
    ; Append the savegame datasize to the savegame header:
#81a4#17a4317
2a 2c 81 
    ld hl, (l812c_savegame_data_size)
#81a7#17a715
eb 
    ex de, hl
#81a8#17a818
73 
    ld (hl), e
#81a9#17a917
23 
    inc hl
#81aa#17aa18
72 
    ld (hl), d
#81ab#17ab17
23 
    inc hl
#81ac#17ac
#81ac#17ac
    ; Append the 2 bytes at (Ld083_game_version) to the savegame header:
#81ac#17ac422
ed 5b 83 d0 
    ld de, (Ld083_game_version)
#81b0#17b018
73 
    ld (hl), e
#81b1#17b117
23 
    inc hl
#81b2#17b218
72 
    ld (hl), d
#81b3#17b317
23 
    inc hl
#81b4#17b4
#81b4#17b4
    ; Append the checksum to the header:
#81b4#17b4422
ed 5b 30 81 
    ld de, (L8130_checksum)
#81b8#17b818
73 
    ld (hl), e
#81b9#17b917
23 
    inc hl
#81ba#17ba18
72 
    ld (hl), d
#81bb#17bb
#81bb#17bb416
dd 21 e4 72 
    ld ix, L725c_videomem_row_pointers + 68 * 2
#81bf#17bf311
21 47 75 
    ld hl, L7547_text_play_record
#81c2#17c2311
11 27 0d 
    ld de, #0d27
#81c5#17c5318
cd 1c d0 
    call Ld01c_draw_string
#81c8#17c8416
dd 21 fa 72 
    ld ix, L725c_videomem_row_pointers + 79 * 2
#81cc#17cc311
21 83 75 
    ld hl, L7583_text_then_any_key
#81cf#17cf318
cd 1c d0 
    call Ld01c_draw_string
#81d2#17d2
#81d2#17d2
    ; Wait until a key is pressed & released:
#81d2#17d2
L81d2_key_press_wait_loop:
#81d2#17d2318
cd d4 bf 
    call Lbfd4_read_keyboard_and_joystick_input
#81d5#17d5213/8
38 fb 
    jr c, L81d2_key_press_wait_loop
#81d7#17d7
L81d7_key_release_wait_loop:
#81d7#17d7318
cd d4 bf 
    call Lbfd4_read_keyboard_and_joystick_input
#81da#17da213/8
30 fb 
    jr nc, L81d7_key_release_wait_loop
#81dc#17dc
#81dc#17dc311
21 38 75 
    ld hl, L7538_text_spaces
#81df#17df318
cd 1c d0 
    call Ld01c_draw_string
#81e2#17e2416
dd 21 e4 72 
    ld ix, L725c_videomem_row_pointers + 68 * 2
#81e6#17e6311
21 92 75 
    ld hl, L7592_text_saving_file
#81e9#17e9318
cd 1c d0 
    call Ld01c_draw_string
#81ec#17ec422
fd 2a 7d 74 
    ld iy, (L747d)
#81f0#17f0422
dd 2a 2e 81 
    ld ix, (L812e_savegame_data_end_ptr)  ; address to save
#81f4#17f4311
11 13 00 
    ld de, 19  ; Size of the header
#81f7#17f715
af 
    xor a
#81f8#17f8
    ; Save the header:
#81f8#17f8318
cd c6 04 
    call L04c6_BIOS_CASSETTE_SAVE_NO_BREAK_TEST
#81fb#17fb311
d2 62 83 
    jp nc, L8362_done_loading_saving_with_pause
#81fe#17fe15
fb 
    ei
#81ff#17ff
    ; Wait 50 interrupts:
#81ff#17ff28
3e 32 
    ld a, 50
#8201#1801314
32 a5 74 
    ld (L74a5_interrupt_timer), a
#8204#1804
L8204_pause_loop:
#8204#1804314
3a a5 74 
    ld a, (L74a5_interrupt_timer)
#8207#180715
b7 
    or a
#8208#1808213/8
20 fa 
    jr nz, L8204_pause_loop
#820a#180a416
dd 21 bc 5c 
    ld ix, L5cbc_render_buffer  ; address to save
#820e#180e422
ed 5b 2c 81 
    ld de, (l812c_savegame_data_size)  ; amount of bytes to save
#8212#181215
3d 
    dec a
#8213#1813
    ; Save the savegame:
#8213#1813318
cd c6 04 
    call L04c6_BIOS_CASSETTE_SAVE_NO_BREAK_TEST
#8216#1816311
c3 62 83 
    jp L8362_done_loading_saving_with_pause
#8219#1819
#8219#1819
L8219_load:
#8219#1819
    ; Load game:
#8219#1819422
fd 2a 7d 74 
    ld iy, (L747d)
#821d#181d416
dd 21 e4 72 
    ld ix, L725c_videomem_row_pointers + 68 * 2
#8221#1821311
21 b0 75 
    ld hl, L75b0_text_searching
#8224#1824311
11 27 0e 
    ld de, #0e27
#8227#1827318
cd 1c d0 
    call Ld01c_draw_string
#822a#182a
L822a:
#822a#182a416
dd 21 bc 5c 
    ld ix, L5cbc_render_buffer  ; address to load to
#822e#182e311
11 12 00 
    ld de, 19 - 1  ; Amount of bytes to load (19)
#8231#1831
    ; Set the flags/values the BIOS routine expects to load:
#8231#183115
af 
    xor a
#8232#183215
37 
    scf
#8233#183315
1c 
    inc e
#8234#183415
08 
    ex af, af'  ; since we are skipping tests, we need to pre "ex" af, since the function would do this during the tests.
#8235#183515
f3 
    di
#8236#1836318
cd 62 05 
    call L0562_BIOS_READ_FROM_TAPE_SKIP_TESTS
#8239#1839112
f5 
    push af
#823a#183a28
3e 7f 
        ld a, #7f
#823c#183c212
db fe 
        in a, (ULA_PORT)
#823e#183e15
1f 
        rra
#823f#183f311
d2 1d 83 
        jp nc, L831d_done_loading_saving_pop  ; If space (break?) was pressed, cancel.
#8242#1842111
f1 
    pop af
#8243#1843213/8
30 e5 
    jr nc, L822a  ; If load failed, retry.
#8245#1845416
dd 21 bc 5c 
    ld ix, L5cbc_render_buffer
#8249#1849
#8249#1849
    ; Check header is correct:
#8249#1849
    ; - 1 byte: 30
#8249#1849
    ; - 12 bytes: filename
#8249#1849
    ; - 2 bytes: savegame size
#8249#1849
    ; - 2 bytes: (Ld083_game_version)
#8249#1849
    ; - 2 bytes: checksum
#8249#184928
3e 1e 
    ld a, 30
#824b#184b321
dd be 00 
    cp (ix)
#824e#184e213/8
20 da 
    jr nz, L822a  ; If the first byte is not the header start byte, retry.
#8250#1850416
dd 21 e4 72 
    ld ix, L725c_videomem_row_pointers + 68 * 2
#8254#1854311
21 a1 75 
    ld hl, L75a1_text_found
#8257#1857311
11 27 0e 
    ld de, #0e27
#825a#185a318
cd 1c d0 
    call Ld01c_draw_string
#825d#185d
#825d#185d416
dd 21 bd 5c 
    ld ix, L5cbc_render_buffer + 1
#8261#1861321
dd 5e 0c 
    ld e, (ix + 12)
#8264#1864321
dd 56 0d 
    ld d, (ix + 13)  ; de = savegame size
#8267#1867421
dd 36 0c 20 
    ld (ix + 12), " "  ; replace savegame size by spaces, to print to screen.
#826b#186b421
dd 36 0d 20 
    ld (ix + 13), " "
#826f#186f217
dd e5 
    push ix
#8271#1871112
d5 
    push de
#8272#1872311
21 bc 5c 
        ld hl, L5cbc_render_buffer
#8275#1875211
36 00 
        ld (hl), 0  ; Replace "30" by a 0, so we can draw the string.
#8277#1877416
dd 21 fa 72 
        ld ix, L725c_videomem_row_pointers + 79 * 2
#827b#187b311
11 27 0e 
        ld de, #0e27
#827e#187e318
cd 1c d0 
        call Ld01c_draw_string  ; Draw savegame name
#8281#1881111
d1 
    pop de
#8282#1882216
dd e1 
    pop ix
#8284#1884
#8284#1884
    ; Check if the savegame name matches what the player entered:
#8284#1884314
3a 29 81 
    ld a, (L8129_filename_length)
#8287#188715
b7 
    or a
#8288#1888213/8
20 07 
    jr nz, L8291
#828a#188a
    ; If player did not enter any name, accept any savegame:
#828a#188a311
01 0c 00 
    ld bc, 12
#828d#188d217
dd 09 
    add ix, bc
#828f#188f213
18 10 
    jr L82a1_savegame_name_matches
#8291#1891
L8291:
#8291#1891
    ; Check if names match:
#8291#189128
06 0c 
    ld b, 12
#8293#1893317
2a 2a 81 
    ld hl, (L812a_filename_ptr)
#8296#1896
L8296_savegame_name_check_loop:
#8296#1896321
dd 7e 00 
    ld a, (ix)
#8299#189918
be 
    cp (hl)
#829a#189a213/8
20 8e 
    jr nz, L822a  ; If name does not match, retry
#829c#189c212
dd 23 
    inc ix
#829e#189e17
23 
    inc hl
#829f#189f214/9
10 f5 
    djnz L8296_savegame_name_check_loop
#82a1#18a1
#82a1#18a1
L82a1_savegame_name_matches:
#82a1#18a1422
ed 53 2c 81 
    ld (l812c_savegame_data_size), de
#82a5#18a515
7a 
    ld a, d
#82a6#18a628
e6 f0 
    and 240
#82a8#18a8213/8
20 56 
    jr nz, L8300
#82aa#18aa
    ; Check that the version matches this game:
#82aa#18aa321
dd 5e 02 
    ld e, (ix + 2)
#82ad#18ad321
dd 56 03 
    ld d, (ix + 3)
#82b0#18b0317
2a 83 d0 
    ld hl, (Ld083_game_version)
#82b3#18b315
b7 
    or a
#82b4#18b4217
ed 52 
    sbc hl, de
#82b6#18b6213/8
20 48 
    jr nz, L8300
#82b8#18b8321
dd 6e 04 
    ld l, (ix + 4)
#82bb#18bb321
dd 66 05 
    ld h, (ix + 5)
#82be#18be317
22 30 81 
    ld (L8130_checksum), hl
#82c1#18c1
    
#82c1#18c1416
dd 21 e4 72 
    ld ix, L725c_videomem_row_pointers + 68 * 2
#82c5#18c5311
21 74 75 
    ld hl, L7574_text_loading
#82c8#18c8311
11 27 0e 
    ld de, #0e27
#82cb#18cb318
cd 1c d0 
    call Ld01c_draw_string
#82ce#18ce
#82ce#18ce
    ; Load savegame data:
#82ce#18ce416
dd 21 bc 5c 
    ld ix, L5cbc_render_buffer
#82d2#18d2422
ed 5b 2c 81 
    ld de, (l812c_savegame_data_size)
#82d6#18d6
#82d6#18d6
    ; Set the flags/values the BIOS routine expects to load:
#82d6#18d615
37 
    scf
#82d7#18d728
3e ff 
    ld a, 255
#82d9#18d915
14 
    inc d
#82da#18da15
08 
    ex af, af'
#82db#18db15
15 
    dec d
#82dc#18dc15
f3 
    di
#82dd#18dd318
cd 62 05 
    call L0562_BIOS_READ_FROM_TAPE_SKIP_TESTS
#82e0#18e0112
f5 
    push af
#82e1#18e128
3e 7f 
        ld a, 127
#82e3#18e3212
db fe 
        in a, (ULA_PORT)
#82e5#18e515
1f 
        rra
#82e6#18e6213/8
30 35 
        jr nc, L831d_done_loading_saving_pop  ; If space (break?) was pressed, cancel.
#82e8#18e8111
f1 
    pop af
#82e9#18e9416
dd 21 65 75 
    ld ix, L7565_text_loading_error
#82ed#18ed213/8
30 15 
    jr nc, L8304
#82ef#18ef
#82ef#18ef311
11 bc 5c 
    ld de, L5cbc_render_buffer
#82f2#18f2317
2a 2c 81 
    ld hl, (l812c_savegame_data_size)
#82f5#18f5318
cd 8c 83 
    call L838c_checksum
#82f8#18f8317
2a 30 81 
    ld hl, (L8130_checksum)
#82fb#18fb15
b7 
    or a
#82fc#18fc217
ed 42 
    sbc hl, bc
#82fe#18fe213/8
28 20 
    jr z, L8320_found_valid_savegame
#8300#1900
#8300#1900
L8300:
#8300#1900
    ; Load error: version mismatch
#8300#1900416
dd 21 56 75 
    ld ix, L7556_text_invalid_file
#8304#1904
L8304:
#8304#1904
    ; Load error
#8304#1904217
dd e5 
    push ix
#8306#1906111
e1 
    pop hl
#8307#1907416
dd 21 e4 72 
    ld ix, L725c_videomem_row_pointers + 68 * 2
#830b#190b311
11 27 0e 
    ld de, #0e27
#830e#190e318
cd 1c d0 
    call Ld01c_draw_string
#8311#1911311
21 38 75 
    ld hl, L7538_text_spaces
#8314#1914416
dd 21 fa 72 
    ld ix, L725c_videomem_row_pointers + 79 * 2
#8318#1918318
cd 1c d0 
    call Ld01c_draw_string
#831b#191b213
18 45 
    jr L8362_done_loading_saving_with_pause
#831d#191d
#831d#191d
L831d_done_loading_saving_pop:
#831d#191d111
f1 
    pop af
#831e#191e213
18 42 
    jr L8362_done_loading_saving_with_pause
#8320#1920
#8320#1920
L8320_found_valid_savegame:
#8320#1920
    ; Found a valid savegame, restore state:
#8320#1920311
21 bc 5c 
    ld hl, L5cbc_render_buffer
#8323#1923311
11 ad 6a 
    ld de, L6aad_savegame_data_start
#8326#1926311
01 77 00 
    ld bc, 119
#8329#1929223/18
ed b0 
    ldir
#832b#192b
#832b#192b
    ; Restore the additional area state information:
#832b#192b314
3a 82 d0 
    ld a, (Ld082_n_areas)
#832e#192e15
4f 
    ld c, a
#832f#192f416
fd 21 d1 d0 
    ld iy, Ld0d1_area_offsets
#8333#1933
L8333_area_loop:
#8333#1933321
fd 5e 00 
    ld e, (iy)
#8336#1936321
fd 56 01 
    ld d, (iy + 1)
#8339#1939212
fd 23 
    inc iy
#833b#193b212
fd 23 
    inc iy
#833d#193d416
dd 21 82 d0 
    ld ix, Ld082_area_reference_start
#8341#1941217
dd 19 
    add ix, de
#8343#1943321
dd 46 01 
    ld b, (ix + AREA_N_OBJECTS)
#8346#1946311
11 08 00 
    ld de, 8
#8349#1949217
dd 19 
    add ix, de
#834b#194b
L834b:
#834b#194b18
7e 
    ld a, (hl)
#834c#194c321
dd 77 00 
    ld (ix + OBJECT_TYPE_AND_FLAGS), a
#834f#194f17
23 
    inc hl
#8350#1950321
dd 5e 08 
    ld e, (ix + OBJECT_SIZE)
#8353#1953217
dd 19 
    add ix, de
#8355#1955214/9
10 f4 
    djnz L834b
#8357#195715
0d 
    dec c
#8358#1958213/8
20 d9 
    jr nz, L8333_area_loop
#835a#195a15
fb 
    ei
#835b#195b314
3a d7 6a 
    ld a, (L6ad7_current_border_color)
#835e#195e212
d3 fe 
    out (ULA_PORT), a
#8360#1960213
18 11 
    jr L8373_done_loading_saving
#8362#1962
#8362#1962
L8362_done_loading_saving_with_pause:
#8362#196215
fb 
    ei
#8363#1963314
3a d7 6a 
    ld a, (L6ad7_current_border_color)
#8366#1966212
d3 fe 
    out (ULA_PORT), a  ; Set the border color.
#8368#1968
    ; Wait 50 interrupts:
#8368#196828
3e 32 
    ld a, 50
#836a#196a314
32 a5 74 
    ld (L74a5_interrupt_timer), a
#836d#196d
L836d_pause_loop:
#836d#196d314
3a a5 74 
    ld a, (L74a5_interrupt_timer)
#8370#197015
b7 
    or a
#8371#1971213/8
20 fa 
    jr nz, L836d_pause_loop
#8373#1973
#8373#1973
L8373_done_loading_saving:
#8373#1973311
21 fd ff 
    ld hl, #fffd
#8376#1976317
22 6c 74 
    ld (L746c_game_flags), hl
#8379#197928
3e 01 
    ld a, 1
#837b#197b314
32 66 74 
    ld (L7466_need_attribute_refresh_flag), a
#837e#197e314
32 77 74 
    ld (L7477_render_buffer_effect), a  ; fade in effect when rendering
#8381#1981318
cd aa 83 
    call L83aa_redraw_whole_screen
#8384#198415
af 
    xor a
#8385#1985314
32 6c 74 
    ld (L746c_game_flags), a
#8388#1988314
32 6d 74 
    ld (L746c_game_flags + 1), a
#838b#198b111
c9 
    ret
#838c#198c
#838c#198c
#838c#198c
; --------------------------------
#838c#198c
; Calculates the check sum of a block of data.
#838c#198c
; Input:
#838c#198c
; - de: ptr to the data to calculate the checksum for
#838c#198c
; - hl: length of the data
#838c#198c
; Output:
#838c#198c
; - bc: 16bit checksum
#838c#198c
L838c_checksum:
#838c#198c
    ; Initialize checksum to 0:
#838c#198c15
af 
    xor a
#838d#198d15
47 
    ld b, a
#838e#198e15
4f 
    ld c, a
#838f#198f
L838f_checksum_loop:
#838f#198f
    ; xor each pair of bytes in the data with "bc":
#838f#198f18
1a 
    ld a, (de)
#8390#199015
a8 
    xor b
#8391#199115
47 
    ld b, a
#8392#199217
13 
    inc de
#8393#199317
2b 
    dec hl
#8394#199415
7d 
    ld a, l
#8395#199515
b4 
    or h
#8396#1996213/8
28 09 
    jr z, L83a1_checksum_done
#8398#199818
1a 
    ld a, (de)
#8399#199915
a9 
    xor c
#839a#199a15
4f 
    ld c, a
#839b#199b17
13 
    inc de
#839c#199c17
2b 
    dec hl
#839d#199d15
7d 
    ld a, l
#839e#199e15
b4 
    or h
#839f#199f213/8
20 ee 
    jr nz, L838f_checksum_loop
#83a1#19a1
L83a1_checksum_done:
#83a1#19a1210
cb 20 
    sla b
#83a3#19a3210
cb 11 
    rl c
#83a5#19a5210
cb 10 
    rl b
#83a7#19a7210
cb 11 
    rl c
#83a9#19a9111
c9 
    ret
#83aa#19aa
#83aa#19aa
#83aa#19aa
; --------------------------------
#83aa#19aa
; Redraws the whole screen, including:
#83aa#19aa
; - UI elements
#83aa#19aa
; - 3d view
#83aa#19aa
L83aa_redraw_whole_screen:
#83aa#19aa217
dd e5 
    push ix
#83ac#19ac217
fd e5 
    push iy
#83ae#19ae112
e5 
    push hl
#83af#19af112
d5 
    push de
#83b0#19b0112
c5 
    push bc
#83b1#19b1112
f5 
    push af
#83b2#19b2314
3a 74 74 
        ld a, (L7474_check_if_object_crushed_player_flag)
#83b5#19b515
b7 
        or a
#83b6#19b6213/8
28 07 
        jr z, L83bf_no_need_to_check_crush
#83b8#19b8318
cd aa ca 
        call Lcaaa_check_if_object_crushed_player
#83bb#19bb15
b7 
        or a
#83bc#19bc311
c2 0b 84 
        jp nz, L840b_update_ui_and_done
#83bf#19bf
L83bf_no_need_to_check_crush:
#83bf#19bf314
3a 6c 74 
        ld a, (L746c_game_flags)
#83c2#19c2210
cb 57 
        bit 2, a
#83c4#19c4213/8
28 25 
        jr z, L83eb_no_need_to_reproject_objects
#83c6#19c6318
cd b7 8b 
        call L8bb7_determine_rendering_volume
#83c9#19c9318
cd de 95 
        call L95de_init_rotation_matrix
#83cc#19cc15
af 
        xor a
#83cd#19cd314
32 69 74 
        ld (L7469_n_spirits_found_in_current_area), a
#83d0#19d0422
dd 2a 63 74 
        ld ix, (L7463_global_area_objects)
#83d4#19d4314
3a 65 74 
        ld a, (L7465_global_area_n_objects)
#83d7#19d715
b7 
        or a
#83d8#19d8318/11
c4 31 84 
        call nz, L8431_project_objects
#83db#19db422
dd 2a d1 6a 
        ld ix, (L6ad1_current_area_objects)
#83df#19df314
3a d0 6a 
        ld a, (L6ad0_current_area_n_objects)
#83e2#19e215
b7 
        or a
#83e3#19e3318/11
c4 31 84 
        call nz, L8431_project_objects
#83e6#19e6318
cd 2d 9c 
        call L9c2d_sort_objects_for_rendering
#83e9#19e9213
18 13 
        jr L83fe_rerender
#83eb#19eb
L83eb_no_need_to_reproject_objects:
#83eb#19eb
        ; If there is a lightning, re-render for sure:
#83eb#19eb314
3a 0e 6b 
        ld a, (L6b0e_lightning_time_seconds_countdown)
#83ee#19ee15
b7 
        or a
#83ef#19ef213/8
20 06 
        jr nz, L83f7  ; if there is no lightning, rerender only if the re-render flag is set.
#83f1#19f1314
3a 19 6b 
        ld a, (L6b19_current_area_flags)
#83f4#19f415
b7 
        or a
#83f5#19f5213/8
20 07 
        jr nz, L83fe_rerender
#83f7#19f7
L83f7:
#83f7#19f7314
3a 6d 74 
        ld a, (L746c_game_flags + 1)
#83fa#19fa210
cb 5f 
        bit 3, a  ; check if we need to re-render.
#83fc#19fc213/8
28 0d 
        jr z, L840b_update_ui_and_done  ; skip re-render
#83fe#19fe
L83fe_rerender:
#83fe#19fe318
cd 52 bc 
        call Lbc52_update_UI
#8401#1a01318
cd 46 9d 
        call L9d46_render_3d_view
#8404#1a04318
cd bc 9d 
        call L9dbc_render_buffer_with_effects
#8407#1a07213
18 05 
        jr L840e_continue
#8409#1a09213
18 03 
        jr L840e_continue  ; Note: unreachable?
#840b#1a0b
L840b_update_ui_and_done:
#840b#1a0b318
cd 52 bc 
        call Lbc52_update_UI
#840e#1a0e
L840e_continue:
#840e#1a0e
        ; Check if we need to reprint the current room name:
#840e#1a0e314
3a 6d 74 
        ld a, (L746c_game_flags + 1)
#8411#1a11210
cb 6f 
        bit 5, a
#8413#1a13213/8
28 13 
        jr z, L8428_done
#8415#1a15
#8415#1a15
L8415_pause_loop:
#8415#1a15314
3a a5 74 
        ld a, (L74a5_interrupt_timer)
#8418#1a1815
b7 
        or a
#8419#1a19213/8
20 fa 
        jr nz, L8415_pause_loop
#841b#1a1b
        ; Print the current room name:
#841b#1a1b311
21 bf 6a 
        ld hl, L6abf_current_area_name_string
#841e#1a1e416
dd 21 5a 73 
        ld ix, L735a_ui_message_row_pointers
#8422#1a22311
11 00 0f 
        ld de, #0f00  ; string length = 15, no x offset
#8425#1a25318
cd 1c d0 
        call Ld01c_draw_string
#8428#1a28
L8428_done:
#8428#1a28111
f1 
    pop af
#8429#1a29111
c1 
    pop bc
#842a#1a2a111
d1 
    pop de
#842b#1a2b111
e1 
    pop hl
#842c#1a2c216
fd e1 
    pop iy
#842e#1a2e216
dd e1 
    pop ix
#8430#1a30111
c9 
    ret
#8431#1a31
#8431#1a31
#8431#1a31
; --------------------------------
#8431#1a31
; Projects all objects from 3d coordinates to 2d coordinates, determining which ones have to be drawn.
#8431#1a31
; - When this function is called this has already happened:
#8431#1a31
;   - rendering cube volume has been calculated
#8431#1a31
;   - rotation matrix has already been set
#8431#1a31
; Input:
#8431#1a31
; - a: number of objects
#8431#1a31
; - ix: pointer to objects
#8431#1a31
L8431_project_objects:
#8431#1a31
L8431_object_loop:
#8431#1a31112
f5 
    push af
#8432#1a32422
dd 22 9d 74 
        ld (L749d_object_currently_being_processed_ptr), ix
#8436#1a36321
dd 7e 00 
        ld a, (ix + OBJECT_TYPE_AND_FLAGS)
#8439#1a3928
e6 0f 
        and #0f
#843b#1a3b311
ca fb 84 
        jp z, L84fb_next_object
#843e#1a3e422
dd cb 00 76 
        bit 6, (ix + OBJECT_TYPE_AND_FLAGS)
#8442#1a42311
c2 fb 84 
        jp nz, L84fb_next_object
#8445#1a4528
fe 02 
        cp 2  ; Check if it's a spirit
#8447#1a47213/8
20 07 
        jr nz, L8450_not_a_spirit
#8449#1a49
        ; It is a spirit, increment the counter of spirits found:
#8449#1a49311
21 69 74 
        ld hl, L7469_n_spirits_found_in_current_area
#844c#1a4c112
34 
        inc (hl)
#844d#1a4d311
c3 fb 84 
        jp L84fb_next_object
#8450#1a50
L8450_not_a_spirit:
#8450#1a50314
3a bd 6a 
        ld a, (L6abd_cull_by_rendering_volume_flag)
#8453#1a5315
b7 
        or a
#8454#1a54213/8
20 1b 
        jr nz, L8471_skip_rendering_volume_cull_check
#8456#1a56
#8456#1a56
        ; Rendering cube cull check:
#8456#1a56
        ; Check if the object intersects with the rendering volume:
#8456#1a56311
21 5d 74 
        ld hl, L745d_rendering_cube_volume
#8459#1a5928
06 03 
        ld b, 3  ; 3 iterations, one for X, one for Y, one for Z
#845b#1a5b
L845b_rendering_volume_cull_check_loop:
#845b#1a5b321
dd 7e 01 
        ld a, (ix + OBJECT_X)
#845e#1a5e18
be 
        cp (hl)
#845f#1a5f213/8
28 03 
        jr z, L8464
#8461#1a61311
f2 fb 84 
        jp p, L84fb_next_object  ; Outside of rendering volume
#8464#1a64
L8464:
#8464#1a64321
dd 86 04 
        add a, (ix + OBJECT_SIZE_X)
#8467#1a6717
23 
        inc hl
#8468#1a6818
be 
        cp (hl)
#8469#1a69311
fa fb 84 
        jp m, L84fb_next_object  ; Outside of rendering volume
#846c#1a6c212
dd 23 
        inc ix
#846e#1a6e17
23 
        inc hl
#846f#1a6f214/9
10 ea 
        djnz L845b_rendering_volume_cull_check_loop
#8471#1a71
#8471#1a71
        ; Passed the cull check, object intersects with the rendering volume!
#8471#1a71
L8471_skip_rendering_volume_cull_check:
#8471#1a71422
ed 5b 99 74 
        ld de, (L7499_3d_object_bounding_box_relative_to_player_ptr)
#8475#1a7515
af 
        xor a
#8476#1a76422
dd 2a 9d 74 
        ld ix, (L749d_object_currently_being_processed_ptr)
#847a#1a7a311
21 ad 6a 
        ld hl, L6aad_player_current_x
#847d#1a7d28
06 03 
        ld b, 3
#847f#1a7f
        ; This loop iterates 3 times, one for x, one for y and one for z:
#847f#1a7f
        ; It is used to:
#847f#1a7f
        ; - check if the player is within the bounding box defined by the object (stored in L5e62_player_collision_with_object_flags).
#847f#1a7f
        ; - store the relative bounding box coordinates relative to the player in the pointer in L7499_3d_object_bounding_box_relative_to_player_ptr.
#847f#1a7f
L847f_player_coordinate_loop:
#847f#1a7f112
c5 
        push bc
#8480#1a8018
4e 
            ld c, (hl)
#8481#1a8117
23 
            inc hl
#8482#1a8218
46 
            ld b, (hl)  ; bc = player coordinate (x, y or z)
#8483#1a8317
23 
            inc hl
#8484#1a84112
e5 
            push hl
#8485#1a8528
2e 00 
                ld l, 0
#8487#1a87321
dd 66 01 
                ld h, (ix + OBJECT_X)
#848a#1a8a210
cb 3c 
                srl h
#848c#1a8c210
cb 1d 
                rr l
#848e#1a8e210
cb 3c 
                srl h
#8490#1a90210
cb 1d 
                rr l  ; hl = object coordinate * 64
#8492#1a9215
b7 
                or a
#8493#1a93217
ed 42 
                sbc hl, bc  ; hl = object coordinate * 64 - player coordinate
#8495#1a95213/8
28 05 
                jr z, L849c
#8497#1a97311
fa 9c 84 
                jp m, L849c
#849a#1a9a
                ; player coordinate < object coordinate 1
#849a#1a9a210
cb f7 
                set 6, a
#849c#1a9c
L849c:
#849c#1a9c210
cb 3f 
                srl a
#849e#1a9e
                ; save the object coordinate - player coordinate to (de)
#849e#1a9e15
eb 
                ex de, hl
#849f#1a9f18
73 
                    ld (hl), e
#84a0#1aa017
23 
                    inc hl
#84a1#1aa118
72 
                    ld (hl), d
#84a2#1aa217
23 
                    inc hl
#84a3#1aa315
eb 
                ex de, hl
#84a4#1aa4
#84a4#1aa428
0e 00 
                ld c, 0
#84a6#1aa6321
dd 46 04 
                ld b, (ix + OBJECT_SIZE_X)
#84a9#1aa9210
cb 38 
                srl b
#84ab#1aab210
cb 19 
                rr c
#84ad#1aad210
cb 38 
                srl b
#84af#1aaf210
cb 19 
                rr c  ; bc = object size * 64
#84b1#1ab115
b7 
                or a
#84b2#1ab2217
ed 4a 
                adc hl, bc  ; hl = (coordinate + size) * 64 - player coordinate
#84b4#1ab4311
f2 b9 84 
                jp p, L84b9
#84b7#1ab7
                ; player coordinate > object coordinate 2
#84b7#1ab7210
cb f7 
                set 6, a
#84b9#1ab9
L84b9:
#84b9#1ab9210
cb 3f 
                srl a
#84bb#1abb
                ; save the object coordinate 2 - player coordinate to (de)
#84bb#1abb15
eb 
                ex de, hl
#84bc#1abc18
73 
                    ld (hl), e
#84bd#1abd17
23 
                    inc hl
#84be#1abe18
72 
                    ld (hl), d
#84bf#1abf17
23 
                    inc hl
#84c0#1ac015
eb 
                ex de, hl
#84c1#1ac1212
dd 23 
                inc ix
#84c3#1ac3111
e1 
            pop hl
#84c4#1ac4111
c1 
        pop bc
#84c5#1ac5214/9
10 b8 
        djnz L847f_player_coordinate_loop
#84c7#1ac7
        ; If player is inside of the bounding box, we will have a = #3f
#84c7#1ac7
        ; Each of the 6 bits represents a collision in one of the 6 directions one can collide with a cube,
#84c7#1ac7
        ; If this is 0, it means collision, any other thing than 0 is NO collision.
#84c7#1ac7314
32 62 5e 
        ld (L5e62_player_collision_with_object_flags), a
#84ca#1aca422
dd 2a 9d 74 
        ld ix, (L749d_object_currently_being_processed_ptr)
#84ce#1ace321
dd 7e 07 
        ld a, (ix + OBJECT_ID)
#84d1#1ad1314
32 68 74 
        ld (L7468_focus_object_id), a
#84d4#1ad4321
dd 7e 00 
        ld a, (ix + OBJECT_TYPE_AND_FLAGS)
#84d7#1ad728
e6 0f 
        and #0f
#84d9#1ad9314
32 61 5e 
        ld (L5e61_object_currently_being_processed_type), a
#84dc#1adc28
fe 01 
        cp OBJECT_TYPE_CUBE
#84de#1ade213/8
20 05 
        jr nz, L84e5
#84e0#1ae0318
cd 61 96 
        call L9661_project_cube_objects
#84e3#1ae3213
18 16 
        jr L84fb_next_object
#84e5#1ae5
L84e5:
#84e5#1ae528
fe 03 
        cp OBJECT_TYPE_RECTANGLE
#84e7#1ae7213/8
20 05 
        jr nz, L84ee
#84e9#1ae9318
cd 5b 9b 
        call L9b5b_project_rectangle_objects
#84ec#1aec213
18 0d 
        jr L84fb_next_object
#84ee#1aee
L84ee:
#84ee#1aee28
fe 0a 
        cp OBJECT_TYPE_LINE
#84f0#1af0311
f2 f8 84 
        jp p, L84f8
#84f3#1af3318
cd bb 97 
        call L97bb_project_other_solids
#84f6#1af6213
18 03 
        jr L84fb_next_object
#84f8#1af8
L84f8:
#84f8#1af8
        ; Objects with ID >= 10 means that they are basic shapes (line, triangle, quad, pentagon, hexagon.):
#84f8#1af8
        ; - they have ID - 8 vertices in their geometry.
#84f8#1af8318
cd c5 9a 
        call L9ac5_project_flat_shape_object
#84fb#1afb
L84fb_next_object:
#84fb#1afb
        ; Get the pointer to the next object, and loop:
#84fb#1afb422
dd 2a 9d 74 
        ld ix, (L749d_object_currently_being_processed_ptr)
#84ff#1aff321
dd 5e 08 
        ld e, (ix + OBJECT_SIZE)
#8502#1b0228
16 00 
        ld d, 0
#8504#1b04217
dd 19 
        add ix, de
#8506#1b06111
f1 
    pop af
#8507#1b0715
3d 
    dec a
#8508#1b08311
c2 31 84 
    jp nz, L8431_object_loop
#850b#1b0b111
c9 
    ret
#850c#1b0c
#850c#1b0c
#850c#1b0c
; --------------------------------
#850c#1b0c
; Auxiliary variables for L850f_apply_rotation_matrix_to_object_vertices
#850c#1b0c
L850c_vertex_times_matrix_24bit_accumulator:  ; 24 bit number buffer
#850c#1b0c3
    db #00, #00, #00
#850f#1b0f
#850f#1b0f
#850f#1b0f
; --------------------------------
#850f#1b0f
; Given object vertex coordinates already relative to the player,
#850f#1b0f
; stored in (L5e63_3d_vertex_coordinates_relative_to_player), this
#850f#1b0f
; method multiplies them by the rotation matrix (L5e55_rotation_matrix),
#850f#1b0f
; and stores the results in (L5e9f_3d_vertex_coordinates_after_rotation_matrix).
#850f#1b0f
L850f_apply_rotation_matrix_to_object_vertices:
#850f#1b0f416
fd 21 63 5e 
    ld iy, L5e63_3d_vertex_coordinates_relative_to_player
#8513#1b13311
21 9f 5e 
    ld hl, L5e9f_3d_vertex_coordinates_after_rotation_matrix
#8516#1b16314
3a 96 74 
    ld a, (L7496_current_drawing_primitive_n_vertices)
#8519#1b1915
4f 
    ld c, a
#851a#1b1a
L851a_vertex_loop:
#851a#1b1a
    ; Multiply the vertex 3d vector by the rotation matrix:
#851a#1b1a416
dd 21 55 5e 
    ld ix, L5e55_rotation_matrix
#851e#1b1e28
06 03 
    ld b, 3
#8520#1b20
L8520_coordinate_loop:
#8520#1b20112
e5 
    push hl
#8521#1b21
        ; Zero out the 24bit accumulator:
#8521#1b2115
af 
        xor a
#8522#1b22314
32 0c 85 
        ld (L850c_vertex_times_matrix_24bit_accumulator), a
#8525#1b25314
32 0d 85 
        ld (L850c_vertex_times_matrix_24bit_accumulator + 1), a
#8528#1b28314
32 0e 85 
        ld (L850c_vertex_times_matrix_24bit_accumulator + 2), a
#852b#1b2b
        ; x * matrix[b][0]
#852b#1b2b321
dd 7e 00 
        ld a, (ix)  ; ix points to the rotation matrix
#852e#1b2e212
dd 23 
        inc ix
#8530#1b3015
b7 
        or a
#8531#1b31213/8
28 0f 
        jr z, L8542_multiply_by_0
#8533#1b33321
fd 6e 00 
        ld l, (iy)
#8536#1b36321
fd 66 01 
        ld h, (iy + 1)  ; Get "x" vertex coordinate
#8539#1b39318
cd 08 a1 
        call La108_a_times_hl_signed
#853c#1b3c314
32 0e 85 
        ld (L850c_vertex_times_matrix_24bit_accumulator + 2), a
#853f#1b3f317
22 0c 85 
        ld (L850c_vertex_times_matrix_24bit_accumulator), hl
#8542#1b42
L8542_multiply_by_0:
#8542#1b42
        ; y * matrix[b][1]
#8542#1b42321
dd 7e 00 
        ld a, (ix)
#8545#1b45212
dd 23 
        inc ix
#8547#1b4715
b7 
        or a
#8548#1b48213/8
28 19 
        jr z, L8563_multiply_by_0
#854a#1b4a321
fd 6e 02 
        ld l, (iy + 2)
#854d#1b4d321
fd 66 03 
        ld h, (iy + 3)  ; Get "y" vertex coordinate
#8550#1b50318
cd 08 a1 
        call La108_a_times_hl_signed
#8553#1b53
        ; Add to the 24 bit accumulator:
#8553#1b53422
ed 5b 0c 85 
        ld de, (L850c_vertex_times_matrix_24bit_accumulator)
#8557#1b57112
19 
        add hl, de
#8558#1b58317
22 0c 85 
        ld (L850c_vertex_times_matrix_24bit_accumulator), hl
#855b#1b5b15
5f 
        ld e, a
#855c#1b5c314
3a 0e 85 
        ld a, (L850c_vertex_times_matrix_24bit_accumulator + 2)
#855f#1b5f15
8b 
        adc a, e
#8560#1b60314
32 0e 85 
        ld (L850c_vertex_times_matrix_24bit_accumulator + 2), a
#8563#1b63
L8563_multiply_by_0:
#8563#1b63
        ; z * matrix[b][2]
#8563#1b63321
dd 7e 00 
        ld a, (ix)
#8566#1b66212
dd 23 
        inc ix
#8568#1b6815
b7 
        or a
#8569#1b69213/8
28 19 
        jr z, L8584_multiply_by_0
#856b#1b6b321
fd 6e 04 
        ld l, (iy + 4)
#856e#1b6e321
fd 66 05 
        ld h, (iy + 5)  ; Get "z" vertex coordinate
#8571#1b71318
cd 08 a1 
        call La108_a_times_hl_signed
#8574#1b74
        ; Add to the 24 bit accumulator:
#8574#1b74422
ed 5b 0c 85 
        ld de, (L850c_vertex_times_matrix_24bit_accumulator)
#8578#1b78112
19 
        add hl, de
#8579#1b79317
22 0c 85 
        ld (L850c_vertex_times_matrix_24bit_accumulator), hl
#857c#1b7c15
5f 
        ld e, a
#857d#1b7d314
3a 0e 85 
        ld a, (L850c_vertex_times_matrix_24bit_accumulator + 2)
#8580#1b8015
8b 
        adc a, e
#8581#1b81314
32 0e 85 
        ld (L850c_vertex_times_matrix_24bit_accumulator + 2), a
#8584#1b84
L8584_multiply_by_0:
#8584#1b84317
2a 0c 85 
        ld hl, (L850c_vertex_times_matrix_24bit_accumulator)
#8587#1b87314
3a 0e 85 
        ld a, (L850c_vertex_times_matrix_24bit_accumulator + 2)
#858a#1b8a
        ; (a, e) = (a, hl) / 64
#858a#1b8a112
29 
        add hl, hl
#858b#1b8b15
17 
        rla
#858c#1b8c112
29 
        add hl, hl
#858d#1b8d15
17 
        rla
#858e#1b8e15
5c 
        ld e, h
#858f#1b8f111
e1 
    pop hl
#8590#1b9018
73 
    ld (hl), e
#8591#1b9117
23 
    inc hl
#8592#1b9218
77 
    ld (hl), a
#8593#1b9317
23 
    inc hl
#8594#1b94214/9
10 8a 
    djnz L8520_coordinate_loop
#8596#1b96
    ; next vertex:
#8596#1b96311
11 06 00 
    ld de, 6
#8599#1b99217
fd 19 
    add iy, de
#859b#1b9b15
0d 
    dec c
#859c#1b9c311
c2 1a 85 
    jp nz, L851a_vertex_loop
#859f#1b9f111
c9 
    ret
#85a0#1ba0
#85a0#1ba0
#85a0#1ba0
; --------------------------------
#85a0#1ba0
; Auxiliary variables for L85ae_clip_edge
#85a0#1ba0
L85a0_vertex1_coordinates:
#85a0#1ba06
    dw #0000, #0000, #0000
#85a6#1ba6
L85a6_vertex2_coordinates:
#85a6#1ba66
    dw #0000, #0000, #0000
#85ac#1bac
L85ac_vertex_frustum_checks:
#85ac#1bac2
    db #00, #00
#85ae#1bae
#85ae#1bae
#85ae#1bae
; --------------------------------
#85ae#1bae
; This function clips an edge to make sure both vertices are inside of the viewing area.
#85ae#1bae
; - If both fail the same frustum visibility check, the edge is discarded.
#85ae#1bae
; - Otherwise, for each failed test, a point that intersects with the viewing volume is calculated and the
#85ae#1bae
;   point that was outside of the volume is replaced.
#85ae#1bae
; - At the end, if all 5 frustum checks were able to be successfully passed, the points are
#85ae#1bae
;   projected.
#85ae#1bae
; Note: I think this method contains several bugs, that might be hard to detect, as
#85ae#1bae
;       they might only show up in certain corner cases. But this should be verified.
#85ae#1bae
;       I am, of course, not 100% sure.
#85ae#1bae
; Input:
#85ae#1bae
; - ix: ptr to "L5ee8_already_projected_vertex_coordinates" entry for this edge (+ 1)
#85ae#1bae
; - hl: pointer to 3d vertex 1 (after rotation matrix)
#85ae#1bae
; - iy: pointer to 3d vertex 2 (after rotation matrix)
#85ae#1bae
; - c: frustum checks of vertex 1
#85ae#1bae
; - b: frustum checks of vertex 2
#85ae#1bae
L85ae_clip_edge:
#85ae#1bae
    ; Save the vertex info to local variables:
#85ae#1bae422
ed 43 ac 85 
    ld (L85ac_vertex_frustum_checks), bc
#85b2#1bb2311
01 06 00 
    ld bc, 6
#85b5#1bb5311
11 a0 85 
    ld de, L85a0_vertex1_coordinates
#85b8#1bb8223/18
ed b0 
    ldir
#85ba#1bba28
0e 06 
    ld c, 6
#85bc#1bbc217
fd e5 
    push iy
#85be#1bbe111
e1 
    pop hl
#85bf#1bbf223/18
ed b0 
    ldir
#85c1#1bc1
#85c1#1bc1217
dd e5 
    push ix
#85c3#1bc3216
fd e1 
    pop iy  ; iy = ptr to "L5ee8_already_projected_vertex_coordinates" entry for this edge (+ 1)
#85c5#1bc5422
ed 4b ac 85 
    ld bc, (L85ac_vertex_frustum_checks)
#85c9#1bc9210
cb 41 
    bit 0, c
#85cb#1bcb213/8
20 07 
    jr nz, L85d4
#85cd#1bcd
    ; First vertex is behind the camera
#85cd#1bcd210
cb 40 
    bit 0, b
#85cf#1bcf311
ca cb 88 
    jp z, L88cb_mark_as_processed_and_return  ; if both are behind the camera, this edge projects no points.
#85d2#1bd2213
18 05 
    jr L85d9
#85d4#1bd4
#85d4#1bd4
L85d4:
#85d4#1bd4
    ; First point is in front of the camera
#85d4#1bd4210
cb 40 
    bit 0, b
#85d6#1bd6311
c2 66 86 
    jp nz, L8666
#85d9#1bd9
#85d9#1bd9
L85d9:
#85d9#1bd9
    ; One point is behind the camera, and one in front:
#85d9#1bd9317
2a a4 85 
    ld hl, (L85a0_vertex1_coordinates + 2 * 2)  ; hl = v1.z
#85dc#1bdc422
ed 5b aa 85 
    ld de, (L85a6_vertex2_coordinates + 2 * 2)  ; de = v2.z
#85e0#1be015
af 
    xor a
#85e1#1be1217
ed 52 
    sbc hl, de  ; hl = (v1.z - v2.z)
#85e3#1be3112
e5 
    push hl
#85e4#1be415
44 
        ld b, h  ; bc = (v1.z - v2.z)
#85e5#1be515
4d 
        ld c, l
#85e6#1be6317
2a a6 85 
        ld hl, (L85a6_vertex2_coordinates)  ; hl = v1.x
#85e9#1be9422
ed 5b a0 85 
        ld de, (L85a0_vertex1_coordinates)  ; de = v2.x
#85ed#1bed15
b7 
        or a
#85ee#1bee217
ed 52 
        sbc hl, de  ; hl = v1.x - v2.x
#85f0#1bf0422
ed 5b a4 85 
        ld de, (L85a0_vertex1_coordinates + 2 * 2)  ; d2 = v1.z
#85f4#1bf4318
cd 5e a1 
        call La15e_de_times_hl_signed  ; (de, hl) = v1.z * (v1.x - v2.x)
#85f7#1bf7318
cd b7 b1 
        call Lb1b7_de_hl_divided_by_bc_signed  ; (de, hl) = (v1.z * (v1.x - v2.x)) / (v1.z - v2.z)
#85fa#1bfa422
ed 5b a0 85 
        ld de, (L85a0_vertex1_coordinates)  ; v1.x
#85fe#1bfe112
19 
        add hl, de  ; hl = v1.z * (v1.x - v2.x) / (v1.z - v2.z) + v1.x
#85ff#1bff111
c1 
    pop bc  ; bc = (v1.z - v2.z)
#8600#1c00112
e5 
    push hl
#8601#1c01317
2a a8 85 
        ld hl, (L85a6_vertex2_coordinates + 1 * 2)
#8604#1c04422
ed 5b a2 85 
        ld de, (L85a0_vertex1_coordinates + 1 * 2)
#8608#1c0815
b7 
        or a
#8609#1c09217
ed 52 
        sbc hl, de  ; hl = v2.y - v1.y
#860b#1c0b422
ed 5b a4 85 
        ld de, (L85a0_vertex1_coordinates + 2 * 2)
#860f#1c0f318
cd 5e a1 
        call La15e_de_times_hl_signed  ; (de, hl) = v1.z * (v2.y - v1.y)
#8612#1c12318
cd b7 b1 
        call Lb1b7_de_hl_divided_by_bc_signed  ; (de, hl) = v1.z * (v2.y - v1.y) / (v1.z - v2.z)
#8615#1c15422
ed 5b a2 85 
        ld de, (L85a0_vertex1_coordinates + 1 * 2)
#8619#1c19112
19 
        add hl, de  ; (de, hl) = v1.z * (v2.y - v1.y) / (v1.z - v2.z) + v1.y
#861a#1c1a311
11 00 00 
        ld de, 0
#861d#1c1d314
3a ac 85 
        ld a, (L85ac_vertex_frustum_checks)
#8620#1c20210
cb 47 
        bit 0, a
#8622#1c22213/8
20 0d 
        jr nz, L8631_overwrite_vertex2
#8624#1c24
        ; Overwrite vertex 1:
#8624#1c24
        ; BUG? I think y and z are flipped here and this is wrongly calculated
#8624#1c24317
22 a2 85 
        ld (L85a0_vertex1_coordinates + 1 * 2), hl  ; v1.y = 0
#8627#1c27111
e1 
    pop hl
#8628#1c28317
22 a0 85 
    ld (L85a0_vertex1_coordinates), hl  ; v1.x = v1.z * (v1.x - v2.x) / (v1.z - v2.z) + v1.x
#862b#1c2b422
ed 53 a4 85 
    ld (L85a0_vertex1_coordinates + 2 * 2), de  ; v1.z = v1.z * (v2.y - v1.y) / (v1.z - v2.z) + v1.y
#862f#1c2f213
18 0b 
    jr L863c_both_vertices_in_front_of_camera
#8631#1c31
L8631_overwrite_vertex2:
#8631#1c31
    ; BUG? I think y and z are flipped here and this is wrongly calculated
#8631#1c31317
22 a8 85 
    ld (L85a6_vertex2_coordinates + 1 * 2), hl
#8634#1c34111
e1 
    pop hl
#8635#1c35317
22 a6 85 
    ld (L85a6_vertex2_coordinates), hl
#8638#1c38422
ed 53 aa 85 
    ld (L85a6_vertex2_coordinates + 2 * 2), de
#863c#1c3c
#863c#1c3c
L863c_both_vertices_in_front_of_camera:
#863c#1c3c
    ; Update bit 1 of the frustum checks for the new points:
#863c#1c3c422
ed 4b ac 85 
    ld bc, (L85ac_vertex_frustum_checks)
#8640#1c40
    ; BUG? bit "1" was "x - z" check in "L9246_object_visibility_check", but here
#8640#1c40
    ;      the code is doing "y - z" instead, which should be bit 2.
#8640#1c40210
cb c8 
    set 1, b
#8642#1c42210
cb c9 
    set 1, c
#8644#1c44317
2a a4 85 
    ld hl, (L85a0_vertex1_coordinates + 2 * 2)  ; v1.z
#8647#1c47422
ed 5b a2 85 
    ld de, (L85a0_vertex1_coordinates + 1 * 2)  ; v1.y
#864b#1c4b15
b7 
    or a
#864c#1c4c217
ed 52 
    sbc hl, de  ; hl = v1.y - v1.z
#864e#1c4e311
f2 53 86 
    jp p, L8653
#8651#1c51210
cb 89 
    res 1, c
#8653#1c53
L8653:
#8653#1c53317
2a aa 85 
    ld hl, (L85a6_vertex2_coordinates + 2 * 2)  ; v2.z
#8656#1c56422
ed 5b a8 85 
    ld de, (L85a6_vertex2_coordinates + 1 * 2)  ; v2.y
#865a#1c5a15
b7 
    or a
#865b#1c5b217
ed 52 
    sbc hl, de  ; hl = v2.y - v2.z
#865d#1c5d311
f2 62 86 
    jp p, L8662
#8660#1c60210
cb 88 
    res 1, b
#8662#1c62
L8662:
#8662#1c62422
ed 43 ac 85 
    ld (L85ac_vertex_frustum_checks), bc
#8666#1c66
#8666#1c66
    ; The remainder of this function is made out of 4 blocks analogous to the one above,
#8666#1c66
    ; in each block, if both vertexes are found to fail the same frustum check, the edge is
#8666#1c66
    ; ignored, otherwise, if only one of them fails it, a point that intersects with the plane
#8666#1c66
    ; that defines the frustum check in question is found, and the point that failed the check 
#8666#1c66
    ; is overwritten. This is done for all 4 remaining frustum checks, and at the end, 
#8666#1c66
    ; we can be sure that both points are inside the viewing area.
#8666#1c66
    ; Ensure both vertices pass frustum check 1:
#8666#1c66
L8666:
#8666#1c66210
cb 49 
    bit 1, c
#8668#1c68213/8
20 07 
    jr nz, L8671
#866a#1c6a210
cb 48 
    bit 1, b
#866c#1c6c311
ca cb 88 
    jp z, L88cb_mark_as_processed_and_return
#866f#1c6f213
18 05 
    jr L8676
#8671#1c71
L8671:
#8671#1c71210
cb 48 
    bit 1, b
#8673#1c73311
c2 e6 86 
    jp nz, L86e6_both_vertices_pass_frustum_check1
#8676#1c76
L8676:
#8676#1c76317
2a a4 85 
    ld hl, (L85a0_vertex1_coordinates + 2 * 2)
#8679#1c79422
ed 5b a2 85 
    ld de, (L85a0_vertex1_coordinates + 1 * 2)
#867d#1c7d15
af 
    xor a
#867e#1c7e217
ed 52 
    sbc hl, de
#8680#1c80112
e5 
    push hl
#8681#1c81317
2a a8 85 
    ld hl, (L85a6_vertex2_coordinates + 1 * 2)
#8684#1c84416
dd 21 b3 86 
    ld ix, L86b3
#8688#1c88
L8688:
#8688#1c8815
af 
    xor a
#8689#1c89217
ed 52 
    sbc hl, de
#868b#1c8b422
ed 5b aa 85 
    ld de, (L85a6_vertex2_coordinates + 2 * 2)
#868f#1c8f15
af 
    xor a
#8690#1c90217
ed 52 
    sbc hl, de
#8692#1c92422
ed 5b a4 85 
    ld de, (L85a0_vertex1_coordinates + 2 * 2)
#8696#1c96112
19 
    add hl, de
#8697#1c9715
44 
    ld b, h
#8698#1c9815
4d 
    ld c, l
#8699#1c99317
2a aa 85 
    ld hl, (L85a6_vertex2_coordinates + 2 * 2)
#869c#1c9c15
b7 
    or a
#869d#1c9d217
ed 52 
    sbc hl, de
#869f#1c9f111
d1 
    pop de
#86a0#1ca0112
d5 
    push de
#86a1#1ca1112
c5 
    push bc
#86a2#1ca2318
cd 5e a1 
    call La15e_de_times_hl_signed
#86a5#1ca5318
cd b7 b1 
    call Lb1b7_de_hl_divided_by_bc_signed
#86a8#1ca8422
ed 5b a4 85 
    ld de, (L85a0_vertex1_coordinates + 2 * 2)
#86ac#1cac112
19 
    add hl, de
#86ad#1cad111
c1 
    pop bc
#86ae#1cae111
d1 
    pop de
#86af#1caf112
e5 
    push hl
#86b0#1cb0112
d5 
    push de
#86b1#1cb1210
dd e9 
    jp ix
#86b3#1cb3
L86b3:
#86b3#1cb3317
2a a6 85 
    ld hl, (L85a6_vertex2_coordinates)
#86b6#1cb6422
ed 5b a0 85 
    ld de, (L85a0_vertex1_coordinates)
#86ba#1cba15
af 
    xor a
#86bb#1cbb217
ed 52 
    sbc hl, de
#86bd#1cbd111
d1 
    pop de
#86be#1cbe318
cd 5e a1 
    call La15e_de_times_hl_signed
#86c1#1cc1318
cd b7 b1 
    call Lb1b7_de_hl_divided_by_bc_signed
#86c4#1cc4422
ed 5b a0 85 
    ld de, (L85a0_vertex1_coordinates)
#86c8#1cc8112
19 
    add hl, de
#86c9#1cc9314
3a ac 85 
    ld a, (L85ac_vertex_frustum_checks)
#86cc#1ccc210
cb 4f 
    bit 1, a
#86ce#1cce213/8
20 0c 
    jr nz, L86dc
#86d0#1cd0317
22 a0 85 
    ld (L85a0_vertex1_coordinates), hl
#86d3#1cd3111
e1 
    pop hl
#86d4#1cd4317
22 a2 85 
    ld (L85a0_vertex1_coordinates + 1 * 2), hl
#86d7#1cd7317
22 a4 85 
    ld (L85a0_vertex1_coordinates + 2 * 2), hl
#86da#1cda213
18 0a 
    jr L86e6_both_vertices_pass_frustum_check1
#86dc#1cdc
L86dc:
#86dc#1cdc317
22 a6 85 
    ld (L85a6_vertex2_coordinates), hl
#86df#1cdf111
e1 
    pop hl
#86e0#1ce0317
22 a8 85 
    ld (L85a6_vertex2_coordinates + 1 * 2), hl
#86e3#1ce3317
22 aa 85 
    ld (L85a6_vertex2_coordinates + 2 * 2), hl
#86e6#1ce6
#86e6#1ce6
L86e6_both_vertices_pass_frustum_check1:
#86e6#1ce6
    ; BUG? Same as above, I think these are flipped!
#86e6#1ce6
    ;      bit "2" was "y - z" check in "L9246_object_visibility_check", but here
#86e6#1ce6
    ;      the code is doing "x - z" instead, which should be bit 1.
#86e6#1ce6422
ed 4b ac 85 
    ld bc, (L85ac_vertex_frustum_checks)
#86ea#1cea210
cb d0 
    set 2, b
#86ec#1cec210
cb d1 
    set 2, c
#86ee#1cee317
2a a4 85 
    ld hl, (L85a0_vertex1_coordinates + 2 * 2)  ; v1.z
#86f1#1cf1422
ed 5b a0 85 
    ld de, (L85a0_vertex1_coordinates)  ; v1.x
#86f5#1cf515
b7 
    or a
#86f6#1cf6217
ed 52 
    sbc hl, de
#86f8#1cf8311
f2 fd 86 
    jp p, L86fd
#86fb#1cfb210
cb 91 
    res 2, c
#86fd#1cfd
L86fd:
#86fd#1cfd317
2a aa 85 
    ld hl, (L85a6_vertex2_coordinates + 2 * 2)  ; v2.z
#8700#1d00422
ed 5b a6 85 
    ld de, (L85a6_vertex2_coordinates)  ; v2.x
#8704#1d0415
b7 
    or a
#8705#1d05217
ed 52 
    sbc hl, de
#8707#1d07311
f2 0c 87 
    jp p, L870c
#870a#1d0a210
cb 90 
    res 2, b
#870c#1d0c
L870c:
#870c#1d0c422
ed 43 ac 85 
    ld (L85ac_vertex_frustum_checks), bc
#8710#1d10210
cb 51 
    bit 2, c
#8712#1d12213/8
20 07 
    jr nz, L871b
#8714#1d14210
cb 50 
    bit 2, b
#8716#1d16311
ca cb 88 
    jp z, L88cb_mark_as_processed_and_return
#8719#1d19213
18 05 
    jr L8720
#871b#1d1b
L871b:
#871b#1d1b210
cb 50 
    bit 2, b
#871d#1d1d311
c2 68 87 
    jp nz, L8768_both_vertices_pass_frustum_check2
#8720#1d20
L8720:
#8720#1d20317
2a a4 85 
    ld hl, (L85a0_vertex1_coordinates + 2 * 2)
#8723#1d23422
ed 5b a0 85 
    ld de, (L85a0_vertex1_coordinates)
#8727#1d2715
af 
    xor a
#8728#1d28217
ed 52 
    sbc hl, de
#872a#1d2a112
e5 
    push hl
#872b#1d2b317
2a a6 85 
    ld hl, (L85a6_vertex2_coordinates)
#872e#1d2e416
dd 21 35 87 
    ld ix, L8735
#8732#1d32311
c3 88 86 
    jp L8688
#8735#1d35
L8735:
#8735#1d35317
2a a8 85 
    ld hl, (L85a6_vertex2_coordinates + 1 * 2)
#8738#1d38422
ed 5b a2 85 
    ld de, (L85a0_vertex1_coordinates + 1 * 2)
#873c#1d3c15
af 
    xor a
#873d#1d3d217
ed 52 
    sbc hl, de
#873f#1d3f111
d1 
    pop de
#8740#1d40318
cd 5e a1 
    call La15e_de_times_hl_signed
#8743#1d43318
cd b7 b1 
    call Lb1b7_de_hl_divided_by_bc_signed
#8746#1d46422
ed 5b a2 85 
    ld de, (L85a0_vertex1_coordinates + 1 * 2)
#874a#1d4a112
19 
    add hl, de
#874b#1d4b314
3a ac 85 
    ld a, (L85ac_vertex_frustum_checks)
#874e#1d4e210
cb 57 
    bit 2, a
#8750#1d50213/8
20 0c 
    jr nz, L875e
#8752#1d52317
22 a2 85 
    ld (L85a0_vertex1_coordinates + 1 * 2), hl
#8755#1d55111
e1 
    pop hl
#8756#1d56317
22 a0 85 
    ld (L85a0_vertex1_coordinates), hl
#8759#1d59317
22 a4 85 
    ld (L85a0_vertex1_coordinates + 2 * 2), hl
#875c#1d5c213
18 0a 
    jr L8768_both_vertices_pass_frustum_check2
#875e#1d5e
L875e:
#875e#1d5e317
22 a8 85 
    ld (L85a6_vertex2_coordinates + 1 * 2), hl
#8761#1d61111
e1 
    pop hl
#8762#1d62317
22 a6 85 
    ld (L85a6_vertex2_coordinates), hl
#8765#1d65317
22 aa 85 
    ld (L85a6_vertex2_coordinates + 2 * 2), hl
#8768#1d68
#8768#1d68
L8768_both_vertices_pass_frustum_check2:
#8768#1d68422
ed 4b ac 85 
    ld bc, (L85ac_vertex_frustum_checks)
#876c#1d6c210
cb d8 
    set 3, b
#876e#1d6e210
cb d9 
    set 3, c
#8770#1d70317
2a a4 85 
    ld hl, (L85a0_vertex1_coordinates + 2 * 2)  ; v1.z
#8773#1d73422
ed 5b a2 85 
    ld de, (L85a0_vertex1_coordinates + 1 * 2)  ; v1.y
#8777#1d7715
b7 
    or a
#8778#1d78217
ed 5a 
    adc hl, de
#877a#1d7a311
f2 7f 87 
    jp p, L877f
#877d#1d7d210
cb 99 
    res 3, c
#877f#1d7f
L877f:
#877f#1d7f317
2a aa 85 
    ld hl, (L85a6_vertex2_coordinates + 2 * 2)  ; v2.z
#8782#1d82422
ed 5b a8 85 
    ld de, (L85a6_vertex2_coordinates + 1 * 2)  ; v2.y
#8786#1d8615
b7 
    or a
#8787#1d87217
ed 5a 
    adc hl, de
#8789#1d89311
f2 8e 87 
    jp p, L878e
#878c#1d8c210
cb 98 
    res 3, b
#878e#1d8e
L878e:
#878e#1d8e422
ed 43 ac 85 
    ld (L85ac_vertex_frustum_checks), bc
#8792#1d92210
cb 59 
    bit 3, c
#8794#1d94213/8
20 07 
    jr nz, L879d
#8796#1d96210
cb 58 
    bit 3, b
#8798#1d98311
ca cb 88 
    jp z, L88cb_mark_as_processed_and_return
#879b#1d9b213
18 05 
    jr L87a2
#879d#1d9d
L879d:
#879d#1d9d210
cb 58 
    bit 3, b
#879f#1d9f311
c2 1b 88 
    jp nz, L881b_both_vertices_pass_frustum_check3
#87a2#1da2
L87a2:
#87a2#1da2317
2a a4 85 
    ld hl, (L85a0_vertex1_coordinates + 2 * 2)
#87a5#1da5422
ed 5b a2 85 
    ld de, (L85a0_vertex1_coordinates + 1 * 2)
#87a9#1da9112
19 
    add hl, de
#87aa#1daa112
e5 
    push hl
#87ab#1dab317
2a a8 85 
    ld hl, (L85a6_vertex2_coordinates + 1 * 2)
#87ae#1dae416
dd 21 de 87 
    ld ix, L87de
#87b2#1db2
L87b2:
#87b2#1db215
eb 
    ex de, hl
#87b3#1db315
af 
    xor a
#87b4#1db4217
ed 52 
    sbc hl, de
#87b6#1db6422
ed 5b aa 85 
    ld de, (L85a6_vertex2_coordinates + 2 * 2)
#87ba#1dba15
af 
    xor a
#87bb#1dbb217
ed 52 
    sbc hl, de
#87bd#1dbd422
ed 5b a4 85 
    ld de, (L85a0_vertex1_coordinates + 2 * 2)
#87c1#1dc1112
19 
    add hl, de
#87c2#1dc215
44 
    ld b, h
#87c3#1dc315
4d 
    ld c, l
#87c4#1dc4317
2a aa 85 
    ld hl, (L85a6_vertex2_coordinates + 2 * 2)
#87c7#1dc715
b7 
    or a
#87c8#1dc8217
ed 52 
    sbc hl, de
#87ca#1dca111
d1 
    pop de
#87cb#1dcb112
d5 
    push de
#87cc#1dcc112
c5 
    push bc
#87cd#1dcd318
cd 5e a1 
    call La15e_de_times_hl_signed
#87d0#1dd0318
cd b7 b1 
    call Lb1b7_de_hl_divided_by_bc_signed
#87d3#1dd3422
ed 5b a4 85 
    ld de, (L85a0_vertex1_coordinates + 2 * 2)
#87d7#1dd7112
19 
    add hl, de
#87d8#1dd8111
c1 
    pop bc
#87d9#1dd9111
d1 
    pop de
#87da#1dda112
e5 
    push hl
#87db#1ddb112
d5 
    push de
#87dc#1ddc210
dd e9 
    jp ix
#87de#1dde
L87de:
#87de#1dde317
2a a6 85 
    ld hl, (L85a6_vertex2_coordinates)
#87e1#1de1422
ed 5b a0 85 
    ld de, (L85a0_vertex1_coordinates)
#87e5#1de515
af 
    xor a
#87e6#1de6217
ed 52 
    sbc hl, de
#87e8#1de8111
d1 
    pop de
#87e9#1de9318
cd 5e a1 
    call La15e_de_times_hl_signed
#87ec#1dec318
cd b7 b1 
    call Lb1b7_de_hl_divided_by_bc_signed
#87ef#1def422
ed 5b a0 85 
    ld de, (L85a0_vertex1_coordinates)
#87f3#1df3112
19 
    add hl, de
#87f4#1df4111
d1 
    pop de
#87f5#1df515
7b 
    ld a, e
#87f6#1df615
2f 
    cpl
#87f7#1df715
4f 
    ld c, a
#87f8#1df815
7a 
    ld a, d
#87f9#1df915
2f 
    cpl
#87fa#1dfa15
47 
    ld b, a
#87fb#1dfb17
03 
    inc bc
#87fc#1dfc314
3a ac 85 
    ld a, (L85ac_vertex_frustum_checks)
#87ff#1dff210
cb 5f 
    bit 3, a
#8801#1e01213/8
20 0d 
    jr nz, L8810
#8803#1e03317
22 a0 85 
    ld (L85a0_vertex1_coordinates), hl
#8806#1e06422
ed 43 a2 85 
    ld (L85a0_vertex1_coordinates + 1 * 2), bc
#880a#1e0a422
ed 53 a4 85 
    ld (L85a0_vertex1_coordinates + 2 * 2), de
#880e#1e0e213
18 0b 
    jr L881b_both_vertices_pass_frustum_check3
#8810#1e10
L8810:
#8810#1e10317
22 a6 85 
    ld (L85a6_vertex2_coordinates), hl
#8813#1e13422
ed 43 a8 85 
    ld (L85a6_vertex2_coordinates + 1 * 2), bc
#8817#1e17422
ed 53 aa 85 
    ld (L85a6_vertex2_coordinates + 2 * 2), de
#881b#1e1b
#881b#1e1b
L881b_both_vertices_pass_frustum_check3:
#881b#1e1b422
ed 4b ac 85 
    ld bc, (L85ac_vertex_frustum_checks)
#881f#1e1f210
cb e0 
    set 4, b
#8821#1e21210
cb e1 
    set 4, c
#8823#1e23317
2a a4 85 
    ld hl, (L85a0_vertex1_coordinates + 2 * 2)
#8826#1e26422
ed 5b a0 85 
    ld de, (L85a0_vertex1_coordinates)
#882a#1e2a15
b7 
    or a
#882b#1e2b217
ed 5a 
    adc hl, de
#882d#1e2d311
f2 32 88 
    jp p, L8832
#8830#1e30210
cb a1 
    res 4, c
#8832#1e32
L8832:
#8832#1e32317
2a aa 85 
    ld hl, (L85a6_vertex2_coordinates + 2 * 2)
#8835#1e35422
ed 5b a6 85 
    ld de, (L85a6_vertex2_coordinates)
#8839#1e3915
b7 
    or a
#883a#1e3a217
ed 5a 
    adc hl, de
#883c#1e3c311
f2 41 88 
    jp p, L8841
#883f#1e3f210
cb a0 
    res 4, b
#8841#1e41
L8841:
#8841#1e41422
ed 43 ac 85 
    ld (L85ac_vertex_frustum_checks), bc
#8845#1e45210
cb 61 
    bit 4, c
#8847#1e47213/8
20 07 
    jr nz, L8850
#8849#1e49210
cb 60 
    bit 4, b
#884b#1e4b311
ca cb 88 
    jp z, L88cb_mark_as_processed_and_return
#884e#1e4e213
18 05 
    jr L8855
#8850#1e50
L8850:
#8850#1e50210
cb 60 
    bit 4, b
#8852#1e52311
c2 a5 88 
    jp nz, L88a5_both_vertices_pass_frustum_check4
#8855#1e55
L8855:
#8855#1e55317
2a a4 85 
    ld hl, (L85a0_vertex1_coordinates + 2 * 2)
#8858#1e58422
ed 5b a0 85 
    ld de, (L85a0_vertex1_coordinates)
#885c#1e5c112
19 
    add hl, de
#885d#1e5d112
e5 
    push hl
#885e#1e5e317
2a a6 85 
    ld hl, (L85a6_vertex2_coordinates)
#8861#1e61416
dd 21 68 88 
    ld ix, L8868
#8865#1e65311
c3 b2 87 
    jp L87b2
#8868#1e68
L8868:
#8868#1e68317
2a a8 85 
    ld hl, (L85a6_vertex2_coordinates + 1 * 2)
#886b#1e6b422
ed 5b a2 85 
    ld de, (L85a0_vertex1_coordinates + 1 * 2)
#886f#1e6f15
af 
    xor a
#8870#1e70217
ed 52 
    sbc hl, de
#8872#1e72111
d1 
    pop de
#8873#1e73318
cd 5e a1 
    call La15e_de_times_hl_signed
#8876#1e76318
cd b7 b1 
    call Lb1b7_de_hl_divided_by_bc_signed
#8879#1e79422
ed 5b a2 85 
    ld de, (L85a0_vertex1_coordinates + 1 * 2)
#887d#1e7d112
19 
    add hl, de
#887e#1e7e111
d1 
    pop de
#887f#1e7f15
7b 
    ld a, e
#8880#1e8015
2f 
    cpl
#8881#1e8115
4f 
    ld c, a
#8882#1e8215
7a 
    ld a, d
#8883#1e8315
2f 
    cpl
#8884#1e8415
47 
    ld b, a
#8885#1e8517
03 
    inc bc
#8886#1e86314
3a ac 85 
    ld a, (L85ac_vertex_frustum_checks)
#8889#1e89210
cb 67 
    bit 4, a
#888b#1e8b213/8
20 0d 
    jr nz, L889a
#888d#1e8d422
ed 43 a0 85 
    ld (L85a0_vertex1_coordinates), bc
#8891#1e91317
22 a2 85 
    ld (L85a0_vertex1_coordinates + 1 * 2), hl
#8894#1e94422
ed 53 a4 85 
    ld (L85a0_vertex1_coordinates + 2 * 2), de
#8898#1e98213
18 0b 
    jr L88a5_both_vertices_pass_frustum_check4
#889a#1e9a
L889a:
#889a#1e9a422
ed 43 a6 85 
    ld (L85a6_vertex2_coordinates), bc
#889e#1e9e317
22 a8 85 
    ld (L85a6_vertex2_coordinates + 1 * 2), hl
#88a1#1ea1422
ed 53 aa 85 
    ld (L85a6_vertex2_coordinates + 2 * 2), de
#88a5#1ea5
#88a5#1ea5
L88a5_both_vertices_pass_frustum_check4:
#88a5#1ea5
    ; We are done clipping the edge, now project whichever vertex needs
#88a5#1ea5
    ; projecting:
#88a5#1ea528
3e ff 
    ld a, #ff
#88a7#1ea7321
fd be 00 
    cp (iy)
#88aa#1eaa213/8
20 0d 
    jr nz, L88b9
#88ac#1eac
    ; Vertex 1 needs projecting:
#88ac#1eac416
dd 21 a0 85 
    ld ix, L85a0_vertex1_coordinates
#88b0#1eb0318
cd fc 90 
    call L90fc_project_one_vertex
#88b3#1eb3321
fd 71 00 
    ld (iy), c  ; x
#88b6#1eb6321
fd 70 01 
    ld (iy + 1), b  ; y
#88b9#1eb9
L88b9:
#88b9#1eb9321
fd be 02 
    cp (iy + 2)
#88bc#1ebc213/8
20 0d 
    jr nz, L88cb_mark_as_processed_and_return
#88be#1ebe
    ; Vertex 2 needs projecting:
#88be#1ebe416
dd 21 a6 85 
    ld ix, L85a6_vertex2_coordinates
#88c2#1ec2318
cd fc 90 
    call L90fc_project_one_vertex
#88c5#1ec5321
fd 71 02 
    ld (iy + 2), c  ; x
#88c8#1ec8321
fd 70 03 
    ld (iy + 3), b  ; y
#88cb#1ecb
L88cb_mark_as_processed_and_return:
#88cb#1ecb28
3e 01 
    ld a, 1
#88cd#1ecd321
fd 77 ffff 
    ld (iy - 1), a  ; mark edge as processed
#88d0#1ed0111
c9 
    ret
#88d1#1ed1
#88d1#1ed1
#88d1#1ed1
; --------------------------------
#88d1#1ed1
; Checks if the normal of a face points away from the camera (and potentially we do not need to draw the face).
#88d1#1ed1
; Input:
#88d1#1ed1
; - iy: pointer to the vertex indexes of this face
#88d1#1ed1
; Output:
#88d1#1ed1
; - a: 1 (back face), 0 (front face).
#88d1#1ed1
; - carry flag set (same as "a"): back face.
#88d1#1ed1
L88d1_normal_direction_check:
#88d1#1ed1217
dd e5 
    push ix
#88d3#1ed3112
e5 
    push hl
#88d4#1ed4112
d5 
    push de
#88d5#1ed5112
c5 
    push bc
#88d6#1ed6422
dd 2a 24 5f 
        ld ix, (L5f24_shape_edges_ptr)
#88da#1eda212
dd 23 
        inc ix  ; skip the number of edges
#88dc#1edc217
dd e5 
        push ix
#88de#1ede321
fd 7e 00 
            ld a, (iy)
#88e1#1ee115
6f 
            ld l, a
#88e2#1ee228
e6 7f 
            and #7f  ; get the index (remove a potential flag in the msb)
#88e4#1ee415
4f 
            ld c, a
#88e5#1ee528
06 00 
            ld b, 0
#88e7#1ee7210
cb 21 
            sla c
#88e9#1ee9217
dd 09 
            add ix, bc  ; ix = ptr to the edge
#88eb#1eeb321
dd 4e 00 
            ld c, (ix)  ; c = vertex index 1
#88ee#1eee321
dd 7e 01 
            ld a, (ix + 1)  ; a = vertex index 2
#88f1#1ef1210
cb 7d 
            bit 7, l  ; vertex index flag check
#88f3#1ef3213/8
28 03 
            jr z, L88f8
#88f5#1ef5
            ; Invert the vertexes in the current edge:
#88f5#1ef515
61 
            ld h, c
#88f6#1ef615
4f 
            ld c, a
#88f7#1ef715
7c 
            ld a, h
#88f8#1ef8
L88f8:
#88f8#1ef8311
21 9f 5e 
            ld hl, L5e9f_3d_vertex_coordinates_after_rotation_matrix
#88fb#1efb210
cb 21 
            sla c
#88fd#1efd112
09 
            add hl, bc
#88fe#1efe210
cb 21 
            sla c
#8900#1f00112
09 
            add hl, bc  ; hl += 6 * vertex index 1
#8901#1f01311
11 63 5e 
            ld de, L5e63_3d_vertex_coordinates_relative_to_player
#8904#1f04
            ; Copy vertex 1:
#8904#1f0428
0e 06 
            ld c, 6
#8906#1f06223/18
ed b0 
            ldir
#8908#1f0815
4f 
            ld c, a
#8909#1f09311
21 9f 5e 
            ld hl, L5e9f_3d_vertex_coordinates_after_rotation_matrix
#890c#1f0c210
cb 21 
            sla c
#890e#1f0e112
09 
            add hl, bc
#890f#1f0f210
cb 21 
            sla c
#8911#1f11112
09 
            add hl, bc  ; hl += 6 * vertex index 2
#8912#1f12
            ; Copy vertex 2:
#8912#1f1228
0e 06 
            ld c, 6
#8914#1f14223/18
ed b0 
            ldir
#8916#1f16321
fd 7e 01 
            ld a, (iy + 1)
#8919#1f1915
6f 
            ld l, a
#891a#1f1a28
e6 7f 
            and #7f  ; get the index (remove a potential flag in the msb)
#891c#1f1c216
dd e1 
        pop ix
#891e#1f1e15
4f 
        ld c, a
#891f#1f1f210
cb 21 
        sla c
#8921#1f21217
dd 09 
        add ix, bc  ; ix = ptr to the edge
#8923#1f23321
dd 4e 00 
        ld c, (ix)
#8926#1f26210
cb 7d 
        bit 7, l
#8928#1f28213/8
20 03 
        jr nz, L892d
#892a#1f2a321
dd 4e 01 
        ld c, (ix + 1)  ; if edge flip flag is 1, get the other vertex.
#892d#1f2d
L892d:
#892d#1f2d311
21 9f 5e 
        ld hl, L5e9f_3d_vertex_coordinates_after_rotation_matrix
#8930#1f30210
cb 21 
        sla c
#8932#1f32112
09 
        add hl, bc
#8933#1f33210
cb 21 
        sla c
#8935#1f35112
09 
        add hl, bc  ; hl += 6 * vertex index 1
#8936#1f36
        ; Copy vertex 3:
#8936#1f3628
0e 06 
        ld c, 6
#8938#1f38223/18
ed b0 
        ldir
#893a#1f3a
#893a#1f3a
        ; At this point we have picked the first 3 vertices of the face.
#893a#1f3a
        ; We now calculate the normal vector:
#893a#1f3a
        ; OPTIMIZATION: faces should have the normal pre-calculated, rather than doing all this calculation each time.
#893a#1f3a
        ;   Just one additional point to be ran through the rotation matrix, and we avoid all of this.
#893a#1f3a15
60 
        ld h, b
#893b#1f3b15
69 
        ld l, c  ; hl = 0
#893c#1f3c317
22 75 5e 
        ld (L5e75_48_bit_accumulator), hl
#893f#1f3f317
22 77 5e 
        ld (L5e75_48_bit_accumulator + 2), hl
#8942#1f42317
22 79 5e 
        ld (L5e75_48_bit_accumulator + 4), hl
#8945#1f45317
2a 67 5e 
        ld hl, (L5e63_3d_vertex_coordinates_relative_to_player + 2 * 2)  ; z vertex 1
#8948#1f48422
ed 5b 6d 5e 
        ld de, (L5e63_3d_vertex_coordinates_relative_to_player + 5 * 2)  ; z vertex 2
#894c#1f4c15
b7 
        or a
#894d#1f4d217
ed 52 
        sbc hl, de  ; hl = z1 - z2
#894f#1f4f112
e5 
        push hl
#8950#1f50317
2a 71 5e 
            ld hl, (L5e63_3d_vertex_coordinates_relative_to_player + 7 * 2)  ; y vertex 3
#8953#1f53422
ed 5b 6b 5e 
            ld de, (L5e63_3d_vertex_coordinates_relative_to_player + 4 * 2)  ; y vertex 2
#8957#1f5715
b7 
            or a
#8958#1f58217
ed 52 
            sbc hl, de  ; hl = y3 - y2
#895a#1f5a111
d1 
        pop de
#895b#1f5b318
cd 5e a1 
        call La15e_de_times_hl_signed  ; (de, hl) = (z1 - z2) * (y3 - y2)
#895e#1f5e112
d5 
        push de
#895f#1f5f112
e5 
            push hl
#8960#1f60317
2a 65 5e 
                ld hl, (L5e63_3d_vertex_coordinates_relative_to_player + 1 * 2)  ; y vertex 1
#8963#1f63422
ed 5b 6b 5e 
                ld de, (L5e63_3d_vertex_coordinates_relative_to_player + 4 * 2)  ; y vertex 2
#8967#1f6715
b7 
                or a
#8968#1f68217
ed 52 
                sbc hl, de
#896a#1f6a112
e5 
                push hl
#896b#1f6b317
2a 73 5e 
                    ld hl, (L5e63_3d_vertex_coordinates_relative_to_player + 8 * 2)  ; z vertex 3
#896e#1f6e422
ed 5b 6d 5e 
                    ld de, (L5e63_3d_vertex_coordinates_relative_to_player + 5 * 2)  ; z vertex 2
#8972#1f7215
b7 
                    or a
#8973#1f73217
ed 52 
                    sbc hl, de
#8975#1f75111
d1 
                pop de
#8976#1f76318
cd 5e a1 
                call La15e_de_times_hl_signed
#8979#1f79111
c1 
            pop bc
#897a#1f7a15
af 
            xor a
#897b#1f7b217
ed 42 
            sbc hl, bc
#897d#1f7d111
c1 
        pop bc
#897e#1f7e15
eb 
        ex de, hl
#897f#1f7f217
ed 42 
            sbc hl, bc
#8981#1f8115
eb 
        ex de, hl
#8982#1f82422
ed 4b 69 5e 
        ld bc, (L5e63_3d_vertex_coordinates_relative_to_player + 3 * 2)  ; x vertex 2
#8986#1f86318
cd 30 8a 
        call L8a30_48bitmul_add
#8989#1f89317
2a 63 5e 
        ld hl, (L5e63_3d_vertex_coordinates_relative_to_player)  ; x vertex 1
#898c#1f8c422
ed 5b 69 5e 
        ld de, (L5e63_3d_vertex_coordinates_relative_to_player + 3 * 2)  ; x vertex 2
#8990#1f9015
b7 
        or a
#8991#1f91217
ed 52 
        sbc hl, de
#8993#1f93112
e5 
        push hl
#8994#1f94317
2a 73 5e 
            ld hl, (L5e63_3d_vertex_coordinates_relative_to_player + 8 * 2)  ; z vertex 3
#8997#1f97422
ed 5b 6d 5e 
            ld de, (L5e63_3d_vertex_coordinates_relative_to_player + 5 * 2)  ; z vertex 2
#899b#1f9b15
b7 
            or a
#899c#1f9c217
ed 52 
            sbc hl, de
#899e#1f9e111
d1 
        pop de
#899f#1f9f318
cd 5e a1 
        call La15e_de_times_hl_signed
#89a2#1fa2112
d5 
        push de
#89a3#1fa3112
e5 
            push hl
#89a4#1fa4317
2a 67 5e 
                ld hl, (L5e63_3d_vertex_coordinates_relative_to_player + 2 * 2)  ; z vertex 1
#89a7#1fa7422
ed 5b 6d 5e 
                ld de, (L5e63_3d_vertex_coordinates_relative_to_player + 5 * 2)  ; z vertex 2
#89ab#1fab15
b7 
                or a
#89ac#1fac217
ed 52 
                sbc hl, de
#89ae#1fae112
e5 
                push hl
#89af#1faf317
2a 6f 5e 
                    ld hl, (L5e63_3d_vertex_coordinates_relative_to_player + 6 * 2)  ; x vertex 3
#89b2#1fb2422
ed 5b 69 5e 
                    ld de, (L5e63_3d_vertex_coordinates_relative_to_player + 3 * 2)  ; x vertex 2
#89b6#1fb615
b7 
                    or a
#89b7#1fb7217
ed 52 
                    sbc hl, de
#89b9#1fb9111
d1 
                pop de
#89ba#1fba318
cd 5e a1 
                call La15e_de_times_hl_signed
#89bd#1fbd111
c1 
            pop bc
#89be#1fbe15
af 
            xor a
#89bf#1fbf217
ed 42 
            sbc hl, bc
#89c1#1fc1111
c1 
        pop bc
#89c2#1fc215
eb 
        ex de, hl
#89c3#1fc3217
ed 42 
        sbc hl, bc
#89c5#1fc515
eb 
        ex de, hl
#89c6#1fc6422
ed 4b 6b 5e 
        ld bc, (L5e63_3d_vertex_coordinates_relative_to_player + 4 * 2)
#89ca#1fca318
cd 30 8a 
        call L8a30_48bitmul_add
#89cd#1fcd317
2a 65 5e 
        ld hl, (L5e63_3d_vertex_coordinates_relative_to_player + 2)
#89d0#1fd0422
ed 5b 6b 5e 
        ld de, (L5e63_3d_vertex_coordinates_relative_to_player + 4 * 2)
#89d4#1fd415
b7 
        or a
#89d5#1fd5217
ed 52 
        sbc hl, de
#89d7#1fd7112
e5 
        push hl
#89d8#1fd8317
2a 6f 5e 
            ld hl, (L5e63_3d_vertex_coordinates_relative_to_player + 6 * 2)
#89db#1fdb422
ed 5b 69 5e 
            ld de, (L5e63_3d_vertex_coordinates_relative_to_player + 3 * 2)
#89df#1fdf15
b7 
            or a
#89e0#1fe0217
ed 52 
            sbc hl, de
#89e2#1fe2111
d1 
        pop de
#89e3#1fe3318
cd 5e a1 
        call La15e_de_times_hl_signed  ; (de, hl) = (z v1 - y v2) * (x v3 - x v2)
#89e6#1fe6112
d5 
        push de
#89e7#1fe7112
e5 
            push hl
#89e8#1fe8317
2a 63 5e 
                ld hl, (L5e63_3d_vertex_coordinates_relative_to_player)
#89eb#1feb422
ed 5b 69 5e 
                ld de, (L5e63_3d_vertex_coordinates_relative_to_player + 3 * 2)
#89ef#1fef15
b7 
                or a
#89f0#1ff0217
ed 52 
                sbc hl, de
#89f2#1ff2112
e5 
                push hl
#89f3#1ff3317
2a 71 5e 
                    ld hl, (L5e63_3d_vertex_coordinates_relative_to_player + 7 * 2)
#89f6#1ff6422
ed 5b 6b 5e 
                    ld de, (L5e63_3d_vertex_coordinates_relative_to_player + 4 * 2)
#89fa#1ffa15
b7 
                    or a
#89fb#1ffb217
ed 52 
                    sbc hl, de
#89fd#1ffd111
d1 
                pop de
#89fe#1ffe318
cd 5e a1 
                call La15e_de_times_hl_signed  ; (de, hl) = (x v1 - x v2) * (y v3 - y v2)
#8a01#2001111
c1 
            pop bc
#8a02#200215
af 
            xor a
#8a03#2003217
ed 42 
            sbc hl, bc
#8a05#2005111
c1 
        pop bc
#8a06#200615
eb 
        ex de, hl
#8a07#2007217
ed 42 
        sbc hl, bc  ; hl = (z v1 - y v2) * (x v3 - x v2) - (x v1 - x v2) * (y v3 - y v2)
#8a09#2009112
e5 
        push hl
#8a0a#200a15
eb 
            ex de, hl
#8a0b#200b422
ed 4b 6d 5e 
            ld bc, (L5e63_3d_vertex_coordinates_relative_to_player + 5 * 2)
#8a0f#200f318
cd 30 8a 
            call L8a30_48bitmul_add
#8a12#2012111
e1 
        pop hl
#8a13#2013314
3a 7a 5e 
        ld a, (L5e75_48_bit_accumulator + 5)
#8a16#2016
#8a16#2016
        ; Check if the normal points forward or backwards:
#8a16#2016
        ; At this point:
#8a16#2016
        ; - a: has the most significant byte of the accumulator (to get the sign of the z coordinate of the normal).
#8a16#2016
        ; - hl: most significant word of "(x v1 - x v2) * (y v3 - y v2) - (z v1 - y v2) * (x v3 - x v2)"
#8a16#201615
6f 
        ld l, a
#8a17#201715
ac 
        xor h
#8a18#2018311
f2 1f 8a 
        jp p, L8a1f
#8a1b#201b
        ; We get here if the "normal z" has the same sign as "(x v1 - x v2) * (y v3 - y v2) - (z v1 - y v2) * (x v3 - x v2)".
#8a1b#201b
        ; This gives the face a chance to be drawn if when projected to the screen no vertices fall inside of the view area,
#8a1b#201b
        ; and the code will check if it's that the face is too big and covers the whole screen.
#8a1b#201b
        ; Note: I am not sure of what the math means here, as I have not tried to derive what the value of the calculation
#8a1b#201b
        ;       means.
#8a1b#201b15
af 
        xor a
#8a1c#201c314
32 28 5f 
        ld (L5f28_cull_face_when_no_projected_vertices), a
#8a1f#201f
L8a1f:
#8a1f#201f15
7d 
        ld a, l
#8a20#202015
b7 
        or a
#8a21#2021311
f2 27 8a 
        jp p, L8a27
#8a24#2024
        ; Normal points towrads the camera, this is a front face.
#8a24#202415
af 
        xor a
#8a25#2025213
18 03 
        jr L8a2a
#8a27#2027
L8a27:
#8a27#2027
        ; Normal points away from camera, this is a back face.
#8a27#202728
3e 01 
        ld a, 1
#8a29#202915
37 
        scf
#8a2a#202a
L8a2a:
#8a2a#202a111
c1 
    pop bc
#8a2b#202b111
d1 
    pop de
#8a2c#202c111
e1 
    pop hl
#8a2d#202d216
dd e1 
    pop ix
#8a2f#202f111
c9 
    ret
#8a30#2030
#8a30#2030
#8a30#2030
; --------------------------------
#8a30#2030
; Performs the following operation:
#8a30#2030
; - First, calculate the multiplication bc * (bc, hl)
#8a30#2030
; - Then add the 48 bit result to the 48 bit number in (L5e75_48_bit_accumulator)
#8a30#2030
; - Result is saved in (L5e75_48_bit_accumulator)
#8a30#2030
; The signed 32 bit result is returned in (DE,HL)
#8a30#2030
; Input:
#8a30#2030
; - bc
#8a30#2030
; - (de, hl)
#8a30#2030
; - 6 bytes in (L5e75_48_bit_accumulator)
#8a30#2030
; Output:
#8a30#2030
; - 6 bytes in (L5e75_48_bit_accumulator)
#8a30#2030
L8a30_48bitmul_add:
#8a30#2030210
cb 7a 
    bit 7, d
#8a32#2032213/8
28 14 
    jr z, L8a48_de_hl_positive
#8a34#2034
    ; if (de, hl) is negative, calculate the absolute value:
#8a34#203415
7c 
    ld a, h
#8a35#203515
2f 
    cpl
#8a36#203615
67 
    ld h, a
#8a37#203715
7d 
    ld a, l
#8a38#203815
2f 
    cpl
#8a39#203915
6f 
    ld l, a
#8a3a#203a15
7a 
    ld a, d
#8a3b#203b15
2f 
    cpl
#8a3c#203c15
57 
    ld d, a
#8a3d#203d15
7b 
    ld a, e
#8a3e#203e15
2f 
    cpl
#8a3f#203f15
5f 
    ld e, a
#8a40#2040
#8a40#204017
23 
    inc hl
#8a41#204115
7d 
    ld a, l
#8a42#204215
b4 
    or h
#8a43#204328
3e 01 
    ld a, 1  ; mark that we changed the sign
#8a45#2045213/8
20 01 
    jr nz, L8a48_de_hl_positive
#8a47#204717
13 
    inc de
#8a48#2048
L8a48_de_hl_positive:
#8a48#2048210
cb 78 
    bit 7, b
#8a4a#204a213/8
28 0b 
    jr z, L8a57_bc_positive
#8a4c#204c
    ; if bc is negative, calculate the absolute value:
#8a4c#204c112
f5 
    push af
#8a4d#204d15
78 
        ld a, b
#8a4e#204e15
2f 
        cpl
#8a4f#204f15
47 
        ld b, a
#8a50#205015
79 
        ld a, c
#8a51#205115
2f 
        cpl
#8a52#205215
4f 
        ld c, a
#8a53#205317
03 
        inc bc
#8a54#2054111
f1 
    pop af
#8a55#205528
ee 01 
    xor 1  ; mark that we changed the sign (if we changed the sign of only one of bc, or (de, hl), a = 1).
#8a57#2057
L8a57_bc_positive:
#8a57#2057
    ; Perform a multiplciation in the following way:
#8a57#2057
    ;    de hl
#8a57#2057
    ;  *    bc
#8a57#2057
    ;  -------
#8a57#2057
    ;    AA BB <- bc * hl
#8a57#2057
    ; CC DD
#8a57#2057
    ; --------
#8a57#2057
    ; hl bc de
#8a57#2057112
d5 
    push de
#8a58#205815
59 
        ld e, c
#8a59#205915
50 
        ld d, b
#8a5a#205a318
cd b4 8a 
        call L8ab4_de_times_hl_signed  ; (AA, BB) = hl * bc
#8a5d#205d
        ; We temporarily save the result in RAM:
#8a5d#205d317
22 7b 5e 
        ld (L5e7b_48bitmul_tmp1), hl  ; save BB
#8a60#2060422
ed 53 7d 5e 
        ld (L5e7d_48bitmul_tmp2), de  ; save AA
#8a64#2064111
d1 
    pop de
#8a65#206515
69 
    ld l, c
#8a66#206615
60 
    ld h, b
#8a67#2067318
cd b4 8a 
    call L8ab4_de_times_hl_signed  ; (CC, DD) = de * bc
#8a6a#206a422
ed 4b 7d 5e 
    ld bc, (L5e7d_48bitmul_tmp2)  ; recover AA
#8a6e#206e112
09 
    add hl, bc  ; AA + DD
#8a6f#206f15
44 
    ld b, h
#8a70#207015
4d 
    ld c, l  ; bc = AA + DD
#8a71#2071311
21 00 00 
    ld hl, 0
#8a74#2074217
ed 5a 
    adc hl, de  ; hl = CC + (carry of AA + DD)
#8a76#2076422
ed 5b 7b 5e 
    ld de, (L5e7b_48bitmul_tmp1)  ; recover BB
#8a7a#207a
    ; At this point (hl, bc, de) has the absolute value of the 48 bit result of the multiplication
#8a7a#207a
    ; Check if we need to change the sign of the result:
#8a7a#207a15
b7 
    or a
#8a7b#207b213/8
28 1d 
    jr z, L8a9a_result_is_positive
#8a7d#207d
    ; Make the result negative:
#8a7d#207d15
7c 
    ld a, h
#8a7e#207e15
2f 
    cpl
#8a7f#207f15
67 
    ld h, a
#8a80#208015
7d 
    ld a, l
#8a81#208115
2f 
    cpl
#8a82#208215
6f 
    ld l, a
#8a83#208315
78 
    ld a, b
#8a84#208415
2f 
    cpl
#8a85#208515
47 
    ld b, a
#8a86#208615
79 
    ld a, c
#8a87#208715
2f 
    cpl
#8a88#208815
4f 
    ld c, a
#8a89#208915
7a 
    ld a, d
#8a8a#208a15
2f 
    cpl
#8a8b#208b15
57 
    ld d, a
#8a8c#208c15
7b 
    ld a, e
#8a8d#208d15
2f 
    cpl
#8a8e#208e15
5f 
    ld e, a
#8a8f#208f17
13 
    inc de
#8a90#209015
7b 
    ld a, e
#8a91#209115
b2 
    or d
#8a92#2092213/8
20 06 
    jr nz, L8a9a_result_is_positive
#8a94#209417
03 
    inc bc
#8a95#209515
79 
    ld a, c
#8a96#209615
b0 
    or b
#8a97#2097213/8
20 01 
    jr nz, L8a9a_result_is_positive
#8a99#209917
23 
    inc hl
#8a9a#209a
L8a9a_result_is_positive:
#8a9a#209a
    ; At this point (hl, bc, de) has the 48 bit result of the multiplication
#8a9a#209a
    ; Add this 48 bit number with the 48 bit number stored in (L5e75_48_bit_accumulator)
#8a9a#209a112
e5 
    push hl
#8a9b#209b317
2a 75 5e 
        ld hl, (L5e75_48_bit_accumulator)
#8a9e#209e112
19 
        add hl, de
#8a9f#209f317
22 75 5e 
        ld (L5e75_48_bit_accumulator), hl
#8aa2#20a2317
2a 77 5e 
        ld hl, (L5e75_48_bit_accumulator + 2)
#8aa5#20a5217
ed 4a 
        adc hl, bc
#8aa7#20a7317
22 77 5e 
        ld (L5e75_48_bit_accumulator + 2), hl
#8aaa#20aa317
2a 79 5e 
        ld hl, (L5e75_48_bit_accumulator + 4)
#8aad#20ad111
c1 
    pop bc
#8aae#20ae217
ed 4a 
    adc hl, bc
#8ab0#20b0317
22 79 5e 
    ld (L5e75_48_bit_accumulator + 4), hl
#8ab3#20b3111
c9 
    ret
#8ab4#20b4
#8ab4#20b4
#8ab4#20b4
; --------------------------------
#8ab4#20b4
; Signed multiplication between DE and HL.
#8ab4#20b4
; The signed 32 bit result is returned in (DE,HL)
#8ab4#20b4
; Input:
#8ab4#20b4
; - de
#8ab4#20b4
; - hl
#8ab4#20b4
; Output:
#8ab4#20b4
; - de, hl
#8ab4#20b4
L8ab4_de_times_hl_signed:
#8ab4#20b4112
c5 
    push bc
#8ab5#20b5112
f5 
    push af
#8ab6#20b615
7c 
        ld a, h
#8ab7#20b715
4d 
        ld c, l
#8ab8#20b828
06 10 
        ld b, 16
#8aba#20ba311
21 00 00 
        ld hl, 0
#8abd#20bd
L8abd:
#8abd#20bd210
cb 21 
        sla c
#8abf#20bf15
17 
        rla
#8ac0#20c0213/8
38 0c 
        jr c, L8ace
#8ac2#20c2214/9
10 f9 
        djnz L8abd
#8ac4#20c415
50 
        ld d, b
#8ac5#20c515
58 
        ld e, b
#8ac6#20c6213
18 11 
        jr L8ad9
#8ac8#20c8
L8ac8:
#8ac8#20c8112
29 
        add hl, hl
#8ac9#20c9210
cb 11 
        rl c
#8acb#20cb15
17 
        rla
#8acc#20cc213/8
30 07 
        jr nc, L8ad5
#8ace#20ce
L8ace:
#8ace#20ce112
19 
        add hl, de
#8acf#20cf213/8
30 04 
        jr nc, L8ad5
#8ad1#20d115
0c 
        inc c
#8ad2#20d2213/8
20 01 
        jr nz, L8ad5
#8ad4#20d415
3c 
        inc a
#8ad5#20d5
L8ad5:
#8ad5#20d5214/9
10 f1 
        djnz L8ac8
#8ad7#20d715
57 
        ld d, a
#8ad8#20d815
59 
        ld e, c
#8ad9#20d9
L8ad9:
#8ad9#20d9111
f1 
    pop af
#8ada#20da111
c1 
    pop bc
#8adb#20db111
c9 
    ret
#8adc#20dc
#8adc#20dc
#8adc#20dc
; --------------------------------
#8adc#20dc
; Projects an object, and if it falls within the screen, add it to the list of objects to draw,
#8adc#20dc
; assuming that all vertexes are in screen (if a single one is out, whole object is discarted)
#8adc#20dc
; Input:
#8adc#20dc
; - iy: face definition ptr:
#8adc#20dc
;   - first byte is number of faces
#8adc#20dc
;   - then, each face has:
#8adc#20dc
;     - attribute
#8adc#20dc
;     - number of vertices
#8adc#20dc
;     - then one byte per vertex (index)
#8adc#20dc
L8adc_project_object_and_add_to_render_list_internal:
#8adc#20dc314
3a 96 74 
    ld a, (L7496_current_drawing_primitive_n_vertices)
#8adf#20df15
47 
    ld b, a
#8ae0#20e0
    ; Initialize the L5ee8_already_projected_vertex_coordinates array:
#8ae0#20e0
    ; Since different edges might share vertexes, when we project a vertex,
#8ae0#20e0
    ; we mark it in this array, to prevent projecting them again.
#8ae0#20e0311
21 e8 5e 
    ld hl, L5ee8_already_projected_vertex_coordinates
#8ae3#20e328
3e ff 
    ld a, #ff  ; mark that a vertex has not been projected.
#8ae5#20e5
L8ae5:
#8ae5#20e518
77 
    ld (hl), a
#8ae6#20e617
23 
    inc hl
#8ae7#20e717
23 
    inc hl
#8ae8#20e8214/9
10 fb 
    djnz L8ae5
#8aea#20ea
#8aea#20ea15
af 
    xor a
#8aeb#20eb314
32 5f 5e 
    ld (L5e5f_add_to_projected_objects_flag), a
#8aee#20ee317
2a 97 74 
    ld hl, (L7497_next_projected_vertex_ptr)
#8af1#20f1314
3a 68 74 
    ld a, (L7468_focus_object_id)
#8af4#20f4
    ; Start writing the projected vertex data:
#8af4#20f418
77 
    ld (hl), a  ; object ID
#8af5#20f517
23 
    inc hl
#8af6#20f6211
36 00 
    ld (hl), 0  ; number of primitives (init to zero, and will be incremented each time a face is added).
#8af8#20f817
23 
    inc hl
#8af9#20f9321
fd 46 00 
    ld b, (iy)  ; number of faces
#8afc#20fc212
fd 23 
    inc iy
#8afe#20fe
L8afe_face_loop:
#8afe#20fe112
c5 
    push bc
#8aff#20ff321
fd 7e 00 
        ld a, (iy)  ; a = texture ID.
#8b02#2102212
fd 23 
        inc iy
#8b04#2104321
fd 46 00 
        ld b, (iy)  ; b = number of vertices in the face.
#8b07#2107212
fd 23 
        inc iy
#8b09#2109
        ; If it's a transparent face, ignore:
#8b09#210915
b7 
        or a
#8b0a#210a213/8
28 18 
        jr z, L8b24_skip_face_bytes_and_next_face
#8b0c#210c210
cb 27 
        sla a
#8b0e#210e210
cb 27 
        sla a
#8b10#2110210
cb 27 
        sla a
#8b12#2112210
cb 27 
        sla a
#8b14#211415
4f 
        ld c, a
#8b15#2115314
3a 60 5e 
        ld a, (L5e60_projection_pre_work_type)
#8b18#2118
        ;   - if a == 0: indicates that vertices can be projected directly.
#8b18#2118
        ;   - if a == 1: we need to call L88d1_normal_direction_check before projection, and if back-face, we cull
#8b18#2118
        ;   - if a == 2: we need to call L88d1_normal_direction_check before projection, and if back-face we need to use L5f26_alternative_shape_edges_ptr
#8b18#211815
b7 
        or a
#8b19#2119213/8
28 35 
        jr z, L8b50_ready_to_project
#8b1b#211b28
fe 01 
        cp 1
#8b1d#211d213/8
20 0d 
        jr nz, L8b2c
#8b1f#211f
#8b1f#211f
        ; Normal check, and cull if failed:
#8b1f#211f318
cd d1 88 
        call L88d1_normal_direction_check
#8b22#2122213/8
30 2c 
        jr nc, L8b50_ready_to_project
#8b24#2124
        ; back face!
#8b24#2124
L8b24_skip_face_bytes_and_next_face:
#8b24#212415
48 
        ld c, b
#8b25#212528
06 00 
        ld b, 0
#8b27#2127217
fd 09 
        add iy, bc
#8b29#2129311
c3 b1 8b 
        jp L8bb1_next_face
#8b2c#212c
#8b2c#212c
L8b2c:
#8b2c#212c318
cd d1 88 
        call L88d1_normal_direction_check
#8b2f#212f314
3a 6a 74 
        ld a, (L746a_current_drawing_texture_id)
#8b32#2132213/8
30 0f 
        jr nc, L8b43
#8b34#2134
        ; back face, we need to swap texture ID, and use alternative shape edges ptr:
#8b34#213428
e6 f0 
        and #f0
#8b36#2136213/8
28 ec 
        jr z, L8b24_skip_face_bytes_and_next_face
#8b38#213815
4f 
        ld c, a
#8b39#2139422
ed 5b 26 5f 
        ld de, (L5f26_alternative_shape_edges_ptr)
#8b3d#213d422
ed 53 24 5f 
        ld (L5f24_shape_edges_ptr), de
#8b41#2141213
18 0d 
        jr L8b50_ready_to_project
#8b43#2143
#8b43#2143
L8b43:
#8b43#214328
e6 0f 
        and #0f
#8b45#2145213/8
28 dd 
        jr z, L8b24_skip_face_bytes_and_next_face
#8b47#2147210
cb 27 
        sla a
#8b49#2149210
cb 27 
        sla a
#8b4b#214b210
cb 27 
        sla a
#8b4d#214d210
cb 27 
        sla a
#8b4f#214f15
4f 
        ld c, a
#8b50#2150
L8b50_ready_to_project:
#8b50#2150
        ; At this point:
#8b50#2150
        ; - b: number of vertices
#8b50#2150
        ; - c: texture ID (in the most significant 4 bits)
#8b50#2150
        ; - hl: pointer to the resulting projected vertex data (about to write texture byte)
#8b50#2150
        ; - iy: ptr to the face vertex indexes
#8b50#215015
79 
        ld a, c
#8b51#215115
b0 
        or b
#8b52#215218
77 
        ld (hl), a  ; save # vertices and texture ID
#8b53#215317
23 
        inc hl
#8b54#2154
L8b54_vertex_loop:
#8b54#2154112
c5 
        push bc
#8b55#2155321
fd 7e 00 
            ld a, (iy)  ; edge index
#8b58#215828
e6 7f 
            and #7f  ; get the index (remove a potential flag in the msb)
#8b5a#215a210
cb 27 
            sla a
#8b5c#215c15
4f 
            ld c, a
#8b5d#215d28
06 00 
            ld b, 0
#8b5f#215f422
dd 2a 24 5f 
            ld ix, (L5f24_shape_edges_ptr)
#8b63#2163212
dd 23 
            inc ix  ; skip the number of edges
#8b65#2165217
dd 09 
            add ix, bc  ; ix = ptr to the edge
#8b67#2167422
fd cb 00 7e 
            bit 7, (iy)
#8b6b#216b213/8
28 02 
            jr z, L8b6f
#8b6d#216d212
dd 23 
            inc ix  ; If the msb flag is set, we invert the vertex in the edge
#8b6f#216f
L8b6f:
#8b6f#216f212
fd 23 
            inc iy  ; next index
#8b71#2171321
dd 4e 00 
            ld c, (ix)  ; get the vertex index
#8b74#2174210
cb 21 
            sla c  ; vertex index * 2
#8b76#2176416
dd 21 e8 5e 
            ld ix, L5ee8_already_projected_vertex_coordinates
#8b7a#217a217
dd 09 
            add ix, bc
#8b7c#217c321
dd 7e 00 
            ld a, (ix)
#8b7f#217f
            ; Check if we have already projected the vertex:
#8b7f#217f28
fe ff 
            cp #ff
#8b81#2181213/8
20 18 
            jr nz, L8b9b_already_projected
#8b83#2183
            ; We have not projected it yet, so, we project it now:
#8b83#2183217
dd e5 
            push ix
#8b85#2185416
dd 21 9f 5e 
                ld ix, L5e9f_3d_vertex_coordinates_after_rotation_matrix
#8b89#2189217
dd 09 
                add ix, bc
#8b8b#218b217
dd 09 
                add ix, bc
#8b8d#218d217
dd 09 
                add ix, bc
#8b8f#218f318
cd fc 90 
                call L90fc_project_one_vertex
#8b92#2192216
dd e1 
            pop ix
#8b94#2194
            ; Save the projected coordinates (c, b) to the temporary L5ee8_already_projected_vertex_coordinates array.
#8b94#2194321
dd 71 00 
            ld (ix), c
#8b97#2197321
dd 70 01 
            ld (ix + 1), b
#8b9a#219a15
79 
            ld a, c  ; a = projected x
#8b9b#219b
L8b9b_already_projected:
#8b9b#219b
            ; Write the projected coordiantes to the projected vertices data for rendering:
#8b9b#219b18
77 
            ld (hl), a  ; x
#8b9c#219c17
23 
            inc hl
#8b9d#219d321
dd 7e 01 
            ld a, (ix + 1)  ; y
#8ba0#21a018
77 
            ld (hl), a
#8ba1#21a117
23 
            inc hl
#8ba2#21a2111
c1 
        pop bc
#8ba3#21a3214/9
10 af 
        djnz L8b54_vertex_loop
#8ba5#21a5
#8ba5#21a528
3e 01 
        ld a, 1
#8ba7#21a7314
32 5f 5e 
        ld (L5e5f_add_to_projected_objects_flag), a
#8baa#21aa422
dd 2a 97 74 
        ld ix, (L7497_next_projected_vertex_ptr)
#8bae#21ae325
dd 34 01 
        inc (ix + 1)  ; increment the number of primitives counter
#8bb1#21b1
L8bb1_next_face:
#8bb1#21b1111
c1 
    pop bc
#8bb2#21b215
05 
    dec b
#8bb3#21b3311
c2 fe 8a 
    jp nz, L8afe_face_loop
#8bb6#21b6111
c9 
    ret
#8bb7#21b7
#8bb7#21b7
#8bb7#21b7
; --------------------------------
#8bb7#21b7
; Sets the rendering volume, a cube (to prune which obejcts to render).
#8bb7#21b7
L8bb7_determine_rendering_volume:
#8bb7#21b7314
3a bd 6a 
    ld a, (L6abd_cull_by_rendering_volume_flag)  ; if we are not culling by volume, just return
#8bba#21ba15
b7 
    or a
#8bbb#21bb112/6
c0 
    ret nz
#8bbc#21bc
    ; Clear the L745d_rendering_cube_volume to #ff:
#8bbc#21bc311
21 5d 74 
    ld hl, L745d_rendering_cube_volume
#8bbf#21bf28
06 06 
    ld b, 6
#8bc1#21c115
3d 
    dec a
#8bc2#21c2
L8bc2_clear_memory_loop:
#8bc2#21c218
77 
    ld (hl), a  ; a == #ff here
#8bc3#21c317
23 
    inc hl
#8bc4#21c4214/9
10 fc 
    djnz L8bc2_clear_memory_loop
#8bc6#21c6
#8bc6#21c6
    ; This loop is executed 4 times, each time adjusting the
#8bc6#21c6
    ; pitch/yaw andles up or down by 8 units, and each time,
#8bc6#21c6
    ; the values in L745d_rendering_cube_volume are being set: 
#8bc6#21c628
26 04 
    ld h, 4
#8bc8#21c8416
dd 21 5d 74 
    ld ix, L745d_rendering_cube_volume
#8bcc#21cc
L8bcc_angle_loop:
#8bcc#21cc15
7c 
    ld a, h  ; h is the iteration index (4, 3, 2, 1)
#8bcd#21cd28
fe 03 
    cp 3
#8bcf#21cf314
3a b7 6a 
    ld a, (L6ab7_player_yaw_angle)
#8bd2#21d2213/8
30 0a 
    jr nc, L8bde
#8bd4#21d4
    ; Iterations 1, 2:
#8bd4#21d4
    ; If we are too close to the upper limit, wrap around
#8bd4#21d428
c6 08 
    add a, 8
#8bd6#21d628
fe 48 
    cp FULL_ROTATION_DEGREES
#8bd8#21d8213/8
38 0a 
    jr c, L8be4_yaw_set
#8bda#21da28
d6 48 
    sub FULL_ROTATION_DEGREES
#8bdc#21dc213
18 06 
    jr L8be4_yaw_set
#8bde#21de
L8bde:
#8bde#21de
    ; Iterations 3, 4:
#8bde#21de
    ; If we are too close to the lower limit, wrap around
#8bde#21de28
d6 08 
    sub 8
#8be0#21e0213/8
30 02 
    jr nc, L8be4_yaw_set
#8be2#21e228
c6 48 
    add a, FULL_ROTATION_DEGREES
#8be4#21e4
L8be4_yaw_set:
#8be4#21e4
    ; Here we have a = (L6ab7_player_yaw_angle)
#8be4#21e415
47 
    ld b, a
#8be5#21e5210
cb 44 
    bit 0, h
#8be7#21e7314
3a b6 6a 
    ld a, (L6ab6_player_pitch_angle)
#8bea#21ea213/8
28 0a 
    jr z, L8bf6
#8bec#21ec
    ; Iterations 1 and 3:
#8bec#21ec28
c6 08 
    add a, 8
#8bee#21ee28
fe 48 
    cp FULL_ROTATION_DEGREES
#8bf0#21f0213/8
38 0a 
    jr c, L8bfc_pitch_set
#8bf2#21f228
d6 48 
    sub FULL_ROTATION_DEGREES
#8bf4#21f4213
18 06 
    jr L8bfc_pitch_set
#8bf6#21f6
L8bf6:
#8bf6#21f6
    ; Iterations 2 and 4:
#8bf6#21f628
d6 08 
    sub 8
#8bf8#21f8213/8
30 02 
    jr nc, L8bfc_pitch_set
#8bfa#21fa28
c6 48 
    add a, FULL_ROTATION_DEGREES
#8bfc#21fc
L8bfc_pitch_set:
#8bfc#21fc15
4f 
    ld c, a
#8bfd#21fd
    ; Here: b = yaw, c = pitch.
#8bfd#21fd15
78 
    ld a, b
#8bfe#21fe28
fe 12 
    cp FULL_ROTATION_DEGREES / 4
#8c00#2200213/8
30 04 
    jr nc, L8c06
#8c02#220228
16 01 
    ld d, 1
#8c04#2204213
18 12 
    jr L8c18
#8c06#2206
L8c06:
#8c06#220628
fe 24 
    cp FULL_ROTATION_DEGREES / 2
#8c08#2208213/8
30 04 
    jr nc, L8c0e
#8c0a#220a28
16 03 
    ld d, 3
#8c0c#220c213
18 0a 
    jr L8c18
#8c0e#220e
L8c0e:
#8c0e#220e28
fe 36 
    cp 3 * FULL_ROTATION_DEGREES / 4
#8c10#2210213/8
30 04 
    jr nc, L8c16
#8c12#221228
16 05 
    ld d, 5
#8c14#2214213
18 02 
    jr L8c18
#8c16#2216
L8c16:
#8c16#221628
16 07 
    ld d, 7
#8c18#2218
L8c18:
#8c18#221815
79 
    ld a, c
#8c19#221928
fe 12 
    cp FULL_ROTATION_DEGREES / 4
#8c1b#221b213/8
30 03 
    jr nc, L8c20
#8c1d#221d15
14 
    inc d
#8c1e#221e213
18 16 
    jr L8c36
#8c20#2220
L8c20:
#8c20#222028
fe 24 
    cp FULL_ROTATION_DEGREES / 2
#8c22#2222213/8
30 04 
    jr nc, L8c28
#8c24#222428
3e 05 
    ld a, 5
#8c26#2226213
18 06 
    jr L8c2e
#8c28#2228
L8c28:
#8c28#222828
fe 36 
    cp 3 * FULL_ROTATION_DEGREES / 4
#8c2a#222a213/8
30 0a 
    jr nc, L8c36
#8c2c#222c28
3e 04 
    ld a, 4
#8c2e#222e
L8c2e:
#8c2e#222e15
82 
    add a, d
#8c2f#222f28
fe 09 
    cp 9
#8c31#2231213/8
38 02 
    jr c, L8c35
#8c33#223328
d6 08 
    sub 8
#8c35#2235
L8c35:
#8c35#223515
57 
    ld d, a
#8c36#2236
L8c36:
#8c36#2236
    ; Here:
#8c36#2236
    ; - d has some number based on the quadrants of pitch/yaw
#8c36#2236
    ; - these are used to set the limits:
#8c36#2236
    ;   - in the x/z axis, the maximum limits are [0, 127]
#8c36#2236
    ;   - in the y axis it is [0, 63]
#8c36#2236
    ; - all limits that are not set will be replaced by player coordinates.
#8c36#223615
15 
    dec d
#8c37#2237213/8
20 06 
    jr nz, L8c3f
#8c39#2239
    ; d == 1: yaw 1st quadrant, pitch 4th quadrant:
#8c39#2239421
dd 36 00 7f 
    ld (ix), 127
#8c3d#223d213
18 44 
    jr L8c83
#8c3f#223f
L8c3f:
#8c3f#223f15
15 
    dec d
#8c40#2240213/8
20 06 
    jr nz, L8c48
#8c42#2242
    ; d == 2: yaw 1st quadrant, pitch 1st quadrant:
#8c42#2242421
dd 36 00 7f 
    ld (ix), 127
#8c46#2246213
18 45 
    jr L8c8d
#8c48#2248
L8c48:
#8c48#224815
15 
    dec d
#8c49#2249213/8
20 0a 
    jr nz, L8c55
#8c4b#224b
    ; d == 3: yaw 2nd quadrant, pitch 4th quadrant:
#8c4b#224b421
dd 36 00 7f 
    ld (ix), 127
#8c4f#224f421
dd 36 02 3f 
    ld (ix + 2), 63
#8c53#2253213
18 21 
    jr L8c76
#8c55#2255
L8c55:
#8c55#225515
15 
    dec d
#8c56#2256213/8
20 06 
    jr nz, L8c5e
#8c58#2258
    ; d == 4: yaw 2nd quadrant, pitch 1st quadrant:
#8c58#2258421
dd 36 00 7f 
    ld (ix), 127
#8c5c#225c213
18 14 
    jr L8c72
#8c5e#225e
L8c5e:
#8c5e#225e15
15 
    dec d
#8c5f#225f213/8
20 0a 
    jr nz, L8c6b
#8c61#2261
    ; d == 5: yaw 1st quadrant, pitch 4th quadrant, or
#8c61#2261
    ;         yaw 2nd quadrant, pitch 1st quadrant
#8c61#2261421
dd 36 01 00 
    ld (ix + 1), 0
#8c65#2265421
dd 36 02 3f 
    ld (ix + 2), 63
#8c69#2269213
18 0b 
    jr L8c76
#8c6b#226b
L8c6b:
#8c6b#226b15
15 
    dec d
#8c6c#226c213/8
20 0e 
    jr nz, L8c7c
#8c6e#226e
    ; d == 6: ...
#8c6e#226e421
dd 36 01 00 
    ld (ix + 1), 0
#8c72#2272
L8c72:
#8c72#2272421
dd 36 03 00 
    ld (ix + 3), 0
#8c76#2276
L8c76:
#8c76#2276421
dd 36 05 00 
    ld (ix + 5), 0
#8c7a#227a213
18 19 
    jr L8c95
#8c7c#227c
L8c7c:
#8c7c#227c15
15 
    dec d
#8c7d#227d213/8
20 0a 
    jr nz, L8c89
#8c7f#227f
    ; d == 7: ...
#8c7f#227f421
dd 36 01 00 
    ld (ix + 1), 0
#8c83#2283
L8c83:
#8c83#2283421
dd 36 02 3f 
    ld (ix + 2), 63
#8c87#2287213
18 08 
    jr L8c91
#8c89#2289
L8c89:
#8c89#2289
    ; d == 8: ...
#8c89#2289421
dd 36 01 00 
    ld (ix + 1), 0
#8c8d#228d
L8c8d:
#8c8d#228d421
dd 36 03 00 
    ld (ix + 3), 0
#8c91#2291
L8c91:
#8c91#2291421
dd 36 04 7f 
    ld (ix + 4), 127
#8c95#2295
L8c95:
#8c95#229515
25 
    dec h
#8c96#2296311
c2 cc 8b 
    jp nz, L8bcc_angle_loop
#8c99#2299
#8c99#2299
    ; Replace any of the coordinates we have not set above,
#8c99#2299
    ; with the player x, y, or z coordinates:
#8c99#2299
    ; These correspond to areas that are "behind" the player, and
#8c99#2299
    ; hence we use the player coordinates to prune.
#8c99#2299317
2a ad 6a 
    ld hl, (L6aad_player_current_x)
#8c9c#229c112
29 
    add hl, hl
#8c9d#229d112
29 
    add hl, hl
#8c9e#229e28
3e ff 
    ld a, 255
#8ca0#22a0321
dd be 00 
    cp (ix)
#8ca3#22a3213/8
20 06 
    jr nz, L8cab
#8ca5#22a515
24 
    inc h
#8ca6#22a6321
dd 74 00 
    ld (ix), h
#8ca9#22a9213
18 08 
    jr L8cb3
#8cab#22ab
L8cab:
#8cab#22ab321
dd be 01 
    cp (ix + 1)
#8cae#22ae213/8
20 03 
    jr nz, L8cb3
#8cb0#22b0321
dd 74 01 
    ld (ix + 1), h
#8cb3#22b3
L8cb3:
#8cb3#22b3317
2a af 6a 
    ld hl, (L6aaf_player_current_y)
#8cb6#22b6112
29 
    add hl, hl
#8cb7#22b7112
29 
    add hl, hl
#8cb8#22b8321
dd be 02 
    cp (ix + 2)
#8cbb#22bb213/8
20 06 
    jr nz, L8cc3
#8cbd#22bd15
24 
    inc h
#8cbe#22be321
dd 74 02 
    ld (ix + 2), h
#8cc1#22c1213
18 08 
    jr L8ccb
#8cc3#22c3
L8cc3:
#8cc3#22c3321
dd be 03 
    cp (ix + 3)
#8cc6#22c6213/8
20 03 
    jr nz, L8ccb
#8cc8#22c8321
dd 74 03 
    ld (ix + 3), h
#8ccb#22cb
L8ccb:
#8ccb#22cb317
2a b1 6a 
    ld hl, (L6ab1_player_current_z)
#8cce#22ce112
29 
    add hl, hl
#8ccf#22cf112
29 
    add hl, hl
#8cd0#22d0321
dd be 04 
    cp (ix + 4)
#8cd3#22d3213/8
20 06 
    jr nz, L8cdb
#8cd5#22d515
24 
    inc h
#8cd6#22d6321
dd 74 04 
    ld (ix + 4), h
#8cd9#22d9213
18 08 
    jr L8ce3
#8cdb#22db
L8cdb:
#8cdb#22db321
dd be 05 
    cp (ix + 5)
#8cde#22de213/8
20 03 
    jr nz, L8ce3
#8ce0#22e0321
dd 74 05 
    ld (ix + 5), h
#8ce3#22e3
L8ce3:
#8ce3#22e3111
c9 
    ret
#8ce4#22e4
#8ce4#22e4
#8ce4#22e4
; --------------------------------
#8ce4#22e4
; Auxiliary variables for L8cf0_project_object_and_add_to_render_list_clipping_internal
#8ce4#22e4
L8ce4_projected_data_current_ptr_tmp:  ; Temporary storage of the current vertex data ptr.
#8ce4#22e42
    dw #0000
#8ce6#22e6
L8ce6_current_face_texture_ID:
#8ce6#22e61
    db #00
#8ce7#22e7
L8ce7_current_face_normal_check_result:  ; Caches the result of the normal check for the current face
#8ce7#22e71
    db #00
#8ce8#22e8
L8ce8_screen_corner_coordinates:  ; Used to insert new vertices when clipping.
#8ce8#22e82
    db SCREEN_WIDTH_IN_PIXELS, SCREEN_HEIGHT_IN_PIXELS
#8cea#22ea2
    db #00, SCREEN_HEIGHT_IN_PIXELS
#8cec#22ec2
    db #00, #00
#8cee#22ee2
    db SCREEN_WIDTH_IN_PIXELS, #00
#8cf0#22f0
#8cf0#22f0
#8cf0#22f0
; --------------------------------
#8cf0#22f0
; Projects an object, and if it falls within the screen, add it to the list of objects to draw,
#8cf0#22f0
; assuming that we will have to clip some of the edges as some vertices are outside the viewing area.
#8cf0#22f0
; Input:
#8cf0#22f0
; - iy: face definition ptr:
#8cf0#22f0
;   - first byte is number of faces
#8cf0#22f0
;   - then, each face has:
#8cf0#22f0
;     - attribute
#8cf0#22f0
;     - number of vertices
#8cf0#22f0
;     - then one byte per vertex (index)
#8cf0#22f0
L8cf0_project_object_and_add_to_render_list_clipping_internal:
#8cf0#22f0317
2a 24 5f 
    ld hl, (L5f24_shape_edges_ptr)
#8cf3#22f318
46 
    ld b, (hl)  ; number of edges
#8cf4#22f4
    ; Initialize the L5ee8_already_projected_vertex_coordinates array:
#8cf4#22f4
    ; (5 bytes per edge):
#8cf4#22f4
    ;   - 0 if not processed, 1 if processed
#8cf4#22f4
    ;   - projected x (vertex 1)
#8cf4#22f4
    ;   - projected y (vertex 1)
#8cf4#22f4
    ;   - projected x (vertex 2)
#8cf4#22f4
    ;   - projected y (vertex 2)
#8cf4#22f4311
21 e8 5e 
    ld hl, L5ee8_already_projected_vertex_coordinates
#8cf7#22f728
3e ff 
    ld a, #ff
#8cf9#22f928
0e 00 
    ld c, 0
#8cfb#22fb
L8cfb:
#8cfb#22fb18
71 
    ld (hl), c
#8cfc#22fc17
23 
    inc hl
#8cfd#22fd18
77 
    ld (hl), a
#8cfe#22fe17
23 
    inc hl
#8cff#22ff17
23 
    inc hl
#8d00#230018
77 
    ld (hl), a
#8d01#230117
23 
    inc hl
#8d02#230217
23 
    inc hl
#8d03#2303214/9
10 f6 
    djnz L8cfb
#8d05#2305
#8d05#230515
af 
    xor a
#8d06#2306314
32 5f 5e 
    ld (L5e5f_add_to_projected_objects_flag), a
#8d09#2309317
2a 97 74 
    ld hl, (L7497_next_projected_vertex_ptr)
#8d0c#230c314
3a 68 74 
    ld a, (L7468_focus_object_id)
#8d0f#230f
    ; Start writing the projected vertex data:
#8d0f#230f18
77 
    ld (hl), a  ; object ID
#8d10#231017
23 
    inc hl
#8d11#2311211
36 00 
    ld (hl), 0  ; number of primitives (init to zero, and will be incremented each time a face is added).
#8d13#231317
23 
    inc hl
#8d14#2314321
fd 46 00 
    ld b, (iy)  ; number of faces
#8d17#2317212
fd 23 
    inc iy
#8d19#2319
L8d19_face_loop:
#8d19#2319112
c5 
    push bc
#8d1a#231a321
fd 7e 00 
        ld a, (iy)  ; a = texture ID.
#8d1d#231d212
fd 23 
        inc iy
#8d1f#231f321
fd 46 00 
        ld b, (iy)  ; b = number of vertexes/edges in the face.
#8d22#2322212
fd 23 
        inc iy
#8d24#2324
        ; If it's a transparent face, ignore:
#8d24#232415
b7 
        or a
#8d25#2325213/8
28 69 
        jr z, L8d90_skip_face_bytes_and_next_face
#8d27#2327210
cb 27 
        sla a
#8d29#2329210
cb 27 
        sla a
#8d2b#232b210
cb 27 
        sla a
#8d2d#232d210
cb 27 
        sla a
#8d2f#232f15
4f 
        ld c, a  ; c = texture ID (in the most significant nibble).
#8d30#2330
        ; This first loop goes over the edges looking to see if any vertex passed all the
#8d30#2330
        ; frustum checks:
#8d30#2330217
fd e5 
        push iy
#8d32#2332112
e5 
        push hl
#8d33#2333112
c5 
        push bc
#8d34#233428
3e 01 
            ld a, 1
#8d36#2336314
32 28 5f 
            ld (L5f28_cull_face_when_no_projected_vertices), a
#8d39#233928
0e 1e 
            ld c, #1e  ; "c" will accumulate the frustum checks of all the vertexes
#8d3b#233b15
04 
            inc b
#8d3c#233c210
cb 38 
            srl b  ; b = (number of vertexes + 1) * 2
#8d3e#233e28
16 00 
            ld d, 0
#8d40#2340
L8d40_edge_loop:
#8d40#2340321
fd 7e 00 
            ld a, (iy)  ; vertex/edge index
#8d43#234328
e6 7f 
            and #7f  ; get the index (remove a potential flag in the msb)
#8d45#2345210
cb 27 
            sla a
#8d47#234715
5f 
            ld e, a
#8d48#2348422
dd 2a 24 5f 
            ld ix, (L5f24_shape_edges_ptr)
#8d4c#234c212
dd 23 
            inc ix  ; skip the number of vertexes
#8d4e#234e217
dd 19 
            add ix, de  ; ix = ptr to the edge
#8d50#2350321
dd 5e 00 
            ld e, (ix)  ; vertex index 1
#8d53#2353311
21 dc 5e 
            ld hl, L5edc_vertex_rendering_frustum_checks
#8d56#2356112
19 
            add hl, de
#8d57#235718
7e 
            ld a, (hl)
#8d58#235828
fe 1f 
            cp #1f
#8d5a#235a213/8
28 1a 
            jr z, L8d76
#8d5c#235c
            ; vertex outside of view frustum:
#8d5c#235c15
a1 
            and c
#8d5d#235d15
4f 
            ld c, a
#8d5e#235e321
dd 5e 01 
            ld e, (ix + 1)  ; vertex index 2
#8d61#2361311
21 dc 5e 
            ld hl, L5edc_vertex_rendering_frustum_checks
#8d64#2364112
19 
            add hl, de
#8d65#236518
7e 
            ld a, (hl)
#8d66#236628
fe 1f 
            cp #1f
#8d68#2368213/8
28 0c 
            jr z, L8d76
#8d6a#236a
            ; vertex outside of view frustum:
#8d6a#236a15
a1 
            and c
#8d6b#236b15
4f 
            ld c, a
#8d6c#236c212
fd 23 
            inc iy
#8d6e#236e212
fd 23 
            inc iy
#8d70#2370214/9
10 ce 
            djnz L8d40_edge_loop
#8d72#2372
#8d72#237215
4f 
            ld c, a  ; OPTIMIZATION: useless instruction "ld c, a" was just executed above.
#8d73#237315
b7 
            or a
#8d74#2374213/8
28 04 
            jr z, L8d7a
#8d76#2376
L8d76:
#8d76#2376
            ; We get here if one vertex has passed all frustum tests,
#8d76#2376
            ; or if the frustum test accumulator (c) is non zero.
#8d76#237615
af 
            xor a
#8d77#2377314
32 28 5f 
            ld (L5f28_cull_face_when_no_projected_vertices), a
#8d7a#237a
L8d7a:
#8d7a#237a111
c1 
        pop bc  ; restore c: texture ID, b: number of edges of face
#8d7b#237b111
e1 
        pop hl  ; restore hl: ptr to projected vertex data
#8d7c#237c216
fd e1 
        pop iy  ; restore iy: face edge data ptr.
#8d7e#237e
#8d7e#237e314
3a 60 5e 
        ld a, (L5e60_projection_pre_work_type)
#8d81#2381
        ;   - if a == 0: indicates that vertices can be projected directly.
#8d81#2381
        ;   - if a == 1: we need to call L88d1_normal_direction_check before projection, and if back-face, we cull
#8d81#2381
        ;   - if a == 2: we need to call L88d1_normal_direction_check before projection, and if back-face we need to use L5f26_alternative_shape_edges_ptr        
#8d81#238115
b7 
        or a
#8d82#2382213/8
28 43 
        jr z, L8dc7_ready_to_project
#8d84#238428
fe 01 
        cp 1
#8d86#2386213/8
20 10 
        jr nz, L8d98
#8d88#2388
#8d88#2388
        ; Normal check, and cull if failed:
#8d88#2388318
cd d1 88 
        call L88d1_normal_direction_check
#8d8b#238b314
32 e7 8c 
        ld (L8ce7_current_face_normal_check_result), a
#8d8e#238e213/8
30 37 
        jr nc, L8dc7_ready_to_project
#8d90#2390
L8d90_skip_face_bytes_and_next_face:
#8d90#239015
48 
        ld c, b
#8d91#239128
06 00 
        ld b, 0
#8d93#2393217
fd 09 
        add iy, bc
#8d95#2395311
c3 9f 8f 
        jp L8f9f_next_face
#8d98#2398
#8d98#2398
L8d98:
#8d98#2398
        ; Normal check, and use back texture if failed:
#8d98#2398318
cd d1 88 
        call L88d1_normal_direction_check
#8d9b#239b314
32 e7 8c 
        ld (L8ce7_current_face_normal_check_result), a
#8d9e#239e314
3a 6a 74 
        ld a, (L746a_current_drawing_texture_id)
#8da1#23a1213/8
30 17 
        jr nc, L8dba_front_face
#8da3#23a3
        ; back face, we need to swap texture ID, and use alternative shape edges ptr:
#8da3#23a328
e6 f0 
        and #f0
#8da5#23a5213/8
28 e9 
        jr z, L8d90_skip_face_bytes_and_next_face
#8da7#23a715
4f 
        ld c, a
#8da8#23a8422
ed 5b 26 5f 
        ld de, (L5f26_alternative_shape_edges_ptr)
#8dac#23ac422
ed 53 24 5f 
        ld (L5f24_shape_edges_ptr), de
#8db0#23b0
        ; OPTIMIZATION: at this point (L8ce7_current_face_normal_check_result) always contains a 1, so no need to read it and xor, just set to 0.
#8db0#23b0314
3a e7 8c 
        ld a, (L8ce7_current_face_normal_check_result)
#8db3#23b328
ee 01 
        xor 1
#8db5#23b5314
32 e7 8c 
        ld (L8ce7_current_face_normal_check_result), a
#8db8#23b8213
18 0d 
        jr L8dc7_ready_to_project
#8dba#23ba
#8dba#23ba
L8dba_front_face:
#8dba#23ba
        ; Get the texture ID into the most significant nibble of c
#8dba#23ba28
e6 0f 
        and #0f
#8dbc#23bc213/8
28 d2 
        jr z, L8d90_skip_face_bytes_and_next_face
#8dbe#23be210
cb 27 
        sla a
#8dc0#23c0210
cb 27 
        sla a
#8dc2#23c2210
cb 27 
        sla a
#8dc4#23c4210
cb 27 
        sla a
#8dc6#23c615
4f 
        ld c, a
#8dc7#23c7
#8dc7#23c7
L8dc7_ready_to_project:
#8dc7#23c7
        ; At this point:
#8dc7#23c7
        ; c = texture ID (most significant nibble)
#8dc7#23c7
        ; b = number of edges in the face
#8dc7#23c7
        ; hl = ptr to projected vertex data
#8dc7#23c7
        ; iy = face edge data ptr.
#8dc7#23c715
79 
        ld a, c
#8dc8#23c8314
32 e6 8c 
        ld (L8ce6_current_face_texture_ID), a
#8dcb#23cb15
78 
        ld a, b
#8dcc#23cc28
fe 02 
        cp 2
#8dce#23ce213/8
20 01 
        jr nz, L8dd1
#8dd0#23d015
05 
        dec b  ; If the number of edges is 2, make it 1 (a line).
#8dd1#23d1
L8dd1:
#8dd1#23d1
        ; This second edge loop: projects all the vertices, clipping them if necessary.
#8dd1#23d1217
fd e5 
        push iy
#8dd3#23d3112
e5 
        push hl
#8dd4#23d4112
c5 
        push bc
#8dd5#23d528
16 00 
            ld d, 0
#8dd7#23d7
L8dd7_edge_loop_2:
#8dd7#23d7112
c5 
            push bc
#8dd8#23d8321
fd 7e 00 
                ld a, (iy)  ; edge index
#8ddb#23db212
fd 23 
                inc iy
#8ddd#23dd217
fd e5 
                push iy
#8ddf#23df28
e6 7f 
                    and #7f  ; get rid of the edge flip flag.
#8de1#23e115
5f 
                    ld e, a
#8de2#23e2210
cb 27 
                    sla a
#8de4#23e415
4f 
                    ld c, a  ; c = edge index * 2
#8de5#23e5210
cb 27 
                    sla a
#8de7#23e715
83 
                    add a, e
#8de8#23e815
5f 
                    ld e, a  ; e = edge index * 5
#8de9#23e9
                    ; Check if this edge had already been processed:
#8de9#23e9416
dd 21 e8 5e 
                    ld ix, L5ee8_already_projected_vertex_coordinates
#8ded#23ed217
dd 19 
                    add ix, de
#8def#23ef15
af 
                    xor a
#8df0#23f0321
dd be 00 
                    cp (ix)
#8df3#23f3213/8
20 67 
                    jr nz, L8e5c_next_edge
#8df5#23f5212
dd 23 
                    inc ix
#8df7#23f7317
2a 24 5f 
                    ld hl, (L5f24_shape_edges_ptr)
#8dfa#23fa17
23 
                    inc hl
#8dfb#23fb15
59 
                    ld e, c
#8dfc#23fc112
19 
                    add hl, de  ; ptr to the edge
#8dfd#23fd18
5e 
                    ld e, (hl)  ; first vertex of the edge
#8dfe#23fe416
fd 21 dc 5e 
                    ld iy, L5edc_vertex_rendering_frustum_checks
#8e02#2402217
fd 19 
                    add iy, de
#8e04#2404321
fd 7e 00 
                    ld a, (iy)  ; frustum checks for first vertex of the edge
#8e07#240715
4f 
                    ld c, a
#8e08#240828
fe 1f 
                    cp #1f
#8e0a#240a213/8
20 0a 
                    jr nz, L8e16_second_vertex
#8e0c#240c
                    ; Vertex passed all frustum checks:
#8e0c#240c321
dd 7e 00 
                    ld a, (ix)  ; Check if we have already projected it
#8e0f#240f28
fe ff 
                    cp #ff
#8e11#2411213/8
20 03 
                    jr nz, L8e16_second_vertex
#8e13#2413
                    ; We need to project it:
#8e13#2413318
cd a5 8f 
                    call L8fa5_project_one_vertex_for_clipping_projection
#8e16#2416
L8e16_second_vertex:
#8e16#241617
23 
                    inc hl
#8e17#241718
5e 
                    ld e, (hl)  ; second vertex of the edge
#8e18#241817
2b 
                    dec hl
#8e19#2419416
fd 21 dc 5e 
                    ld iy, L5edc_vertex_rendering_frustum_checks
#8e1d#241d217
fd 19 
                    add iy, de
#8e1f#241f321
fd 7e 00 
                    ld a, (iy)  ; frustum checks for second vertex of the edge
#8e22#242215
47 
                    ld b, a
#8e23#242328
fe 1f 
                    cp #1f
#8e25#2425213/8
20 0a 
                    jr nz, L8e31
#8e27#2427321
dd 7e 02 
                    ld a, (ix + 2)  ; second vertex x
#8e2a#242a28
fe ff 
                    cp #ff
#8e2c#242c213/8
20 03 
                    jr nz, L8e31
#8e2e#242e318
cd a5 8f 
                    call L8fa5_project_one_vertex_for_clipping_projection
#8e31#2431
L8e31:
#8e31#2431
                    ; Here c and b contain the frustum checks of the two vertices:
#8e31#243115
78 
                    ld a, b
#8e32#243215
a1 
                    and c
#8e33#243328
fe 1f 
                    cp #1f
#8e35#2435213/8
20 05 
                    jr nz, L8e3c_at_least_one_vertex_outside
#8e37#2437
L8e37:
#8e37#2437
                    ; If both vertices were within the viewable area, or both outside
#8e37#2437
                    ; mark this edge as processed:
#8e37#2437325
dd 34 ffff 
                    inc (ix - 1)  ; mark the eedge as processed
#8e3a#243a213
18 20 
                    jr L8e5c_next_edge
#8e3c#243c
L8e3c_at_least_one_vertex_outside:
#8e3c#243c
                    ; At least one vertex was outside the view frustum, we need to clip:
#8e3c#243c15
78 
                    ld a, b
#8e3d#243d15
b1 
                    or c
#8e3e#243e28
fe 1f 
                    cp #1f
#8e40#2440213/8
20 f5 
                    jr nz, L8e37  ; both vertexes were outside, mark as processed too.
#8e42#2442
                    ; One vertex was in, the other was out:
#8e42#2442210
cb 23 
                    sla e
#8e44#2444416
fd 21 9f 5e 
                    ld iy, L5e9f_3d_vertex_coordinates_after_rotation_matrix
#8e48#2448217
fd 19 
                    add iy, de
#8e4a#244a217
fd 19 
                    add iy, de
#8e4c#244c217
fd 19 
                    add iy, de  ; iy = ptr to 3d vertex 2
#8e4e#244e18
5e 
                    ld e, (hl)  ; get the vertex 1 index again
#8e4f#244f210
cb 23 
                    sla e
#8e51#2451311
21 9f 5e 
                    ld hl, L5e9f_3d_vertex_coordinates_after_rotation_matrix
#8e54#2454112
19 
                    add hl, de
#8e55#2455112
19 
                    add hl, de
#8e56#2456112
19 
                    add hl, de  ; hl = ptr to 3d vertex 1
#8e57#2457318
cd ae 85 
                    call L85ae_clip_edge
#8e5a#245a28
16 00 
                    ld d, 0
#8e5c#245c
L8e5c_next_edge:
#8e5c#245c216
fd e1 
                pop iy
#8e5e#245e111
c1 
            pop bc
#8e5f#245f15
05 
            dec b
#8e60#2460311
c2 d7 8d 
            jp nz, L8dd7_edge_loop_2
#8e63#2463111
c1 
        pop bc
#8e64#2464111
e1 
        pop hl
#8e65#2465216
fd e1 
        pop iy
#8e67#2467
#8e67#2467
        ; At this point:
#8e67#2467
        ; b = number of edges in the face
#8e67#2467
        ; hl = ptr to projected vertex data we are writing to
#8e67#2467
        ; iy = face edge data ptr.
#8e67#2467
#8e67#2467
        ; This third loop adds projected vertices to the projected data, inserting connecting points if necessary.
#8e67#246715
4a 
        ld c, d  ; c = 0 (number of vertices added)
#8e68#2468317
22 e4 8c 
        ld (L8ce4_projected_data_current_ptr_tmp), hl  ; Save the current pointer to the projected vertex data we are writing to
#8e6b#246b17
23 
        inc hl
#8e6c#246c112
c5 
        push bc
#8e6d#246d
L8e6d_edge_loop_3:
#8e6d#246d321
fd 7e 00 
            ld a, (iy)  ; edge index
#8e70#247028
e6 7f 
            and #7f  ; get rid of the edge flip flag.
#8e72#247215
5f 
            ld e, a
#8e73#2473210
cb 27 
            sla a
#8e75#2475210
cb 27 
            sla a
#8e77#247715
83 
            add a, e  ; e = edge index * 5
#8e78#247815
5f 
            ld e, a
#8e79#247928
16 00 
            ld d, 0
#8e7b#247b416
dd 21 e8 5e 
            ld ix, L5ee8_already_projected_vertex_coordinates
#8e7f#247f217
dd 19 
            add ix, de
#8e81#2481
            ; If this edge was not projected, it means it was fully outside of the
#8e81#2481
            ; view area, just ignore:
#8e81#2481321
dd 7e 01 
            ld a, (ix + 1)
#8e84#248428
fe ff 
            cp #ff
#8e86#2486213/8
28 6d 
            jr z, L8ef5_next_edge
#8e88#2488422
fd cb 00 7e 
            bit 7, (iy)  ; Check edge flip flag
#8e8c#248c213/8
28 19 
            jr z, L8ea7_vertices_in_the_correct_order
#8e8e#248e
            ; Flip the projected vertex info:
#8e8e#248e321
dd 5e 01 
            ld e, (ix + 1)
#8e91#2491321
dd 56 03 
            ld d, (ix + 3)
#8e94#249415
7a 
            ld a, d  ; overwrite a with the x projection of the new first vertex.
#8e95#2495321
dd 72 01 
            ld (ix + 1), d
#8e98#2498321
dd 73 03 
            ld (ix + 3), e
#8e9b#249b321
dd 5e 02 
            ld e, (ix + 2)
#8e9e#249e321
dd 56 04 
            ld d, (ix + 4)
#8ea1#24a1321
dd 72 02 
            ld (ix + 2), d
#8ea4#24a4321
dd 73 04 
            ld (ix + 4), e
#8ea7#24a7
L8ea7_vertices_in_the_correct_order:
#8ea7#24a715
5f 
            ld e, a  ; vertex 1 x
#8ea8#24a8321
dd 56 02 
            ld d, (ix + 2)  ; vertex 1 y
#8eab#24ab15
79 
            ld a, c
#8eac#24ac15
b7 
            or a
#8ead#24ad213/8
28 0f 
            jr z, L8ebe  ; If it's the first vertex we project, skip
#8eaf#24af
            ; Check if the coordinates of vertex 1 are the same as the last projected vertex.
#8eaf#24af
            ; These should match if there was no clipping, but when there is clipping, we might
#8eaf#24af
            ; need to insert additional edges to connect clipped points:
#8eaf#24af15
7b 
            ld a, e
#8eb0#24b017
2b 
            dec hl
#8eb1#24b117
2b 
            dec hl
#8eb2#24b218
be 
            cp (hl)  ; compare x coordiantes
#8eb3#24b317
23 
            inc hl
#8eb4#24b4213/8
20 02 
            jr nz, L8eb8  ; no x match
#8eb6#24b615
7a 
            ld a, d
#8eb7#24b718
be 
            cp (hl)  ; compare y coordinates
#8eb8#24b8
L8eb8:
#8eb8#24b817
23 
            inc hl
#8eb9#24b9213/8
28 08 
            jr z, L8ec3_skip_vertex1_insertion
#8ebb#24bb318
cd ea 8f 
            call L8fea_add_connecting_projected_vertices
#8ebe#24be
L8ebe:
#8ebe#24be
            ; Add vertex to projection and increment vertex count ("c"):
#8ebe#24be18
73 
            ld (hl), e
#8ebf#24bf17
23 
            inc hl
#8ec0#24c018
72 
            ld (hl), d
#8ec1#24c117
23 
            inc hl
#8ec2#24c215
0c 
            inc c
#8ec3#24c3
L8ec3_skip_vertex1_insertion:
#8ec3#24c3321
dd 7e 04 
            ld a, (ix + 4)  ; vertex 2 y
#8ec6#24c615
ba 
            cp d
#8ec7#24c7321
dd 7e 03 
            ld a, (ix + 3)  ; vertex 2 x
#8eca#24ca213/8
20 03 
            jr nz, L8ecf
#8ecc#24cc15
bb 
            cp e
#8ecd#24cd213/8
28 08 
            jr z, L8ed7
#8ecf#24cf
L8ecf:
#8ecf#24cf
            ; Vertex 2 is different from vertex 1:
#8ecf#24cf18
77 
            ld (hl), a  ; x coordinate
#8ed0#24d017
23 
            inc hl
#8ed1#24d1321
dd 7e 04 
            ld a, (ix + 4)  ; y coordinate
#8ed4#24d418
77 
            ld (hl), a
#8ed5#24d517
23 
            inc hl
#8ed6#24d615
0c 
            inc c  ; incremenr number of projected vertices
#8ed7#24d7
L8ed7:
#8ed7#24d7
            ; If we had flipped the vertices, put them back in their original order:
#8ed7#24d7422
fd cb 00 7e 
            bit 7, (iy)
#8edb#24db213/8
28 18 
            jr z, L8ef5_next_edge
#8edd#24dd321
dd 5e 01 
            ld e, (ix + 1)
#8ee0#24e0321
dd 56 03 
            ld d, (ix + 3)
#8ee3#24e3321
dd 72 01 
            ld (ix + 1), d
#8ee6#24e6321
dd 73 03 
            ld (ix + 3), e
#8ee9#24e9321
dd 5e 02 
            ld e, (ix + 2)
#8eec#24ec321
dd 56 04 
            ld d, (ix + 4)
#8eef#24ef321
dd 72 02 
            ld (ix + 2), d
#8ef2#24f2321
dd 73 04 
            ld (ix + 4), e
#8ef5#24f5
L8ef5_next_edge:
#8ef5#24f5212
fd 23 
            inc iy
#8ef7#24f715
05 
            dec b
#8ef8#24f8311
c2 6d 8e 
            jp nz, L8e6d_edge_loop_3
#8efb#24fb
#8efb#24fb15
79 
            ld a, c
#8efc#24fc111
c1 
        pop bc  ; restore the number of edges in b
#8efd#24fd422
dd 2a e4 8c 
        ld ix, (L8ce4_projected_data_current_ptr_tmp)
#8f01#250115
4f 
        ld c, a  ; number of projected vertices
#8f02#250228
fe 02 
        cp 2
#8f04#2504213/8
30 63 
        jr nc, L8f69_2_or_more_vertices_projected
#8f06#250628
fe 01 
        cp 1
#8f08#2508213/8
20 02 
        jr nz, L8f0c_0_vertices_projected
#8f0a#250a17
2b 
        dec hl
#8f0b#250b17
2b 
        dec hl
#8f0c#250c
#8f0c#250c
L8f0c_0_vertices_projected:
#8f0c#250c15
78 
        ld a, b
#8f0d#250d28
fe 01 
        cp 1
#8f0f#250f213/8
28 06 
        jr z, L8f17_discard_current_face
#8f11#2511314
3a 28 5f 
        ld a, (L5f28_cull_face_when_no_projected_vertices)
#8f14#251415
b7 
        or a
#8f15#2515213/8
20 06 
        jr nz, L8f1d
#8f17#2517
L8f17_discard_current_face:
#8f17#2517
        ; Ignore this face and all projected points so far
#8f17#2517317
2a e4 8c 
        ld hl, (L8ce4_projected_data_current_ptr_tmp)
#8f1a#251a311
c3 9f 8f 
        jp L8f9f_next_face
#8f1d#251d
#8f1d#251d
L8f1d:
#8f1d#251d314
3a 60 5e 
        ld a, (L5e60_projection_pre_work_type)
#8f20#252015
b7 
        or a
#8f21#2521213/8
20 18 
        jr nz, L8f3b_we_already_did_normal_check
#8f23#2523
        ; When L5e60_projection_pre_work_type is zero, we had not done a normal check,
#8f23#2523
        ; and hence "L5f28_cull_face_when_no_projected_vertices" might not be fully populated,
#8f23#2523
        ; do it now:
#8f23#2523217
fd e5 
        push iy
#8f25#252515
78 
            ld a, b
#8f26#2526210
ed 44 
            neg
#8f28#252815
5f 
            ld e, a
#8f29#252928
16 ff 
            ld d, 255
#8f2b#252b217
fd 19 
            add iy, de  ; iy -= number of edes of the face (to reset to the beginning of this face data)
#8f2d#252d318
cd d1 88 
            call L88d1_normal_direction_check
#8f30#2530216
fd e1 
        pop iy
#8f32#2532314
32 e7 8c 
        ld (L8ce7_current_face_normal_check_result), a
#8f35#2535314
3a 28 5f 
        ld a, (L5f28_cull_face_when_no_projected_vertices)
#8f38#253815
b7 
        or a
#8f39#2539213/8
28 dc 
        jr z, L8f17_discard_current_face
#8f3b#253b
#8f3b#253b
L8f3b_we_already_did_normal_check:
#8f3b#253b318
cd 68 90 
        call L9068_face_covers_whole_screen_check
#8f3e#253e314
3a 28 5f 
        ld a, (L5f28_cull_face_when_no_projected_vertices)
#8f41#254115
b7 
        or a
#8f42#2542213/8
28 d3 
        jr z, L8f17_discard_current_face
#8f44#2544
#8f44#2544
        ; Object occupies the whole screen, set screen coordinates as the projected vertices:
#8f44#2544311
11 e8 8c 
        ld de, L8ce8_screen_corner_coordinates
#8f47#254715
eb 
        ex de, hl
#8f48#2548311
01 08 00 
        ld bc, 8
#8f4b#254b223/18
ed b0 
        ldir
#8f4d#254d314
3a e6 8c 
        ld a, (L8ce6_current_face_texture_ID)
#8f50#255028
f6 04 
        or 4
#8f52#2552321
dd 77 00 
        ld (ix), a
#8f55#2555
        ; Mark that we have objects covering the whols screen:
#8f55#2555311
21 81 74 
        ld hl, L7481_n_objects_covering_the_whole_screen
#8f58#2558112
34 
        inc (hl)
#8f59#2559317
2a 97 74 
        ld hl, (L7497_next_projected_vertex_ptr)
#8f5c#255c17
23 
        inc hl
#8f5d#255d112
34 
        inc (hl)
#8f5e#255e217
cb fe 
        set 7, (hl)
#8f60#256015
eb 
        ex de, hl
#8f61#256128
3e 01 
        ld a, 1
#8f63#2563314
32 5f 5e 
        ld (L5e5f_add_to_projected_objects_flag), a
#8f66#2566111
c1 
    pop bc
#8f67#2567213
18 3b 
    jr L8fa4_ret
#8f69#2569
#8f69#2569
L8f69_2_or_more_vertices_projected:
#8f69#256928
fe 02 
        cp 2
#8f6b#256b213/8
20 05 
        jr nz, L8f72_close_shape
#8f6d#256d
        ; If we projected just 2 vertices:
#8f6d#256d15
78 
        ld a, b
#8f6e#256e28
fe 01 
        cp 1  ; If the original object was just a line, we are done
#8f70#2570213/8
28 1a 
        jr z, L8f8c_successful_face_projection
#8f72#2572
L8f72_close_shape:
#8f72#2572
        ; Check if the last vertex we added matches the very first vertex,
#8f72#2572
        ; if it does, remove it. If it does not, check if we need to insert connecting projected vertices:
#8f72#2572321
dd 5e 01 
        ld e, (ix + 1)
#8f75#2575321
dd 56 02 
        ld d, (ix + 2)
#8f78#257815
7b 
        ld a, e
#8f79#257917
2b 
        dec hl
#8f7a#257a17
2b 
        dec hl
#8f7b#257b18
be 
        cp (hl)
#8f7c#257c17
23 
        inc hl
#8f7d#257d213/8
20 02 
        jr nz, L8f81
#8f7f#257f15
7a 
        ld a, d
#8f80#258018
be 
        cp (hl)
#8f81#2581
L8f81:
#8f81#258117
23 
        inc hl
#8f82#2582213/8
20 05 
        jr nz, L8f89
#8f84#2584
        ; Match, remove the last vertex:
#8f84#258415
0d 
        dec c
#8f85#258517
2b 
        dec hl
#8f86#258617
2b 
        dec hl
#8f87#2587213
18 03 
        jr L8f8c_successful_face_projection
#8f89#2589
L8f89:
#8f89#2589
        ; No match, check for necessary connecting vertices:
#8f89#2589318
cd ea 8f 
        call L8fea_add_connecting_projected_vertices
#8f8c#258c
L8f8c_successful_face_projection:
#8f8c#258c
        ; Add the texture / # of vertices byte, mark as projected, and move to next face.
#8f8c#258c314
3a e6 8c 
        ld a, (L8ce6_current_face_texture_ID)
#8f8f#258f15
b1 
        or c
#8f90#2590321
dd 77 00 
        ld (ix), a
#8f93#2593
#8f93#259328
3e 01 
        ld a, 1
#8f95#2595314
32 5f 5e 
        ld (L5e5f_add_to_projected_objects_flag), a
#8f98#2598422
dd 2a 97 74 
        ld ix, (L7497_next_projected_vertex_ptr)
#8f9c#259c325
dd 34 01 
        inc (ix + 1)  ; increment the number of primitives counter
#8f9f#259f
L8f9f_next_face:
#8f9f#259f111
c1 
    pop bc
#8fa0#25a015
05 
    dec b
#8fa1#25a1311
c2 19 8d 
    jp nz, L8d19_face_loop
#8fa4#25a4
L8fa4_ret:
#8fa4#25a4111
c9 
    ret
#8fa5#25a5
#8fa5#25a5
#8fa5#25a5
; --------------------------------
#8fa5#25a5
; This method projects the vertex with index 'e', and writes the projected coordinates
#8fa5#25a5
; to the L5ee8_already_projected_vertex_coordinates buffer, assuming we are using
#8fa5#25a5
; projection method L8cf0_project_object_and_add_to_render_list_clipping_internal.
#8fa5#25a5
; Input:
#8fa5#25a5
; - e: vertex index.
#8fa5#25a5
L8fa5_project_one_vertex_for_clipping_projection:
#8fa5#25a5217
dd e5 
    push ix
#8fa7#25a7112
e5 
    push hl
#8fa8#25a8112
d5 
    push de
#8fa9#25a9112
c5 
    push bc
#8faa#25aa15
7b 
        ld a, e  ; a = vertex index
#8fab#25ab210
cb 23 
        sla e
#8fad#25ad416
dd 21 9f 5e 
        ld ix, L5e9f_3d_vertex_coordinates_after_rotation_matrix
#8fb1#25b1217
dd 19 
        add ix, de
#8fb3#25b3217
dd 19 
        add ix, de
#8fb5#25b5217
dd 19 
        add ix, de  ; get the 3d vertex pointer
#8fb7#25b7318
cd fc 90 
        call L90fc_project_one_vertex
#8fba#25ba317
2a 24 5f 
        ld hl, (L5f24_shape_edges_ptr)
#8fbd#25bd416
dd 21 e9 5e 
        ld ix, L5ee8_already_projected_vertex_coordinates + 1
#8fc1#25c115
58 
        ld e, b  ; e = projected y
#8fc2#25c218
46 
        ld b, (hl)  ; number of edges
#8fc3#25c317
23 
        inc hl
#8fc4#25c4
        ; This loop goes through the L5ee8_already_projected_vertex_coordinates array,
#8fc4#25c4
        ; and writes projected coordinates for all the vertices that match the current vertex
#8fc4#25c4
        ; we just projected.
#8fc4#25c4
L8fc4_write_projected_vertex_to_buffer:
#8fc4#25c418
be 
        cp (hl)  ; is this the right vertex?
#8fc5#25c5213/8
20 06 
        jr nz, L8fcd
#8fc7#25c7
        ; Yes, write projection data!
#8fc7#25c7321
dd 71 00 
        ld (ix), c  ; projected x
#8fca#25ca321
dd 73 01 
        ld (ix + 1), e  ; projected y
#8fcd#25cd
L8fcd:
#8fcd#25cd212
dd 23 
        inc ix
#8fcf#25cf212
dd 23 
        inc ix
#8fd1#25d117
23 
        inc hl
#8fd2#25d218
be 
        cp (hl)  ; is this the right vertex?
#8fd3#25d3213/8
20 06 
        jr nz, L8fdb
#8fd5#25d5
        ; Yes, write projection data!
#8fd5#25d5321
dd 71 00 
        ld (ix), c  ; projected x
#8fd8#25d8321
dd 73 01 
        ld (ix + 1), e  ; projected y
#8fdb#25db
L8fdb:
#8fdb#25db212
dd 23 
        inc ix
#8fdd#25dd212
dd 23 
        inc ix
#8fdf#25df212
dd 23 
        inc ix
#8fe1#25e117
23 
        inc hl
#8fe2#25e2214/9
10 e0 
        djnz L8fc4_write_projected_vertex_to_buffer
#8fe4#25e4111
c1 
    pop bc
#8fe5#25e5111
d1 
    pop de
#8fe6#25e6111
e1 
    pop hl
#8fe7#25e7216
dd e1 
    pop ix
#8fe9#25e9111
c9 
    ret
#8fea#25ea
#8fea#25ea
#8fea#25ea
; --------------------------------
#8fea#25ea
; Checks if we need to insert additional projected vertices along the screen edges to
#8fea#25ea
; connect the previous projected vertex with the new one we want to add.
#8fea#25ea
; Input:
#8fea#25ea
; - c: number of inserted vertexes so far
#8fea#25ea
; - e: new vertex projected x
#8fea#25ea
; - d: new vertex projected y
#8fea#25ea
; - hl: ptr to projected vertex data we are writing to
#8fea#25ea
; Output:
#8fea#25ea
; - c: updated number of inserted vertexes so far
#8fea#25ea
; - hl: updated ptr to projected vertex data we are writing to
#8fea#25ea
L8fea_add_connecting_projected_vertices:
#8fea#25ea217
dd e5 
    push ix
#8fec#25ec217
fd e5 
    push iy
#8fee#25ee112
e5 
        push hl
#8fef#25ef216
dd e1 
        pop ix
#8ff1#25f1311
21 01 00 
        ld hl, 1
#8ff4#25f428
3e 70 
        ld a, SCREEN_HEIGHT_IN_PIXELS
#8ff6#25f6321
dd be ffff 
        cp (ix - 1)  ; is previous vertex y at the top of the screen?
#8ff9#25f9213/8
28 0e 
        jr z, L9009
#8ffb#25fb15
2c 
        inc l  ; l = 2
#8ffc#25fc15
af 
        xor a
#8ffd#25fd321
dd be fffe 
        cp (ix - 2)  ; is previous vertex x in the left of the screen?
#9000#2600213/8
28 07 
        jr z, L9009
#9002#260215
2c 
        inc l  ; l = 3
#9003#2603321
dd be ffff 
        cp (ix - 1)  ; is previous vertex y in the bottom of the screen?
#9006#2606213/8
28 01 
        jr z, L9009
#9008#260815
6f 
        ld l, a  ; l = 0
#9009#2609
L9009:
#9009#2609
        ; At this point:
#9009#2609
        ; - l = 0: previous vertex at right side of screen
#9009#2609
        ; - l = 1: previous vertex at top of screen
#9009#2609
        ; - l = 2: previous vertex at left side of screen
#9009#2609
        ; - l = 3: previous vertex at bottom of screen
#9009#260928
3e c0 
        ld a, SCREEN_WIDTH_IN_PIXELS
#900b#260b15
bb 
        cp e
#900c#260c213/8
28 0c 
        jr z, L901a
#900e#260e15
24 
        inc h
#900f#260f28
3e 70 
        ld a, SCREEN_HEIGHT_IN_PIXELS
#9011#261115
ba 
        cp d
#9012#2612213/8
28 06 
        jr z, L901a
#9014#261415
24 
        inc h
#9015#261515
af 
        xor a
#9016#261615
bb 
        cp e
#9017#2617213/8
28 01 
        jr z, L901a
#9019#261915
24 
        inc h
#901a#261a
L901a:
#901a#261a
        ; At this point:
#901a#261a
        ; - h = 0: new vertex at right side of screen
#901a#261a
        ; - h = 1: new vertex at top of screen
#901a#261a
        ; - h = 2: new vertex at left side of screen
#901a#261a
        ; - h = 3: new vertex at bottom of screen
#901a#261a15
7c 
        ld a, h
#901b#261b15
bd 
        cp l
#901c#261c213/8
28 42 
        jr z, L9060_done  ; both vertexes are in the same side of the screen, we can just insert the new vertex.
#901e#261e
        ; Previous and new vertex are not on the same edges of the screen, we need to insert an auxiliary vertex:
#901e#261e112
d5 
        push de
#901f#261f
L901f:
#901f#261f
            ; Get the coordinates of the screen corner that would help us come closer to
#901f#261f
            ; the edge of the new projected vertex:
#901f#261f15
5d 
            ld e, l
#9020#262028
16 00 
            ld d, 0
#9022#2622210
cb 23 
            sla e
#9024#2624416
fd 21 e8 8c 
            ld iy, L8ce8_screen_corner_coordinates
#9028#2628217
fd 19 
            add iy, de
#902a#262a321
fd 7e 00 
            ld a, (iy)
#902d#262d321
fd 56 01 
            ld d, (iy + 1)
#9030#2630
            ; Check that we are not adding a point that is identical to the previous one, just in case:
#9030#263015
5f 
            ld e, a
#9031#2631321
dd be fffe 
            cp (ix - 2)
#9034#2634213/8
20 06 
            jr nz, L903c
#9036#263615
7a 
            ld a, d
#9037#2637321
dd be ffff 
            cp (ix - 1)
#903a#263a213/8
28 1b 
            jr z, L9057
#903c#263c
L903c:
#903c#263c
            ; Check that it is not identical to the very first vertex of the face:
#903c#263c422
fd 2a e4 8c 
            ld iy, (L8ce4_projected_data_current_ptr_tmp)
#9040#264015
7b 
            ld a, e
#9041#2641321
fd be 01 
            cp (iy + 1)
#9044#2644213/8
20 06 
            jr nz, L904c
#9046#264615
7a 
            ld a, d
#9047#2647321
fd be 02 
            cp (iy + 2)
#904a#264a213/8
28 0b 
            jr z, L9057
#904c#264c
L904c:
#904c#264c
            ; Insert a new projected vertex:
#904c#264c321
dd 73 00 
            ld (ix), e  ; x
#904f#264f321
dd 72 01 
            ld (ix + 1), d  ; y
#9052#2652212
dd 23 
            inc ix
#9054#2654212
dd 23 
            inc ix
#9056#265615
0c 
            inc c  ; increase number of projected vertices count.
#9057#2657
L9057:
#9057#2657
              ; update the screen edge the new previous vertex is at
#9057#265715
2c 
            inc l
#9058#265815
7d 
            ld a, l
#9059#265928
e6 03 
            and #03
#905b#265b15
6f 
            ld l, a
#905c#265c
            ; Have we brought it to the same edge as the new vertex? if so, we are done.
#905c#265c15
bc 
            cp h
#905d#265d213/8
20 c0 
            jr nz, L901f
#905f#265f111
d1 
        pop de
#9060#2660
L9060_done:
#9060#2660217
dd e5 
        push ix
#9062#2662111
e1 
        pop hl
#9063#2663216
fd e1 
    pop iy
#9065#2665216
dd e1 
    pop ix
#9067#2667111
c9 
    ret
#9068#2668
#9068#2668
#9068#2668
; --------------------------------
#9068#2668
; Checks a face that has resulted in no projected vertices covers the whole screen.
#9068#2668
; Note: I am not sure about how the math in this function works, as I have not tried to derive the
#9068#2668
;       interpretration of he calculations. So, I have named this function based on the effect that
#9068#2668
;       it later has when called.
#9068#2668
; Input:
#9068#2668
; - b: number of edges of face
#9068#2668
; - e: number of edges in current face
#9068#2668
; - iy: face edge data (pointing to the end of the data)
#9068#2668
L9068_face_covers_whole_screen_check:
#9068#2668217
dd e5 
    push ix
#906a#266a217
fd e5 
    push iy
#906c#266c112
e5 
    push hl
#906d#266d15
af 
        xor a
#906e#266e314
32 28 5f 
        ld (L5f28_cull_face_when_no_projected_vertices), a
#9071#267115
78 
        ld a, b
#9072#2672210
ed 44 
        neg
#9074#267415
5f 
        ld e, a
#9075#267528
16 ff 
        ld d, 255
#9077#2677217
fd 19 
        add iy, de  ; iy -= number of edes of the face (to reset to the beginning of this face data)
#9079#2679
L9079:
#9079#2679112
c5 
        push bc
#907a#267a321
fd 7e 00 
            ld a, (iy)
#907d#267d28
e6 7f 
            and #7f
#907f#267f15
5f 
            ld e, a
#9080#268028
16 00 
            ld d, 0
#9082#268215
62 
            ld h, d
#9083#2683210
cb 23 
            sla e
#9085#2685422
dd 2a 24 5f 
            ld ix, (L5f24_shape_edges_ptr)
#9089#2689212
dd 23 
            inc ix
#908b#268b217
dd 19 
            add ix, de
#908d#268d321
dd 6e 00 
            ld l, (ix)
#9090#2690321
dd 5e 01 
            ld e, (ix + 1)
#9093#2693422
fd cb 00 7e 
            bit 7, (iy)  ; vertex flip flag
#9097#2697213/8
28 01 
            jr z, L909a
#9099#269915
eb 
            ex de, hl
#909a#269a
L909a:
#909a#269a217
fd e5 
            push iy
#909c#269c210
cb 23 
                sla e
#909e#269e416
dd 21 9f 5e 
                ld ix, L5e9f_3d_vertex_coordinates_after_rotation_matrix
#90a2#26a2217
dd 19 
                add ix, de
#90a4#26a4210
cb 23 
                sla e
#90a6#26a6217
dd 19 
                add ix, de  ; ix += vertex 1 index * 6
#90a8#26a815
eb 
                ex de, hl
#90a9#26a9210
cb 23 
                sla e
#90ab#26ab416
fd 21 9f 5e 
                ld iy, L5e9f_3d_vertex_coordinates_after_rotation_matrix
#90af#26af217
fd 19 
                add iy, de
#90b1#26b1210
cb 23 
                sla e
#90b3#26b3217
fd 19 
                add iy, de  ; iy += vertex 1 index * 6
#90b5#26b5321
dd 5e 02 
                ld e, (ix + 2)
#90b8#26b8321
dd 56 03 
                ld d, (ix + 3)  ; de = vertex 1 y
#90bb#26bb321
fd 6e 00 
                ld l, (iy)
#90be#26be321
fd 66 01 
                ld h, (iy + 1)  ; hl = vertex 2 x
#90c1#26c1318
cd 5e a1 
                call La15e_de_times_hl_signed  ; (de, hl) = vertex 1 y * vertex 2 x
#90c4#26c4112
d5 
                push de
#90c5#26c5112
e5 
                    push hl
#90c6#26c6321
dd 5e 00 
                        ld e, (ix)
#90c9#26c9321
dd 56 01 
                        ld d, (ix + 1)  ; de = vertex 1 x
#90cc#26cc321
fd 6e 02 
                        ld l, (iy + 2)
#90cf#26cf321
fd 66 03 
                        ld h, (iy + 3)  ; hl = vertex 2 y
#90d2#26d2318
cd 5e a1 
                        call La15e_de_times_hl_signed  ; (de, hl) = vertex 1 x * vertex 2 y
#90d5#26d5111
c1 
                    pop bc
#90d6#26d615
b7 
                    or a
#90d7#26d7217
ed 42 
                    sbc hl, bc  ; (low word) hl = (vertex 1 x * vertex 2 y) - (vertex 1 y * vertex 2 x) (this is done only to get the carry flag for the next operation)
#90d9#26d9111
c1 
                pop bc
#90da#26da15
eb 
                ex de, hl
#90db#26db217
ed 42 
                sbc hl, bc  ; (high word) hl = (vertex 1 x * vertex 2 y) - (vertex 1 y * vertex 2 x)
#90dd#26dd28
2e 01 
                ld l, 1
#90df#26df311
f2 e4 90 
                jp p, L90e4
#90e2#26e228
2e 00 
                ld l, 0
#90e4#26e4
L90e4:
#90e4#26e4216
fd e1 
            pop iy
#90e6#26e6111
c1 
        pop bc
#90e7#26e7314
3a e7 8c 
        ld a, (L8ce7_current_face_normal_check_result)
#90ea#26ea15
bd 
        cp l
#90eb#26eb213/8
20 09 
        jr nz, L90f6
#90ed#26ed212
fd 23 
        inc iy
#90ef#26ef214/9
10 88 
        djnz L9079
#90f1#26f1
        ; Face covers the whole screen!
#90f1#26f128
3e 01 
        ld a, 1
#90f3#26f3314
32 28 5f 
        ld (L5f28_cull_face_when_no_projected_vertices), a
#90f6#26f6
L90f6:
#90f6#26f6111
e1 
    pop hl
#90f7#26f7216
fd e1 
    pop iy
#90f9#26f9216
dd e1 
    pop ix
#90fb#26fb111
c9 
    ret
#90fc#26fc
#90fc#26fc
#90fc#26fc
; --------------------------------
#90fc#26fc
; Projects one vertex from 3d camera coordinates to screen coordinates.
#90fc#26fc
; Input:
#90fc#26fc
; - ix: pointer to a 3d vertex, already transformed, relative to camera view (16 bits per coordinate).
#90fc#26fc
; Output:
#90fc#26fc
; - bc: projected coordinates (c, b) = (x, y)
#90fc#26fc
L90fc_project_one_vertex:
#90fc#26fc112
e5 
    push hl
#90fd#26fd112
d5 
    push de
#90fe#26fe112
f5 
    push af
#90ff#26ff321
dd 56 05 
        ld d, (ix + 5)
#9102#2702321
dd 5e 04 
        ld e, (ix + 4)  ; de = z
#9105#270515
7b 
        ld a, e
#9106#270615
b2 
        or d
#9107#2707213/8
20 05 
        jr nz, L910e_project_x
#9109#2709
        ; If z = 0, just project to the center of the screen.
#9109#2709311
01 60 38 
        ld bc, #3860  ; (96, 56)  (center of the screen).
#910c#270c213
18 62 
        jr L9170_return
#910e#270e
L910e_project_x:
#910e#270e321
dd 66 01 
        ld h, (ix + 1)
#9111#2711321
dd 6e 00 
        ld l, (ix)  ; hl = x
#9114#2714210
cb 7c 
        bit 7, h
#9116#2716213/8
28 0a 
        jr z, L9122
#9118#2718
        ; x is negative:
#9118#2718112
19 
        add hl, de
#9119#271917
2b 
        dec hl  ; hl = x + z - 1
#911a#271a210
cb 7c 
        bit 7, h
#911c#271c213/8
28 0e 
        jr z, L912c
#911e#271e
        ; x + z - 1 is negative
#911e#271e28
0e 00 
        ld c, 0  ; screen x = 0
#9120#2720213
18 1e 
        jr L9140_project_y
#9122#2722
L9122:
#9122#272215
b7 
        or a
#9123#2723217
ed 52 
        sbc hl, de  ; hl = x - z
#9125#2725311
fa 2c 91 
        jp m, L912c
#9128#2728
        ; x - z is negative
#9128#272828
0e c0 
        ld c, SCREEN_WIDTH_IN_PIXELS  ; screen x = 192
#912a#272a213
18 14 
        jr L9140_project_y
#912c#272c
L912c:
#912c#272c28
3e 60 
        ld a, SCREEN_WIDTH_IN_PIXELS / 2
#912e#272e321
dd 66 01 
        ld h, (ix + 1)
#9131#2731321
dd 6e 00 
        ld l, (ix)  ; hl = x
#9134#2734112
d5 
        push de
#9135#2735
            ; OPTIMIZATION: multiplication by 96 can be accelerated with a custom routine.
#9135#2735
            ; (a, hl) = 96 * x
#9135#2735318
cd 08 a1 
            call La108_a_times_hl_signed
#9138#2738
            ; (a, hl) = 96 * x / z
#9138#2738318
cd cc a1 
            call La1cc_a_hl_divided_by_de_signed
#913b#273b111
d1 
        pop de
#913c#273c28
3e 60 
        ld a, SCREEN_WIDTH_IN_PIXELS / 2
#913e#273e15
85 
        add a, l
#913f#273f15
4f 
        ld c, a  ; screen x = 96 * x / z + 96
#9140#2740
L9140_project_y:
#9140#2740321
dd 66 03 
        ld h, (ix + 3)
#9143#2743321
dd 6e 02 
        ld l, (ix + 2)  ; hl = y
#9146#2746210
cb 7c 
        bit 7, h
#9148#2748213/8
28 0a 
        jr z, L9154
#914a#274a
        ; y is negative:
#914a#274a112
19 
        add hl, de
#914b#274b17
2b 
        dec hl  ; hl = y + z - 1
#914c#274c210
cb 7c 
        bit 7, h
#914e#274e213/8
28 0e 
        jr z, L915e
#9150#2750
        ; y + z - 1 is negative
#9150#275028
06 00 
        ld b, 0  ; screen y = 0
#9152#2752213
18 1c 
        jr L9170_return
#9154#2754
L9154:
#9154#275415
b7 
        or a
#9155#2755217
ed 52 
        sbc hl, de  ; hl = y - z
#9157#2757311
fa 5e 91 
        jp m, L915e
#915a#275a
        ; y - z is negative:
#915a#275a28
06 70 
        ld b, SCREEN_HEIGHT_IN_PIXELS  ; screen y = 112  
#915c#275c213
18 12 
        jr L9170_return
#915e#275e
L915e:
#915e#275e28
3e 38 
        ld a, SCREEN_HEIGHT_IN_PIXELS / 2
#9160#2760321
dd 66 03 
        ld h, (ix + 3)
#9163#2763321
dd 6e 02 
        ld l, (ix + 2)  ; hl = y
#9166#2766
        ; OPTIMIZATION: multiplication by 96 can be accelerated with a custom routine.
#9166#2766
        ; (a, hl) = 96 * y
#9166#2766318
cd 08 a1 
        call La108_a_times_hl_signed
#9169#2769
        ; (a, hl) = 96 * y / z
#9169#2769318
cd cc a1 
        call La1cc_a_hl_divided_by_de_signed
#916c#276c28
3e 38 
        ld a, SCREEN_HEIGHT_IN_PIXELS / 2
#916e#276e15
85 
        add a, l
#916f#276f15
47 
        ld b, a  ; screen x = 56 * x / z + 56
#9170#2770
L9170_return:
#9170#2770111
f1 
    pop af
#9171#2771111
d1 
    pop de
#9172#2772111
e1 
    pop hl
#9173#2773111
c9 
    ret
#9174#2774
#9174#2774
#9174#2774
; --------------------------------
#9174#2774
; Auxiliary variables for L9177_rotate_relative_bounding_box
#9174#2774
L9174_24bit_accumulator:
#9174#27743
    db #00, #00, #00
#9177#2777
#9177#2777
#9177#2777
; --------------------------------
#9177#2777
; This method does two things:
#9177#2777
; - Applies the rotation matrix to the first coordinate in (L7499_3d_object_bounding_box_relative_to_player_ptr),
#9177#2777
;   saving it to (L5e9f_3d_vertex_coordinates_after_rotation_matrix).
#9177#2777
; - It then multiplies the width, height, length of the object by each row of the
#9177#2777
;   rotation matrix, and stores the 9 resulting values in (L5e63_3d_vertex_coordinates_relative_to_player).
#9177#2777
; - This method is used for generating vertices for cubes and rectangle objects.
#9177#2777
L9177_rotate_relative_bounding_box:
#9177#2777422
fd 2a 99 74 
    ld iy, (L7499_3d_object_bounding_box_relative_to_player_ptr)  ; These are in 16bit precision.
#917b#277b416
dd 21 55 5e 
    ld ix, L5e55_rotation_matrix
#917f#277f311
21 9f 5e 
    ld hl, L5e9f_3d_vertex_coordinates_after_rotation_matrix
#9182#278228
06 03 
    ld b, 3
#9184#2784
    ; Apply the rotation matrix to the first coordinate in the bounding box, and
#9184#2784
    ; save it in L5e9f_3d_vertex_coordinates_after_rotation_matrix
#9184#2784
L9184_matrix_coordinate_loop:
#9184#2784112
e5 
    push hl
#9185#2785
        ; Multiply the bounding box coordinate 1 by one column of the rotation matrix:
#9185#278515
af 
        xor a
#9186#2786314
32 74 91 
        ld (L9174_24bit_accumulator), a
#9189#2789314
32 75 91 
        ld (L9174_24bit_accumulator + 1), a
#918c#278c314
32 76 91 
        ld (L9174_24bit_accumulator + 2), a
#918f#278f321
dd 7e 00 
        ld a, (ix)  ; get the rotation matrix element
#9192#2792212
dd 23 
        inc ix
#9194#279415
b7 
        or a
#9195#2795213/8
28 0f 
        jr z, L91a6_matrix_cell_is_zero
#9197#2797
        ; L9174_24bit_accumulator = bounding box x * matrix[b][0]
#9197#2797321
fd 6e 00 
        ld l, (iy)
#919a#279a321
fd 66 01 
        ld h, (iy + 1)
#919d#279d318
cd 08 a1 
        call La108_a_times_hl_signed
#91a0#27a0314
32 76 91 
        ld (L9174_24bit_accumulator + 2), a
#91a3#27a3317
22 74 91 
        ld (L9174_24bit_accumulator), hl
#91a6#27a6
L91a6_matrix_cell_is_zero:
#91a6#27a6321
dd 7e 00 
        ld a, (ix)  ; get the next rotation matrix element
#91a9#27a9212
dd 23 
        inc ix
#91ab#27ab15
b7 
        or a
#91ac#27ac213/8
28 19 
        jr z, L91c7_matrix_cell_is_zero
#91ae#27ae
        ; L9174_24bit_accumulator += bounding box z * matrix[b][1]
#91ae#27ae321
fd 6e 04 
        ld l, (iy + 4)
#91b1#27b1321
fd 66 05 
        ld h, (iy + 5)
#91b4#27b4318
cd 08 a1 
        call La108_a_times_hl_signed
#91b7#27b7422
ed 5b 74 91 
        ld de, (L9174_24bit_accumulator)
#91bb#27bb112
19 
        add hl, de
#91bc#27bc317
22 74 91 
        ld (L9174_24bit_accumulator), hl
#91bf#27bf15
5f 
        ld e, a
#91c0#27c0314
3a 76 91 
        ld a, (L9174_24bit_accumulator + 2)
#91c3#27c315
8b 
        adc a, e
#91c4#27c4314
32 76 91 
        ld (L9174_24bit_accumulator + 2), a
#91c7#27c7
L91c7_matrix_cell_is_zero:
#91c7#27c7321
dd 7e 00 
        ld a, (ix)  ; get the next rotation matrix element
#91ca#27ca212
dd 23 
        inc ix
#91cc#27cc15
b7 
        or a
#91cd#27cd213/8
28 19 
        jr z, L91e8_matrix_cell_is_zero
#91cf#27cf
        ; L9174_24bit_accumulator += bounding box y * matrix[b][2]
#91cf#27cf321
fd 6e 08 
        ld l, (iy + 8)
#91d2#27d2321
fd 66 09 
        ld h, (iy + 9)
#91d5#27d5318
cd 08 a1 
        call La108_a_times_hl_signed
#91d8#27d8422
ed 5b 74 91 
        ld de, (L9174_24bit_accumulator)
#91dc#27dc112
19 
        add hl, de
#91dd#27dd317
22 74 91 
        ld (L9174_24bit_accumulator), hl
#91e0#27e015
5f 
        ld e, a
#91e1#27e1314
3a 76 91 
        ld a, (L9174_24bit_accumulator + 2)
#91e4#27e415
8b 
        adc a, e
#91e5#27e5314
32 76 91 
        ld (L9174_24bit_accumulator + 2), a
#91e8#27e8
L91e8_matrix_cell_is_zero:
#91e8#27e8317
2a 74 91 
        ld hl, (L9174_24bit_accumulator)
#91eb#27eb314
3a 76 91 
        ld a, (L9174_24bit_accumulator + 2)
#91ee#27ee112
29 
        add hl, hl
#91ef#27ef15
17 
        rla
#91f0#27f0112
29 
        add hl, hl
#91f1#27f115
17 
        rla
#91f2#27f215
5c 
        ld e, h  ; (a, e) = (a, hl) / 64
#91f3#27f3111
e1 
    pop hl
#91f4#27f418
73 
    ld (hl), e
#91f5#27f517
23 
    inc hl
#91f6#27f618
77 
    ld (hl), a
#91f7#27f717
23 
    inc hl
#91f8#27f8214/9
10 8a 
    djnz L9184_matrix_coordinate_loop
#91fa#27fa
#91fa#27fa
    ; Calculate the 9 terms resulting from multiplying (width, height, length) of the object by
#91fa#27fa
    ; each row of the rotation matrix, and store them in L5e63_3d_vertex_coordinates_relative_to_player (16 bit precision).
#91fa#27fa317
2a 9d 74 
    ld hl, (L749d_object_currently_being_processed_ptr)
#91fd#27fd311
11 04 00 
    ld de, 4
#9200#2800112
19 
    add hl, de
#9201#280115
eb 
    ex de, hl  ; de = points to the (width, height, length) of the object
#9202#2802416
dd 21 55 5e 
    ld ix, L5e55_rotation_matrix
#9206#2806416
fd 21 63 5e 
    ld iy, L5e63_3d_vertex_coordinates_relative_to_player
#920a#280a28
06 03 
    ld b, 3
#920c#280c
    ; 3 iterations, one for width, onr for height, one for length:
#920c#280c
L920c_coordinate_loop:
#920c#280c18
1a 
    ld a, (de)  ; get the w, h or l
#920d#280d17
13 
    inc de
#920e#280e
    ; Multiply by the first row element:
#920e#280e321
dd 6e 00 
    ld l, (ix)
#9211#281115
67 
    ld h, a
#9212#2812318
cd 53 a2 
    call La253_h_times_l_signed
#9215#2815321
fd 75 00 
    ld (iy), l
#9218#2818321
fd 74 01 
    ld (iy + 1), h
#921b#281b212
fd 23 
    inc iy
#921d#281d212
fd 23 
    inc iy
#921f#281f
    ; Multiply by the second row element:
#921f#281f321
dd 6e 03 
    ld l, (ix + 3)
#9222#282215
67 
    ld h, a
#9223#2823318
cd 53 a2 
    call La253_h_times_l_signed
#9226#2826321
fd 75 00 
    ld (iy), l
#9229#2829321
fd 74 01 
    ld (iy + 1), h
#922c#282c212
fd 23 
    inc iy
#922e#282e212
fd 23 
    inc iy
#9230#2830
    ; Multiply by the third row element:
#9230#2830321
dd 6e 06 
    ld l, (ix + 6)
#9233#283315
67 
    ld h, a
#9234#2834318
cd 53 a2 
    call La253_h_times_l_signed
#9237#2837321
fd 75 00 
    ld (iy), l
#923a#283a321
fd 74 01 
    ld (iy + 1), h
#923d#283d212
fd 23 
    inc iy
#923f#283f212
fd 23 
    inc iy
#9241#2841212
dd 23 
    inc ix  ; move to next row of the matrix
#9243#2843214/9
10 c7 
    djnz L920c_coordinate_loop
#9245#2845111
c9 
    ret
#9246#2846
#9246#2846
#9246#2846
; --------------------------------
#9246#2846
; Checks if vertices of an object fall inside of the rendering frustum.
#9246#2846
;
#9246#2846
; Note: in modern 3d engines, the rendering volume is a frustum, but in
#9246#2846
; this engine, this is simplified and they use a pyramid. We could easily
#9246#2846
; turn it to a frustum, changing the 5th test to be a bit a head of the
#9246#2846
; player, rather than exactly at the player. I am still calling it "frustum"
#9246#2846
; for clarity (for those familiar with modern engines).
#9246#2846
; Input:
#9246#2846
; - a: number of vertices.
#9246#2846
; Returns:
#9246#2846
; - z: object is visible, nz: object is not visible.
#9246#2846
; - updates (L5e5e_at_least_one_vertex_outside_rendering_frustum)
#9246#2846
L9246_object_visibility_check:
#9246#2846314
32 96 74 
    ld (L7496_current_drawing_primitive_n_vertices), a
#9249#2849416
fd 21 9f 5e 
    ld iy, L5e9f_3d_vertex_coordinates_after_rotation_matrix
#924d#284d311
11 dc 5e 
    ld de, L5edc_vertex_rendering_frustum_checks
#9250#285015
47 
    ld b, a
#9251#285115
af 
    xor a
#9252#2852314
32 5e 5e 
    ld (L5e5e_at_least_one_vertex_outside_rendering_frustum), a
#9255#285515
4f 
    ld c, a
#9256#2856
L9256_vertex_loop:
#9256#2856112
c5 
    push bc
#9257#2857
        ; This code performs 5 culling checks:
#9257#2857
        ; - assuming the rendering volume is a pyramid (with vertex in the player):
#9257#2857
        ; - 4 checks for the 4 walls of the pyramid
#9257#2857
        ; - a 5th check to see if the object is behind the player
#9257#2857
        ; - 'a' is initialized with 5 bits set to 1, indicating the tests pass.
#9257#2857
        ; - Each time a test fails (vertex is outside the rendering volume), one bit is set to 0.
#9257#285728
3e 1f 
        ld a, #1f
#9259#2859321
fd 4e 04 
        ld c, (iy + 4)
#925c#285c321
fd 46 05 
        ld b, (iy + 5)  ; bc = vertex z
#925f#285f321
fd 6e 00 
        ld l, (iy)
#9262#2862321
fd 66 01 
        ld h, (iy + 1)  ; hl = vertex x
#9265#2865112
e5 
        push hl
#9266#286615
b7 
            or a
#9267#2867217
ed 4a 
            adc hl, bc  ; hl = x + z
#9269#2869311
f2 6e 92 
            jp p, L926e_positive
#926c#286c28
e6 0f 
            and #0f  ; zero out bit 4
#926e#286e
L926e_positive:
#926e#286e321
fd 6e 02 
            ld l, (iy + 2)
#9271#2871321
fd 66 03 
            ld h, (iy + 3)  ; hl = vertex y
#9274#2874112
e5 
            push hl
#9275#287515
b7 
                or a
#9276#2876217
ed 4a 
                adc hl, bc  ; hl = y + z
#9278#2878311
f2 7d 92 
                jp p, L927d_positive
#927b#287b28
e6 17 
                and #17  ; zero out bit 3
#927d#287d
L927d_positive:
#927d#287d111
e1 
            pop hl
#927e#287e15
b7 
            or a
#927f#287f217
ed 42 
            sbc hl, bc  ; hl = y - z
#9281#2881311
fa 86 92 
            jp m, L9286_negative
#9284#288428
e6 1d 
            and #1d  ; zero out bit 2
#9286#2886
L9286_negative:
#9286#2886111
e1 
        pop hl
#9287#288715
b7 
        or a
#9288#2888217
ed 42 
        sbc hl, bc  ; hl = x - z
#928a#288a311
fa 8f 92 
        jp m, L928f_negative
#928d#288d28
e6 1b 
        and #1b  ; zero out bit 1
#928f#288f
L928f_negative:
#928f#288f210
cb 78 
        bit 7, b
#9291#2891213/8
28 02 
        jr z, L9295_z_positive
#9293#2893
        ; vertex behind the camera
#9293#289328
e6 1e 
        and #1e  ; zero out bit 0
#9295#2895
L9295_z_positive:
#9295#2895311
01 06 00 
        ld bc, 6
#9298#2898217
fd 09 
        add iy, bc  ; next vertex
#929a#289a111
c1 
    pop bc
#929b#289b18
12 
    ld (de), a
#929c#289c17
13 
    inc de
#929d#289d28
fe 1f 
    cp #1f
#929f#289f213/8
28 07 
    jr z, L92a8
#92a1#28a1
    ; At least one of the culling tests failed (point is outside the view frustum).
#92a1#28a1
    ; Hence, mark that we will use "L8cf0_project_object_and_add_to_render_list_clipping_internal"
#92a1#28a1
    ; instead of "L8adc_project_object_and_add_to_render_list_internal".
#92a1#28a1
    ; OPTIMIZATION: below, better do ld hl,L5e5e_at_least_one_vertex_outside_rendering_frustum; ld (hl),1
#92a1#28a115
67 
    ld h, a  ; save 'a'
#92a2#28a228
3e 01 
    ld a, 1
#92a4#28a4314
32 5e 5e 
    ld (L5e5e_at_least_one_vertex_outside_rendering_frustum), a
#92a7#28a715
7c 
    ld a, h  ; restore 'a'
#92a8#28a8
L92a8:
#92a8#28a8
    ; - 'c' accumulates the culling checks. 
#92a8#28a8
    ; - 'c' will be #1f if at least one point has passed all the tests, or if collectively,
#92a8#28a8
    ;   each test has been passed by at least one point.
#92a8#28a815
b1 
    or c
#92a9#28a915
4f 
    ld c, a
#92aa#28aa214/9
10 aa 
    djnz L9256_vertex_loop
#92ac#28ac15
79 
    ld a, c
#92ad#28ad28
fe 1f 
    cp #1f
#92af#28af111
c9 
    ret
#92b0#28b0
#92b0#28b0
#92b0#28b0
; --------------------------------
#92b0#28b0
; Projects an object, and if it falls within the screen, add it to the list of objects to draw.
#92b0#28b0
; Input:
#92b0#28b0
; - a: projection type.
#92b0#28b0
;   - if a == 0: indicates that vertices can be projected directly.
#92b0#28b0
;   - if a == 1: we need to call L88d1_normal_direction_check before projection, and if back-face, we cull
#92b0#28b0
;   - if a == 2: we need to call L88d1_normal_direction_check before projection,  we need to use L5f26_alternative_shape_edges_ptr
#92b0#28b0
; - iy: face definition pointer.
#92b0#28b0
L92b0_project_object_and_add_to_render_list:
#92b0#28b0314
32 60 5e 
    ld (L5e60_projection_pre_work_type), a
#92b3#28b3314
3a 5e 5e 
    ld a, (L5e5e_at_least_one_vertex_outside_rendering_frustum)
#92b6#28b615
b7 
    or a
#92b7#28b7213/8
20 05 
    jr nz, L92be
#92b9#28b9
    ; Easy case, all vertices within rendering volume:
#92b9#28b9318
cd dc 8a 
    call L8adc_project_object_and_add_to_render_list_internal
#92bc#28bc213
18 03 
    jr L92c1_continue
#92be#28be
L92be:
#92be#28be
    ; Complex case, not all vertices within rendering volume:
#92be#28be318
cd f0 8c 
    call L8cf0_project_object_and_add_to_render_list_clipping_internal
#92c1#28c1
L92c1_continue:
#92c1#28c1314
3a 5f 5e 
    ld a, (L5e5f_add_to_projected_objects_flag)
#92c4#28c415
b7 
    or a
#92c5#28c5213/8
28 24 
    jr z, L92eb_do_not_draw
#92c7#28c7
    ; This object has to be drawn, add it to the list of projected objects:
#92c7#28c7422
ed 5b 97 74 
    ld de, (L7497_next_projected_vertex_ptr)  ; Get the ptr we just wrote the object to.
#92cb#28cb317
22 97 74 
    ld (L7497_next_projected_vertex_ptr), hl  ; Update the ptr for the next object to just after the current one.
#92ce#28ce317
2a 9b 74 
    ld hl, (L749b_next_object_projected_data_ptr)
#92d1#28d1
    ; Save the pointer to the projected vertex data for this object:
#92d1#28d118
73 
    ld (hl), e
#92d2#28d217
23 
    inc hl
#92d3#28d318
72 
    ld (hl), d
#92d4#28d417
23 
    inc hl
#92d5#28d5
    ; Save the pointer to the relative bounding box for this object:
#92d5#28d5422
ed 5b 99 74 
    ld de, (L7499_3d_object_bounding_box_relative_to_player_ptr)
#92d9#28d918
73 
    ld (hl), e
#92da#28da17
23 
    inc hl
#92db#28db18
72 
    ld (hl), d
#92dc#28dc17
23 
    inc hl
#92dd#28dd317
22 9b 74 
    ld (L749b_next_object_projected_data_ptr), hl
#92e0#28e0
    ; hl = de + 12 (next bounding box ptr)
#92e0#28e0311
21 0c 00 
    ld hl, 12
#92e3#28e3112
19 
    add hl, de
#92e4#28e4317
22 99 74 
    ld (L7499_3d_object_bounding_box_relative_to_player_ptr), hl
#92e7#28e7311
21 6b 74 
    ld hl, L746b_n_objects_to_draw
#92ea#28ea112
34 
    inc (hl)
#92eb#28eb
L92eb_do_not_draw:
#92eb#28eb111
c9 
    ret
#92ec#28ec
#92ec#28ec
#92ec#28ec
; --------------------------------
#92ec#28ec
; Draws a primitive (line, or polygon)
#92ec#28ec
; Input:
#92ec#28ec
; - ix: pointer to the primitive data
#92ec#28ec
; - (L7496_current_drawing_primitive_n_vertices): number of vertices of the primitive.
#92ec#28ec
; Output:
#92ec#28ec
; - ix: ptr to the next primitive.
#92ec#28ec
L92ec_draw_primitive:
#92ec#28ec112
e5 
    push hl
#92ed#28ed112
d5 
    push de
#92ee#28ee112
c5 
    push bc
#92ef#28ef15
08 
    ex af, af'
#92f0#28f0112
f5 
    push af
#92f1#28f115
d9 
    exx
#92f2#28f2112
e5 
    push hl
#92f3#28f3112
d5 
    push de
#92f4#28f4112
c5 
    push bc
#92f5#28f5314
3a 96 74 
        ld a, (L7496_current_drawing_primitive_n_vertices)
#92f8#28f828
fe 02 
        cp 2
#92fa#28fa311
c2 7d 93 
        jp nz, L937d_draw_polygon
#92fd#28fd
        ; Case 1: Draw a line.
#92fd#28fd
        ; Lines are defined by just 4 bytes:
#92fd#28fd321
dd 6e 00 
        ld l, (ix)  ; x1
#9300#2900321
dd 66 01 
        ld h, (ix + 1)  ; y1
#9303#2903321
dd 5e 02 
        ld e, (ix + 2)  ; x2
#9306#2906321
dd 56 03 
        ld d, (ix + 3)  ; y2
#9309#2909311
01 04 00 
        ld bc, 4
#930c#290c217
dd 09 
        add ix, bc  ; move ix to the next primitive.
#930e#290e217
dd e5 
        push ix
#9310#291015
7a 
            ld a, d
#9311#291115
94 
            sub h
#9312#2912213/8
30 03 
            jr nc, L9317_line_drawing_order_set
#9314#2914210
ed 44 
            neg
#9316#291615
eb 
            ex de, hl  ; if the line was to be drawn downwards, swap the points
#9317#2917
L9317_line_drawing_order_set:
#9317#291715
47 
            ld b, a  ; y2 - y1
#9318#291815
7c 
            ld a, h  ; y1
#9319#2919314
32 08 75 
            ld (L7508_current_drawing_row), a
#931c#291c318
cd c4 94 
            call L94c4_calculate_row_ptr_and_texture_ptr
#931f#291f15
78 
            ld a, b
#9320#292015
b7 
            or a
#9321#2921213/8
20 05 
            jr nz, L9328_line_is_not_horizontal
#9323#2923
            ; It is a horizontal line:
#9323#292315
65 
            ld h, l
#9324#292415
53 
            ld d, e
#9325#2925311
c3 b5 94 
            jp L94b5_draw_texture_row_and_return
#9328#2928
L9328_line_is_not_horizontal:
#9328#292815
4d 
            ld c, l  ; starting x pixel
#9329#2929112
c5 
            push bc
#932a#292a15
7c 
                ld a, h
#932b#292b15
92 
                sub d
#932c#292c15
4f 
                ld c, a
#932d#292d28
06 ff 
                ld b, #ff  ; bc = y1 - y2
#932f#292f17
0b 
                dec bc
#9330#293015
7d 
                ld a, l
#9331#293115
93 
                sub e  ; a = x1 - x2
#9332#2932311
11 00 00 
                ld de, 0
#9335#293515
6b 
                ld l, e
#9336#2936213/8
30 01 
                jr nc, L9339
#9338#2938
                ; (de, hl) should be negative
#9338#293817
1b 
                dec de
#9339#2939
L9339:
#9339#293915
67 
                ld h, a  ; hl = (x1 - x2) * 256
#933a#293a
                ; Calculate the line slope:
#933a#293a
                ; - slope = dx * 256 / dy
#933a#293a318
cd b7 b1 
                call Lb1b7_de_hl_divided_by_bc_signed
#933d#293d317
22 04 75 
                ld (L7504_line_drawing_slope), hl
#9340#294028
3e 01 
                ld a, 1
#9342#2942210
cb 7a 
                bit 7, d
#9344#2944213/8
20 02 
                jr nz, L9348_thinning_direction_set
#9346#2946
                ; If the result is negative, mark that we want to thicken the line
#9346#2946
                ; to the left in case the line is to thin to be drawn in any row.
#9346#294628
3e ff 
                ld a, -1
#9348#2948
L9348_thinning_direction_set:
#9348#2948314
32 09 75 
                ld (L7509_line_drawing_thinning_direction), a
#934b#294b111
c1 
            pop bc
#934c#294c15
04 
            inc b  ; number of rows to draw
#934d#294d
            ; Initialize both points (de and hl) to the beginning of the line (bottom):
#934d#294d15
61 
            ld h, c  ; c == starting x pixel
#934e#294e28
2e 00 
            ld l, 0
#9350#295015
54 
            ld d, h
#9351#295115
5d 
            ld e, l
#9352#2952112
c5 
            push bc
#9353#2953
                ; Advance one of the two pixels, so they are offset by 1 vertical pixel.
#9353#2953422
ed 4b 04 75 
                ld bc, (L7504_line_drawing_slope)
#9357#2957112
09 
                add hl, bc
#9358#2958213
18 14 
                jr L936e_line_draw_entry_point
#935a#295a
L935a_line_draw_row_loop:
#935a#295a
            ; Line drawing using fixed-point arithmetic:
#935a#295a
            ; - Keeps two points (one in the current Y position, and one in the previous), and draws
#935a#295a
            ;   horizontal lines at each row to connect them.
#935a#295a112
c5 
            push bc
#935b#295b
                ; Draw pixels from 'd' -> 'h'
#935b#295b318
cd fe 94 
                call L94fe_draw_texture_row
#935e#295e
                ; Mark we are moving to the next row:
#935e#295e314
3a 08 75 
                ld a, (L7508_current_drawing_row)
#9361#296115
3c 
                inc a
#9362#2962314
32 08 75 
                ld (L7508_current_drawing_row), a
#9365#2965422
ed 4b 04 75 
                ld bc, (L7504_line_drawing_slope)
#9369#2969
                ; Advance both current (hl) and previous (de) points:
#9369#296915
eb 
                ex de, hl
#936a#296a112
09 
                add hl, bc
#936b#296b15
54 
                ld d, h
#936c#296c15
5d 
                ld e, l
#936d#296d112
09 
                add hl, bc
#936e#296e
L936e_line_draw_entry_point:
#936e#296e15
7c 
                ld a, h
#936f#296f15
ba 
                cp d
#9370#2970213/8
28 05 
                jr z, L9377_skip_line_thinning
#9372#2972
                ; If 'd != h', move 'h' one pixel in the direction of 'd' to make sure the line is thin when drawn.
#9372#2972314
3a 09 75 
                ld a, (L7509_line_drawing_thinning_direction)
#9375#297515
84 
                add a, h
#9376#297615
67 
                ld h, a
#9377#2977
L9377_skip_line_thinning:
#9377#2977111
c1 
            pop bc
#9378#2978214/9
10 e0 
            djnz L935a_line_draw_row_loop
#937a#297a311
c3 b5 94 
            jp L94b5_draw_texture_row_and_return
#937d#297d
#937d#297d
L937d_draw_polygon:
#937d#297d
        ; Case 2: Draw a triangle.
#937d#297d314
32 0b 75 
        ld (L750b_current_drawing_n_vertices_left), a
#9380#2980
        ; Copy the vertices to a temporary buffer:
#9380#298015
4f 
        ld c, a
#9381#2981210
cb 21 
        sla c
#9383#298328
06 00 
        ld b, 0
#9385#2985217
dd e5 
        push ix
#9387#2987111
e1 
        pop hl
#9388#2988311
11 10 75 
        ld de, L7510_current_drawing_2d_vertex_buffer
#938b#298b223/18
ed b0 
        ldir
#938d#298d
#938d#298d
        ; Make a second copy (so we can iterate to the right without overflowing, starting from any vertex):
#938d#298d217
dd e5 
        push ix
#938f#298f111
e1 
        pop hl
#9390#299015
4f 
        ld c, a
#9391#2991210
cb 21 
        sla c
#9393#2993223/18
ed b0 
        ldir
#9395#2995
#9395#2995112
e5 
        push hl
#9396#2996311
21 11 75 
            ld hl, L7510_current_drawing_2d_vertex_buffer + 1
#9399#299915
54 
            ld d, h
#939a#299a15
5d 
            ld e, l
#939b#299b15
47 
            ld b, a
#939c#299c15
05 
            dec b
#939d#299d18
7e 
            ld a, (hl)
#939e#299e
L939e_find_lowest_point_loop:
#939e#299e17
23 
            inc hl
#939f#299f17
23 
            inc hl
#93a0#29a018
be 
            cp (hl)
#93a1#29a1213/8
38 03 
            jr c, L93a6_not_lowest
#93a3#29a3
            ; new lowest:
#93a3#29a315
54 
            ld d, h  ; save the pointer
#93a4#29a415
5d 
            ld e, l
#93a5#29a518
7e 
            ld a, (hl)  ; save the y coordinate
#93a6#29a6
L93a6_not_lowest:
#93a6#29a6214/9
10 f6 
            djnz L939e_find_lowest_point_loop
#93a8#29a817
1b 
            dec de  ; point to the x coordinate of the lowest point
#93a9#29a9314
32 08 75 
            ld (L7508_current_drawing_row), a
#93ac#29ac318
cd c4 94 
            call L94c4_calculate_row_ptr_and_texture_ptr
#93af#29af112
d5 
            push de
#93b0#29b0216
dd e1 
            pop ix
#93b2#29b2
#93b2#29b2112
d5 
            push de
#93b3#29b3216
fd e1 
            pop iy
#93b5#29b5314
3a 96 74 
            ld a, (L7496_current_drawing_primitive_n_vertices)
#93b8#29b815
3c 
            inc a
#93b9#29b915
4f 
            ld c, a
#93ba#29ba210
cb 21 
            sla c
#93bc#29bc217
fd 09 
            add iy, bc
#93be#29be212
dd 2b 
            dec ix
#93c0#29c0212
dd 2b 
            dec ix
#93c2#29c2
            ; Here:
#93c2#29c2
            ; - ix: at point to the left of lowest
#93c2#29c2
            ; - iy: at the lowest point in the second copy of the vertices.
#93c2#29c2
            ; During the loop, we will move ix forward and iy backwards
#93c2#29c2
            ; (util they meet, and then we are done).
#93c2#29c2
            ; During the loop, we will have:
#93c2#29c2
            ; - hl: x coordinate of the iy line
#93c2#29c2
            ; - de: x coordinate of the ix line
#93c2#29c228
3e 03 
            ld a, #03
#93c4#29c4
            ; The first time we move in the ix or iy lines, we only move 1/2 a step. The
#93c4#29c4
            ; two lowest bits of (L750a_first_loop_flags) indicate if we have already done this.
#93c4#29c4
            ; As soon as we do the 1/2 step, they are set to 0, to do full steps from that point on.
#93c4#29c4314
32 0a 75 
            ld (L750a_first_loop_flags), a
#93c7#29c7314
3a 08 75 
            ld a, (L7508_current_drawing_row)
#93ca#29ca213
18 16 
            jr L93e2_draw_polygon_loop_entry_point
#93cc#29cc
L93cc_draw_polygon_loop:
#93cc#29cc318
cd fe 94 
            call L94fe_draw_texture_row
#93cf#29cf422
ed 4b 04 75 
            ld bc, (L7504_line_drawing_slope)
#93d3#29d3112
09 
            add hl, bc  ; advance the iy line
#93d4#29d4422
ed 4b 06 75 
            ld bc, (L7506_polygon_drawing_second_slope)
#93d8#29d815
eb 
            ex de, hl
#93d9#29d9112
09 
                add hl, bc  ; advance the ix line
#93da#29da15
eb 
            ex de, hl
#93db#29db314
3a 08 75 
            ld a, (L7508_current_drawing_row)
#93de#29de15
3c 
            inc a
#93df#29df314
32 08 75 
            ld (L7508_current_drawing_row), a
#93e2#29e2
L93e2_draw_polygon_loop_entry_point:
#93e2#29e2321
fd be ffff 
            cp (iy - 1)  ; compare the "y" of the next point in iy with the current "y".
#93e5#29e5213/8
20 53 
            jr nz, L943a  ; we have not yet reached the "y" coordinate of the next point
#93e7#29e7
            ; We have reached the "y" coordinate of the next point, advance iy!:
#93e7#29e7
L93e7_skip_horizontal_iy_points_loop:
#93e7#29e7314
3a 0b 75 
            ld a, (L750b_current_drawing_n_vertices_left)
#93ea#29ea15
3d 
            dec a
#93eb#29eb311
fa 93 94 
            jp m, L9493_draw_polygon_done
#93ee#29ee314
32 0b 75 
            ld (L750b_current_drawing_n_vertices_left), a
#93f1#29f1212
fd 2b 
            dec iy
#93f3#29f3212
fd 2b 
            dec iy
#93f5#29f5321
fd 7e 01 
            ld a, (iy + 1)
#93f8#29f8321
fd 96 ffff 
            sub (iy - 1)
#93fb#29fb213/8
28 ea 
            jr z, L93e7_skip_horizontal_iy_points_loop  ; If the next point is also in the same 'y', keep skipping.
#93fd#29fd311
d2 93 94 
            jp nc, L9493_draw_polygon_done  ; If we close the shape, and start moving backwads in 'y', we are done.
#9400#2a0015
3d 
            dec a  ; a is negative here, so, we grow it by one
#9401#2a0115
d9 
            exx
#9402#2a0215
4f 
                ld c, a
#9403#2a0328
06 ff 
                ld b, #ff  ; bc = a (extend sign, as a is negative for sure)
#9405#2a05311
21 00 00 
                ld hl, 0
#9408#2a0815
54 
                ld d, h
#9409#2a0915
5c 
                ld e, h
#940a#2a0a321
fd 7e 00 
                ld a, (iy)  ; x coordinate
#940d#2a0d321
fd 96 fffe 
                sub (iy - 2)  ; a = difference between next point x and this point's x
#9410#2a10213/8
28 07 
                jr z, L9419_slope_calculated
#9412#2a1215
67 
                ld h, a
#9413#2a13213/8
30 01 
                jr nc, L9416_de_hl_positive
#9415#2a1517
1b 
                dec de  ; make (de, hl) negative
#9416#2a16
L9416_de_hl_positive:
#9416#2a16
                ; here: (de, hl) = dx * 256
#9416#2a16
                ; Calculate the iy line slope:
#9416#2a16
                ; - slope = dx * 256 / dy
#9416#2a16318
cd b7 b1 
                call Lb1b7_de_hl_divided_by_bc_signed
#9419#2a19
L9419_slope_calculated:
#9419#2a19317
22 04 75 
                ld (L7504_line_drawing_slope), hl
#941c#2a1c15
d9 
            exx
#941d#2a1d321
fd 66 00 
            ld h, (iy)  ; x coordinate of the iy line
#9420#2a2028
2e 00 
            ld l, 0
#9422#2a22422
ed 4b 04 75 
            ld bc, (L7504_line_drawing_slope)
#9426#2a26314
3a 0a 75 
            ld a, (L750a_first_loop_flags)
#9429#2a29210
cb 47 
            bit 0, a
#942b#2a2b213/8
20 04 
            jr nz, L9431_full_step
#942d#2a2d
            ; If the first-loop flag is set, only do half a step:
#942d#2a2d210
cb 28 
            sra b  ; bc /= 2
#942f#2a2f210
cb 19 
            rr c
#9431#2a31
L9431_full_step:
#9431#2a3128
e6 fe 
            and #fe
#9433#2a33314
32 0a 75 
            ld (L750a_first_loop_flags), a
#9436#2a36112
09 
            add hl, bc  ; move one step for the "iy" point
#9437#2a37314
3a 08 75 
            ld a, (L7508_current_drawing_row)
#943a#2a3a
L943a:
#943a#2a3a321
dd be 03 
            cp (ix + 3)  ; Have we reached the "y" coordinate of the next point in ix?
#943d#2a3d213/8
20 8d 
            jr nz, L93cc_draw_polygon_loop  ; We have not, so, we draw the next row!
#943f#2a3f
L943f_skip_horizontal_ix_points_loop:
#943f#2a3f314
3a 0b 75 
            ld a, (L750b_current_drawing_n_vertices_left)
#9442#2a4215
3d 
            dec a
#9443#2a43311
fa 93 94 
            jp m, L9493_draw_polygon_done
#9446#2a46314
32 0b 75 
            ld (L750b_current_drawing_n_vertices_left), a
#9449#2a49212
dd 23 
            inc ix
#944b#2a4b212
dd 23 
            inc ix
#944d#2a4d321
dd 7e 01 
            ld a, (ix + 1)
#9450#2a50321
dd 96 03 
            sub (ix + 3)
#9453#2a53213/8
28 ea 
            jr z, L943f_skip_horizontal_ix_points_loop  ; If the next point is also in the same 'y', keep skipping.
#9455#2a55213/8
30 3c 
            jr nc, L9493_draw_polygon_done  ; If we close the shape, and start moving backwads in 'y', we are done.
#9457#2a5715
3d 
            dec a
#9458#2a5815
d9 
            exx
#9459#2a5915
4f 
                ld c, a
#945a#2a5a28
06 ff 
                ld b, #ff  ; bc = a (extend sign, as a is negative for sure)
#945c#2a5c311
21 00 00 
                ld hl, 0
#945f#2a5f15
54 
                ld d, h
#9460#2a6015
5c 
                ld e, h
#9461#2a61321
dd 7e 00 
                ld a, (ix)  ; x coordinate
#9464#2a64321
dd 96 02 
                sub (ix + 2)  ; a = difference between next point x and this point's x
#9467#2a67213/8
28 07 
                jr z, L9470_slope_calculated
#9469#2a6915
67 
                ld h, a
#946a#2a6a213/8
30 01 
                jr nc, L946d_de_hl_positive
#946c#2a6c17
1b 
                dec de  ; make (de, hl) negative
#946d#2a6d
L946d_de_hl_positive:
#946d#2a6d
                ; here: (de, hl) = dx * 256
#946d#2a6d
                ; Calculate the ix line slope:
#946d#2a6d
                ; - slope = dx * 256 / dy
#946d#2a6d318
cd b7 b1 
                call Lb1b7_de_hl_divided_by_bc_signed
#9470#2a70
L9470_slope_calculated:
#9470#2a70317
22 06 75 
                ld (L7506_polygon_drawing_second_slope), hl
#9473#2a7315
d9 
            exx
#9474#2a74321
dd 56 00 
            ld d, (ix)  ; x coordinate of the ix line
#9477#2a7728
1e 00 
            ld e, 0
#9479#2a79422
ed 4b 06 75 
            ld bc, (L7506_polygon_drawing_second_slope)
#947d#2a7d314
3a 0a 75 
            ld a, (L750a_first_loop_flags)
#9480#2a80210
cb 4f 
            bit 1, a
#9482#2a82213/8
20 04 
            jr nz, L9488_full_step
#9484#2a84
            ; If the first-loop flag is set, only do half a step:
#9484#2a84210
cb 28 
            sra b  ; bc /= 2
#9486#2a86210
cb 19 
            rr c
#9488#2a88
L9488_full_step:
#9488#2a8828
e6 fd 
            and #fd
#948a#2a8a314
32 0a 75 
            ld (L750a_first_loop_flags), a
#948d#2a8d15
eb 
            ex de, hl
#948e#2a8e112
09 
                add hl, bc
#948f#2a8f15
eb 
            ex de, hl
#9490#2a90311
c3 cc 93 
            jp L93cc_draw_polygon_loop
#9493#2a93
#9493#2a93
L9493_draw_polygon_done:
#9493#2a93
            ; Draw the last row:
#9493#2a93314
3a 0a 75 
            ld a, (L750a_first_loop_flags)
#9496#2a9615
b7 
            or a
#9497#2a97213/8
28 1c 
            jr z, L94b5_draw_texture_row_and_return
#9499#2a99
            ; We have not moved both lines at least once. This means we are probably just
#9499#2a99
            ; drawing a tiny polygon. Hence, here we find the lowest 'x' in d, and the largest 
#9499#2a99
            ; 'x' in e, to draw a line from d to e, so that at least something is visualized.
#9499#2a99311
21 10 75 
            ld hl, L7510_current_drawing_2d_vertex_buffer
#949c#2a9c321
dd 5e 00 
            ld e, (ix)  ; get current 'x'
#949f#2a9f15
53 
            ld d, e  ; min/max 'x' set to the vlaue of the first vertex
#94a0#2aa0314
3a 96 74 
            ld a, (L7496_current_drawing_primitive_n_vertices)
#94a3#2aa315
3d 
            dec a
#94a4#2aa415
47 
            ld b, a
#94a5#2aa5
L94a5_min_max_vertex_loop:
#94a5#2aa517
23 
            inc hl
#94a6#2aa617
23 
            inc hl
#94a7#2aa718
7e 
            ld a, (hl)
#94a8#2aa815
bb 
            cp e
#94a9#2aa9213/8
30 03 
            jr nc, L94ae_not_larger
#94ab#2aab15
5f 
            ld e, a  ; new maximum
#94ac#2aac213
18 04 
            jr L94b2_not_smaller
#94ae#2aae
L94ae_not_larger:
#94ae#2aae15
ba 
            cp d  ; new minimum
#94af#2aaf213/8
38 01 
            jr c, L94b2_not_smaller
#94b1#2ab115
57 
            ld d, a
#94b2#2ab2
L94b2_not_smaller:
#94b2#2ab2214/9
10 f1 
            djnz L94a5_min_max_vertex_loop
#94b4#2ab415
63 
            ld h, e
#94b5#2ab5
L94b5_draw_texture_row_and_return:
#94b5#2ab5318
cd fe 94 
            call L94fe_draw_texture_row
#94b8#2ab8216
dd e1 
        pop ix
#94ba#2aba111
c1 
    pop bc
#94bb#2abb111
d1 
    pop de
#94bc#2abc111
e1 
    pop hl
#94bd#2abd15
d9 
    exx
#94be#2abe111
f1 
    pop af
#94bf#2abf15
08 
    ex af, af'
#94c0#2ac0111
c1 
    pop bc
#94c1#2ac1111
d1 
    pop de
#94c2#2ac2111
e1 
    pop hl
#94c3#2ac3111
c9 
    ret
#94c4#2ac4
#94c4#2ac4
#94c4#2ac4
; --------------------------------
#94c4#2ac4
; Calculates the pointer to row "a", and the texture pointer associated with the
#94c4#2ac4
; current object texture.
#94c4#2ac4
; Input:
#94c4#2ac4
; - a: row (starting from the bottom)
#94c4#2ac4
; - (L746a_current_drawing_texture_id): texture ID.
#94c4#2ac4
L94c4_calculate_row_ptr_and_texture_ptr:
#94c4#2ac4112
e5 
    push hl
#94c5#2ac5112
d5 
    push de
#94c6#2ac6
        ; Calculate the position in the render buffer of row 'a' (starting from the bottom):
#94c6#2ac6
        ; (SCREEN_HEIGHT_IN_PIXELS - a)
#94c6#2ac628
d6 70 
        sub SCREEN_HEIGHT_IN_PIXELS
#94c8#2ac8210
ed 44 
        neg
#94ca#2aca15
6f 
        ld l, a
#94cb#2acb28
26 00 
        ld h, 0
#94cd#2acd112
29 
        add hl, hl
#94ce#2ace112
29 
        add hl, hl
#94cf#2acf112
29 
        add hl, hl
#94d0#2ad015
54 
        ld d, h
#94d1#2ad115
5d 
        ld e, l
#94d2#2ad2112
29 
        add hl, hl
#94d3#2ad3112
19 
        add hl, de  ; hl = (SCREEN_HEIGHT_IN_PIXELS - a) * SCREEN_WIDTH
#94d4#2ad4311
11 bc 5c 
        ld de, L5cbc_render_buffer
#94d7#2ad7112
19 
        add hl, de
#94d8#2ad8317
22 0c 75 
        ld (L750c_current_drawing_row_ptr), hl  ; Store the position of the row in L750c_current_drawing_row_ptr
#94db#2adb
        ; Calculate the texture pattern pointer:
#94db#2adb311
21 88 d0 
        ld hl, Ld088_texture_patterns  ; Each texture is 4 bytes in size
#94de#2ade314
3a 6a 74 
        ld a, (L746a_current_drawing_texture_id)
#94e1#2ae115
3d 
        dec a
#94e2#2ae215
5f 
        ld e, a
#94e3#2ae328
16 00 
        ld d, 0
#94e5#2ae5210
cb 23 
        sla e
#94e7#2ae7210
cb 23 
        sla e
#94e9#2ae9112
19 
        add hl, de  ; hl = Ld088_texture_patterns + 4 * (L746a_current_drawing_texture_id)
#94ea#2aea317
22 0e 75 
        ld (L750e_current_drawing_texture_ptr), hl
#94ed#2aed111
d1 
    pop de
#94ee#2aee111
e1 
    pop hl
#94ef#2aef111
c9 
    ret
#94f0#2af0
#94f0#2af0
#94f0#2af0
; --------------------------------
#94f0#2af0
; Masks:
#94f0#2af0
; - To filter out half of a byte (left half or right half) at various split points.
#94f0#2af0
; - To get the one-hot representation of a given bit.
#94f0#2af0
L94f0_byte_splitting_masks:
#94f0#2af07
    db #80, #c0, #e0, #f0, #f8, #fc, #fe
#94f7#2af7
L94f7_one_hot_pixel_masks:
#94f7#2af77
    db #40, #20, #10, #08, #04, #02, #01
#94fe#2afe
#94fe#2afe
#94fe#2afe
; --------------------------------
#94fe#2afe
; Draws the current texture (L750e_current_drawing_texture_ptr),
#94fe#2afe
; to pixels starting at 'h' and ending before 'd' in row (L7508_current_drawing_row).
#94fe#2afe
; If any of the two extremes (d or h) is ouside of the screen, nothing is drawn.
#94fe#2afe
; Input:
#94fe#2afe
; - h: x1 -> x coordinate of the first pixel to draw.
#94fe#2afe
; - d: x2 -> x coordinate of where to end drawing pixels.
#94fe#2afe
L94fe_draw_texture_row:
#94fe#2afe
    ; Prevent drawing outside of the screen:
#94fe#2afe15
7c 
    ld a, h
#94ff#2aff28
fe c1 
    cp SCREEN_WIDTH_IN_PIXELS + 1
#9501#2b01112/6
d0 
    ret nc
#9502#2b0215
7a 
    ld a, d
#9503#2b0328
fe c1 
    cp SCREEN_WIDTH_IN_PIXELS + 1
#9505#2b05112/6
d0 
    ret nc
#9506#2b06112
e5 
    push hl
#9507#2b07112
d5 
    push de
#9508#2b08
        ; Get the byte we want to draw. Each texture has 4 bytes, defining
#9508#2b08
        ; a repeating texture vertically. So, "current row % 4" is the
#9508#2b08
        ; offset in the current texture we want to use:
#9508#2b08314
3a 08 75 
        ld a, (L7508_current_drawing_row)
#950b#2b0b28
e6 03 
        and #03
#950d#2b0d15
4f 
        ld c, a
#950e#2b0e15
5c 
        ld e, h  ; x coordinate to start drawing to (in pixels)
#950f#2b0f28
06 00 
        ld b, 0
#9511#2b11317
2a 0e 75 
        ld hl, (L750e_current_drawing_texture_ptr)
#9514#2b14112
09 
        add hl, bc
#9515#2b1515
08 
        ex af, af'
#9516#2b1618
7e 
            ld a, (hl)  ; Save byte we want to write to 'ghost a'.
#9517#2b1715
08 
        ex af, af'
#9518#2b18317
2a 0c 75 
        ld hl, (L750c_current_drawing_row_ptr)
#951b#2b1b15
7a 
        ld a, d
#951c#2b1c15
93 
        sub e  ; a = d - h  number of pixels to draw
#951d#2b1d213/8
30 03 
        jr nc, L9522
#951f#2b1f
        ; number of pixels to draw is negative, flip it:
#951f#2b1f15
5a 
        ld e, d
#9520#2b20210
ed 44 
        neg
#9522#2b22
L9522:
#9522#2b22
        ; Here:
#9522#2b22
        ; - a: number of bytes to draw
#9522#2b22
        ; - e: start x coordinate
#9522#2b22
        ; - ghost a: byte to draw
#9522#2b2215
3c 
        inc a  ; increment 'a', as later the djnz will decrement 'b' (which will hold the value of 'a')
#9523#2b2315
47 
        ld b, a
#9524#2b2415
af 
        xor a
#9525#2b2515
57 
        ld d, a
#9526#2b2615
bb 
        cp e
#9527#2b27213/8
20 05 
        jr nz, L952e
#9529#2b29
        ; We start drawing from the left
#9529#2b29214/9
10 31 
        djnz L955c_start_ptr_calculated
#952b#2b2b
        ; If there is only 1 pixel to draw in the left-most part of the screen, do not draw it, just skip.
#952b#2b2b311
c3 bf 95 
        jp L95bf_advance_ptr_to_next_row_and_return
#952e#2b2e
L952e:
#952e#2b2e
        ; Calculate the pointer where to start drawing:
#952e#2b2e15
1d 
        dec e
#952f#2b2f15
7b 
        ld a, e
#9530#2b30210
cb 3b 
        srl e
#9532#2b32210
cb 3b 
        srl e
#9534#2b34210
cb 3b 
        srl e
#9536#2b36112
19 
        add hl, de  ; hl = (L750c_current_drawing_row_ptr) + (start x - 1) / 8
#9537#2b3728
e6 07 
        and #07
#9539#2b39213/8
28 21 
        jr z, L955c_start_ptr_calculated
#953b#2b3b
        ; There are some left-over pixels at the beginning (not a full byte), draw them:
#953b#2b3b15
5f 
        ld e, a
#953c#2b3c15
1d 
        dec e
#953d#2b3d112
e5 
        push hl
#953e#2b3e
            ; Get the pointer in to the one_hot mask of the first bit we want to draw
#953e#2b3e311
21 f7 94 
            ld hl, L94f7_one_hot_pixel_masks
#9541#2b41112
19 
            add hl, de
#9542#2b4228
3e 07 
            ld a, 7
#9544#2b4415
93 
            sub e
#9545#2b4515
5f 
            ld e, a  ; number of pixels to draw
#9546#2b4615
af 
            xor a
#9547#2b47
            ; OPTIMIZATION: the loop below is unnecessary, the one_hot_pixel_masks, should just contain the result of the loop below...
#9547#2b47
L9547_prefix_pixels_mask_loop:
#9547#2b4718
b6 
            or (hl)
#9548#2b4817
23 
            inc hl
#9549#2b4915
05 
            dec b
#954a#2b4a213/8
28 03 
            jr z, L954f_mask_calculated
#954c#2b4c15
1d 
            dec e
#954d#2b4d213/8
20 f8 
            jr nz, L9547_prefix_pixels_mask_loop
#954f#2b4f
L954f_mask_calculated:
#954f#2b4f111
e1 
        pop hl
#9550#2b50
        ; We have calculated the mask corresponding to the first left-over pixels, draw them:
#9550#2b5015
57 
        ld d, a
#9551#2b5115
2f 
        cpl
#9552#2b5218
a6 
        and (hl)
#9553#2b5315
4f 
        ld c, a
#9554#2b5415
08 
        ex af, af'
#9555#2b5515
5f 
            ld e, a  ; texture byte to draw
#9556#2b5615
08 
        ex af, af'
#9557#2b5715
7a 
        ld a, d
#9558#2b5815
a3 
        and e
#9559#2b5915
b1 
        or c
#955a#2b5a18
77 
        ld (hl), a
#955b#2b5b17
23 
        inc hl
#955c#2b5c
L955c_start_ptr_calculated:
#955c#2b5c
        ; Here:
#955c#2b5c
        ; - b: number of pixels to write.
#955c#2b5c
        ; - hl: ptr to where to write them.
#955c#2b5c
        ; - ghost a: byte we want to write.
#955c#2b5c15
58 
        ld e, b
#955d#2b5d210
cb 3b 
        srl e
#955f#2b5f210
cb 3b 
        srl e
#9561#2b61210
cb 3b 
        srl e
#9563#2b6328
16 00 
        ld d, 0
#9565#2b65112
19 
        add hl, de  ; hl now points to the end of where we want to write.
#9566#2b6615
78 
        ld a, b
#9567#2b6728
e6 07 
        and #07
#9569#2b69
        ; If the number of pixels to write was a multiple of 8, we are done!
#9569#2b69213/8
28 16 
        jr z, L9581_byte_to_write_and_amount_calculated
#956b#2b6b
        ; Number of pixels to write is not a multiple of 8, we need to write 'a' left over pixels:
#956b#2b6b15
d9 
        exx
#956c#2b6c
            ; Get the mask to mask out the pixels we do not want to modify:
#956c#2b6c15
3d 
            dec a
#956d#2b6d15
4f 
            ld c, a
#956e#2b6e311
21 f0 94 
            ld hl, L94f0_byte_splitting_masks
#9571#2b7128
06 00 
            ld b, 0
#9573#2b73112
09 
            add hl, bc
#9574#2b7418
7e 
            ld a, (hl)
#9575#2b7515
d9 
        exx
#9576#2b76
        ; Write only the desired number of bits 'd' over to '(hl)':
#9576#2b7615
47 
        ld b, a
#9577#2b7715
2f 
        cpl
#9578#2b7818
a6 
        and (hl)  ; keep only the bits we want to preserve from the background
#9579#2b7915
4f 
        ld c, a
#957a#2b7a15
08 
        ex af, af'
#957b#2b7b15
57 
            ld d, a  ; byte we want to write
#957c#2b7c15
a0 
            and b  ; keep only the bits we want to modify
#957d#2b7d15
b1 
            or c  ; combine them
#957e#2b7e18
77 
            ld (hl), a  ; write to (hl)
#957f#2b7f15
7a 
            ld a, d  ; restore the byte to write in 'ghost a'
#9580#2b8015
08 
        ex af, af'
#9581#2b81
L9581_byte_to_write_and_amount_calculated:
#9581#2b81
        ; Here:
#9581#2b81
        ; - e: number of bytes to write.
#9581#2b81
        ; - ghost a: byte to write.
#9581#2b81
        ; - hl: ptr to the byte after the last byte we need to write.
#9581#2b8115
7b 
        ld a, e
#9582#2b8215
b7 
        or a
#9583#2b83213/8
28 3a 
        jr z, L95bf_advance_ptr_to_next_row_and_return
#9585#2b8515
08 
        ex af, af'
#9586#2b8615
5f 
            ld e, a  ; Save the byte to write in e
#9587#2b8715
08 
        ex af, af'
#9588#2b88210
cb 3f 
        srl a  ; a = number of bytes to write / 2
#958a#2b8a213/8
30 02 
        jr nc, L958e_even_number_of_bytes_left
#958c#2b8c17
2b 
        dec hl
#958d#2b8d18
73 
        ld (hl), e  ; If the number of bytes to write is odd, write the first byte
#958e#2b8e
L958e_even_number_of_bytes_left:
#958e#2b8e213/8
28 2f 
        jr z, L95bf_advance_ptr_to_next_row_and_return
#9590#2b9028
fe 05 
        cp 5
#9592#2b92311
f2 9e 95 
        jp p, L959e_write_bytes_via_push
#9595#2b9515
47 
        ld b, a
#9596#2b96
L9596_write_bytes_via_loop:
#9596#2b96
        ; If there are 10 or less bytes to copy, this is faster:
#9596#2b9617
2b 
        dec hl
#9597#2b9718
73 
        ld (hl), e
#9598#2b9817
2b 
        dec hl
#9599#2b9918
73 
        ld (hl), e
#959a#2b9a214/9
10 fa 
        djnz L9596_write_bytes_via_loop
#959c#2b9c213
18 21 
        jr L95bf_advance_ptr_to_next_row_and_return
#959e#2b9e
L959e_write_bytes_via_push:
#959e#2b9e
        ; If there are more than 10 bytes to copy, this is faster:
#959e#2b9e
        ; Copy value "e" to "a"*2 bytes starting at (hl-1), and going backwards.
#959e#2b9e15
f3 
        di
#959f#2b9f422
ed 73 02 75 
        ld (L7502_sp_tmp), sp
#95a3#2ba317
f9 
        ld sp, hl
#95a4#2ba415
53 
        ld d, e
#95a5#2ba515
4f 
        ld c, a
#95a6#2ba6311
21 ba 95 
        ld hl, L95ba_end_of_pushes
#95a9#2ba915
af 
        xor a
#95aa#2baa15
47 
        ld b, a
#95ab#2bab217
ed 42 
        sbc hl, bc
#95ad#2bad15
e9 
        jp hl  ; Executes "a" "push de" instructions
#95ae#2bae
        ; There are 12 "push de" instructions here, each of them can copy 2 bytes, so, 12*2 = 24, which is
#95ae#2bae
        ; a whole horizontal row of the screen.
#95ae#2bae112
d5 
        push de
#95af#2baf112
d5 
        push de
#95b0#2bb0112
d5 
        push de
#95b1#2bb1112
d5 
        push de
#95b2#2bb2112
d5 
        push de
#95b3#2bb3112
d5 
        push de
#95b4#2bb4112
d5 
        push de
#95b5#2bb5112
d5 
        push de
#95b6#2bb6112
d5 
        push de
#95b7#2bb7112
d5 
        push de
#95b8#2bb8112
d5 
        push de
#95b9#2bb9112
d5 
        push de
#95ba#2bba
L95ba_end_of_pushes:
#95ba#2bba422
ed 7b 02 75 
        ld sp, (L7502_sp_tmp)
#95be#2bbe15
fb 
        ei
#95bf#2bbf
L95bf_advance_ptr_to_next_row_and_return:
#95bf#2bbf317
2a 0c 75 
        ld hl, (L750c_current_drawing_row_ptr)
#95c2#2bc2311
11 e8 ff 
        ld de, -SCREEN_WIDTH
#95c5#2bc5112
19 
        add hl, de
#95c6#2bc6317
22 0c 75 
        ld (L750c_current_drawing_row_ptr), hl
#95c9#2bc9111
d1 
    pop de
#95ca#2bca111
e1 
    pop hl
#95cb#2bcb111
c9 
    ret
#95cc#2bcc
#95cc#2bcc
#95cc#2bcc
; --------------------------------
#95cc#2bcc
; Variables for L95de_init_rotation_matrix
#95cc#2bcc
L95cc_identity_matrix:  ; stored in columns - rows
#95cc#2bcc3
    db #40, #00, #00  ; 1st column
#95cf#2bcf3
    db #00, #40, #00  ; 2nd column
#95d2#2bd23
    db #00, #00, #40  ; 3rd column
#95d5#2bd5
L95d5_scaling_matrix:  ; Used after the rotation matrix is calculated, to apply some scaling in the x and z axis.
#95d5#2bd53
    db #28, #00, #00
#95d8#2bd83
    db #00, #40, #00
#95db#2bdb3
    db #00, #00, #20
#95de#2bde
#95de#2bde
#95de#2bde
; --------------------------------
#95de#2bde
; Computes the rotation matrix (rotation + scale),
#95de#2bde
; and initializes all the pointers and buffers to start projecting 3d objects into 2d coordinates.
#95de#2bde
L95de_init_rotation_matrix:
#95de#2bde
    ; Initialize the yaw rotation matrix to the identity matrix:
#95de#2bde311
01 09 00 
    ld bc, 9
#95e1#2be1311
21 cc 95 
    ld hl, L95cc_identity_matrix
#95e4#2be4311
11 55 5e 
    ld de, L5e55_rotation_matrix
#95e7#2be7223/18
ed b0 
    ldir
#95e9#2be9314
3a b7 6a 
    ld a, (L6ab7_player_yaw_angle)
#95ec#2bec15
b7 
    or a
#95ed#2bed213/8
28 1c 
    jr z, L960b_yaw_matrix_computed
#95ef#2bef
    ; Set L5e55_rotation_matrix to be a 3d rotation matrix around the "y" axis:
#95ef#2bef416
fd 21 c6 73 
    ld iy, L73c6_cosine_sine_table
#95f3#2bf315
87 
    add a, a
#95f4#2bf415
4f 
    ld c, a
#95f5#2bf5217
fd 09 
    add iy, bc
#95f7#2bf7321
fd 7e 01 
    ld a, (iy + 1)  ; sin(yaw)
#95fa#2bfa314
32 55 5e 
    ld (L5e55_rotation_matrix), a
#95fd#2bfd314
32 5d 5e 
    ld (L5e55_rotation_matrix + 8), a
#9600#2c00321
fd 7e 00 
    ld a, (iy)  ; cos(yaw)
#9603#2c03314
32 5b 5e 
    ld (L5e55_rotation_matrix + 6), a
#9606#2c06210
ed 44 
    neg
#9608#2c08314
32 57 5e 
    ld (L5e55_rotation_matrix + 2), a
#960b#2c0b
L960b_yaw_matrix_computed:
#960b#2c0b314
3a b6 6a 
    ld a, (L6ab6_player_pitch_angle)
#960e#2c0e15
b7 
    or a
#960f#2c0f213/8
28 29 
    jr z, L963a_zero_pitch
#9611#2c11
    ; Initialize the yaw rotation matrix to the identity matrix:
#9611#2c1128
0e 09 
    ld c, 9
#9613#2c13311
21 cc 95 
    ld hl, L95cc_identity_matrix
#9616#2c16311
11 4c 5e 
    ld de, L5e4c_pitch_rotation_matrix
#9619#2c19223/18
ed b0 
    ldir
#961b#2c1b
    ; Set L5e4c_pitch_rotation_matrix to be a 3d rotation matrix around the "x" axis:
#961b#2c1b416
fd 21 c6 73 
    ld iy, L73c6_cosine_sine_table
#961f#2c1f15
87 
    add a, a
#9620#2c2015
4f 
    ld c, a
#9621#2c21217
fd 09 
    add iy, bc
#9623#2c23321
fd 7e 01 
    ld a, (iy + 1)  ; sin(pitch)
#9626#2c26314
32 50 5e 
    ld (L5e4c_pitch_rotation_matrix + 4), a
#9629#2c29314
32 54 5e 
    ld (L5e4c_pitch_rotation_matrix + 8), a
#962c#2c2c321
fd 7e 00 
    ld a, (iy)  ; cos(pitch)
#962f#2c2f314
32 51 5e 
    ld (L5e4c_pitch_rotation_matrix + 5), a
#9632#2c32210
ed 44 
    neg
#9634#2c34314
32 53 5e 
    ld (L5e4c_pitch_rotation_matrix + 7), a
#9637#2c37318
cd 89 a0 
    call La089_3x3_matrix_multiply
#963a#2c3a
L963a_zero_pitch:
#963a#2c3a
    ; Multiply the current rotation matrix by a predefined scaling matrix:
#963a#2c3a28
0e 09 
    ld c, 9
#963c#2c3c311
21 d5 95 
    ld hl, L95d5_scaling_matrix
#963f#2c3f311
11 4c 5e 
    ld de, L5e4c_pitch_rotation_matrix
#9642#2c42223/18
ed b0 
    ldir
#9644#2c44318
cd 89 a0 
    call La089_3x3_matrix_multiply
#9647#2c47311
21 a2 5f 
    ld hl, L5fa2_3d_object_bounding_boxes_relative_to_player
#964a#2c4a317
22 99 74 
    ld (L7499_3d_object_bounding_box_relative_to_player_ptr), hl
#964d#2c4d311
21 f4 67 
    ld hl, L67f4_projected_vertex_data
#9650#2c50317
22 97 74 
    ld (L7497_next_projected_vertex_ptr), hl
#9653#2c53311
21 54 67 
    ld hl, L6754_current_room_object_projected_data
#9656#2c56317
22 9b 74 
    ld (L749b_next_object_projected_data_ptr), hl
#9659#2c5915
af 
    xor a
#965a#2c5a314
32 6b 74 
    ld (L746b_n_objects_to_draw), a
#965d#2c5d314
32 81 74 
    ld (L7481_n_objects_covering_the_whole_screen), a
#9660#2c60111
c9 
    ret
#9661#2c61
#9661#2c61
#9661#2c61
; --------------------------------
#9661#2c61
; Projects a cube. Using the object bounding box, generates the 3d vertices for a cube, and
#9661#2c61
; then calls the projection method for adding them to the render list.
#9661#2c61
; Called to project objects with type "OBJECT_TYPE_CUBE"
#9661#2c61
; - When this function is called this has already happened:
#9661#2c61
;   - rendering cube volume has been calculated
#9661#2c61
;   - rotation matrix has already been set
#9661#2c61
;   - cube volume culling check has been done
#9661#2c61
;   - player_collision_with_object_flags has been set
#9661#2c61
;   - object bounding box coordinates relative to player have been stored in
#9661#2c61
;     (L7499_3d_object_bounding_box_relative_to_player_ptr)
#9661#2c61
L9661_project_cube_objects:
#9661#2c61318
cd 77 91 
    call L9177_rotate_relative_bounding_box
#9664#2c64
    ; Calculate the 8 cube vertices, and store them in (L5e9f_3d_vertex_coordinates_after_rotation_matrix):
#9664#2c64317
2a 9f 5e 
    ld hl, (L5e9f_3d_vertex_coordinates_after_rotation_matrix)
#9667#2c67422
ed 5b 63 5e 
    ld de, (L5e63_3d_vertex_coordinates_relative_to_player)
#966b#2c6b112
19 
    add hl, de
#966c#2c6c317
22 a5 5e 
    ld (L5e9f_3d_vertex_coordinates_after_rotation_matrix + 3 * 2), hl
#966f#2c6f317
22 ab 5e 
    ld (L5e9f_3d_vertex_coordinates_after_rotation_matrix + 6 * 2), hl
#9672#2c72317
22 bd 5e 
    ld (L5e9f_3d_vertex_coordinates_after_rotation_matrix + 15 * 2), hl
#9675#2c75317
22 c3 5e 
    ld (L5e9f_3d_vertex_coordinates_after_rotation_matrix + 18 * 2), hl
#9678#2c78317
2a a1 5e 
    ld hl, (L5e9f_3d_vertex_coordinates_after_rotation_matrix + 1 * 2)
#967b#2c7b422
ed 5b 65 5e 
    ld de, (L5e63_3d_vertex_coordinates_relative_to_player + 2)
#967f#2c7f112
19 
    add hl, de
#9680#2c80317
22 a7 5e 
    ld (L5e9f_3d_vertex_coordinates_after_rotation_matrix + 4 * 2), hl
#9683#2c83317
22 ad 5e 
    ld (L5e9f_3d_vertex_coordinates_after_rotation_matrix + 7 * 2), hl
#9686#2c86317
22 bf 5e 
    ld (L5e9f_3d_vertex_coordinates_after_rotation_matrix + 16 * 2), hl
#9689#2c89317
22 c5 5e 
    ld (L5e9f_3d_vertex_coordinates_after_rotation_matrix + 19 * 2), hl
#968c#2c8c317
2a a3 5e 
    ld hl, (L5e9f_3d_vertex_coordinates_after_rotation_matrix + 2 * 2)
#968f#2c8f422
ed 5b 67 5e 
    ld de, (L5e63_3d_vertex_coordinates_relative_to_player + 2 * 2)
#9693#2c93112
19 
    add hl, de
#9694#2c94317
22 a9 5e 
    ld (L5e9f_3d_vertex_coordinates_after_rotation_matrix + 5 * 2), hl
#9697#2c97317
22 af 5e 
    ld (L5e9f_3d_vertex_coordinates_after_rotation_matrix + 8 * 2), hl
#969a#2c9a317
22 c1 5e 
    ld (L5e9f_3d_vertex_coordinates_after_rotation_matrix + 17 * 2), hl
#969d#2c9d317
22 c7 5e 
    ld (L5e9f_3d_vertex_coordinates_after_rotation_matrix + 20 * 2), hl
#96a0#2ca0317
2a 9f 5e 
    ld hl, (L5e9f_3d_vertex_coordinates_after_rotation_matrix)
#96a3#2ca3422
ed 5b 69 5e 
    ld de, (L5e63_3d_vertex_coordinates_relative_to_player + 3 * 2)
#96a7#2ca7112
19 
    add hl, de
#96a8#2ca8317
22 b1 5e 
    ld (L5e9f_3d_vertex_coordinates_after_rotation_matrix + 9 * 2), hl
#96ab#2cab317
22 c9 5e 
    ld (L5e9f_3d_vertex_coordinates_after_rotation_matrix + 21 * 2), hl
#96ae#2cae317
2a ab 5e 
    ld hl, (L5e9f_3d_vertex_coordinates_after_rotation_matrix + 6 * 2)
#96b1#2cb1112
19 
    add hl, de
#96b2#2cb2317
22 ab 5e 
    ld (L5e9f_3d_vertex_coordinates_after_rotation_matrix + 6 * 2), hl
#96b5#2cb5317
2a c3 5e 
    ld hl, (L5e9f_3d_vertex_coordinates_after_rotation_matrix + 18 * 2)
#96b8#2cb8112
19 
    add hl, de
#96b9#2cb9317
22 c3 5e 
    ld (L5e9f_3d_vertex_coordinates_after_rotation_matrix + 18 * 2), hl
#96bc#2cbc317
2a a1 5e 
    ld hl, (L5e9f_3d_vertex_coordinates_after_rotation_matrix + 1 * 2)
#96bf#2cbf422
ed 5b 6b 5e 
    ld de, (L5e63_3d_vertex_coordinates_relative_to_player + 4 * 2)
#96c3#2cc3112
19 
    add hl, de
#96c4#2cc4317
22 b3 5e 
    ld (L5e9f_3d_vertex_coordinates_after_rotation_matrix + 10 * 2), hl
#96c7#2cc7317
22 cb 5e 
    ld (L5e9f_3d_vertex_coordinates_after_rotation_matrix + 22 * 2), hl
#96ca#2cca317
2a ad 5e 
    ld hl, (L5e9f_3d_vertex_coordinates_after_rotation_matrix + 7 * 2)
#96cd#2ccd112
19 
    add hl, de
#96ce#2cce317
22 ad 5e 
    ld (L5e9f_3d_vertex_coordinates_after_rotation_matrix + 7 * 2), hl
#96d1#2cd1317
2a c5 5e 
    ld hl, (L5e9f_3d_vertex_coordinates_after_rotation_matrix + 19 * 2)
#96d4#2cd4112
19 
    add hl, de
#96d5#2cd5317
22 c5 5e 
    ld (L5e9f_3d_vertex_coordinates_after_rotation_matrix + 19 * 2), hl
#96d8#2cd8317
2a a3 5e 
    ld hl, (L5e9f_3d_vertex_coordinates_after_rotation_matrix + 2 * 2)
#96db#2cdb422
ed 5b 6d 5e 
    ld de, (L5e63_3d_vertex_coordinates_relative_to_player + 5 * 2)
#96df#2cdf112
19 
    add hl, de
#96e0#2ce0317
22 b5 5e 
    ld (L5e9f_3d_vertex_coordinates_after_rotation_matrix + 11 * 2), hl
#96e3#2ce3317
22 cd 5e 
    ld (L5e9f_3d_vertex_coordinates_after_rotation_matrix + 23 * 2), hl
#96e6#2ce6317
2a af 5e 
    ld hl, (L5e9f_3d_vertex_coordinates_after_rotation_matrix + 8 * 2)
#96e9#2ce9112
19 
    add hl, de
#96ea#2cea317
22 af 5e 
    ld (L5e9f_3d_vertex_coordinates_after_rotation_matrix + 8 * 2), hl
#96ed#2ced317
2a c7 5e 
    ld hl, (L5e9f_3d_vertex_coordinates_after_rotation_matrix + 20 * 2)
#96f0#2cf0112
19 
    add hl, de
#96f1#2cf1317
22 c7 5e 
    ld (L5e9f_3d_vertex_coordinates_after_rotation_matrix + 20 * 2), hl
#96f4#2cf4317
2a 9f 5e 
    ld hl, (L5e9f_3d_vertex_coordinates_after_rotation_matrix)
#96f7#2cf7422
ed 5b 6f 5e 
    ld de, (L5e63_3d_vertex_coordinates_relative_to_player + 6 * 2)
#96fb#2cfb112
19 
    add hl, de
#96fc#2cfc317
22 b7 5e 
    ld (L5e9f_3d_vertex_coordinates_after_rotation_matrix + 12 * 2), hl
#96ff#2cff317
2a bd 5e 
    ld hl, (L5e9f_3d_vertex_coordinates_after_rotation_matrix + 15 * 2)
#9702#2d02112
19 
    add hl, de
#9703#2d03317
22 bd 5e 
    ld (L5e9f_3d_vertex_coordinates_after_rotation_matrix + 15 * 2), hl
#9706#2d06317
2a c3 5e 
    ld hl, (L5e9f_3d_vertex_coordinates_after_rotation_matrix + 18 * 2)
#9709#2d09112
19 
    add hl, de
#970a#2d0a317
22 c3 5e 
    ld (L5e9f_3d_vertex_coordinates_after_rotation_matrix + 18 * 2), hl
#970d#2d0d317
2a c9 5e 
    ld hl, (L5e9f_3d_vertex_coordinates_after_rotation_matrix + 21 * 2)
#9710#2d10112
19 
    add hl, de
#9711#2d11317
22 c9 5e 
    ld (L5e9f_3d_vertex_coordinates_after_rotation_matrix + 21 * 2), hl
#9714#2d14317
2a a1 5e 
    ld hl, (L5e9f_3d_vertex_coordinates_after_rotation_matrix + 1 * 2)
#9717#2d17422
ed 5b 71 5e 
    ld de, (L5e63_3d_vertex_coordinates_relative_to_player + 7 * 2)
#971b#2d1b112
19 
    add hl, de
#971c#2d1c317
22 b9 5e 
    ld (L5e9f_3d_vertex_coordinates_after_rotation_matrix + 13 * 2), hl
#971f#2d1f317
2a bf 5e 
    ld hl, (L5e9f_3d_vertex_coordinates_after_rotation_matrix + 16 * 2)
#9722#2d22112
19 
    add hl, de
#9723#2d23317
22 bf 5e 
    ld (L5e9f_3d_vertex_coordinates_after_rotation_matrix + 16 * 2), hl
#9726#2d26317
2a c5 5e 
    ld hl, (L5e9f_3d_vertex_coordinates_after_rotation_matrix + 19 * 2)
#9729#2d29112
19 
    add hl, de
#972a#2d2a317
22 c5 5e 
    ld (L5e9f_3d_vertex_coordinates_after_rotation_matrix + 19 * 2), hl
#972d#2d2d317
2a cb 5e 
    ld hl, (L5e9f_3d_vertex_coordinates_after_rotation_matrix + 22 * 2)
#9730#2d30112
19 
    add hl, de
#9731#2d31317
22 cb 5e 
    ld (L5e9f_3d_vertex_coordinates_after_rotation_matrix + 22 * 2), hl
#9734#2d34317
2a a3 5e 
    ld hl, (L5e9f_3d_vertex_coordinates_after_rotation_matrix + 2 * 2)
#9737#2d37422
ed 5b 73 5e 
    ld de, (L5e63_3d_vertex_coordinates_relative_to_player + 8 * 2)
#973b#2d3b112
19 
    add hl, de
#973c#2d3c317
22 bb 5e 
    ld (L5e9f_3d_vertex_coordinates_after_rotation_matrix + 14 * 2), hl
#973f#2d3f317
2a c1 5e 
    ld hl, (L5e9f_3d_vertex_coordinates_after_rotation_matrix + 17 * 2)
#9742#2d42112
19 
    add hl, de
#9743#2d43317
22 c1 5e 
    ld (L5e9f_3d_vertex_coordinates_after_rotation_matrix + 17 * 2), hl
#9746#2d46317
2a c7 5e 
    ld hl, (L5e9f_3d_vertex_coordinates_after_rotation_matrix + 20 * 2)
#9749#2d49112
19 
    add hl, de
#974a#2d4a317
22 c7 5e 
    ld (L5e9f_3d_vertex_coordinates_after_rotation_matrix + 20 * 2), hl
#974d#2d4d317
2a cd 5e 
    ld hl, (L5e9f_3d_vertex_coordinates_after_rotation_matrix + 23 * 2)
#9750#2d50112
19 
    add hl, de
#9751#2d51317
22 cd 5e 
    ld (L5e9f_3d_vertex_coordinates_after_rotation_matrix + 23 * 2), hl
#9754#2d5428
3e 08 
    ld a, 8  ; Number of vertices
#9756#2d56318
cd 46 92 
    call L9246_object_visibility_check
#9759#2d59311
c2 ba 97 
    jp nz, L97ba_return
#975c#2d5c311
21 6d 6b 
    ld hl, L6b6d_cube_edges
#975f#2d5f317
22 24 5f 
    ld (L5f24_shape_edges_ptr), hl
#9762#2d62422
fd 2a 9d 74 
    ld iy, (L749d_object_currently_being_processed_ptr)
#9766#2d66311
21 87 6b 
    ld hl, L6b86_face_definition_for_cubes + 1
#9769#2d6915
af 
    xor a
#976a#2d6a314
32 5f 5e 
    ld (L5e5f_add_to_projected_objects_flag), a
#976d#2d6d314
3a 62 5e 
    ld a, (L5e62_player_collision_with_object_flags)
#9770#2d7015
4f 
    ld c, a
#9771#2d7128
06 03 
    ld b, 3
#9773#2d73311
11 06 00 
    ld de, 6
#9776#2d76
    ; Calculate the attributes to use for each face,
#9776#2d76
    ; This loop iterates 3 times (one per axis), and in each iteration,
#9776#2d76
    ; we compute the attribute of the two faces associated to that axis.
#9776#2d76
L9776_axis_loop:
#9776#2d76210
cb 29 
    sra c
#9778#2d78213/8
38 04 
    jr c, L977e
#977a#2d7a
    ; This face is not visible:
#977a#2d7a211
36 00 
    ld (hl), 0
#977c#2d7c213
18 0d 
    jr L978b_next_face
#977e#2d7e
L977e:
#977e#2d7e
    ; Get the attribute of the first face of the axis:
#977e#2d7e321
fd 7e 09 
    ld a, (iy + OBJECT_ADDITIONAL_DATA)
#9781#2d8128
e6 0f 
    and #0f
#9783#2d8318
77 
    ld (hl), a
#9784#2d84213/8
28 05 
    jr z, L978b_next_face
#9786#2d86
    ; OPTIMIZATION: There is no point on this code, we should just change the line above to jr nz, L97ba_return
#9786#2d86
    ; Mark that we should not render the object.
#9786#2d8628
3e 01 
    ld a, 1
#9788#2d88314
32 5f 5e 
    ld (L5e5f_add_to_projected_objects_flag), a
#978b#2d8b
L978b_next_face:
#978b#2d8b112
19 
    add hl, de
#978c#2d8c210
cb 29 
    sra c
#978e#2d8e213/8
38 04 
    jr c, L9794
#9790#2d90211
36 00 
    ld (hl), 0
#9792#2d92213
18 13 
    jr L97a7
#9794#2d94
L9794:
#9794#2d94
    ; Get the attribute of the second face of the axis:
#9794#2d94321
fd 7e 09 
    ld a, (iy + OBJECT_ADDITIONAL_DATA)
#9797#2d97210
cb 3f 
    srl a
#9799#2d99210
cb 3f 
    srl a
#979b#2d9b210
cb 3f 
    srl a
#979d#2d9d210
cb 3f 
    srl a
#979f#2d9f18
77 
    ld (hl), a
#97a0#2da0213/8
28 05 
    jr z, L97a7
#97a2#2da2
    ; OPTIMIZATION: There is no point on this code, we should just change the line above to jr nz, L97ba_return
#97a2#2da2
    ; Mark that we should not render the object.
#97a2#2da228
3e 01 
    ld a, 1
#97a4#2da4314
32 5f 5e 
    ld (L5e5f_add_to_projected_objects_flag), a
#97a7#2da7
L97a7:
#97a7#2da7112
19 
    add hl, de
#97a8#2da8212
fd 23 
    inc iy
#97aa#2daa214/9
10 ca 
    djnz L9776_axis_loop
#97ac#2dac
#97ac#2dac314
3a 5f 5e 
    ld a, (L5e5f_add_to_projected_objects_flag)
#97af#2daf15
b7 
    or a
#97b0#2db0213/8
28 08 
    jr z, L97ba_return
#97b2#2db215
af 
    xor a
#97b3#2db3416
fd 21 86 6b 
    ld iy, L6b86_face_definition_for_cubes
#97b7#2db7318
cd b0 92 
    call L92b0_project_object_and_add_to_render_list
#97ba#2dba
L97ba_return:
#97ba#2dba111
c9 
    ret
#97bb#2dbb
#97bb#2dbb
#97bb#2dbb
; --------------------------------
#97bb#2dbb
; This method is used for synthesizing other solid shapes than cubes, and projecting them.
#97bb#2dbb
; It works as follows:
#97bb#2dbb
; - First the function determines the obeject type by comparing some of its dimensions.
#97bb#2dbb
; - Once the type of object is determined, the different vertices of the object are synthesized based on these dimensions.
#97bb#2dbb
;   - To do this, the code stores the 4 additional dimension data in the object data in (L5f29_extra_solid_dimensions),
#97bb#2dbb
;     then, via a collection of cases, it uses those to synthesize vertices.
#97bb#2dbb
; - Once we have the vertices, they are transformed, visibility check is carried out, and if it is passed, the object is projected.
#97bb#2dbb
; 
#97bb#2dbb
; The method is called for objects of type different than rectangle (3), cube (1), or flat shapes (>=10).
#97bb#2dbb
; Specifically, the method considers types 4, 5, 6, 7, 8 and 9.
#97bb#2dbb
L97bb_project_other_solids:
#97bb#2dbb422
dd 2a 9d 74 
    ld ix, (L749d_object_currently_being_processed_ptr)
#97bf#2dbf
    ; We first determine the shape of the object:
#97bf#2dbf
    ; - It seems that rather than relying on the IDs, this code relies on comparing
#97bf#2dbf
    ;   the additional dimensions that are stored in the object data starting at offset 12.
#97bf#2dbf
    ; - For example, if (ix + 12) != (ix + 14) && (ix + 13) == (ix + 15), the object is considered to be a wedge.
#97bf#2dbf321
dd 7e 0c 
    ld a, (ix + 12)
#97c2#2dc2321
dd be 0e 
    cp (ix + 14)
#97c5#2dc5213/8
28 1e 
    jr z, L97e5
#97c7#2dc7321
dd 7e 0d 
    ld a, (ix + 13)
#97ca#2dca321
dd be 0f 
    cp (ix + 15)
#97cd#2dcd213/8
20 0b 
    jr nz, L97da
#97cf#2dcf
    ; Wedge object:
#97cf#2dcf416
fd 21 ea 6b 
    ld iy, L6bea_face_definition_for_wedges
#97d3#2dd3311
21 d7 6b 
    ld hl, L6bd7_wedge_edges
#97d6#2dd628
3e 06 
    ld a, 6  ; wedges have 6 vertexes
#97d8#2dd8213
18 27 
    jr L9801_shape_determined
#97da#2dda
L97da:
#97da#2dda
    ; Hourglass object:
#97da#2dda416
fd 21 50 6c 
    ld iy, L6c50_face_definition_for_hourglasses
#97de#2dde311
21 37 6c 
    ld hl, L6c37_hourglass_edges
#97e1#2de128
3e 08 
    ld a, 8  ; hourglasses have 8 vertexes
#97e3#2de3213
18 1c 
    jr L9801_shape_determined
#97e5#2de5
L97e5:
#97e5#2de5321
dd 7e 0d 
    ld a, (ix + 13)
#97e8#2de8321
dd be 0f 
    cp (ix + 15)
#97eb#2deb213/8
28 0b 
    jr z, L97f8
#97ed#2ded
    ; Triangle hourglass object:
#97ed#2ded416
fd 21 1a 6c 
    ld iy, L6c1a_face_definition_for_triangle_hourglasses
#97f1#2df1311
21 07 6c 
    ld hl, L6c07_triangle_houglass_edges
#97f4#2df428
3e 06 
    ld a, 6  ; triangle hourglasses have 6 vertexes
#97f6#2df6213
18 09 
    jr L9801_shape_determined
#97f8#2df8
L97f8:
#97f8#2df8
    ; Pyramid obect:
#97f8#2df8416
fd 21 bc 6b 
    ld iy, L6bbc_face_definition_for_pyramids
#97fc#2dfc311
21 ab 6b 
    ld hl, L6bab_pyramid_edges
#97ff#2dff28
3e 05 
    ld a, 5  ; pyramids have 5 vertexes
#9801#2e01
#9801#2e01
L9801_shape_determined:
#9801#2e01314
32 96 74 
    ld (L7496_current_drawing_primitive_n_vertices), a
#9804#2e04317
22 24 5f 
    ld (L5f24_shape_edges_ptr), hl
#9807#2e0728
06 04 
    ld b, 4
#9809#2e09311
21 29 5f 
    ld hl, L5f29_extra_solid_dimensions
#980c#2e0c
L980c_extra_dimension_loop:
#980c#2e0c321
dd 56 0c 
    ld d, (ix + 12)
#980f#2e0f28
1e 00 
    ld e, 0
#9811#2e11210
cb 3a 
    srl d
#9813#2e13210
cb 1b 
    rr e
#9815#2e15210
cb 3a 
    srl d
#9817#2e17210
cb 1b 
    rr e  ; de = (ix + 12) * 64
#9819#2e1918
73 
    ld (hl), e  ; save the coordinate in L5f29_extra_solid_dimensions
#981a#2e1a17
23 
    inc hl
#981b#2e1b18
72 
    ld (hl), d
#981c#2e1c17
23 
    inc hl
#981d#2e1d212
dd 23 
    inc ix
#981f#2e1f214/9
10 eb 
    djnz L980c_extra_dimension_loop
#9821#2e21
#9821#2e21422
dd 2a 99 74 
    ld ix, (L7499_3d_object_bounding_box_relative_to_player_ptr)
#9825#2e25314
3a 61 5e 
    ld a, (L5e61_object_currently_being_processed_type)
#9828#2e2828
fe 04 
    cp 4
#982a#2e2a311
c2 6f 98 
    jp nz, L986f
#982d#2e2d
#982d#2e2d
    ; Object type 4:
#982d#2e2d321
dd 66 0b 
    ld h, (ix + 11)
#9830#2e30321
dd 6e 0a 
    ld l, (ix + 10)
#9833#2e33317
22 67 5e 
    ld (L5e63_3d_vertex_coordinates_relative_to_player + 2 * 2), hl
#9836#2e36317
22 79 5e 
    ld (L5e63_3d_vertex_coordinates_relative_to_player + 11 * 2), hl
#9839#2e39321
dd 66 09 
    ld h, (ix + 9)
#983c#2e3c321
dd 6e 08 
    ld l, (ix + 8)
#983f#2e3f317
22 6d 5e 
    ld (L5e63_3d_vertex_coordinates_relative_to_player + 5 * 2), hl
#9842#2e42317
22 73 5e 
    ld (L5e63_3d_vertex_coordinates_relative_to_player + 8 * 2), hl
#9845#2e45422
ed 5b 2b 5f 
    ld de, (L5f29_extra_solid_dimensions + 1 * 2)
#9849#2e49422
ed 4b 2f 5f 
    ld bc, (L5f29_extra_solid_dimensions + 3 * 2)
#984d#2e4d318
cd 5e 98 
    call L985e_project_other_solids_auxiliary_fn1
#9850#2e50321
dd 66 01 
    ld h, (ix + 1)
#9853#2e53321
dd 6e 00 
    ld l, (ix)
#9856#2e56321
dd 56 03 
    ld d, (ix + 3)
#9859#2e59321
dd 5e 02 
    ld e, (ix + 2)
#985c#2e5c213
18 45 
    jr L98a3
#985e#2e5e
#985e#2e5e
; Auxiliary local function, since this code is shared by two different object types:
#985e#2e5e
L985e_project_other_solids_auxiliary_fn1:
#985e#2e5e112
e5 
    push hl
#985f#2e5f112
19 
        add hl, de
#9860#2e60317
22 85 5e 
        ld (L5e63_3d_vertex_coordinates_relative_to_player + 17 * 2), hl
#9863#2e63317
22 8b 5e 
        ld (L5e63_3d_vertex_coordinates_relative_to_player + 20 * 2), hl
#9866#2e66111
e1 
    pop hl
#9867#2e67112
09 
    add hl, bc
#9868#2e68317
22 7f 5e 
    ld (L5e63_3d_vertex_coordinates_relative_to_player + 14 * 2), hl
#986b#2e6b317
22 91 5e 
    ld (L5e63_3d_vertex_coordinates_relative_to_player + 23 * 2), hl
#986e#2e6e111
c9 
    ret
#986f#2e6f
#986f#2e6f
L986f:
#986f#2e6f28
fe 05 
    cp 5
#9871#2e71311
c2 ef 98 
    jp nz, L98ef
#9874#2e74
#9874#2e74
    ; Object type 5:
#9874#2e74321
dd 66 0b 
    ld h, (ix + 11)
#9877#2e77321
dd 6e 0a 
    ld l, (ix + 10)
#987a#2e7a317
22 6d 5e 
    ld (L5e63_3d_vertex_coordinates_relative_to_player + 5 * 2), hl
#987d#2e7d317
22 73 5e 
    ld (L5e63_3d_vertex_coordinates_relative_to_player + 8 * 2), hl
#9880#2e80321
dd 66 09 
    ld h, (ix + 9)
#9883#2e83321
dd 6e 08 
    ld l, (ix + 8)
#9886#2e86317
22 67 5e 
    ld (L5e63_3d_vertex_coordinates_relative_to_player + 2 * 2), hl
#9889#2e89317
22 79 5e 
    ld (L5e63_3d_vertex_coordinates_relative_to_player + 11 * 2), hl
#988c#2e8c422
ed 4b 2b 5f 
    ld bc, (L5f29_extra_solid_dimensions + 2)
#9890#2e90422
ed 5b 2f 5f 
    ld de, (L5f29_extra_solid_dimensions + 3 * 2)
#9894#2e94318
cd 5e 98 
    call L985e_project_other_solids_auxiliary_fn1
#9897#2e97321
dd 56 01 
    ld d, (ix + 1)
#989a#2e9a321
dd 5e 00 
    ld e, (ix)
#989d#2e9d321
dd 66 03 
    ld h, (ix + 3)
#98a0#2ea0321
dd 6e 02 
    ld l, (ix + 2)
#98a3#2ea3
L98a3:
#98a3#2ea3317
22 63 5e 
    ld (L5e63_3d_vertex_coordinates_relative_to_player), hl
#98a6#2ea6317
22 69 5e 
    ld (L5e63_3d_vertex_coordinates_relative_to_player + 3 * 2), hl
#98a9#2ea9317
22 6f 5e 
    ld (L5e63_3d_vertex_coordinates_relative_to_player + 6 * 2), hl
#98ac#2eac317
22 75 5e 
    ld (L5e63_3d_vertex_coordinates_relative_to_player + 9 * 2), hl
#98af#2eaf15
eb 
    ex de, hl
#98b0#2eb0317
22 7b 5e 
    ld (L5e63_3d_vertex_coordinates_relative_to_player + 12 * 2), hl
#98b3#2eb3317
22 81 5e 
    ld (L5e63_3d_vertex_coordinates_relative_to_player + 15 * 2), hl
#98b6#2eb6317
22 87 5e 
    ld (L5e63_3d_vertex_coordinates_relative_to_player + 18 * 2), hl
#98b9#2eb9317
22 8d 5e 
    ld (L5e63_3d_vertex_coordinates_relative_to_player + 21 * 2), hl
#98bc#2ebc321
dd 66 07 
    ld h, (ix + 7)
#98bf#2ebf321
dd 6e 06 
    ld l, (ix + 6)
#98c2#2ec2317
22 71 5e 
    ld (L5e63_3d_vertex_coordinates_relative_to_player + 7 * 2), hl
#98c5#2ec5317
22 77 5e 
    ld (L5e63_3d_vertex_coordinates_relative_to_player + 10 * 2), hl
#98c8#2ec8321
dd 66 05 
    ld h, (ix + 5)
#98cb#2ecb321
dd 6e 04 
    ld l, (ix + 4)
#98ce#2ece317
22 65 5e 
    ld (L5e63_3d_vertex_coordinates_relative_to_player + 2), hl
#98d1#2ed1317
22 6b 5e 
    ld (L5e63_3d_vertex_coordinates_relative_to_player + 4 * 2), hl
#98d4#2ed4112
e5 
    push hl
#98d5#2ed5422
ed 5b 29 5f 
        ld de, (L5f29_extra_solid_dimensions)
#98d9#2ed9112
19 
        add hl, de
#98da#2eda317
22 7d 5e 
        ld (L5e63_3d_vertex_coordinates_relative_to_player + 13 * 2), hl
#98dd#2edd317
22 89 5e 
        ld (L5e63_3d_vertex_coordinates_relative_to_player + 19 * 2), hl
#98e0#2ee0111
e1 
    pop hl
#98e1#2ee1422
ed 5b 2d 5f 
    ld de, (L5f29_extra_solid_dimensions + 2 * 2)
#98e5#2ee5112
19 
    add hl, de
#98e6#2ee6317
22 83 5e 
    ld (L5e63_3d_vertex_coordinates_relative_to_player + 16 * 2), hl
#98e9#2ee9317
22 8f 5e 
    ld (L5e63_3d_vertex_coordinates_relative_to_player + 22 * 2), hl
#98ec#2eec311
c3 73 9a 
    jp L9a73_object_vertices_created
#98ef#2eef
L98ef:
#98ef#2eef28
fe 06 
    cp 6
#98f1#2ef1213/8
20 42 
    jr nz, L9935
#98f3#2ef3
#98f3#2ef3
    ; Object type 6:
#98f3#2ef3321
dd 66 03 
    ld h, (ix + 3)
#98f6#2ef6321
dd 6e 02 
    ld l, (ix + 2)
#98f9#2ef9317
22 6f 5e 
    ld (L5e63_3d_vertex_coordinates_relative_to_player + 6 * 2), hl
#98fc#2efc317
22 75 5e 
    ld (L5e63_3d_vertex_coordinates_relative_to_player + 9 * 2), hl
#98ff#2eff321
dd 66 01 
    ld h, (ix + 1)
#9902#2f02321
dd 6e 00 
    ld l, (ix)
#9905#2f05317
22 63 5e 
    ld (L5e63_3d_vertex_coordinates_relative_to_player), hl
#9908#2f08317
22 69 5e 
    ld (L5e63_3d_vertex_coordinates_relative_to_player + 3 * 2), hl
#990b#2f0b422
ed 5b 29 5f 
    ld de, (L5f29_extra_solid_dimensions)
#990f#2f0f422
ed 4b 2d 5f 
    ld bc, (L5f29_extra_solid_dimensions + 2 * 2)
#9913#2f13318
cd 24 99 
    call L9924_project_other_solids_auxiliary_fn2
#9916#2f16321
dd 56 05 
    ld d, (ix + 5)
#9919#2f19321
dd 5e 04 
    ld e, (ix + 4)
#991c#2f1c321
dd 66 07 
    ld h, (ix + 7)
#991f#2f1f321
dd 6e 06 
    ld l, (ix + 6)
#9922#2f22213
18 45 
    jr L9969
#9924#2f24
#9924#2f24
; Auxiliary local function, since this code is shared by two different object types:
#9924#2f24
L9924_project_other_solids_auxiliary_fn2:
#9924#2f24112
e5 
    push hl
#9925#2f25112
19 
        add hl, de
#9926#2f26317
22 7b 5e 
        ld (L5e63_3d_vertex_coordinates_relative_to_player + 12 * 2), hl
#9929#2f29317
22 87 5e 
        ld (L5e63_3d_vertex_coordinates_relative_to_player + 18 * 2), hl
#992c#2f2c111
e1 
    pop hl
#992d#2f2d112
09 
    add hl, bc
#992e#2f2e317
22 81 5e 
    ld (L5e63_3d_vertex_coordinates_relative_to_player + 15 * 2), hl
#9931#2f31317
22 8d 5e 
    ld (L5e63_3d_vertex_coordinates_relative_to_player + 21 * 2), hl
#9934#2f34111
c9 
    ret
#9935#2f35
#9935#2f35
L9935:
#9935#2f3528
fe 07 
    cp 7
#9937#2f37311
c2 b5 99 
    jp nz, L99b5
#993a#2f3a
#993a#2f3a
    ; Object type 7:
#993a#2f3a321
dd 66 03 
    ld h, (ix + 3)
#993d#2f3d321
dd 6e 02 
    ld l, (ix + 2)
#9940#2f40317
22 63 5e 
    ld (L5e63_3d_vertex_coordinates_relative_to_player), hl
#9943#2f43317
22 69 5e 
    ld (L5e63_3d_vertex_coordinates_relative_to_player + 3 * 2), hl
#9946#2f46321
dd 66 01 
    ld h, (ix + 1)
#9949#2f49321
dd 6e 00 
    ld l, (ix)
#994c#2f4c317
22 6f 5e 
    ld (L5e63_3d_vertex_coordinates_relative_to_player + 6 * 2), hl
#994f#2f4f317
22 75 5e 
    ld (L5e63_3d_vertex_coordinates_relative_to_player + 9 * 2), hl
#9952#2f52422
ed 4b 29 5f 
    ld bc, (L5f29_extra_solid_dimensions)
#9956#2f56422
ed 5b 2d 5f 
    ld de, (L5f29_extra_solid_dimensions + 2 * 2)
#995a#2f5a318
cd 24 99 
    call L9924_project_other_solids_auxiliary_fn2
#995d#2f5d321
dd 66 05 
    ld h, (ix + 5)
#9960#2f60321
dd 6e 04 
    ld l, (ix + 4)
#9963#2f63321
dd 56 07 
    ld d, (ix + 7)
#9966#2f66321
dd 5e 06 
    ld e, (ix + 6)
#9969#2f69
L9969:
#9969#2f69317
22 7d 5e 
    ld (L5e63_3d_vertex_coordinates_relative_to_player + 13 * 2), hl
#996c#2f6c317
22 83 5e 
    ld (L5e63_3d_vertex_coordinates_relative_to_player + 16 * 2), hl
#996f#2f6f317
22 89 5e 
    ld (L5e63_3d_vertex_coordinates_relative_to_player + 19 * 2), hl
#9972#2f72317
22 8f 5e 
    ld (L5e63_3d_vertex_coordinates_relative_to_player + 22 * 2), hl
#9975#2f7515
eb 
    ex de, hl
#9976#2f76317
22 65 5e 
    ld (L5e63_3d_vertex_coordinates_relative_to_player + 2), hl
#9979#2f79317
22 6b 5e 
    ld (L5e63_3d_vertex_coordinates_relative_to_player + 4 * 2), hl
#997c#2f7c317
22 71 5e 
    ld (L5e63_3d_vertex_coordinates_relative_to_player + 7 * 2), hl
#997f#2f7f317
22 77 5e 
    ld (L5e63_3d_vertex_coordinates_relative_to_player + 10 * 2), hl
#9982#2f82321
dd 66 0b 
    ld h, (ix + 11)
#9985#2f85321
dd 6e 0a 
    ld l, (ix + 10)
#9988#2f88317
22 6d 5e 
    ld (L5e63_3d_vertex_coordinates_relative_to_player + 5 * 2), hl
#998b#2f8b317
22 73 5e 
    ld (L5e63_3d_vertex_coordinates_relative_to_player + 8 * 2), hl
#998e#2f8e321
dd 66 09 
    ld h, (ix + 9)
#9991#2f91321
dd 6e 08 
    ld l, (ix + 8)
#9994#2f94317
22 67 5e 
    ld (L5e63_3d_vertex_coordinates_relative_to_player + 2 * 2), hl
#9997#2f97317
22 79 5e 
    ld (L5e63_3d_vertex_coordinates_relative_to_player + 11 * 2), hl
#999a#2f9a112
e5 
    push hl
#999b#2f9b422
ed 5b 2b 5f 
    ld de, (L5f29_extra_solid_dimensions + 2)
#999f#2f9f112
19 
    add hl, de
#99a0#2fa0317
22 7f 5e 
    ld (L5e63_3d_vertex_coordinates_relative_to_player + 14 * 2), hl
#99a3#2fa3317
22 91 5e 
    ld (L5e63_3d_vertex_coordinates_relative_to_player + 23 * 2), hl
#99a6#2fa6111
e1 
    pop hl
#99a7#2fa7422
ed 5b 2f 5f 
    ld de, (L5f29_extra_solid_dimensions + 3 * 2)
#99ab#2fab112
19 
    add hl, de
#99ac#2fac317
22 85 5e 
    ld (L5e63_3d_vertex_coordinates_relative_to_player + 17 * 2), hl
#99af#2faf317
22 8b 5e 
    ld (L5e63_3d_vertex_coordinates_relative_to_player + 20 * 2), hl
#99b2#2fb2311
c3 73 9a 
    jp L9a73_object_vertices_created
#99b5#2fb5
#99b5#2fb5
L99b5:
#99b5#2fb528
fe 08 
    cp 8
#99b7#2fb7213/8
20 42 
    jr nz, L99fb_object_type_9
#99b9#2fb9
#99b9#2fb9
    ; Object type 8:
#99b9#2fb9321
dd 66 07 
    ld h, (ix + 7)
#99bc#2fbc321
dd 6e 06 
    ld l, (ix + 6)
#99bf#2fbf317
22 65 5e 
    ld (L5e63_3d_vertex_coordinates_relative_to_player + 2), hl
#99c2#2fc2317
22 77 5e 
    ld (L5e63_3d_vertex_coordinates_relative_to_player + 10 * 2), hl
#99c5#2fc5321
dd 66 05 
    ld h, (ix + 5)
#99c8#2fc8321
dd 6e 04 
    ld l, (ix + 4)
#99cb#2fcb317
22 6b 5e 
    ld (L5e63_3d_vertex_coordinates_relative_to_player + 4 * 2), hl
#99ce#2fce317
22 71 5e 
    ld (L5e63_3d_vertex_coordinates_relative_to_player + 7 * 2), hl
#99d1#2fd1422
ed 5b 2b 5f 
    ld de, (L5f29_extra_solid_dimensions + 2)
#99d5#2fd5422
ed 4b 2f 5f 
    ld bc, (L5f29_extra_solid_dimensions + 3 * 2)
#99d9#2fd9318
cd ea 99 
    call L99ea_project_other_solids_auxiliary_fn3
#99dc#2fdc321
dd 56 09 
    ld d, (ix + 9)
#99df#2fdf321
dd 5e 08 
    ld e, (ix + 8)
#99e2#2fe2321
dd 66 0b 
    ld h, (ix + 11)
#99e5#2fe5321
dd 6e 0a 
    ld l, (ix + 10)
#99e8#2fe8213
18 40 
    jr L9a2a
#99ea#2fea
#99ea#2fea
; Auxiliary local function, since this code is shared by two different object types:
#99ea#2fea
L99ea_project_other_solids_auxiliary_fn3:
#99ea#2fea112
e5 
    push hl
#99eb#2feb112
19 
        add hl, de
#99ec#2fec317
22 83 5e 
        ld (L5e63_3d_vertex_coordinates_relative_to_player + 16 * 2), hl
#99ef#2fef317
22 89 5e 
        ld (L5e63_3d_vertex_coordinates_relative_to_player + 19 * 2), hl
#99f2#2ff2111
e1 
    pop hl
#99f3#2ff3112
09 
    add hl, bc
#99f4#2ff4317
22 7d 5e 
    ld (L5e63_3d_vertex_coordinates_relative_to_player + 13 * 2), hl
#99f7#2ff7317
22 8f 5e 
    ld (L5e63_3d_vertex_coordinates_relative_to_player + 22 * 2), hl
#99fa#2ffa111
c9 
    ret
#99fb#2ffb
#99fb#2ffb
L99fb_object_type_9:
#99fb#2ffb
    ; Object type 9:
#99fb#2ffb321
dd 66 07 
    ld h, (ix + 7)
#99fe#2ffe321
dd 6e 06 
    ld l, (ix + 6)
#9a01#3001317
22 6b 5e 
    ld (L5e63_3d_vertex_coordinates_relative_to_player + 4 * 2), hl
#9a04#3004317
22 71 5e 
    ld (L5e63_3d_vertex_coordinates_relative_to_player + 7 * 2), hl
#9a07#3007321
dd 66 05 
    ld h, (ix + 5)
#9a0a#300a321
dd 6e 04 
    ld l, (ix + 4)
#9a0d#300d317
22 65 5e 
    ld (L5e63_3d_vertex_coordinates_relative_to_player + 2), hl
#9a10#3010317
22 77 5e 
    ld (L5e63_3d_vertex_coordinates_relative_to_player + 10 * 2), hl
#9a13#3013422
ed 4b 2b 5f 
    ld bc, (L5f29_extra_solid_dimensions + 2)
#9a17#3017422
ed 5b 2f 5f 
    ld de, (L5f29_extra_solid_dimensions + 3 * 2)
#9a1b#301b318
cd ea 99 
    call L99ea_project_other_solids_auxiliary_fn3
#9a1e#301e321
dd 66 09 
    ld h, (ix + 9)
#9a21#3021321
dd 6e 08 
    ld l, (ix + 8)
#9a24#3024321
dd 56 0b 
    ld d, (ix + 11)
#9a27#3027321
dd 5e 0a 
    ld e, (ix + 10)
#9a2a#302a
L9a2a:
#9a2a#302a317
22 7f 5e 
    ld (L5e63_3d_vertex_coordinates_relative_to_player + 14 * 2), hl
#9a2d#302d317
22 85 5e 
    ld (L5e63_3d_vertex_coordinates_relative_to_player + 17 * 2), hl
#9a30#3030317
22 8b 5e 
    ld (L5e63_3d_vertex_coordinates_relative_to_player + 20 * 2), hl
#9a33#3033317
22 91 5e 
    ld (L5e63_3d_vertex_coordinates_relative_to_player + 23 * 2), hl
#9a36#303615
eb 
    ex de, hl
#9a37#3037317
22 67 5e 
    ld (L5e63_3d_vertex_coordinates_relative_to_player + 2 * 2), hl
#9a3a#303a317
22 6d 5e 
    ld (L5e63_3d_vertex_coordinates_relative_to_player + 5 * 2), hl
#9a3d#303d317
22 73 5e 
    ld (L5e63_3d_vertex_coordinates_relative_to_player + 8 * 2), hl
#9a40#3040317
22 79 5e 
    ld (L5e63_3d_vertex_coordinates_relative_to_player + 11 * 2), hl
#9a43#3043321
dd 66 03 
    ld h, (ix + 3)
#9a46#3046321
dd 6e 02 
    ld l, (ix + 2)
#9a49#3049317
22 6f 5e 
    ld (L5e63_3d_vertex_coordinates_relative_to_player + 6 * 2), hl
#9a4c#304c317
22 75 5e 
    ld (L5e63_3d_vertex_coordinates_relative_to_player + 9 * 2), hl
#9a4f#304f321
dd 66 01 
    ld h, (ix + 1)
#9a52#3052321
dd 6e 00 
    ld l, (ix)
#9a55#3055317
22 63 5e 
    ld (L5e63_3d_vertex_coordinates_relative_to_player), hl
#9a58#3058317
22 69 5e 
    ld (L5e63_3d_vertex_coordinates_relative_to_player + 3 * 2), hl
#9a5b#305b112
e5 
    push hl
#9a5c#305c422
ed 5b 29 5f 
        ld de, (L5f29_extra_solid_dimensions)
#9a60#3060112
19 
        add hl, de
#9a61#3061317
22 7b 5e 
        ld (L5e63_3d_vertex_coordinates_relative_to_player + 12 * 2), hl
#9a64#3064317
22 87 5e 
        ld (L5e63_3d_vertex_coordinates_relative_to_player + 18 * 2), hl
#9a67#3067111
e1 
    pop hl
#9a68#3068422
ed 5b 2d 5f 
    ld de, (L5f29_extra_solid_dimensions + 2 * 2)
#9a6c#306c112
19 
    add hl, de
#9a6d#306d317
22 81 5e 
    ld (L5e63_3d_vertex_coordinates_relative_to_player + 15 * 2), hl
#9a70#3070317
22 8d 5e 
    ld (L5e63_3d_vertex_coordinates_relative_to_player + 21 * 2), hl
#9a73#3073
#9a73#3073
L9a73_object_vertices_created:
#9a73#3073
    ; At this point all the vertices of the object have been synthesized,
#9a73#3073
    ; and we are ready to transform it and potentially project it.
#9a73#3073217
fd e5 
    push iy
#9a75#3075318
cd 0f 85 
        call L850f_apply_rotation_matrix_to_object_vertices
#9a78#3078314
3a 96 74 
        ld a, (L7496_current_drawing_primitive_n_vertices)
#9a7b#307b318
cd 46 92 
        call L9246_object_visibility_check
#9a7e#307e216
fd e1 
    pop iy
#9a80#3080213/8
20 42 
    jr nz, L9ac4_return
#9a82#3082422
dd 2a 9d 74 
    ld ix, (L749d_object_currently_being_processed_ptr)
#9a86#308628
16 00 
    ld d, 0
#9a88#3088321
fd 46 00 
    ld b, (iy)
#9a8b#308b
    ; The following loop reads the texture IDs of each face and assigns them.
#9a8b#308b
    ; Each iteration of the loop has 2 parts:
#9a8b#308b
    ; - one reading the least significant nibble, and one reading the most significant one
#9a8b#308b
    ; - this is because each byte encodes the texture of two faces. So, each full loop
#9a8b#308b
    ;   assigns textures to two faces.
#9a8b#308b217
fd e5 
    push iy
#9a8d#308d212
fd 23 
        inc iy
#9a8f#308f
L9a8f:
#9a8f#308f321
dd 7e 09 
        ld a, (ix + OBJECT_ADDITIONAL_DATA)
#9a92#309228
e6 0f 
        and #0f
#9a94#3094321
fd 77 00 
        ld (iy), a
#9a97#3097321
fd 5e 01 
        ld e, (iy + 1)
#9a9a#309a15
1c 
        inc e
#9a9b#309b15
1c 
        inc e
#9a9c#309c217
fd 19 
        add iy, de
#9a9e#309e214/9
10 02 
        djnz L9aa2
#9aa0#30a0
        ; If the number of faces is odd, we will eventually end the loop here:
#9aa0#30a0213
18 1b 
        jr L9abd_pop_iy_project_object_and_return
#9aa2#30a2
L9aa2:
#9aa2#30a2321
dd 7e 09 
        ld a, (ix + OBJECT_ADDITIONAL_DATA)
#9aa5#30a528
e6 f0 
        and #f0
#9aa7#30a7210
cb 3f 
        srl a
#9aa9#30a9210
cb 3f 
        srl a
#9aab#30ab210
cb 3f 
        srl a
#9aad#30ad210
cb 3f 
        srl a
#9aaf#30af321
fd 77 00 
        ld (iy), a
#9ab2#30b2321
fd 5e 01 
        ld e, (iy + 1)
#9ab5#30b515
1c 
        inc e
#9ab6#30b615
1c 
        inc e
#9ab7#30b7217
fd 19 
        add iy, de
#9ab9#30b9212
dd 23 
        inc ix
#9abb#30bb214/9
10 d2 
        djnz L9a8f
#9abd#30bd
L9abd_pop_iy_project_object_and_return:
#9abd#30bd216
fd e1 
    pop iy
#9abf#30bf28
3e 01 
    ld a, 1
#9ac1#30c1318
cd b0 92 
    call L92b0_project_object_and_add_to_render_list
#9ac4#30c4
L9ac4_return:
#9ac4#30c4111
c9 
    ret
#9ac5#30c5
#9ac5#30c5
#9ac5#30c5
; --------------------------------
#9ac5#30c5
; - Computes the object bounding box in player-relative coordinates.
#9ac5#30c5
; - Then projects all the vertices from 3d to 2d.
#9ac5#30c5
; - If the object is within the viewport, it adds it to the rendering list.
#9ac5#30c5
; - Called to project objects with ID >= 10
#9ac5#30c5
; - When this function is called this has already happened:
#9ac5#30c5
;   - rendering cube volume has been calculated
#9ac5#30c5
;   - rotation matrix has already been set
#9ac5#30c5
;   - cube volume culling check has been done
#9ac5#30c5
;   - player_collision_with_object_flags has been set
#9ac5#30c5
;   - object bounding box coordinates relative to player have been stored in
#9ac5#30c5
;     (L7499_3d_object_bounding_box_relative_to_player_ptr)
#9ac5#30c5
L9ac5_project_flat_shape_object:
#9ac5#30c5422
dd 2a 9d 74 
    ld ix, (L749d_object_currently_being_processed_ptr)
#9ac9#30c9314
3a 61 5e 
    ld a, (L5e61_object_currently_being_processed_type)
#9acc#30cc28
d6 08 
    sub 8
#9ace#30ce314
32 96 74 
    ld (L7496_current_drawing_primitive_n_vertices), a
#9ad1#30d115
47 
    ld b, a
#9ad2#30d2321
dd 7e 09 
    ld a, (ix + 9)
#9ad5#30d5314
32 6a 74 
    ld (L746a_current_drawing_texture_id), a
#9ad8#30d8
#9ad8#30d8
    ; This loop calculates the object vertex coordinates, relative the the player by
#9ad8#30d8
    ; subtracting the player coordinates from them, and stores them in
#9ad8#30d8
    ; (L5e63_3d_vertex_coordinates_relative_to_player).
#9ad8#30d8416
fd 21 63 5e 
    ld iy, L5e63_3d_vertex_coordinates_relative_to_player
#9adc#30dc
L9adc_vertex_loop:
#9adc#30dc112
c5 
    push bc
#9add#30dd311
21 ad 6a 
        ld hl, L6aad_player_current_x
#9ae0#30e028
06 03 
        ld b, 3
#9ae2#30e2
        ; Iterate 3 times: one for x, one for y, one for z.
#9ae2#30e2
L9ae2_3_coordinates_loop:
#9ae2#30e218
5e 
        ld e, (hl)
#9ae3#30e317
23 
        inc hl
#9ae4#30e418
56 
        ld d, (hl)  ; de = player coordinate
#9ae5#30e517
23 
        inc hl
#9ae6#30e6112
e5 
        push hl
#9ae7#30e7321
dd 66 0a 
            ld h, (ix + 10)
#9aea#30ea28
2e 00 
            ld l, 0
#9aec#30ec210
cb 3c 
            srl h
#9aee#30ee210
cb 1d 
            rr l
#9af0#30f0210
cb 3c 
            srl h
#9af2#30f2210
cb 1d 
            rr l  ; hl = vertex coordinate * 64
#9af4#30f415
b7 
            or a
#9af5#30f5217
ed 52 
            sbc hl, de  ; subtract the player coordinate
#9af7#30f7321
fd 75 00 
            ld (iy), l
#9afa#30fa321
fd 74 01 
            ld (iy + 1), h
#9afd#30fd212
fd 23 
            inc iy
#9aff#30ff212
fd 23 
            inc iy
#9b01#3101212
dd 23 
            inc ix
#9b03#3103111
e1 
        pop hl
#9b04#3104214/9
10 dc 
        djnz L9ae2_3_coordinates_loop
#9b06#3106111
c1 
    pop bc
#9b07#3107214/9
10 d3 
    djnz L9adc_vertex_loop
#9b09#3109
#9b09#3109318
cd 0f 85 
    call L850f_apply_rotation_matrix_to_object_vertices
#9b0c#310c314
3a 96 74 
    ld a, (L7496_current_drawing_primitive_n_vertices)
#9b0f#310f318
cd 46 92 
    call L9246_object_visibility_check
#9b12#3112213/8
20 46 
    jr nz, L9b5a_object_not_visible
#9b14#3114416
fd 21 b0 6c 
    ld iy, L6cb0_face_definition_for_flat_objects
#9b18#3118314
3a 96 74 
    ld a, (L7496_current_drawing_primitive_n_vertices)
#9b1b#311b314
32 b2 6c 
    ld (L6cb0_face_definition_for_flat_objects + 2), a
#9b1e#311e28
fe 02 
    cp 2
#9b20#3120213/8
20 0e 
    jr nz, L9b30_more_than_2_vertexes
#9b22#3122
#9b22#3122
    ; Object is a line (2 vertexes):
#9b22#3122311
21 75 6c 
    ld hl, L6c75_line_edges
#9b25#3125314
3a 6a 74 
    ld a, (L746a_current_drawing_texture_id)
#9b28#312828
e6 0f 
    and #0f
#9b2a#312a314
32 b1 6c 
    ld (L6cb0_face_definition_for_flat_objects + 1), a
#9b2d#312d15
af 
    xor a
#9b2e#312e213
18 24 
    jr L9b54
#9b30#3130
#9b30#3130
L9b30_more_than_2_vertexes:
#9b30#3130
    ; Object has more than 2 vertexes:
#9b30#3130
#9b30#3130
    ; If it has 3 vertexes
#9b30#3130311
21 7a 6c 
    ld hl, L6c7a_triangle_edges_top
#9b33#3133311
11 81 6c 
    ld de, L6c81_triangle_edges_bottom
#9b36#313628
fe 03 
    cp 3
#9b38#3138213/8
28 10 
    jr z, L9b4a
#9b3a#313a
#9b3a#313a
    ; If it has 4 vertexes
#9b3a#313a311
21 88 6c 
    ld hl, L6c88_rectangle_edges_top
#9b3d#313d311
11 91 6c 
    ld de, L6c91_rectangle_edges_bottom
#9b40#314028
fe 04 
    cp 4
#9b42#3142213/8
28 06 
    jr z, L9b4a  ; If it has 4 vertexes
#9b44#3144
#9b44#3144
    ; If it has 5 vertexes
#9b44#3144311
21 9a 6c 
    ld hl, L6c9a_pentagon_edges_top
#9b47#3147311
11 a5 6c 
    ld de, L6ca5_pentagon_edges_bottom
#9b4a#314a
L9b4a:
#9b4a#314a421
fd 36 01 01 
    ld (iy + 1), 1  ; L6cb0_face_definition_for_flat_objects + 1
#9b4e#314e422
ed 53 26 5f 
    ld (L5f26_alternative_shape_edges_ptr), de
#9b52#315228
3e 02 
    ld a, 2
#9b54#3154
L9b54:
#9b54#3154317
22 24 5f 
    ld (L5f24_shape_edges_ptr), hl
#9b57#3157318
cd b0 92 
    call L92b0_project_object_and_add_to_render_list
#9b5a#315a
L9b5a_object_not_visible:
#9b5a#315a111
c9 
    ret
#9b5b#315b
#9b5b#315b
#9b5b#315b
; --------------------------------
#9b5b#315b
; Projects a rectangle. Using the object bounding box, generates the 3d vertices for a rectangle, and
#9b5b#315b
; then calls the projection method for adding them to the render list.
#9b5b#315b
; Called to project objects with type "OBJECT_TYPE_RECTANGLE"
#9b5b#315b
; - When this function is called this has already happened:
#9b5b#315b
;   - rendering cube volume has been calculated
#9b5b#315b
;   - rotation matrix has already been set
#9b5b#315b
;   - cube volume culling check has been done
#9b5b#315b
;   - player_collision_with_object_flags has been set
#9b5b#315b
;   - object bounding box coordinates relative to player have been stored in
#9b5b#315b
;     (L7499_3d_object_bounding_box_relative_to_player_ptr)
#9b5b#315b
L9b5b_project_rectangle_objects:
#9b5b#315b422
fd 2a 9d 74 
    ld iy, (L749d_object_currently_being_processed_ptr)
#9b5f#315f314
3a 62 5e 
    ld a, (L5e62_player_collision_with_object_flags)
#9b62#316215
4f 
    ld c, a
#9b63#3163321
fd 7e 04 
    ld a, (iy + OBJECT_SIZE_X)
#9b66#3166321
fd 46 05 
    ld b, (iy + OBJECT_SIZE_Y)
#9b69#3169321
fd 56 09 
    ld d, (iy + OBJECT_ADDITIONAL_DATA)
#9b6c#316c
    ; Assume x == 0
#9b6c#316c416
dd 21 6f 5e 
    ld ix, L5e63_3d_vertex_coordinates_relative_to_player + 6 * 2  ; vertex 3
#9b70#3170416
fd 21 69 5e 
    ld iy, L5e63_3d_vertex_coordinates_relative_to_player + 3 * 2  ; vertex 2
#9b74#317415
b7 
    or a
#9b75#3175213/8
28 1c 
    jr z, L9b93_rectangle_orientation_set  ; If rectangle has size x == 0, we guessed right
#9b77#3177
    ; Rectangle has size x != 0:
#9b77#3177
    ; Assume y == 0
#9b77#3177416
dd 21 63 5e 
    ld ix, L5e63_3d_vertex_coordinates_relative_to_player  ; vertex 1
#9b7b#317b416
fd 21 6f 5e 
    ld iy, L5e63_3d_vertex_coordinates_relative_to_player + 6 * 2  ; vertex 3
#9b7f#317f210
cb 39 
    srl c
#9b81#3181210
cb 39 
    srl c
#9b83#318315
78 
    ld a, b
#9b84#318415
b7 
    or a
#9b85#3185213/8
28 0c 
    jr z, L9b93_rectangle_orientation_set  ; If rectangle has size y == 0, we guessed right
#9b87#3187
    ; Rectangle is vertical (has size y != 0):
#9b87#3187416
dd 21 69 5e 
    ld ix, L5e63_3d_vertex_coordinates_relative_to_player + 3 * 2  ; vertex 3
#9b8b#318b416
fd 21 63 5e 
    ld iy, L5e63_3d_vertex_coordinates_relative_to_player  ; vertex 1
#9b8f#318f210
cb 39 
    srl c
#9b91#3191210
cb 39 
    srl c
#9b93#3193
L9b93_rectangle_orientation_set:
#9b93#3193
    ; At this point:
#9b93#3193
    ; - ix, iy point to the two vertexes we need to edit
#9b93#3193
    ; - the lowest 2 bits of c indicate the player collision wrt to the flat dimension of the rectangle.
#9b93#319315
7a 
    ld a, d  ; a == object additional data.
#9b94#3194210
cb 41 
    bit 0, c  ; Check if player is above or below the rectangle
#9b96#3196213/8
28 0a 
    jr z, L9ba2
#9b98#3198
    ; Player is above the rectangle:
#9b98#319828
e6 0f 
    and #0f  ; get rectangle attribute (top face)
#9b9a#319a311
ca 2c 9c 
    jp z, L9c2c_return  ; If it's transparent, we are done
#9b9d#319d311
21 91 6c 
    ld hl, L6c91_rectangle_edges_bottom
#9ba0#31a0213
18 10 
    jr L9bb2_attribute_obtained
#9ba2#31a2
L9ba2:
#9ba2#31a228
e6 f0 
    and #f0  ; get rectangle attribute (bottom face)
#9ba4#31a4311
ca 2c 9c 
    jp z, L9c2c_return  ; If it's transparent, we are done
#9ba7#31a7210
cb 3f 
    srl a
#9ba9#31a9210
cb 3f 
    srl a
#9bab#31ab210
cb 3f 
    srl a
#9bad#31ad210
cb 3f 
    srl a  ; shift the attribute/texture to be in the lowest 4 bits.
#9baf#31af311
21 88 6c 
    ld hl, L6c88_rectangle_edges_top
#9bb2#31b2
L9bb2_attribute_obtained:
#9bb2#31b2
    ; At this point:
#9bb2#31b2
    ; - ix, iy point to the two vertexes we need to edit
#9bb2#31b2
    ; - a: attribute (texture) to use
#9bb2#31b2
    ; - hl: edge pointer
#9bb2#31b2314
32 b1 6c 
    ld (L6cb0_face_definition_for_flat_objects + 1), a
#9bb5#31b5317
22 24 5f 
    ld (L5f24_shape_edges_ptr), hl
#9bb8#31b8
#9bb8#31b8
    ; Generate the 4 vertices of the rectangle, based on the information above:
#9bb8#31b8217
dd e5 
    push ix
#9bba#31ba217
fd e5 
    push iy
#9bbc#31bc318
cd 77 91 
        call L9177_rotate_relative_bounding_box
#9bbf#31bf216
fd e1 
    pop iy
#9bc1#31c1216
dd e1 
    pop ix
#9bc3#31c3317
2a 9f 5e 
    ld hl, (L5e9f_3d_vertex_coordinates_after_rotation_matrix)
#9bc6#31c6321
dd 5e 00 
    ld e, (ix)
#9bc9#31c9321
dd 56 01 
    ld d, (ix + 1)
#9bcc#31cc112
19 
    add hl, de
#9bcd#31cd317
22 a5 5e 
    ld (L5e9f_3d_vertex_coordinates_after_rotation_matrix + 3 * 2), hl
#9bd0#31d0321
fd 4e 00 
    ld c, (iy)
#9bd3#31d3321
fd 46 01 
    ld b, (iy + 1)
#9bd6#31d6112
09 
    add hl, bc
#9bd7#31d7317
22 ab 5e 
    ld (L5e9f_3d_vertex_coordinates_after_rotation_matrix + 6 * 2), hl
#9bda#31da15
b7 
    or a
#9bdb#31db217
ed 52 
    sbc hl, de
#9bdd#31dd317
22 b1 5e 
    ld (L5e9f_3d_vertex_coordinates_after_rotation_matrix + 9 * 2), hl
#9be0#31e0317
2a a1 5e 
    ld hl, (L5e9f_3d_vertex_coordinates_after_rotation_matrix + 1 * 2)
#9be3#31e3321
dd 5e 02 
    ld e, (ix + 2)
#9be6#31e6321
dd 56 03 
    ld d, (ix + 3)
#9be9#31e9112
19 
    add hl, de
#9bea#31ea317
22 a7 5e 
    ld (L5e9f_3d_vertex_coordinates_after_rotation_matrix + 4 * 2), hl
#9bed#31ed321
fd 4e 02 
    ld c, (iy + 2)
#9bf0#31f0321
fd 46 03 
    ld b, (iy + 3)
#9bf3#31f3112
09 
    add hl, bc
#9bf4#31f4317
22 ad 5e 
    ld (L5e9f_3d_vertex_coordinates_after_rotation_matrix + 7 * 2), hl
#9bf7#31f715
b7 
    or a
#9bf8#31f8217
ed 52 
    sbc hl, de
#9bfa#31fa317
22 b3 5e 
    ld (L5e9f_3d_vertex_coordinates_after_rotation_matrix + 10 * 2), hl
#9bfd#31fd317
2a a3 5e 
    ld hl, (L5e9f_3d_vertex_coordinates_after_rotation_matrix + 2 * 2)
#9c00#3200321
dd 5e 04 
    ld e, (ix + 4)
#9c03#3203321
dd 56 05 
    ld d, (ix + 5)
#9c06#3206112
19 
    add hl, de
#9c07#3207317
22 a9 5e 
    ld (L5e9f_3d_vertex_coordinates_after_rotation_matrix + 5 * 2), hl
#9c0a#320a321
fd 4e 04 
    ld c, (iy + 4)
#9c0d#320d321
fd 46 05 
    ld b, (iy + 5)
#9c10#3210112
09 
    add hl, bc
#9c11#3211317
22 af 5e 
    ld (L5e9f_3d_vertex_coordinates_after_rotation_matrix + 8 * 2), hl
#9c14#321415
b7 
    or a
#9c15#3215217
ed 52 
    sbc hl, de
#9c17#3217317
22 b5 5e 
    ld (L5e9f_3d_vertex_coordinates_after_rotation_matrix + 11 * 2), hl
#9c1a#321a28
3e 04 
    ld a, 4
#9c1c#321c314
32 b2 6c 
    ld (L6cb0_face_definition_for_flat_objects + 2), a  ; Number of vertices of this object.
#9c1f#321f318
cd 46 92 
    call L9246_object_visibility_check
#9c22#3222213/8
20 08 
    jr nz, L9c2c_return
#9c24#322415
af 
    xor a
#9c25#3225416
fd 21 b0 6c 
    ld iy, L6cb0_face_definition_for_flat_objects
#9c29#3229318
cd b0 92 
    call L92b0_project_object_and_add_to_render_list
#9c2c#322c
L9c2c_return:
#9c2c#322c111
c9 
    ret
#9c2d#322d
#9c2d#322d
#9c2d#322d
; --------------------------------
#9c2d#322d
; Sorts the projected objects in the order we shoulr render them using bubble sort.
#9c2d#322d
L9c2d_sort_objects_for_rendering:
#9c2d#322d314
3a 6b 74 
    ld a, (L746b_n_objects_to_draw)
#9c30#3230112
f5 
    push af
#9c31#3231
L9c31_whole_object_pass_loop:
#9c31#3231111
f1 
    pop af
#9c32#323215
3d 
    dec a
#9c33#3233311
ca 45 9d 
    jp z, L9d45_ret
#9c36#3236311
fa 45 9d 
    jp m, L9d45_ret
#9c39#3239112
f5 
    push af
#9c3a#323a311
21 56 67 
        ld hl, L6754_current_room_object_projected_data + 2
#9c3d#323d
        ; Initialize the flag that will trigger another sorting iteration:
#9c3d#323d15
af 
        xor a
#9c3e#323e314
32 32 5f 
        ld (L5f32_sorting_any_change), a
#9c41#3241314
3a 6b 74 
        ld a, (L746b_n_objects_to_draw)
#9c44#324415
3d 
        dec a  ; Iterate for n_objects - 1 (since we are comparing one object with the next for sorting).
#9c45#3245
L9c45_objects_loop:
#9c45#3245112
f5 
        push af
#9c46#3246112
e5 
            push hl
#9c47#3247
                ; Get the pointer to bounding box from the first object:
#9c47#324718
5e 
                ld e, (hl)
#9c48#324817
23 
                inc hl
#9c49#324918
56 
                ld d, (hl)
#9c4a#324a422
ed 53 33 5f 
                ld (L5f33_sorting_boundingbox_ptr1), de
#9c4e#324e17
23 
                inc hl
#9c4f#324f
                ; Get the pointer to bounding box from the second object:
#9c4f#324f17
23 
                inc hl  ; skip the vertex pointer
#9c50#325017
23 
                inc hl
#9c51#325118
5e 
                ld e, (hl)
#9c52#325217
23 
                inc hl
#9c53#325318
56 
                ld d, (hl)
#9c54#3254422
ed 53 35 5f 
                ld (L5f35_sorting_boundingbox_ptr2), de
#9c58#325815
af 
                xor a
#9c59#3259314
32 31 5f 
                ld (L5f31_sorting_comparison_result), a
#9c5c#325c422
dd 2a 33 5f 
                ld ix, (L5f33_sorting_boundingbox_ptr1)  ; ptr to object 1 bounding box (relative to player)
#9c60#3260422
fd 2a 35 5f 
                ld iy, (L5f35_sorting_boundingbox_ptr2)  ; ptr to object 2 bounding box (relative to player)
#9c64#326428
06 03 
                ld b, 3
#9c66#3266
                ; 3 iterations, one for X, onr for Y, one for Z:
#9c66#3266
                ; I annotated the coordinates as "x1", "x2" below, but that's only for the first
#9c66#3266
                ; iteration, after that it's y1, y2, and then z1, z2.
#9c66#3266
L9c66_bounding_box_axis_loop:
#9c66#3266
                ; Each iteration writes 2 bits, so, shift this 2 bits to the left:
#9c66#3266311
21 31 5f 
                ld hl, L5f31_sorting_comparison_result
#9c69#326918
7e 
                ld a, (hl)
#9c6a#326a15
87 
                add a, a
#9c6b#326b15
87 
                add a, a
#9c6c#326c18
77 
                ld (hl), a
#9c6d#326d
#9c6d#326d321
fd 56 03 
                ld d, (iy + 3)
#9c70#3270321
fd 5e 02 
                ld e, (iy + 2)  ; de = bbox2.x2
#9c73#3273422
ed 53 3d 5f 
                ld (L5f3d_sorting_bbox2_c2), de
#9c77#3277321
dd 66 01 
                ld h, (ix + 1)
#9c7a#327a321
dd 6e 00 
                ld l, (ix)  ; hl = bbox1.x1
#9c7d#327d317
22 37 5f 
                ld (L5f37_sorting_bbox1_c1), hl
#9c80#328015
b7 
                or a
#9c81#3281217
ed 52 
                sbc hl, de  ; hl = bbox1.x1 - bbox2.x2 (only used to check which is larger)
#9c83#3283321
dd 56 03 
                ld d, (ix + 3)
#9c86#3286321
dd 5e 02 
                ld e, (ix + 2)  ; de = bbox1.x2
#9c89#3289321
fd 66 01 
                ld h, (iy + 1)
#9c8c#328c321
fd 6e 00 
                ld l, (iy)  ; hl = bbox2.x1
#9c8f#328f317
22 39 5f 
                ld (L5f39_sorting_bbox2_c1), hl
#9c92#3292311
f2 9b 9c 
                jp p, L9c9b_one_object_clearly_further_than_the_other
#9c95#329515
b7 
                or a
#9c96#3296217
ed 52 
                sbc hl, de  ; hl = bbox2.x1 - bbox1.x2
#9c98#3298311
fa f3 9c 
                jp m, L9cf3_objects_incomparable_in_this_axis
#9c9b#329b
#9c9b#329b
L9c9b_one_object_clearly_further_than_the_other:
#9c9b#329b422
ed 53 3b 5f 
                ld (L5f3b_sorting_bbox1_c2), de  ; bbox1.x2
#9c9f#329f314
3a 38 5f 
                ld a, (L5f37_sorting_bbox1_c1 + 1)  ; bbox1.x1
#9ca2#32a228
e6 80 
                and #80  ; keep the sign
#9ca4#32a415
5f 
                ld e, a  ; sign of bbox1.x1
#9ca5#32a515
7a 
                ld a, d
#9ca6#32a628
e6 80 
                and #80  ; keep the sign
#9ca8#32a815
bb 
                cp e
#9ca9#32a9
                ; If pbject 1 has a bounding box that covers the 0 coordinate, and does not overlap with the other object,
#9ca9#32a9
                ; it must be clsoer to the player in this axis:
#9ca9#32a9213/8
20 3b 
                jr nz, L9ce6_first_object_is_closer
#9cab#32ab
                ; Object 1 is completely to one side of the player, not directly in front:
#9cab#32ab314
3a 3e 5f 
                ld a, (L5f3d_sorting_bbox2_c2 + 1)
#9cae#32ae28
e6 80 
                and #80  ; keep the sign
#9cb0#32b015
57 
                ld d, a
#9cb1#32b1314
3a 3a 5f 
                ld a, (L5f39_sorting_bbox2_c1 + 1)
#9cb4#32b428
e6 80 
                and #80  ; keep the sign
#9cb6#32b615
ba 
                cp d
#9cb7#32b7
                ; If pbject 2 has a bounding box that covers the 0 coordinate, and does not overlap with the other object,
#9cb7#32b7
                ; it must be clsoer to the player in this axis:
#9cb7#32b7213/8
20 33 
                jr nz, L9cec_second_object_is_closer
#9cb9#32b9
#9cb9#32b9
                ; Object 2 is completely to one side of the player, not directly in front:
#9cb9#32b915
bb 
                cp e
#9cba#32ba
                ; if each object is in a different side, we cannot make any judgement
#9cba#32ba213/8
20 37 
                jr nz, L9cf3_objects_incomparable_in_this_axis
#9cbc#32bc
#9cbc#32bc
                ; Both objects are on the same side of the player:
#9cbc#32bc
                ; Compare their coordinates and check which is closer (taking into acount the sign):
#9cbc#32bc422
ed 5b 37 5f 
                ld de, (L5f37_sorting_bbox1_c1)
#9cc0#32c0317
2a 39 5f 
                ld hl, (L5f39_sorting_bbox2_c1)
#9cc3#32c315
7c 
                ld a, h
#9cc4#32c428
e6 80 
                and #80  ; keep the sign
#9cc6#32c6217
ed 52 
                sbc hl, de
#9cc8#32c8213/8
28 09 
                jr z, L9cd3
#9cca#32ca15
6f 
                ld l, a
#9ccb#32cb15
7c 
                ld a, h
#9ccc#32cc28
e6 80 
                and #80  ; keep the sign
#9cce#32ce15
bd 
                cp l
#9ccf#32cf213/8
28 15 
                jr z, L9ce6_first_object_is_closer
#9cd1#32d1213
18 19 
                jr L9cec_second_object_is_closer
#9cd3#32d3
L9cd3:
#9cd3#32d3317
2a 3d 5f 
                ld hl, (L5f3d_sorting_bbox2_c2)
#9cd6#32d6422
ed 5b 3b 5f 
                ld de, (L5f3b_sorting_bbox1_c2)
#9cda#32da15
7c 
                ld a, h
#9cdb#32db28
e6 80 
                and #80  ; keep the sign
#9cdd#32dd217
ed 52 
                sbc hl, de
#9cdf#32df15
6f 
                ld l, a
#9ce0#32e015
7c 
                ld a, h
#9ce1#32e128
e6 80 
                and #80  ; keep the sign
#9ce3#32e315
bd 
                cp l
#9ce4#32e4213/8
20 06 
                jr nz, L9cec_second_object_is_closer
#9ce6#32e6
L9ce6_first_object_is_closer:
#9ce6#32e6311
21 31 5f 
                ld hl, L5f31_sorting_comparison_result
#9ce9#32e9112
34 
                inc (hl)  ; mark object 1 closer
#9cea#32ea213
18 07 
                jr L9cf3_objects_incomparable_in_this_axis
#9cec#32ec
L9cec_second_object_is_closer:
#9cec#32ec311
21 31 5f 
                ld hl, L5f31_sorting_comparison_result
#9cef#32ef18
7e 
                ld a, (hl)
#9cf0#32f028
f6 02 
                or 2  ; mark object 2 closer
#9cf2#32f218
77 
                ld (hl), a
#9cf3#32f3
L9cf3_objects_incomparable_in_this_axis:
#9cf3#32f3
                ; We cannot make any judgement, just move to the next object:
#9cf3#32f3311
11 04 00 
                ld de, 4
#9cf6#32f6217
dd 19 
                add ix, de
#9cf8#32f8217
fd 19 
                add iy, de
#9cfa#32fa15
05 
                dec b
#9cfb#32fb311
c2 66 9c 
                jp nz, L9c66_bounding_box_axis_loop
#9cfe#32fe28
0e 04 
                ld c, 4
#9d00#3300111
e1 
            pop hl
#9d01#3301314
3a 31 5f 
            ld a, (L5f31_sorting_comparison_result)
#9d04#3304
            ; If object 2 is clearly closer in one axis, keep order as is:
#9d04#330428
fe 20 
            cp #20
#9d06#3306213/8
28 2f 
            jr z, L9d37_next_object
#9d08#330828
fe 08 
            cp #08
#9d0a#330a213/8
28 2b 
            jr z, L9d37_next_object
#9d0c#330c28
fe 02 
            cp #02
#9d0e#330e213/8
28 27 
            jr z, L9d37_next_object
#9d10#3310
            ; If object 2 is clearly closer in more than one axis, also keep order as is:
#9d10#331028
fe 28 
            cp #28
#9d12#3312213/8
28 23 
            jr z, L9d37_next_object
#9d14#331428
fe 0a 
            cp #0a
#9d16#3316213/8
28 1f 
            jr z, L9d37_next_object
#9d18#331828
fe 22 
            cp #22
#9d1a#331a213/8
28 1b 
            jr z, L9d37_next_object
#9d1c#331c28
fe 2a 
            cp #2a
#9d1e#331e
#9d1e#331e
            ; If we could not make any decision, keep order as is:
#9d1e#331e213/8
28 17 
            jr z, L9d37_next_object
#9d20#3320
#9d20#3320
            ; Otherwise, swap objects:
#9d20#332028
3e 01 
            ld a, 1
#9d22#3322314
32 32 5f 
            ld (L5f32_sorting_any_change), a
#9d25#332515
54 
            ld d, h
#9d26#332615
5d 
            ld e, l
#9d27#332717
2b 
            dec hl
#9d28#332817
2b 
            dec hl
#9d29#332917
13 
            inc de
#9d2a#332a17
13 
            inc de
#9d2b#332b15
41 
            ld b, c  ; b = 4
#9d2c#332c
            ; To flip the objects, we just need to flip the two pointers,
#9d2c#332c
            ; the one to vertices, and the one to the bounding boxes.
#9d2c#332c
L9d2c_flip_objects_loop:
#9d2c#332c18
4e 
            ld c, (hl)
#9d2d#332d18
1a 
            ld a, (de)
#9d2e#332e18
77 
            ld (hl), a
#9d2f#332f15
79 
            ld a, c
#9d30#333018
12 
            ld (de), a
#9d31#333117
23 
            inc hl
#9d32#333217
13 
            inc de
#9d33#3333214/9
10 f7 
            djnz L9d2c_flip_objects_loop
#9d35#333528
0e 02 
            ld c, 2
#9d37#3337
L9d37_next_object:
#9d37#3337112
09 
            add hl, bc
#9d38#3338111
f1 
        pop af
#9d39#333915
3d 
        dec a
#9d3a#333a311
c2 45 9c 
        jp nz, L9c45_objects_loop
#9d3d#333d314
3a 32 5f 
        ld a, (L5f32_sorting_any_change)
#9d40#334015
b7 
        or a
#9d41#3341311
c2 31 9c 
        jp nz, L9c31_whole_object_pass_loop  ; if any change has happened, we need to do another pass
#9d44#3344111
f1 
    pop af
#9d45#3345
L9d45_ret:
#9d45#3345111
c9 
    ret
#9d46#3346
#9d46#3346
#9d46#3346
; --------------------------------
#9d46#3346
; Renders all the objects in the current room, and potentially the background, if necessary.
#9d46#3346
; After rendering the room, it overlays the movement pointer if active.
#9d46#3346
L9d46_render_3d_view:
#9d46#3346314
3a 6b 74 
    ld a, (L746b_n_objects_to_draw)
#9d49#334915
57 
    ld d, a
#9d4a#334a314
3a 81 74 
    ld a, (L7481_n_objects_covering_the_whole_screen)
#9d4d#334d15
b7 
    or a
#9d4e#334e213/8
28 23 
    jr z, L9d73_do_not_skip_objects
#9d50#3350314
32 3f 5f 
    ld (L5f3f_n_objects_covering_the_whole_screen_left), a
#9d53#3353
    ; When there are obejcts covering the whole screen, there is no point drawing everything that
#9d53#3353
    ; is behind them, so, we skip all objects until we reach those:
#9d53#3353311
21 54 67 
    ld hl, L6754_current_room_object_projected_data
#9d56#3356
L9d56_skip_object_loop:
#9d56#335618
4e 
    ld c, (hl)
#9d57#335717
23 
    inc hl
#9d58#335818
46 
    ld b, (hl)
#9d59#335917
23 
    inc hl
#9d5a#335a17
23 
    inc hl
#9d5b#335b17
23 
    inc hl
#9d5c#335c17
03 
    inc bc
#9d5d#335d18
0a 
    ld a, (bc)  ; number of primitives
#9d5e#335e15
b7 
    or a
#9d5f#335f213/8
28 0d 
    jr z, L9d6e
#9d61#3361210
cb 7f 
    bit 7, a
#9d63#3363213/8
28 09 
    jr z, L9d6e
#9d65#3365314
3a 3f 5f 
    ld a, (L5f3f_n_objects_covering_the_whole_screen_left)
#9d68#336815
3d 
    dec a
#9d69#3369314
32 3f 5f 
    ld (L5f3f_n_objects_covering_the_whole_screen_left), a
#9d6c#336c213/8
28 16 
    jr z, L9d84_objects_loop_entry_point
#9d6e#336e
L9d6e:
#9d6e#336e15
15 
    dec d
#9d6f#336f213/8
28 3d 
    jr z, L9dae_done_drawing_objects
#9d71#3371213
18 e3 
    jr L9d56_skip_object_loop
#9d73#3373
#9d73#3373
L9d73_do_not_skip_objects:
#9d73#3373
    ; Note: the background (including the skybox) is only drawn when
#9d73#3373
    ; there are no objects to skip, which is interesting.
#9d73#3373318
cd ff a2 
    call La2ff_render_background
#9d76#3376311
21 54 67 
    ld hl, L6754_current_room_object_projected_data
#9d79#3379
L9d79_objects_loop:
#9d79#337915
7a 
    ld a, d
#9d7a#337a15
b7 
    or a
#9d7b#337b213/8
28 31 
    jr z, L9dae_done_drawing_objects
#9d7d#337d
    ; Get the pointer to the primitive (vertex) data:
#9d7d#337d18
4e 
    ld c, (hl)
#9d7e#337e17
23 
    inc hl
#9d7f#337f18
46 
    ld b, (hl)
#9d80#338017
23 
    inc hl
#9d81#338117
23 
    inc hl
#9d82#338217
23 
    inc hl
#9d83#338317
03 
    inc bc  ; skip object ID
#9d84#3384
L9d84_objects_loop_entry_point:
#9d84#338418
0a 
    ld a, (bc)
#9d85#338515
b7 
    or a  ; number of primitives to draw
#9d86#3386213/8
28 23 
    jr z, L9dab_done_drawing_object
#9d88#338828
e6 7f 
    and #7f
#9d8a#338a17
03 
    inc bc  ; skip the number of primitives byte
#9d8b#338b112
c5 
    push bc
#9d8c#338c216
dd e1 
    pop ix
#9d8e#338e15
47 
    ld b, a
#9d8f#338f
    ; b: number of primitives to draw for the current object.
#9d8f#338f
L9d8f_primitive_loop:
#9d8f#338f321
dd 7e 00 
    ld a, (ix)
#9d92#3392
    ; Read object type and texture:
#9d92#3392
    ; a = xxxxyyyy: 'xxxx' is the texture ID, 'yyyy' is the number of vertices.
#9d92#3392212
dd 23 
    inc ix
#9d94#339415
4f 
    ld c, a
#9d95#3395210
cb 3f 
    srl a
#9d97#3397210
cb 3f 
    srl a
#9d99#3399210
cb 3f 
    srl a
#9d9b#339b210
cb 3f 
    srl a
#9d9d#339d314
32 6a 74 
    ld (L746a_current_drawing_texture_id), a
#9da0#33a015
79 
    ld a, c
#9da1#33a128
e6 0f 
    and #0f
#9da3#33a3314
32 96 74 
    ld (L7496_current_drawing_primitive_n_vertices), a
#9da6#33a6318
cd ec 92 
    call L92ec_draw_primitive
#9da9#33a9214/9
10 e4 
    djnz L9d8f_primitive_loop
#9dab#33ab
L9dab_done_drawing_object:
#9dab#33ab15
15 
    dec d
#9dac#33ac213
18 cb 
    jr L9d79_objects_loop
#9dae#33ae
L9dae_done_drawing_objects:
#9dae#33ae314
3a 1c 6b 
    ld a, (L6b1c_movement_or_pointer)
#9db1#33b115
b7 
    or a
#9db2#33b2213/8
20 07 
    jr nz, L9dbb
#9db4#33b4314
3a 20 6b 
    ld a, (L6b20_display_movement_pointer_flag)
#9db7#33b715
b7 
    or a
#9db8#33b8318/11
c4 8c cd 
    call nz, Lcd8c_draw_movement_center_pointer
#9dbb#33bb
L9dbb:
#9dbb#33bb111
c9 
    ret
#9dbc#33bc
#9dbc#33bc
#9dbc#33bc
; --------------------------------
#9dbc#33bc
; Changes the viewport attributes if necessary, and renders the render buffer to
#9dbc#33bc
; video memory.
#9dbc#33bc
; Also, if requested via 'L7477_render_buffer_effect', it applies an effect such
#9dbc#33bc
; as fade-in, or opening/closing the gate over the viewport.
#9dbc#33bc
L9dbc_render_buffer_with_effects:
#9dbc#33bc112
f5 
    push af
#9dbd#33bd314
3a 69 74 
        ld a, (L7469_n_spirits_found_in_current_area)
#9dc0#33c0314
32 2a 6b 
        ld (L6b2a_spirit_in_room), a
#9dc3#33c3314
3a 66 74 
        ld a, (L7466_need_attribute_refresh_flag)
#9dc6#33c615
b7 
        or a
#9dc7#33c7318/11
c4 52 b2 
        call nz, Lb252_set_screen_area_attributes
#9dca#33ca314
3a 77 74 
        ld a, (L7477_render_buffer_effect)
#9dcd#33cd15
b7 
        or a
#9dce#33ce213/8
20 06 
        jr nz, L9dd6_render_effect
#9dd0#33d0318
cd 98 a2 
        call La298_render_buffer_render
#9dd3#33d3311
c3 df 9d 
        jp L9ddf
#9dd6#33d6
L9dd6_render_effect:
#9dd6#33d628
fe 01 
        cp 1
#9dd8#33d8318/11
cc 79 b5 
        call z, Lb579_render_buffer_fade_in
#9ddb#33db15
37 
        scf
#9ddc#33dc318/11
c4 09 ce 
        call nz, Lce09_gate_open_close_effect
#9ddf#33df
L9ddf:
#9ddf#33df318
cd 48 b5 
        call Lb548_draw_pointer_if_pointer_mode
#9de2#33e2111
f1 
    pop af
#9de3#33e3111
c9 
    ret
#9de4#33e4
#9de4#33e4
#9de4#33e4
; --------------------------------
#9de4#33e4
; Variables used by "L9dec_game_tick".
#9de4#33e4
L9de4_pressed_keys_functions:
#9de4#33e45
    db #e6, #7f, #03, #c5, #dd  ; Stores the game functions of all the keys currently held down by the player.
#9de9#33e9
L9de9_current_key_index:
#9de9#33e91
    db #e1
#9dea#33ea
L9dea_game_over_reason_message:
#9dea#33ea
    ; If you die, this contains the reason for which you died.
#9dea#33ea2
    db #47, #dd
#9dec#33ec
#9dec#33ec
#9dec#33ec
; --------------------------------
#9dec#33ec
; Executes one game update tick:
#9dec#33ec
; - Reads player input from keyboard/joystick
#9dec#33ec
; - Executes the desired actions
#9dec#33ec
; - Checks if the game is over and displays game over screen
#9dec#33ec
L9dec_game_tick:
#9dec#33ec311
21 00 00 
    ld hl, 0
#9def#33ef317
22 6c 74 
    ld (L746c_game_flags), hl
#9df2#33f215
7c 
    ld a, h
#9df3#33f3314
32 80 74 
    ld (L7480_under_pointer_object_ID), a
#9df6#33f6314
32 77 74 
    ld (L7477_render_buffer_effect), a  ; no render effect
#9df9#33f9314
32 7f 74 
    ld (L747f_player_event), a
#9dfc#33fc314
32 73 74 
    ld (L7473_timer_event), a
#9dff#33ff314
32 7a 74 
    ld (L747a_requested_SFX), a
#9e02#3402314
32 76 74 
    ld (L7476_trigger_collision_event_flag), a
#9e05#3405314
32 2b 6b 
    ld (L6b2b_desired_eye_compass_frame), a
#9e08#3408314
32 e9 9d 
    ld (L9de9_current_key_index), a
#9e0b#340b314
3a 0e 6b 
    ld a, (L6b0e_lightning_time_seconds_countdown)
#9e0e#340e15
b7 
    or a
#9e0f#340f213/8
20 42 
    jr nz, L9e53_countdown_not_zero
#9e11#3411
    ; Each time the second countdown reaches zero, if (L6b19_current_area_flags) is != 0, there is a lightning
#9e11#3411211
ed 5f 
    ld a, r
#9e13#341328
e6 3f 
    and #3f
#9e15#341528
c6 0a 
    add a, 10
#9e17#3417314
32 0e 6b 
    ld (L6b0e_lightning_time_seconds_countdown), a  ; (L6b0e_lightning_time_seconds_countdown) = 10 + randint(0, 64)
#9e1a#341a314
3a 19 6b 
    ld a, (L6b19_current_area_flags)
#9e1d#341d15
b7 
    or a
#9e1e#341e213/8
28 33 
    jr z, L9e53_countdown_not_zero
#9e20#3420314
3a dd 6a 
    ld a, (L6add_desired_attribute_color)
#9e23#3423112
f5 
    push af
#9e24#3424
        ; Change attributes, and wait for one interrupt:
#9e24#342428
e6 c7 
        and #c7
#9e26#342628
f6 38 
        or #38
#9e28#3428314
32 dd 6a 
        ld (L6add_desired_attribute_color), a
#9e2b#342b15
af 
        xor a
#9e2c#342c314
32 78 74 
        ld (L7478_interrupt_executed_flag), a
#9e2f#342f
L9e2f_wait_for_interrupt_loop:
#9e2f#342f314
3a 78 74 
        ld a, (L7478_interrupt_executed_flag)
#9e32#343215
b7 
        or a
#9e33#3433213/8
28 fa 
        jr z, L9e2f_wait_for_interrupt_loop
#9e35#3435318
cd 52 b2 
        call Lb252_set_screen_area_attributes
#9e38#3438111
f1 
    pop af
#9e39#3439
    ; Restore attributes, and wait for another interrupt:
#9e39#3439314
32 dd 6a 
    ld (L6add_desired_attribute_color), a
#9e3c#343c15
af 
    xor a
#9e3d#343d314
32 78 74 
    ld (L7478_interrupt_executed_flag), a
#9e40#3440
L9e40_wait_for_interrupt_loop:
#9e40#3440314
3a 78 74 
    ld a, (L7478_interrupt_executed_flag)
#9e43#344315
b7 
    or a
#9e44#3444213/8
28 fa 
    jr z, L9e40_wait_for_interrupt_loop
#9e46#3446318
cd 52 b2 
    call Lb252_set_screen_area_attributes
#9e49#3449
#9e49#344928
3e 08 
    ld a, SFX_LIGHTNING
#9e4b#344b318
cd ca c4 
    call Lc4ca_play_SFX
#9e4e#344e28
3e 08 
    ld a, 8
#9e50#3450314
32 6d 74 
    ld (L746c_game_flags + 1), a
#9e53#3453
#9e53#3453
L9e53_countdown_not_zero:
#9e53#3453314
3a e2 6a 
    ld a, (L6adf_game_boolean_variables + 3)
#9e56#3456210
cb 77 
    bit 6, a
#9e58#3458213/8
28 09 
    jr z, L9e63
#9e5a#345a28
3e 05 
    ld a, GAME_OVER_REASON_ESCAPED
#9e5c#345c314
32 79 74 
    ld (L7479_current_game_state), a
#9e5f#345f112
f5 
    push af
#9e60#3460311
c3 25 9f 
        jp L9f25_game_over
#9e63#3463
L9e63:
#9e63#3463314
3a 75 74 
    ld a, (L7475_call_Lcba4_check_for_player_falling_flag)
#9e66#346615
b7 
    or a
#9e67#3467213/8
28 0c 
    jr z, L9e75_regular_control
#9e69#3469314
3a 79 74 
    ld a, (L7479_current_game_state)
#9e6c#346c15
b7 
    or a
#9e6d#346d213/8
20 06 
    jr nz, L9e75_regular_control
#9e6f#346f318
cd a4 cb 
    call Lcba4_check_for_player_falling
#9e72#3472311
c3 a0 9f 
    jp L9fa0_ret
#9e75#3475
L9e75_regular_control:
#9e75#3475318
cd d4 bf 
    call Lbfd4_read_keyboard_and_joystick_input
#9e78#3478112
f5 
    push af
#9e79#3479314
3a 79 74 
        ld a, (L7479_current_game_state)
#9e7c#347c15
b7 
        or a
#9e7d#347d311
c2 25 9f 
        jp nz, L9f25_game_over
#9e80#3480311
21 21 6b 
        ld hl, L6b21_time_unit6_previous
#9e83#3483314
3a 22 6b 
        ld a, (L6b22_time_unit6)
#9e86#348618
be 
        cp (hl)
#9e87#3487213/8
28 06 
        jr z, L9e8f
#9e89#348918
77 
        ld (hl), a
#9e8a#348a28
3e 08 
        ld a, 8
#9e8c#348c314
32 73 74 
        ld (L7473_timer_event), a
#9e8f#348f
L9e8f:
#9e8f#348f111
f1 
    pop af
#9e90#3490311
d2 a0 9f 
    jp nc, L9fa0_ret  ; no key pressed
#9e93#3493
    ; Some key was pressed:
#9e93#3493
    ; Go through the pressed keys, and use the input mapping to identify their functions
#9e93#3493314
3a 9f 74 
    ld a, (L749f_number_of_pressed_keys)
#9e96#349615
47 
    ld b, a
#9e97#3497311
11 e4 9d 
    ld de, L9de4_pressed_keys_functions
#9e9a#349a416
dd 21 a0 74 
    ld ix, L74a0_pressed_keys_buffer
#9e9e#349e
L9e9e_check_pressed_keys_loop:
#9e9e#349e112
c5 
    push bc
#9e9f#349f321
dd 4e 00 
        ld c, (ix)
#9ea2#34a2311
21 84 76 
        ld hl, L7684_input_mapping
#9ea5#34a528
06 0c 
        ld b, 3 * 4  ; the 4 movement keys have 3 possible bindings per key
#9ea7#34a715
79 
        ld a, c
#9ea8#34a8
L9ea8_movement_key_loop:
#9ea8#34a818
be 
        cp (hl)
#9ea9#34a917
23 
        inc hl
#9eaa#34aa213/8
28 12 
        jr z, L9ebe_key_found
#9eac#34ac17
23 
        inc hl
#9ead#34ad17
23 
        inc hl
#9eae#34ae214/9
10 f8 
        djnz L9ea8_movement_key_loop
#9eb0#34b028
06 0d 
        ld b, 13  ; There are 13 other keys to check (each encoded as a 2 byte pair):
#9eb2#34b215
79 
        ld a, c
#9eb3#34b3
L9eb3_other_key_loop:
#9eb3#34b318
be 
        cp (hl)
#9eb4#34b417
23 
        inc hl
#9eb5#34b5213/8
28 0e 
        jr z, L9ec5_key_found
#9eb7#34b717
23 
        inc hl
#9eb8#34b8214/9
10 f9 
        djnz L9eb3_other_key_loop
#9eba#34ba28
3e 7f 
        ld a, 127  ; no function
#9ebc#34bc213
18 08 
        jr L9ec6_save_key_game_function
#9ebe#34be
L9ebe_key_found:
#9ebe#34be314
3a 1c 6b 
        ld a, (L6b1c_movement_or_pointer)
#9ec1#34c115
b7 
        or a
#9ec2#34c2213/8
28 01 
        jr z, L9ec5_key_found
#9ec4#34c417
23 
        inc hl
#9ec5#34c5
L9ec5_key_found:
#9ec5#34c518
7e 
        ld a, (hl)
#9ec6#34c6
L9ec6_save_key_game_function:
#9ec6#34c618
12 
        ld (de), a  ; store the function of the pressed key
#9ec7#34c717
13 
        inc de
#9ec8#34c8212
dd 23 
        inc ix  ; next key press
#9eca#34ca111
c1 
    pop bc
#9ecb#34cb214/9
10 d1 
    djnz L9e9e_check_pressed_keys_loop
#9ecd#34cd
    ; Now that we have stored all the requested game functions by key presses,
#9ecd#34cd
    ; Go through them one by one and execute them:
#9ecd#34cd314
3a e4 9d 
    ld a, (L9de4_pressed_keys_functions)
#9ed0#34d0
L9ed0_check_request_key_functions_loop:
#9ed0#34d028
fe 01 
    cp 1
#9ed2#34d2311
fa df 9e 
    jp m, L9edf
#9ed5#34d528
fe 15 
    cp 21
#9ed7#34d7311
f2 df 9e 
    jp p, L9edf
#9eda#34da318
cd e5 ae 
    call Laee5_executes_movement_related_pressed_key_functions
#9edd#34dd213
18 31 
    jr L9f10_next_key_function
#9edf#34df
L9edf:
#9edf#34df28
fe 15 
    cp 21
#9ee1#34e1311
fa 06 9f 
    jp m, L9f06
#9ee4#34e428
fe 1f 
    cp 31
#9ee6#34e6311
f2 06 9f 
    jp p, L9f06
#9ee9#34e928
fe 16 
    cp 22
#9eeb#34eb213/8
20 14 
    jr nz, L9f01_process_key_function
#9eed#34ed
    ; Throw rock:
#9eed#34ed15
47 
    ld b, a
#9eee#34ee314
3a 1c 6b 
    ld a, (L6b1c_movement_or_pointer)
#9ef1#34f115
b7 
    or a
#9ef2#34f215
78 
    ld a, b
#9ef3#34f3213/8
20 0c 
    jr nz, L9f01_process_key_function
#9ef5#34f5
    ; If we want to throw a rock in "movement" mode, we do:
#9ef5#34f5
    ; - first toogle the mode (function 30)
#9ef5#34f5
    ; - then throw the rock (function 22)
#9ef5#34f5
    ; - tootle mode again (function 30)
#9ef5#34f528
3e 1e 
    ld a, INPUT_SWITCH_BETWEEN_MOVEMENT_AND_POINTER
#9ef7#34f7318
cd f9 b2 
    call Lb2f9_execute_pressed_key_function
#9efa#34fa28
3e 16 
    ld a, INPUT_THROW_ROCK
#9efc#34fc318
cd f9 b2 
    call Lb2f9_execute_pressed_key_function
#9eff#34ff28
3e 1e 
    ld a, INPUT_SWITCH_BETWEEN_MOVEMENT_AND_POINTER
#9f01#3501
L9f01_process_key_function:
#9f01#3501318
cd f9 b2 
    call Lb2f9_execute_pressed_key_function
#9f04#3504213
18 0a 
    jr L9f10_next_key_function
#9f06#3506
L9f06:
#9f06#350628
fe 29 
    cp INPUT_INFO_MENU  ; player requested load/save/quit menu?
#9f08#3508213/8
20 06 
    jr nz, L9f10_next_key_function
#9f0a#350a318
cd 24 c2 
    call Lc224_load_save_quit_menu
#9f0d#350d311
c3 a0 9f 
    jp L9fa0_ret
#9f10#3510
L9f10_next_key_function:
#9f10#3510311
21 e9 9d 
    ld hl, L9de9_current_key_index
#9f13#3513314
3a 9f 74 
    ld a, (L749f_number_of_pressed_keys)
#9f16#3516112
34 
    inc (hl)
#9f17#351718
be 
    cp (hl)
#9f18#3518311
ca a0 9f 
    jp z, L9fa0_ret  ; If we have checked them all, we are done
#9f1b#351b
    ; Get the next requested key function:
#9f1b#351b18
4e 
    ld c, (hl)
#9f1c#351c28
06 00 
    ld b, 0
#9f1e#351e311
21 e4 9d 
    ld hl, L9de4_pressed_keys_functions
#9f21#3521112
09 
    add hl, bc
#9f22#352218
7e 
    ld a, (hl)
#9f23#3523213
18 ab 
    jr L9ed0_check_request_key_functions_loop
#9f25#3525
#9f25#3525
L9f25_game_over:
#9f25#3525
    ; Game over: "a" contains the reason for this to happen.
#9f25#3525
    ; Draw the game text # "a"
#9f25#3525111
e1 
    pop hl  ; To cancel "push af" without destroying "a".
#9f26#352615
47 
    ld b, a
#9f27#3527311
21 b9 6c 
    ld hl, L6cb9_game_text
#9f2a#352a311
11 10 00 
    ld de, 16
#9f2d#352d
L9f2d_find_text_loop:
#9f2d#352d112
19 
    add hl, de
#9f2e#352e214/9
10 fd 
    djnz L9f2d_find_text_loop
#9f30#3530416
dd 21 5a 73 
    ld ix, L735a_ui_message_row_pointers
#9f34#3534311
11 00 0f 
    ld de, #0f00
#9f37#3537317
22 ea 9d 
    ld (L9dea_game_over_reason_message), hl
#9f3a#353a318
cd 1c d0 
    call Ld01c_draw_string
#9f3d#353d28
fe 05 
    cp GAME_OVER_REASON_ESCAPED
#9f3f#353f318/11
cc a1 9f 
    call z, L9fa1_escape_castle_sequence
#9f42#3542213/8
28 09 
    jr z, L9f4d_prepare_game_stats_for_game_over
#9f44#3544
#9f44#354428
fe 03 
    cp GAME_OVER_REASON_CRUSHED
#9f46#3546318/11
c4 46 9d 
    call nz, L9d46_render_3d_view
#9f49#354915
b7 
    or a  ; reset carry flag (to set a close gate animation)
#9f4a#354a318
cd 09 ce 
    call Lce09_gate_open_close_effect
#9f4d#354d
#9f4d#354d
L9f4d_prepare_game_stats_for_game_over:
#9f4d#354d318
cd 9b c3 
    call Lc39b_update_number_of_collected_keys_text
#9f50#3550318
cd cb c3 
    call Lc3cb_update_number_of_spirits_destroyed_text
#9f53#3553318
cd b8 c3 
    call Lc3b8_update_score_text
#9f56#3556416
dd 21 5a 73 
    ld ix, L735a_ui_message_row_pointers
#9f5a#355a311
11 00 0f 
    ld de, #0f00
#9f5d#355d
#9f5d#355d
L9f5d_display_game_score_loop:
#9f5d#355d
    ; Loops alternating score, collected keys and spirits destroyed, 
#9f5d#355d
    ; (flipping between them once per secont), until a key is pressed.
#9f5d#355d318
cd 83 9f 
    call L9f83_pause_of_exit_with_key
#9f60#3560311
21 6a 7d 
    ld hl, L7d6a_text_score
#9f63#3563318
cd 1c d0 
    call Ld01c_draw_string
#9f66#3566318
cd 83 9f 
    call L9f83_pause_of_exit_with_key
#9f69#3569311
21 4a 7d 
    ld hl, L7d4a_text_collected
#9f6c#356c318
cd 1c d0 
    call Ld01c_draw_string
#9f6f#356f318
cd 83 9f 
    call L9f83_pause_of_exit_with_key
#9f72#3572311
21 5a 7d 
    ld hl, L7d5a_text_destroyed
#9f75#3575318
cd 1c d0 
    call Ld01c_draw_string
#9f78#3578318
cd 83 9f 
    call L9f83_pause_of_exit_with_key
#9f7b#357b317
2a ea 9d 
    ld hl, (L9dea_game_over_reason_message)
#9f7e#357e318
cd 1c d0 
    call Ld01c_draw_string
#9f81#3581213
18 da 
    jr L9f5d_display_game_score_loop
#9f83#3583
#9f83#3583
L9f83_pause_of_exit_with_key:
#9f83#358328
3e 32 
    ld a, 50  ; 1 second pause
#9f85#3585314
32 a5 74 
    ld (L74a5_interrupt_timer), a
#9f88#3588
L9f88_pause_or_wait_for_key_loop:
#9f88#3588318
cd d4 bf 
    call Lbfd4_read_keyboard_and_joystick_input
#9f8b#358b213/8
38 07 
    jr c, L9f94_exit_indicating_game_is_over
#9f8d#358d314
3a a5 74 
    ld a, (L74a5_interrupt_timer)
#9f90#359015
b7 
    or a
#9f91#3591213/8
20 f5 
    jr nz, L9f88_pause_or_wait_for_key_loop
#9f93#3593111
c9 
    ret
#9f94#3594
#9f94#3594
L9f94_exit_indicating_game_is_over:
#9f94#3594111
e1 
    pop hl  ; simulate a ret, to get out of the "L9f5d" loop
#9f95#359528
3e 03 
    ld a, SFX_MENU_SELECT
#9f97#3597318
cd ca c4 
    call Lc4ca_play_SFX
#9f9a#359a311
21 02 00 
    ld hl, 2  ; flag that indicates game is over
#9f9d#359d317
22 6c 74 
    ld (L746c_game_flags), hl
#9fa0#35a0
L9fa0_ret:
#9fa0#35a0111
c9 
    ret
#9fa1#35a1
#9fa1#35a1
#9fa1#35a1
; --------------------------------
#9fa1#35a1
; Game ending sequence: rotates the player toward the castle, and moves away.
#9fa1#35a1
L9fa1_escape_castle_sequence:
#9fa1#35a1112
f5 
    push af
#9fa2#35a2311
21 04 00 
        ld hl, 4
#9fa5#35a5317
22 6c 74 
        ld (L746c_game_flags), hl
#9fa8#35a8
        ; Start by automatically rotating the player to have:
#9fa8#35a8
        ; - yaw = FULL_ROTATION_DEGREES / 2
#9fa8#35a8
        ; - pitch = 0
#9fa8#35a8311
11 02 02 
        ld de, #0202
#9fab#35ab314
3a b7 6a 
        ld a, (L6ab7_player_yaw_angle)
#9fae#35ae28
fe 24 
        cp FULL_ROTATION_DEGREES / 2
#9fb0#35b0213/8
38 02 
        jr c, L9fb4_turn_right
#9fb2#35b228
1e fe 
        ld e, -2
#9fb4#35b4
L9fb4_turn_right:
#9fb4#35b4314
3a b6 6a 
        ld a, (L6ab6_player_pitch_angle)
#9fb7#35b728
fe 24 
        cp FULL_ROTATION_DEGREES / 2
#9fb9#35b9213/8
30 02 
        jr nc, L9fbd_look_down
#9fbb#35bb28
16 fe 
        ld d, -2
#9fbd#35bd
L9fbd_look_down:
#9fbd#35bd
L9fbd_rotate_loop:
#9fbd#35bd314
3a b7 6a 
        ld a, (L6ab7_player_yaw_angle)
#9fc0#35c028
fe 24 
        cp FULL_ROTATION_DEGREES / 2
#9fc2#35c2213/8
20 08 
        jr nz, L9fcc_yaw_updated
#9fc4#35c4
        ; We have the desired "yaw", so, no "yaw" rotation:
#9fc4#35c428
1e 00 
        ld e, 0
#9fc6#35c6314
3a b6 6a 
        ld a, (L6ab6_player_pitch_angle)
#9fc9#35c915
b7 
        or a
#9fca#35ca213/8
28 1b 
        jr z, L9fe7_facing_the_desired_direction
#9fcc#35cc
L9fcc_yaw_updated:
#9fcc#35cc314
3a b7 6a 
        ld a, (L6ab7_player_yaw_angle)
#9fcf#35cf15
83 
        add a, e
#9fd0#35d0314
32 b7 6a 
        ld (L6ab7_player_yaw_angle), a
#9fd3#35d3314
3a b6 6a 
        ld a, (L6ab6_player_pitch_angle)
#9fd6#35d615
b7 
        or a
#9fd7#35d7213/8
28 06 
        jr z, L9fdf_pitch_updated
#9fd9#35d915
82 
        add a, d
#9fda#35da28
fe 48 
        cp FULL_ROTATION_DEGREES
#9fdc#35dc213/8
20 01 
        jr nz, L9fdf_pitch_updated
#9fde#35de15
af 
        xor a
#9fdf#35df
L9fdf_pitch_updated:
#9fdf#35df314
32 b6 6a 
        ld (L6ab6_player_pitch_angle), a
#9fe2#35e2318
cd aa 83 
        call L83aa_redraw_whole_screen
#9fe5#35e5213
18 d6 
        jr L9fbd_rotate_loop
#9fe7#35e7
#9fe7#35e7
L9fe7_facing_the_desired_direction:
#9fe7#35e7
        ; We are facing the desired direction, now move the player away from the castle.
#9fe7#35e7311
11 00 02 
        ld de, 512  ; desired movement speed
#9fea#35ea28
3e 01 
        ld a, 1
#9fec#35ec314
32 bd 6a 
        ld (L6abd_cull_by_rendering_volume_flag), a  ; do not cull by volume, render everything!
#9fef#35ef
L9fef_movement_loop:
#9fef#35ef317
2a b1 6a 
        ld hl, (L6ab1_player_current_z)
#9ff2#35f2112
19 
        add hl, de
#9ff3#35f315
7c 
        ld a, h
#9ff4#35f428
e6 c0 
        and 192
#9ff6#35f6213/8
20 08 
        jr nz, La000_ending_sequence_done
#9ff8#35f8317
22 b1 6a 
        ld (L6ab1_player_current_z), hl
#9ffb#35fb318
cd aa 83 
        call L83aa_redraw_whole_screen
#9ffe#35fe213
18 ef 
        jr L9fef_movement_loop
#a000#3600
La000_ending_sequence_done:
#a000#3600111
f1 
    pop af
#a001#3601111
c9 
    ret
#a002#3602
#a002#3602
#a002#3602
; --------------------------------
#a002#3602
; Auxiliary variables for La005_check_rules
#a002#3602
; Script that is triggered when interacting with an object that
#a002#3602
; has no rules no rule was found for the event, and the player collided:
#a002#3602
La002_script_size:
#a002#36021
    db 2  ; 2 bytes
#a003#3603
La003_script:
#a003#3603
    ; Rule that matches with a "movement event" (as there are no extra flags in the first byte),
#a003#3603
    ; and triggers an SFX.
#a003#36032
    db RULE_TYPE_REQUEST_SFX_NEXT_FRAME, SFX_MENU_SELECT
#a005#3605
#a005#3605
#a005#3605
; --------------------------------
#a005#3605
; If a player of timer event was triggered, check if any rule needs to be triggered.
#a005#3605
; This function checks rules in:
#a005#3605
; - The current selected object
#a005#3605
; - The global game rules
#a005#3605
; - The current area rules
#a005#3605
La005_check_rules:
#a005#3605311
21 7f 74 
    ld hl, L747f_player_event
#a008#3608314
3a 73 74 
    ld a, (L7473_timer_event)
#a00b#360b18
b6 
    or (hl)
#a00c#360c112/6
c8 
    ret z  ; If there are no player nor timer events, return.
#a00d#360d
#a00d#360d18
77 
    ld (hl), a  ; save the aggregate of L747f_player_event and L7473_timer_event in L747f_player_event.
#a00e#360e314
3a 80 74 
    ld a, (L7480_under_pointer_object_ID)
#a011#361115
b7 
    or a
#a012#3612213/8
28 3c 
    jr z, La050_check_global_rules
#a014#3614314
32 68 74 
    ld (L7468_focus_object_id), a
#a017#3617
    ; Find the selected object:
#a017#361715
af 
    xor a
#a018#3618318
cd 86 b2 
    call Lb286_find_object_by_id
#a01b#361b15
b7 
    or a
#a01c#361c213/8
20 32 
    jr nz, La050_check_global_rules  ; If we could not find it, skip
#a01e#361e
    ; We found the selected object!
#a01e#361e321
dd 7e 00 
    ld a, (ix)
#a021#362128
e6 0f 
    and #0f  ; a = object type
#a023#3623
#a023#3623416
fd 21 2c 6b 
    ld iy, L6b2c_expected_object_size_by_type
#a027#362715
5f 
    ld e, a
#a028#362828
16 00 
    ld d, 0
#a02a#362a217
fd 19 
    add iy, de
#a02c#362c321
fd 5e 00 
    ld e, (iy)  ; e = expected size of this object (anything beyond is rules).
#a02f#362f321
dd 7e 08 
    ld a, (ix + OBJECT_SIZE)
#a032#363215
93 
    sub e
#a033#3633213/8
28 0b 
    jr z, La040_no_rule_data_in_the_object
#a035#3635217
dd 19 
    add ix, de
#a037#3637318
cd e2 b7 
    call Lb7e2_execute_script
#a03a#363a314
3a 71 74 
    ld a, (L7471_event_rule_found)
#a03d#363d15
b7 
    or a
#a03e#363e213/8
20 10 
    jr nz, La050_check_global_rules
#a040#3640
La040_no_rule_data_in_the_object:
#a040#3640314
3a 76 74 
    ld a, (L7476_trigger_collision_event_flag)
#a043#364315
b7 
    or a
#a044#3644213/8
28 0a 
    jr z, La050_check_global_rules
#a046#3646
    ; Player collided with an object, trigger the default collision rule:
#a046#3646314
3a 02 a0 
    ld a, (La002_script_size)  ; size
#a049#3649416
dd 21 03 a0 
    ld ix, La003_script  ; rules
#a04d#364d318
cd e2 b7 
    call Lb7e2_execute_script
#a050#3650
#a050#3650
La050_check_global_rules:
#a050#3650422
dd 2a 6e 74 
    ld ix, (L746e_global_rules_ptr)
#a054#3654321
dd 7e 00 
    ld a, (ix)  ; a = number of scripts
#a057#365715
b7 
    or a
#a058#3658213/8
28 12 
    jr z, La06c_global_rules_done
#a05a#365a212
dd 23 
    inc ix
#a05c#365c15
47 
    ld b, a
#a05d#365d
#a05d#365d
La05d_global_script_loop:
#a05d#365d321
dd 7e 00 
    ld a, (ix)  ; size of the script
#a060#3660212
dd 23 
    inc ix
#a062#3662318
cd e2 b7 
    call Lb7e2_execute_script
#a065#366515
5f 
    ld e, a
#a066#366628
16 00 
    ld d, 0
#a068#3668217
dd 19 
    add ix, de  ; next script
#a06a#366a214/9
10 f1 
    djnz La05d_global_script_loop
#a06c#366c
#a06c#366c
La06c_global_rules_done:
#a06c#366c422
dd 2a d5 6a 
    ld ix, (L6ad5_current_area_rules)
#a070#3670321
dd 7e 00 
    ld a, (ix)  ; a = number of rules
#a073#367315
b7 
    or a
#a074#3674213/8
28 12 
    jr z, La088_done
#a076#3676212
dd 23 
    inc ix
#a078#367815
47 
    ld b, a
#a079#3679
La079_current_area_script_loop:
#a079#3679321
dd 7e 00 
    ld a, (ix)  ; script size
#a07c#367c212
dd 23 
    inc ix
#a07e#367e318
cd e2 b7 
    call Lb7e2_execute_script
#a081#368115
5f 
    ld e, a
#a082#368228
16 00 
    ld d, 0
#a084#3684217
dd 19 
    add ix, de  ; next script
#a086#3686214/9
10 f1 
    djnz La079_current_area_script_loop
#a088#3688
La088_done:
#a088#3688111
c9 
    ret
#a089#3689
#a089#3689
#a089#3689
; --------------------------------
#a089#3689
; 3x3 Matrix multiplication:
#a089#3689
; L5e55_rotation_matrix = L5e55_rotation_matrix * L5e4c_pitch_rotation_matrix
#a089#3689
La089_3x3_matrix_multiply:
#a089#3689311
21 40 5f 
    ld hl, L5f40_16_bit_tmp_matrix
#a08c#368c317
22 52 5f 
    ld (L5f52_16_bit_tmp_matrix_ptr), hl
#a08f#368f416
dd 21 4c 5e 
    ld ix, L5e4c_pitch_rotation_matrix
#a093#3693416
fd 21 55 5e 
    ld iy, L5e55_rotation_matrix
#a097#369728
06 03 
    ld b, 3
#a099#3699
    ; Multiply L5e4c_pitch_rotation_matrix by L5e55_rotation_matrix,
#a099#3699
    ; And store the result (16bits per number) in L5f52_16_bit_tmp_matrix_ptr
#a099#3699
La099_matmul_row_loop:
#a099#3699112
c5 
    push bc
#a09a#369a28
06 03 
        ld b, 3
#a09c#369c
La09c_matmul_column_loop:
#a09c#369c112
c5 
        push bc
#a09d#369d28
06 03 
            ld b, 3
#a09f#369f311
11 00 00 
            ld de, 0
#a0a2#36a2
La0a2_matmul_inner_loop:
#a0a2#36a2112
c5 
            push bc
#a0a3#36a3321
dd 66 00 
                ld h, (ix)
#a0a6#36a6212
dd 23 
                inc ix
#a0a8#36a8321
fd 6e 00 
                ld l, (iy)
#a0ab#36ab311
01 03 00 
                ld bc, 3
#a0ae#36ae217
fd 09 
                add iy, bc
#a0b0#36b0318
cd 53 a2 
                call La253_h_times_l_signed
#a0b3#36b3112
19 
                add hl, de
#a0b4#36b415
eb 
                ex de, hl  ; de += h * l
#a0b5#36b5111
c1 
            pop bc
#a0b6#36b6214/9
10 ea 
            djnz La0a2_matmul_inner_loop
#a0b8#36b8317
2a 52 5f 
            ld hl, (L5f52_16_bit_tmp_matrix_ptr)
#a0bb#36bb18
73 
            ld (hl), e
#a0bc#36bc17
23 
            inc hl
#a0bd#36bd18
72 
            ld (hl), d
#a0be#36be17
23 
            inc hl
#a0bf#36bf317
22 52 5f 
            ld (L5f52_16_bit_tmp_matrix_ptr), hl
#a0c2#36c2311
01 fd ff 
            ld bc, -3
#a0c5#36c5217
dd 09 
            add ix, bc
#a0c7#36c7311
01 f8 ff 
            ld bc, -8
#a0ca#36ca217
fd 09 
            add iy, bc
#a0cc#36cc111
c1 
        pop bc
#a0cd#36cd214/9
10 cd 
        djnz La09c_matmul_column_loop
#a0cf#36cf311
01 03 00 
        ld bc, 3
#a0d2#36d2217
dd 09 
        add ix, bc
#a0d4#36d4311
01 fd ff 
        ld bc, -3
#a0d7#36d7217
fd 09 
        add iy, bc
#a0d9#36d9111
c1 
    pop bc
#a0da#36da214/9
10 bd 
    djnz La099_matmul_row_loop
#a0dc#36dc
    ; Copy the 16bit results over to the 8 bit matrix "L5e55_rotation_matrix" 
#a0dc#36dc28
06 09 
    ld b, 9
#a0de#36de416
dd 21 40 5f 
    ld ix, L5f40_16_bit_tmp_matrix
#a0e2#36e2416
fd 21 55 5e 
    ld iy, L5e55_rotation_matrix
#a0e6#36e6
La0e6:
#a0e6#36e6
    ; the 8bit value is constructed by dividing the 16bit one by 4:
#a0e6#36e6321
dd 56 01 
    ld d, (ix + 1)
#a0e9#36e9425
dd cb 00 26 
    sla (ix)
#a0ed#36ed210
cb 12 
    rl d
#a0ef#36ef425
dd cb 00 26 
    sla (ix)
#a0f3#36f3210
cb 12 
    rl d
#a0f5#36f5422
dd cb 00 7e 
    bit 7, (ix)
#a0f9#36f9213/8
28 01 
    jr z, La0fc_positive
#a0fb#36fb15
14 
    inc d
#a0fc#36fc
La0fc_positive:
#a0fc#36fc321
fd 72 00 
    ld (iy), d
#a0ff#36ff212
fd 23 
    inc iy
#a101#3701212
dd 23 
    inc ix
#a103#3703212
dd 23 
    inc ix
#a105#3705214/9
10 df 
    djnz La0e6
#a107#3707111
c9 
    ret
#a108#3708
#a108#3708
#a108#3708
; --------------------------------
#a108#3708
; Signed multiplication between A and HL.
#a108#3708
; The signed 24 bit result is returned in (A,HL)
#a108#3708
; Input:
#a108#3708
; - a
#a108#3708
; - hl
#a108#3708
; Output:
#a108#3708
; - a, hl
#a108#3708
La108_a_times_hl_signed:
#a108#370815
b7 
    or a
#a109#3709213/8
20 03 
    jr nz, La10e
#a10b#370b15
67 
    ld h, a
#a10c#370c15
6f 
    ld l, a
#a10d#370d111
c9 
    ret
#a10e#370e
La10e:
#a10e#370e112
c5 
    push bc
#a10f#370f15
47 
        ld b, a
#a110#371015
7d 
        ld a, l
#a111#371115
b4 
        or h
#a112#3712213/8
20 02 
        jr nz, La116
#a114#3714111
c1 
    pop bc
#a115#3715111
c9 
    ret
#a116#3716
La116:
#a116#371628
0e 00 
        ld c, 0
#a118#3718210
cb 78 
        bit 7, b
#a11a#371a213/8
28 05 
        jr z, La121
#a11c#371c15
78 
        ld a, b
#a11d#371d210
ed 44 
        neg
#a11f#371f15
47 
        ld b, a
#a120#372015
0c 
        inc c
#a121#3721
La121:
#a121#3721210
cb 7c 
        bit 7, h
#a123#3723213/8
28 0b 
        jr z, La130
#a125#372515
7c 
        ld a, h
#a126#372615
2f 
        cpl
#a127#372715
67 
        ld h, a
#a128#372815
7d 
        ld a, l
#a129#372915
2f 
        cpl
#a12a#372a15
6f 
        ld l, a
#a12b#372b17
23 
        inc hl
#a12c#372c15
79 
        ld a, c
#a12d#372d28
ee 01 
        xor 1
#a12f#372f15
4f 
        ld c, a
#a130#3730
La130:
#a130#3730112
d5 
        push de
#a131#373115
78 
            ld a, b
#a132#373215
eb 
            ex de, hl
#a133#3733311
21 00 00 
            ld hl, 0
#a136#373628
06 08 
            ld b, 8
#a138#3738
La138:
#a138#3738210
cb 27 
            sla a
#a13a#373a213/8
38 08 
            jr c, La144
#a13c#373c214/9
10 fa 
            djnz La138
#a13e#373e213
18 1b 
            jr La15b
#a140#3740
La140:
#a140#3740112
29 
            add hl, hl
#a141#374115
17 
            rla
#a142#3742213/8
30 03 
            jr nc, La147
#a144#3744
La144:
#a144#3744112
19 
            add hl, de
#a145#374528
ce 00 
            adc a, 0
#a147#3747
La147:
#a147#3747214/9
10 f7 
            djnz La140
#a149#3749210
cb 41 
            bit 0, c
#a14b#374b213/8
28 0e 
            jr z, La15b
#a14d#374d15
2f 
            cpl
#a14e#374e15
47 
            ld b, a
#a14f#374f15
7c 
            ld a, h
#a150#375015
2f 
            cpl
#a151#375115
67 
            ld h, a
#a152#375215
7d 
            ld a, l
#a153#375315
2f 
            cpl
#a154#375415
6f 
            ld l, a
#a155#375515
78 
            ld a, b
#a156#3756311
11 01 00 
            ld de, 1
#a159#3759112
19 
            add hl, de
#a15a#375a15
8a 
            adc a, d
#a15b#375b
La15b:
#a15b#375b111
d1 
        pop de
#a15c#375c111
c1 
    pop bc
#a15d#375d111
c9 
    ret
#a15e#375e
#a15e#375e
#a15e#375e
; --------------------------------
#a15e#375e
; Signed multiplication between DE and HL.
#a15e#375e
; The signed 32 bit result is returned in (DE,HL)
#a15e#375e
; Input:
#a15e#375e
; - de
#a15e#375e
; - hl
#a15e#375e
; Output:
#a15e#375e
; - de, hl
#a15e#375e
La15e_de_times_hl_signed:
#a15e#375e112
f5 
    push af
#a15f#375f15
7c 
        ld a, h
#a160#376015
b5 
        or l
#a161#3761213/8
20 04 
        jr nz, La167
#a163#376315
57 
        ld d, a
#a164#376415
5f 
        ld e, a
#a165#3765111
f1 
        pop af
#a166#3766111
c9 
    ret
#a167#3767
La167:
#a167#376715
7a 
        ld a, d
#a168#376815
b3 
        or e
#a169#3769213/8
20 04 
        jr nz, La16f
#a16b#376b15
67 
        ld h, a
#a16c#376c15
6f 
        ld l, a
#a16d#376d111
f1 
    pop af
#a16e#376e111
c9 
    ret
#a16f#376f
La16f:
#a16f#376f112
c5 
        push bc
#a170#377028
0e 00 
            ld c, 0
#a172#3772210
cb 7c 
            bit 7, h
#a174#3774213/8
28 08 
            jr z, La17e
#a176#377615
7c 
            ld a, h
#a177#377715
2f 
            cpl
#a178#377815
67 
            ld h, a
#a179#377915
7d 
            ld a, l
#a17a#377a15
2f 
            cpl
#a17b#377b15
6f 
            ld l, a
#a17c#377c17
23 
            inc hl
#a17d#377d15
0c 
            inc c
#a17e#377e
La17e:
#a17e#377e210
cb 7a 
            bit 7, d
#a180#3780213/8
28 0b 
            jr z, La18d
#a182#378215
7a 
            ld a, d
#a183#378315
2f 
            cpl
#a184#378415
57 
            ld d, a
#a185#378515
7b 
            ld a, e
#a186#378615
2f 
            cpl
#a187#378715
5f 
            ld e, a
#a188#378817
13 
            inc de
#a189#378915
79 
            ld a, c
#a18a#378a28
ee 01 
            xor 1
#a18c#378c15
4f 
            ld c, a
#a18d#378d
La18d:
#a18d#378d112
c5 
            push bc
#a18e#378e15
7c 
                ld a, h
#a18f#378f15
4d 
                ld c, l
#a190#379028
06 10 
                ld b, 16
#a192#3792311
21 00 00 
                ld hl, 0
#a195#3795
La195:
#a195#3795210
cb 21 
                sla c
#a197#379715
17 
                rla
#a198#3798213/8
38 0d 
                jr c, La1a7
#a19a#379a214/9
10 f9 
                djnz La195
#a19c#379c15
50 
                ld d, b
#a19d#379d15
58 
                ld e, b
#a19e#379e111
c1 
            pop bc
#a19f#379f213
18 28 
            jr La1c9
#a1a1#37a1
La1a1:
#a1a1#37a1112
29 
                add hl, hl
#a1a2#37a2210
cb 11 
                rl c
#a1a4#37a415
17 
                rla
#a1a5#37a5213/8
30 07 
                jr nc, La1ae
#a1a7#37a7
La1a7:
#a1a7#37a7112
19 
                add hl, de
#a1a8#37a8213/8
30 04 
                jr nc, La1ae
#a1aa#37aa15
0c 
                inc c
#a1ab#37ab213/8
20 01 
                jr nz, La1ae
#a1ad#37ad15
3c 
                inc a
#a1ae#37ae
La1ae:
#a1ae#37ae214/9
10 f1 
                djnz La1a1
#a1b0#37b015
57 
                ld d, a
#a1b1#37b115
59 
                ld e, c
#a1b2#37b2111
c1 
            pop bc
#a1b3#37b3210
cb 41 
            bit 0, c
#a1b5#37b5213/8
28 12 
            jr z, La1c9
#a1b7#37b715
7c 
            ld a, h
#a1b8#37b815
2f 
            cpl
#a1b9#37b915
67 
            ld h, a
#a1ba#37ba15
7d 
            ld a, l
#a1bb#37bb15
2f 
            cpl
#a1bc#37bc15
6f 
            ld l, a
#a1bd#37bd15
7a 
            ld a, d
#a1be#37be15
2f 
            cpl
#a1bf#37bf15
57 
            ld d, a
#a1c0#37c015
7b 
            ld a, e
#a1c1#37c115
2f 
            cpl
#a1c2#37c215
5f 
            ld e, a
#a1c3#37c317
23 
            inc hl
#a1c4#37c415
7d 
            ld a, l
#a1c5#37c515
b4 
            or h
#a1c6#37c6213/8
20 01 
            jr nz, La1c9
#a1c8#37c817
13 
            inc de
#a1c9#37c9
La1c9:
#a1c9#37c9111
c1 
        pop bc
#a1ca#37ca111
f1 
    pop af
#a1cb#37cb111
c9 
    ret
#a1cc#37cc
#a1cc#37cc
#a1cc#37cc
; --------------------------------
#a1cc#37cc
; Signed division between (A,HL) and DE.
#a1cc#37cc
; Result stored in (A,HL)
#a1cc#37cc
; Input:
#a1cc#37cc
; - a, hl
#a1cc#37cc
; - de
#a1cc#37cc
; Output:
#a1cc#37cc
; - a, hl
#a1cc#37cc
La1cc_a_hl_divided_by_de_signed:
#a1cc#37cc112
c5 
    push bc
#a1cd#37cd15
47 
        ld b, a
#a1ce#37ce15
b5 
        or l
#a1cf#37cf213/8
20 07 
        jr nz, La1d8
#a1d1#37d115
b4 
        or h
#a1d2#37d2213/8
20 04 
        jr nz, La1d8
#a1d4#37d415
57 
        ld d, a
#a1d5#37d515
5f 
        ld e, a
#a1d6#37d6111
c1 
    pop bc
#a1d7#37d7111
c9 
    ret
#a1d8#37d8
La1d8:
#a1d8#37d828
0e 00 
        ld c, 0
#a1da#37da210
cb 7a 
        bit 7, d
#a1dc#37dc213/8
28 08 
        jr z, La1e6
#a1de#37de15
7a 
        ld a, d
#a1df#37df15
2f 
        cpl
#a1e0#37e015
57 
        ld d, a
#a1e1#37e115
7b 
        ld a, e
#a1e2#37e215
2f 
        cpl
#a1e3#37e315
5f 
        ld e, a
#a1e4#37e417
13 
        inc de
#a1e5#37e515
0c 
        inc c
#a1e6#37e6
La1e6:
#a1e6#37e615
78 
        ld a, b
#a1e7#37e7210
cb 7f 
        bit 7, a
#a1e9#37e9213/8
28 13 
        jr z, La1fe
#a1eb#37eb15
2f 
        cpl
#a1ec#37ec15
47 
        ld b, a
#a1ed#37ed15
7c 
        ld a, h
#a1ee#37ee15
2f 
        cpl
#a1ef#37ef15
67 
        ld h, a
#a1f0#37f015
7d 
        ld a, l
#a1f1#37f115
2f 
        cpl
#a1f2#37f215
6f 
        ld l, a
#a1f3#37f315
79 
        ld a, c
#a1f4#37f428
ee 01 
        xor 1
#a1f6#37f615
4f 
        ld c, a
#a1f7#37f717
23 
        inc hl
#a1f8#37f815
7d 
        ld a, l
#a1f9#37f915
b4 
        or h
#a1fa#37fa15
78 
        ld a, b
#a1fb#37fb213/8
20 01 
        jr nz, La1fe
#a1fd#37fd15
3c 
        inc a
#a1fe#37fe
La1fe:
#a1fe#37fe15
47 
        ld b, a
#a1ff#37ff15
79 
        ld a, c
#a200#380015
d9 
        exx
#a201#3801112
c5 
        push bc
#a202#380215
4f 
            ld c, a
#a203#380315
d9 
            exx
#a204#380415
78 
            ld a, b
#a205#380515
b7 
            or a
#a206#380628
06 18 
            ld b, 24
#a208#3808
La208:
#a208#3808210
cb 15 
            rl l
#a20a#380a210
cb 14 
            rl h
#a20c#380c15
17 
            rla
#a20d#380d213/8
38 06 
            jr c, La215
#a20f#380f214/9
10 f7 
            djnz La208
#a211#381115
50 
            ld d, b
#a212#381215
58 
            ld e, b
#a213#3813213
18 3c 
            jr La251
#a215#3815
La215:
#a215#381515
4f 
            ld c, a
#a216#381615
78 
            ld a, b
#a217#381715
d9 
            exx
#a218#381815
47 
                ld b, a
#a219#381915
d9 
            exx
#a21a#381a15
79 
            ld a, c
#a21b#381b15
44 
            ld b, h
#a21c#381c15
4d 
            ld c, l
#a21d#381d311
21 00 00 
            ld hl, 0
#a220#3820213
18 06 
            jr La228
#a222#3822
La222:
#a222#382215
d9 
            exx
#a223#3823210
cb 11 
            rl c
#a225#3825210
cb 10 
            rl b
#a227#382715
17 
            rla
#a228#3828
La228:
#a228#3828217
ed 6a 
            adc hl, hl
#a22a#382a217
ed 52 
            sbc hl, de
#a22c#382c213/8
30 01 
            jr nc, La22f
#a22e#382e112
19 
            add hl, de
#a22f#382f
La22f:
#a22f#382f15
3f 
            ccf
#a230#383015
d9 
            exx
#a231#3831214/9
10 ef 
                djnz La222
#a233#383315
d9 
            exx
#a234#3834210
cb 11 
            rl c
#a236#3836210
cb 10 
            rl b
#a238#383815
17 
            rla
#a239#383915
eb 
            ex de, hl
#a23a#383a15
60 
            ld h, b
#a23b#383b15
69 
            ld l, c
#a23c#383c15
d9 
            exx
#a23d#383d210
cb 41 
            bit 0, c
#a23f#383f111
c1 
        pop bc
#a240#384015
d9 
        exx
#a241#3841213/8
28 0e 
        jr z, La251
#a243#384315
2f 
        cpl
#a244#384415
4f 
        ld c, a
#a245#384515
7c 
        ld a, h
#a246#384615
2f 
        cpl
#a247#384715
67 
        ld h, a
#a248#384815
7d 
        ld a, l
#a249#384915
2f 
        cpl
#a24a#384a15
6f 
        ld l, a
#a24b#384b15
79 
        ld a, c
#a24c#384c311
01 01 00 
        ld bc, 1
#a24f#384f112
09 
        add hl, bc
#a250#385015
88 
        adc a, b
#a251#3851
La251:
#a251#3851111
c1 
    pop bc
#a252#3852111
c9 
    ret
#a253#3853
#a253#3853
#a253#3853
; --------------------------------
#a253#3853
; Signed multiplication between H and L.
#a253#3853
; The signed 16 bit result is returned in HL
#a253#3853
; Input:
#a253#3853
; - h
#a253#3853
; - l
#a253#3853
; Output:
#a253#3853
; - hl
#a253#3853
La253_h_times_l_signed:
#a253#3853112
f5 
    push af
#a254#385415
7d 
        ld a, l
#a255#385515
b7 
        or a
#a256#3856213/8
20 04 
        jr nz, La25c
#a258#385828
26 00 
        ld h, 0
#a25a#385a111
f1 
        pop af
#a25b#385b111
c9 
    ret
#a25c#385c
La25c:
#a25c#385c15
7c 
        ld a, h
#a25d#385d15
b7 
        or a
#a25e#385e213/8
20 04 
        jr nz, La264
#a260#386028
2e 00 
        ld l, 0
#a262#3862111
f1 
    pop af
#a263#3863111
c9 
    ret
#a264#3864
La264:
#a264#3864112
c5 
        push bc
#a265#3865112
d5 
        push de
#a266#386628
0e 00 
            ld c, 0
#a268#3868210
cb 7c 
            bit 7, h
#a26a#386a213/8
28 05 
            jr z, La271
#a26c#386c15
7c 
            ld a, h
#a26d#386d210
ed 44 
            neg
#a26f#386f15
67 
            ld h, a
#a270#387015
0d 
            dec c
#a271#3871
La271:
#a271#3871210
cb 7d 
            bit 7, l
#a273#3873213/8
28 08 
            jr z, La27d
#a275#387515
7d 
            ld a, l
#a276#3876210
ed 44 
            neg
#a278#387815
6f 
            ld l, a
#a279#387928
3e ff 
            ld a, 255
#a27b#387b15
91 
            sub c
#a27c#387c15
4f 
            ld c, a
#a27d#387d
La27d:
#a27d#387d15
79 
            ld a, c
#a27e#387e15
5d 
            ld e, l
#a27f#387f28
16 00 
            ld d, 0
#a281#388115
6a 
            ld l, d
#a282#388228
06 08 
            ld b, 8
#a284#3884
La284:
#a284#3884112
29 
            add hl, hl
#a285#3885213/8
30 01 
            jr nc, La288
#a287#3887112
19 
            add hl, de
#a288#3888
La288:
#a288#3888214/9
10 fa 
            djnz La284
#a28a#388a15
b7 
            or a
#a28b#388b213/8
28 07 
            jr z, La294
#a28d#388d15
7c 
            ld a, h
#a28e#388e15
2f 
            cpl
#a28f#388f15
67 
            ld h, a
#a290#389015
7d 
            ld a, l
#a291#389115
2f 
            cpl
#a292#389215
6f 
            ld l, a
#a293#389317
23 
            inc hl
#a294#3894
La294:
#a294#3894111
d1 
        pop de
#a295#3895111
c1 
        pop bc
#a296#3896111
f1 
        pop af
#a297#3897111
c9 
    ret
#a298#3898
#a298#3898
#a298#3898
; --------------------------------
#a298#3898
; Renders the render buffer to video memory
#a298#3898
La298_render_buffer_render:
#a298#3898217
dd e5 
    push ix
#a29a#389a112
e5 
    push hl
#a29b#389b112
d5 
    push de
#a29c#389c112
c5 
    push bc
#a29d#389d112
f5 
    push af
#a29e#389e416
dd 21 5c 72 
        ld ix, L725c_videomem_row_pointers
#a2a2#38a228
3e 70 
        ld a, SCREEN_HEIGHT * 8
#a2a4#38a4311
21 bc 5c 
        ld hl, L5cbc_render_buffer
#a2a7#38a7
La2a7_row_loop:
#a2a7#38a7321
dd 5e 00 
        ld e, (ix)
#a2aa#38aa321
dd 56 01 
        ld d, (ix + 1)
#a2ad#38ad212
dd 23 
        inc ix
#a2af#38af212
dd 23 
        inc ix
#a2b1#38b1218
ed a0 
        ldi
#a2b3#38b3218
ed a0 
        ldi
#a2b5#38b5218
ed a0 
        ldi
#a2b7#38b7218
ed a0 
        ldi
#a2b9#38b9218
ed a0 
        ldi
#a2bb#38bb218
ed a0 
        ldi
#a2bd#38bd218
ed a0 
        ldi
#a2bf#38bf218
ed a0 
        ldi
#a2c1#38c1218
ed a0 
        ldi
#a2c3#38c3218
ed a0 
        ldi
#a2c5#38c5218
ed a0 
        ldi
#a2c7#38c7218
ed a0 
        ldi
#a2c9#38c9218
ed a0 
        ldi
#a2cb#38cb218
ed a0 
        ldi
#a2cd#38cd218
ed a0 
        ldi
#a2cf#38cf218
ed a0 
        ldi
#a2d1#38d1218
ed a0 
        ldi
#a2d3#38d3218
ed a0 
        ldi
#a2d5#38d5218
ed a0 
        ldi
#a2d7#38d7218
ed a0 
        ldi
#a2d9#38d9218
ed a0 
        ldi
#a2db#38db218
ed a0 
        ldi
#a2dd#38dd218
ed a0 
        ldi
#a2df#38df218
ed a0 
        ldi
#a2e1#38e115
3d 
        dec a
#a2e2#38e2311
c2 a7 a2 
        jp nz, La2a7_row_loop
#a2e5#38e5314
3a 7a 74 
        ld a, (L747a_requested_SFX)
#a2e8#38e815
b7 
        or a
#a2e9#38e9318/11
c4 ca c4 
        call nz, Lc4ca_play_SFX
#a2ec#38ec15
af 
        xor a
#a2ed#38ed314
32 7a 74 
        ld (L747a_requested_SFX), a
#a2f0#38f0111
f1 
    pop af
#a2f1#38f1111
c1 
    pop bc
#a2f2#38f2111
d1 
    pop de
#a2f3#38f3111
e1 
    pop hl
#a2f4#38f4216
dd e1 
    pop ix
#a2f6#38f6111
c9 
    ret
#a2f7#38f7
#a2f7#38f7
#a2f7#38f7
; --------------------------------
#a2f7#38f7
La2f7_skybox_n_rows_to_draw:
#a2f7#38f71
    db 0
#a2f8#38f8
La2f8_skybox_n_rows_to_skip:
#a2f8#38f81
    db 0
#a2f9#38f9
La2f9_lightning_height:
#a2f9#38f91
    db 0
#a2fa#38fa
La2fa_lightning_frame:
#a2fa#38fa1
    db 0
#a2fb#38fb
La2fb_floor_texture_id:
#a2fb#38fb1
    db #21
#a2fc#38fc
La2fc_sky_texture_id:
#a2fc#38fc1
    db #5c
#a2fd#38fd
La2fd_lightning_x:
#a2fd#38fd2
    dw 0
#a2ff#38ff
#a2ff#38ff
#a2ff#38ff
; --------------------------------
#a2ff#38ff
; Renders the background of the 3d scene.
#a2ff#38ff
; The background includes:
#a2ff#38ff
; - sky
#a2ff#38ff
; - potentially mountains (if we are outdoors)
#a2ff#38ff
; - floor
#a2ff#38ff
; - potentially a lightning
#a2ff#38ff
La2ff_render_background:
#a2ff#38ff112
e5 
    push hl
#a300#3900112
d5 
    push de
#a301#3901112
c5 
    push bc
#a302#3902112
f5 
    push af
#a303#390315
af 
        xor a
#a304#3904314
32 f7 a2 
        ld (La2f7_skybox_n_rows_to_draw), a
#a307#3907314
32 f8 a2 
        ld (La2f8_skybox_n_rows_to_skip), a
#a30a#390a314
32 f9 a2 
        ld (La2f9_lightning_height), a
#a30d#390d314
32 fa a2 
        ld (La2fa_lightning_frame), a
#a310#3910314
3a 19 6b 
        ld a, (L6b19_current_area_flags)
#a313#391315
b7 
        or a
#a314#3914311
ca ec a3 
        jp z, La3ec_done
#a317#391715
47 
        ld b, a
#a318#391828
e6 0f 
        and #0f
#a31a#391a314
32 fc a2 
        ld (La2fc_sky_texture_id), a
#a31d#391d15
78 
        ld a, b
#a31e#391e28
e6 f0 
        and #f0
#a320#3920210
cb 3f 
        srl a
#a322#3922210
cb 3f 
        srl a
#a324#3924210
cb 3f 
        srl a
#a326#3926210
cb 3f 
        srl a
#a328#3928314
32 fb a2 
        ld (La2fb_floor_texture_id), a
#a32b#392b311
ca b6 a3 
        jp z, La3b6_no_floor_texture
#a32e#392e314
3a fc a2 
        ld a, (La2fc_sky_texture_id)
#a331#393115
b7 
        or a
#a332#3932311
ca bf a3 
        jp z, La3bf_no_sky_texture
#a335#3935314
3a b6 6a 
        ld a, (L6ab6_player_pitch_angle)
#a338#393828
fe 08 
        cp 8
#a33a#393a311
fa 49 a3 
        jp m, La349_both_sky_and_floor_visible  ; player looking down only a bit
#a33d#393d28
fe 1d 
        cp 29
#a33f#393f311
fa bf a3 
        jp m, La3bf_no_sky_texture  ; player looking down heavily (sky is not visible)
#a342#394228
fe 3d 
        cp 61
#a344#3944311
fa b6 a3 
        jp m, La3b6_no_floor_texture  ; player is looking up a lot (floor is not visible)
#a347#394728
d6 48 
        sub FULL_ROTATION_DEGREES  ; making the angle in between [-36, 36]
#a349#3949
La349_both_sky_and_floor_visible:
#a349#3949
        ; Player is not looking too down or too up, hence both floor and sky are visible:
#a349#3949
        ; Determine the number of rows of sky and floor, notice that, since the screen is
#a349#3949
        ; 112/113 pixels tall, the number of rows of sky + floor must add up to 113.
#a349#3949311
01 00 71 
        ld bc, #7100  ; b = 113, c = 0 (number of rows to draw for sky / floor)
#a34c#394c311
21 0b 00 
        ld hl, 11
#a34f#394f318
cd 08 a1 
        call La108_a_times_hl_signed  ; hl = pitch * 11
#a352#3952311
11 3c 00 
        ld de, 60
#a355#395515
b7 
        or a
#a356#3956217
ed 5a 
        adc hl, de  ; hl = pitch * 11 + 60
#a358#395815
7d 
        ld a, l  ; a = (pitch * 11 + 60) % 256
#a359#3959311
fa 66 a3 
        jp m, La366
#a35c#395c15
4f 
        ld c, a
#a35d#395d28
fe 71 
        cp 113
#a35f#395f213/8
38 05 
        jr c, La366
#a361#3961
        ; no sky, all floor: (set c = 113, and b = 0)
#a361#396115
48 
        ld c, b
#a362#396228
06 00 
        ld b, 0
#a364#3964213
18 60 
        jr La3c6_number_of_rows_of_sky_floor_decided
#a366#3966
La366:
#a366#396615
57 
        ld d, a
#a367#3967314
3a 0e 6b 
        ld a, (L6b0e_lightning_time_seconds_countdown)
#a36a#396a15
b7 
        or a
#a36b#396b15
7a 
        ld a, d
#a36c#396c213/8
20 23 
        jr nz, La391
#a36e#396e
        ; L6b0e_lightning_time_seconds_countdown == 0: draw a lightning
#a36e#396e
        ; Here: 
#a36e#396e
        ; - a = (pitch * 11 + 60) % 256
#a36e#396e
        ; - hl = pitch * 11 + 60
#a36e#396e311
11 60 00 
        ld de, 96
#a371#3971217
ed 5a 
        adc hl, de
#a373#397315
57 
        ld d, a  ; save a temporarily
#a374#3974311
fa 90 a3 
        jp m, La390  ; The player is looking too down for the lightning to be visible, skip
#a377#397715
7d 
        ld a, l
#a378#3978311
21 f9 a2 
        ld hl, La2f9_lightning_height
#a37b#397b18
77 
        ld (hl), a
#a37c#397c28
fe 57 
        cp 87
#a37e#397e213/8
38 10 
        jr c, La390
#a380#3980211
36 56 
        ld (hl), 86
#a382#398228
fe 72 
        cp 114
#a384#3984213/8
38 0a 
        jr c, La390
#a386#398615
78 
        ld a, b
#a387#398715
91 
        sub c
#a388#398828
d6 0a 
        sub 10
#a38a#398a18
77 
        ld (hl), a
#a38b#398b28
3e 56 
        ld a, 86
#a38d#398d18
96 
        sub (hl)
#a38e#398e17
23 
        inc hl  ; hl = La2fa_lightning_frame
#a38f#398f18
77 
        ld (hl), a
#a390#3990
La390:
#a390#399015
7a 
        ld a, d  ; restore the value we had in a 
#a391#3991
La391:
#a391#3991311
21 f7 a2 
        ld hl, La2f7_skybox_n_rows_to_draw
#a394#399428
c6 12 
        add a, 18
#a396#3996311
fa b0 a3 
        jp m, La3b0
#a399#399918
77 
        ld (hl), a
#a39a#399a28
fe 13 
        cp 19
#a39c#399c213/8
38 12 
        jr c, La3b0
#a39e#399e211
36 12 
        ld (hl), 18
#a3a0#39a028
fe 72 
        cp 114
#a3a2#39a2213/8
38 0c 
        jr c, La3b0
#a3a4#39a415
78 
        ld a, b
#a3a5#39a515
91 
        sub c
#a3a6#39a618
77 
        ld (hl), a
#a3a7#39a728
3e 12 
        ld a, 18
#a3a9#39a918
96 
        sub (hl)
#a3aa#39aa17
23 
        inc hl  ; hl = La2f8_skybox_n_rows_to_skip
#a3ab#39ab18
77 
        ld (hl), a
#a3ac#39ac28
06 00 
        ld b, 0
#a3ae#39ae213
18 16 
        jr La3c6_number_of_rows_of_sky_floor_decided
#a3b0#39b0
La3b0:
#a3b0#39b015
78 
        ld a, b
#a3b1#39b115
91 
        sub c
#a3b2#39b218
96 
        sub (hl)
#a3b3#39b315
47 
        ld b, a
#a3b4#39b4213
18 10 
        jr La3c6_number_of_rows_of_sky_floor_decided
#a3b6#39b6
La3b6_no_floor_texture:
#a3b6#39b628
06 71 
        ld b, 113
#a3b8#39b815
af 
        xor a
#a3b9#39b9314
32 f7 a2 
        ld (La2f7_skybox_n_rows_to_draw), a
#a3bc#39bc15
4f 
        ld c, a
#a3bd#39bd213
18 07 
        jr La3c6_number_of_rows_of_sky_floor_decided
#a3bf#39bf
La3bf_no_sky_texture:
#a3bf#39bf15
af 
        xor a
#a3c0#39c0314
32 f7 a2 
        ld (La2f7_skybox_n_rows_to_draw), a
#a3c3#39c315
47 
        ld b, a
#a3c4#39c428
0e 71 
        ld c, 113
#a3c6#39c6
La3c6_number_of_rows_of_sky_floor_decided:
#a3c6#39c6
        ; Here:
#a3c6#39c6
        ; b: number of sky rows to draw
#a3c6#39c6
        ; c: number of floor rows to draw
#a3c6#39c6311
21 bc 5c 
        ld hl, L5cbc_render_buffer
#a3c9#39c915
78 
        ld a, b
#a3ca#39ca15
b7 
        or a
#a3cb#39cb213/8
28 06 
        jr z, La3d3_sky_drawn
#a3cd#39cd314
3a fc a2 
        ld a, (La2fc_sky_texture_id)
#a3d0#39d0318
cd f1 a3 
        call La3f1_draw_floor_sky_texture
#a3d3#39d3
La3d3_sky_drawn:
#a3d3#39d3314
3a f7 a2 
        ld a, (La2f7_skybox_n_rows_to_draw)
#a3d6#39d615
b7 
        or a
#a3d7#39d7318/11
c4 16 a4 
        call nz, La416_draw_skybox  ; draws the mountains
#a3da#39da314
3a f9 a2 
        ld a, (La2f9_lightning_height)
#a3dd#39dd15
b7 
        or a
#a3de#39de318/11
c4 74 a4 
        call nz, La474_draw_lightning
#a3e1#39e115
79 
        ld a, c
#a3e2#39e215
b7 
        or a
#a3e3#39e3213/8
28 07 
        jr z, La3ec_done  ; If there are no floor rows to draw, we are done.
#a3e5#39e515
41 
        ld b, c
#a3e6#39e6314
3a fb a2 
        ld a, (La2fb_floor_texture_id)
#a3e9#39e9318
cd f1 a3 
        call La3f1_draw_floor_sky_texture
#a3ec#39ec
La3ec_done:
#a3ec#39ec111
f1 
    pop af
#a3ed#39ed111
c1 
    pop bc
#a3ee#39ee111
d1 
    pop de
#a3ef#39ef111
e1 
    pop hl
#a3f0#39f0111
c9 
    ret
#a3f1#39f1
#a3f1#39f1
#a3f1#39f1
; --------------------------------
#a3f1#39f1
; Draws the floor texture.
#a3f1#39f1
; Input:
#a3f1#39f1
; - hl: pointer to where to draw the skybox/floor
#a3f1#39f1
; - a: texture ID
#a3f1#39f1
; - b: n skybox/floor rows to draw
#a3f1#39f1
La3f1_draw_floor_sky_texture:
#a3f1#39f115
eb 
    ex de, hl
#a3f2#39f2311
21 88 d0 
        ld hl, Ld088_texture_patterns
#a3f5#39f515
3d 
        dec a
#a3f6#39f615
87 
        add a, a
#a3f7#39f715
87 
        add a, a
#a3f8#39f8112
c5 
        push bc
#a3f9#39f915
4f 
            ld c, a
#a3fa#39fa28
06 00 
            ld b, 0
#a3fc#39fc112
09 
            add hl, bc
#a3fd#39fd111
c1 
        pop bc
#a3fe#39fe15
eb 
    ex de, hl
#a3ff#39ff
    ; Here:
#a3ff#39ff
    ; - hl: pointer to where to draw
#a3ff#39ff
    ; - de: Ld088_texture_patterns + (a-1)*4
#a3ff#39ff
La3ff_floor_draw_loop_y:
#a3ff#39ff112
c5 
    push bc
#a400#3a00112
d5 
    push de
#a401#3a01
        ; Get the appropriate byte of the texture for this row:
#a401#3a0115
78 
        ld a, b
#a402#3a0228
e6 03 
        and #03
#a404#3a0415
4f 
        ld c, a
#a405#3a0528
06 00 
        ld b, 0
#a407#3a0715
eb 
        ex de, hl
#a408#3a08112
09 
            add hl, bc
#a409#3a0915
eb 
        ex de, hl
#a40a#3a0a18
1a 
        ld a, (de)
#a40b#3a0b28
06 18 
        ld b, SCREEN_WIDTH
#a40d#3a0d
La40d_floor_draw_loop_x:
#a40d#3a0d18
77 
        ld (hl), a
#a40e#3a0e17
23 
        inc hl
#a40f#3a0f214/9
10 fc 
        djnz La40d_floor_draw_loop_x
#a411#3a11111
d1 
    pop de
#a412#3a12111
c1 
    pop bc
#a413#3a13214/9
10 ea 
    djnz La3ff_floor_draw_loop_y
#a415#3a15111
c9 
    ret
#a416#3a16
#a416#3a16
#a416#3a16
; --------------------------------
#a416#3a16
; Draws the skybox. In this case, a range of mountains.
#a416#3a16
; Input:
#a416#3a16
; - hl: pointer to where to draw
#a416#3a16
La416_draw_skybox:
#a416#3a16314
3a cf 6a 
    ld a, (L6acf_current_area_id)
#a419#3a1928
fe 01 
    cp 1  ; wilderness
#a41b#3a1b213/8
28 09 
    jr z, La426
#a41d#3a1d
    ; If we are not outdoors, do not draw mountains:
#a41d#3a1d314
3a f7 a2 
    ld a, (La2f7_skybox_n_rows_to_draw)
#a420#3a2015
47 
    ld b, a
#a421#3a21314
3a fc a2 
    ld a, (La2fc_sky_texture_id)
#a424#3a24213
18 cb 
    jr La3f1_draw_floor_sky_texture
#a426#3a26
La426:
#a426#3a26
    ; Draw outdoors skybox
#a426#3a26112
c5 
    push bc
#a427#3a27112
e5 
        push hl
#a428#3a28314
3a b7 6a 
            ld a, (L6ab7_player_yaw_angle)
#a42b#3a2b28
e6 07 
            and #07
#a42d#3a2d15
87 
            add a, a
#a42e#3a2e311
21 f2 78 
            ld hl, L78f2_background_mountains_gfx
#a431#3a3115
5f 
            ld e, a
#a432#3a3228
16 00 
            ld d, 0
#a434#3a34112
19 
            add hl, de  ; Get the byte where to start reading the mountain graphic (to get horizontal rotation) 
#a435#3a3528
d6 10 
            sub 16
#a437#3a37210
ed 44 
            neg
#a439#3a39
            ; Calculate the number of bytes left to draw in a row from 
#a439#3a39
            ; the place where we start reading:
#a439#3a3915
4f 
            ld c, a  ; c = 16 - (yaw_angle % 8)
#a43a#3a3a
            ; Skip rows of the mountain:
#a43a#3a3a314
3a f8 a2 
            ld a, (La2f8_skybox_n_rows_to_skip)
#a43d#3a3d15
b7 
            or a
#a43e#3a3e213/8
28 06 
            jr z, La446_no_rows_to_skip
#a440#3a4015
47 
            ld b, a
#a441#3a4128
1e 10 
            ld e, 16
#a443#3a43
La443_vertical_offset_loop:
#a443#3a43112
19 
            add hl, de
#a444#3a44214/9
10 fd 
            djnz La443_vertical_offset_loop
#a446#3a46
La446_no_rows_to_skip:
#a446#3a46111
d1 
        pop de
#a447#3a47314
3a f7 a2 
        ld a, (La2f7_skybox_n_rows_to_draw)
#a44a#3a4a15
47 
        ld b, a
#a44b#3a4b
La44b_drawing_loop_y:
#a44b#3a4b112
c5 
        push bc
#a44c#3a4c112
e5 
            push hl
#a44d#3a4d
                ; Each row is drawn in two parts:
#a44d#3a4d
                ; - The first part is starting from some offset, and we draw until the end
#a44d#3a4d
                ; - Then, we "wrap-around" the row, and start drawing from the beginning, until we fill one row of the screen.
#a44d#3a4d
                ; - Since we want to draw 24 bytes (screen width), and skybox is 16 bytes in width,
#a44d#3a4d
                ;   we might need to loop a couple of times.
#a44d#3a4d
                ; Draw the first part of the row:
#a44d#3a4d28
3e 18 
                ld a, SCREEN_WIDTH
#a44f#3a4f28
06 00 
                ld b, 0
#a451#3a5115
91 
                sub c
#a452#3a52223/18
ed b0 
                ldir
#a454#3a54
                ; Draw the second part of the row:
#a454#3a54
La454_drawing_loop_x:
#a454#3a54311
01 f0 ff 
                ld bc, -16
#a457#3a57112
09 
                add hl, bc
#a458#3a5828
fe 11 
                cp 17
#a45a#3a5a213/8
38 09 
                jr c, La465_no_need_for_more_loops
#a45c#3a5c311
01 10 00 
                ld bc, 16
#a45f#3a5f223/18
ed b0 
                ldir
#a461#3a6128
d6 10 
                sub 16
#a463#3a63213
18 ef 
                jr La454_drawing_loop_x
#a465#3a65
La465_no_need_for_more_loops:
#a465#3a6515
4f 
                ld c, a
#a466#3a6628
06 00 
                ld b, 0
#a468#3a68223/18
ed b0 
                ldir
#a46a#3a6a111
e1 
            pop hl
#a46b#3a6b28
0e 10 
            ld c, 16
#a46d#3a6d112
09 
            add hl, bc
#a46e#3a6e111
c1 
        pop bc
#a46f#3a6f214/9
10 da 
        djnz La44b_drawing_loop_y
#a471#3a7115
eb 
        ex de, hl
#a472#3a72111
c1 
    pop bc
#a473#3a73111
c9 
    ret
#a474#3a74
#a474#3a74
#a474#3a74
; --------------------------------
#a474#3a74
; Draws a lightning at a random horizontal position in the screen
#a474#3a74
La474_draw_lightning:
#a474#3a74211
ed 5f 
    ld a, r
#a476#3a76
La476_modulo_20_loop:
#a476#3a7628
fe 14 
    cp 20
#a478#3a78213/8
38 04 
    jr c, La47e_a_lower_than_20
#a47a#3a7a28
d6 14 
    sub 20
#a47c#3a7c213
18 f8 
    jr La476_modulo_20_loop
#a47e#3a7e
La47e_a_lower_than_20:
#a47e#3a7e
    ; a = random number between [0, 19]
#a47e#3a7e314
32 fd a2 
    ld (La2fd_lightning_x), a
#a481#3a81112
e5 
    push hl
#a482#3a82112
c5 
    push bc
#a483#3a83314
3a f9 a2 
        ld a, (La2f9_lightning_height)
#a486#3a8615
47 
        ld b, a
#a487#3a87314
3a f7 a2 
        ld a, (La2f7_skybox_n_rows_to_draw)
#a48a#3a8a28
d6 08 
        sub 8
#a48c#3a8c213/8
30 01 
        jr nc, La48f
#a48e#3a8e15
af 
        xor a
#a48f#3a8f
La48f:
#a48f#3a8f15
80 
        add a, b
#a490#3a9015
eb 
        ex de, hl
#a491#3a9115
67 
            ld h, a
#a492#3a9228
2e e8 
            ld l, -SCREEN_WIDTH
#a494#3a94318
cd 53 a2 
            call La253_h_times_l_signed
#a497#3a97112
19 
            add hl, de
#a498#3a9815
eb 
        ex de, hl
#a499#3a99311
21 9b 7a 
        ld hl, L7a9b_lightning_gfx
#a49c#3a9c314
3a fa a2 
        ld a, (La2fa_lightning_frame)
#a49f#3a9f15
87 
        add a, a
#a4a0#3aa015
4f 
        ld c, a
#a4a1#3aa128
06 00 
        ld b, 0
#a4a3#3aa3112
09 
        add hl, bc
#a4a4#3aa415
eb 
        ex de, hl
#a4a5#3aa5
        ; Here:
#a4a5#3aa5
        ; - hl = a * -SCREEN_WIDTH + ptr where to start drawing after sky/mountains
#a4a5#3aa5
        ; - de = L7a9b_lightning_gfx + (La2fa_lightning_frame) * 2
#a4a5#3aa5314
3a f9 a2 
        ld a, (La2f9_lightning_height)
#a4a8#3aa815
47 
        ld b, a
#a4a9#3aa9
La4a9_row_loop:
#a4a9#3aa9112
c5 
        push bc
#a4aa#3aaa112
e5 
            push hl
#a4ab#3aab422
ed 4b fd a2 
                ld bc, (La2fd_lightning_x)  ; Add a random amount (in [0, 20])
#a4af#3aaf112
09 
                add hl, bc
#a4b0#3ab015
eb 
                ex de, hl
#a4b1#3ab128
06 02 
                    ld b, 2
#a4b3#3ab3
La4b3_loop:
#a4b3#3ab3
                    ; Note: this rendering code does not make sense. The effect is just
#a4b3#3ab3
                    ; adding the mask as an "or", but it does it in a very convoluted
#a4b3#3ab3
                    ; and wasteful way.
#a4b3#3ab318
1a 
                    ld a, (de)  ; read a pixel from the screen
#a4b4#3ab415
4f 
                    ld c, a
#a4b5#3ab515
2f 
                    cpl  ; invert it
#a4b6#3ab618
a6 
                    and (hl)  ; apply and mask
#a4b7#3ab715
b1 
                    or c  ; add the original pixel again
#a4b8#3ab818
12 
                    ld (de), a  ; write it back to screen
#a4b9#3ab917
23 
                    inc hl
#a4ba#3aba17
13 
                    inc de
#a4bb#3abb214/9
10 f6 
                    djnz La4b3_loop
#a4bd#3abd15
eb 
                ex de, hl
#a4be#3abe111
e1 
            pop hl
#a4bf#3abf311
01 18 00 
            ld bc, SCREEN_WIDTH
#a4c2#3ac2112
09 
            add hl, bc
#a4c3#3ac3111
c1 
        pop bc
#a4c4#3ac4214/9
10 e3 
        djnz La4a9_row_loop
#a4c6#3ac6111
c1 
    pop bc
#a4c7#3ac7111
e1 
    pop hl
#a4c8#3ac8111
c9 
    ret
#a4c9#3ac9
#a4c9#3ac9
#a4c9#3ac9
; --------------------------------
#a4c9#3ac9
; Resets the game state to start a new game.
#a4c9#3ac9
La4c9_init_game_state:
#a4c9#3ac9217
dd e5 
    push ix
#a4cb#3acb112
e5 
    push hl
#a4cc#3acc112
d5 
    push de
#a4cd#3acd112
c5 
    push bc
#a4ce#3ace112
f5 
    push af
#a4cf#3acf28
3e 01 
        ld a, 1
#a4d1#3ad1314
32 79 74 
        ld (L7479_current_game_state), a
#a4d4#3ad428
3e 3f 
        ld a, 63
#a4d6#3ad6314
32 7b 74 
        ld (L747b), a
#a4d9#3ad928
3e ff 
        ld a, 255
#a4db#3adb314
32 20 6b 
        ld (L6b20_display_movement_pointer_flag), a
#a4de#3ade28
3e 20 
        ld a, 32  ; Initial value of the spirit meter
#a4e0#3ae0314
32 1f 6b 
        ld (L6b1f_current_spirit_meter), a
#a4e3#3ae315
af 
        xor a
#a4e4#3ae4314
32 7a 74 
        ld (L747a_requested_SFX), a
#a4e7#3ae7314
32 1c 6b 
        ld (L6b1c_movement_or_pointer), a
#a4ea#3aea314
32 1e 6b 
        ld (L6b1e_time_unit5), a
#a4ed#3aed314
32 74 74 
        ld (L7474_check_if_object_crushed_player_flag), a
#a4f0#3af0314
32 75 74 
        ld (L7475_call_Lcba4_check_for_player_falling_flag), a
#a4f3#3af328
06 2f 
        ld b, (L6b0d_new_key_taken - L6adf_game_boolean_variables) + 1  ; 47 bytes
#a4f5#3af5311
21 df 6a 
        ld hl, L6adf_game_boolean_variables
#a4f8#3af8
La4f8_mem_init_loop:
#a4f8#3af818
77 
        ld (hl), a
#a4f9#3af917
23 
        inc hl
#a4fa#3afa214/9
10 fc 
        djnz La4f8_mem_init_loop
#a4fc#3afc314
3a 23 6b 
        ld a, (L6b23_set_bit7_byte_3_flag_at_start)
#a4ff#3aff15
b7 
        or a
#a500#3b00213/8
28 05 
        jr z, La507
#a502#3b02311
21 e2 6a 
        ld hl, L6adf_game_boolean_variables + 3
#a505#3b05217
cb fe 
        set 7, (hl)
#a507#3b07
La507:
#a507#3b07314
3a 87 d0 
        ld a, (Ld087_starting_strength)
#a50a#3b0a314
32 0a 6b 
        ld (L6b0a_current_strength), a
#a50d#3b0d28
3e 02 
        ld a, 2
#a50f#3b0f314
32 b8 6a 
        ld (L6ab8_player_crawling), a  ; start not crawling
#a512#3b12314
32 0b 6b 
        ld (L6b0b_selected_movement_mode), a  ; start running
#a515#3b15318
cd f0 c0 
        call Lc0f0_get_initial_area_pointers
#a518#3b18314
3a 82 d0 
        ld a, (Ld082_n_areas)
#a51b#3b1b15
4f 
        ld c, a
#a51c#3b1c311
21 d1 d0 
        ld hl, Ld0d1_area_offsets
#a51f#3b1f
La51f_area_loop:
#a51f#3b1f18
5e 
        ld e, (hl)
#a520#3b2017
23 
        inc hl
#a521#3b2118
56 
        ld d, (hl)
#a522#3b2217
23 
        inc hl
#a523#3b23416
dd 21 82 d0 
        ld ix, Ld082_area_reference_start
#a527#3b27217
dd 19 
        add ix, de  ; ix = ptr to the area.
#a529#3b29321
dd 7e 01 
        ld a, (ix + AREA_N_OBJECTS)
#a52c#3b2c15
b7 
        or a
#a52d#3b2d213/8
28 1b 
        jr z, La54a_done_with_objects
#a52f#3b2f311
11 08 00 
        ld de, AREA_HEADER_SIZE
#a532#3b32217
dd 19 
        add ix, de
#a534#3b3415
47 
        ld b, a
#a535#3b35
La535_object_loop:
#a535#3b35
        ; Reset the state of each object:
#a535#3b35321
dd 7e 00 
        ld a, (ix + OBJECT_TYPE_AND_FLAGS)
#a538#3b3828
e6 8f 
        and #8f
#a53a#3b3a210
cb 7f 
        bit 7, a
#a53c#3b3c213/8
28 02 
        jr z, La540
#a53e#3b3e28
f6 40 
        or #40
#a540#3b40
La540:
#a540#3b40321
dd 77 00 
        ld (ix), a
#a543#3b43321
dd 5e 08 
        ld e, (ix + OBJECT_SIZE)
#a546#3b46217
dd 19 
        add ix, de
#a548#3b48214/9
10 eb 
        djnz La535_object_loop
#a54a#3b4a
La54a_done_with_objects:
#a54a#3b4a15
0d 
        dec c
#a54b#3b4b213/8
20 d2 
        jr nz, La51f_area_loop
#a54d#3b4d314
3a 85 d0 
        ld a, (Ld085_initial_area_id)
#a550#3b50314
32 cf 6a 
        ld (L6acf_current_area_id), a
#a553#3b53314
3a 86 d0 
        ld a, (Ld086_initial_player_object)
#a556#3b56314
32 67 74 
        ld (L7467_player_starting_position_object_id), a
#a559#3b59318
cd 63 a5 
        call La563_load_and_reset_new_area
#a55c#3b5c111
f1 
    pop af
#a55d#3b5d111
c1 
    pop bc
#a55e#3b5e111
d1 
    pop de
#a55f#3b5f111
e1 
    pop hl
#a560#3b60216
dd e1 
    pop ix
#a562#3b62111
c9 
    ret
#a563#3b63
#a563#3b63
#a563#3b63
; --------------------------------
#a563#3b63
; Searches and loads the area with ID (L6acf_current_area_id),
#a563#3b63
; teleporting the player to the desired start position (L7467_player_starting_position_object_id).
#a563#3b63
La563_load_and_reset_new_area:
#a563#3b63217
dd e5 
    push ix
#a565#3b65112
e5 
    push hl
#a566#3b66112
d5 
    push de
#a567#3b67112
c5 
    push bc
#a568#3b68112
f5 
    push af
#a569#3b69318
cd 43 c1 
        call Lc143_load_and_reset_current_area
#a56c#3b6c314
3a 67 74 
        ld a, (L7467_player_starting_position_object_id)
#a56f#3b6f314
32 68 74 
        ld (L7468_focus_object_id), a
#a572#3b7215
af 
        xor a
#a573#3b73318
cd 86 b2 
        call Lb286_find_object_by_id
#a576#3b7615
b7 
        or a
#a577#3b77213/8
20 4c 
        jr nz, La5c5_done
#a579#3b79311
11 20 00 
        ld de, 32
#a57c#3b7c15
42 
        ld b, d
#a57d#3b7d321
dd 7e 01 
        ld a, (ix + OBJECT_X)
#a580#3b8028
fe ff 
        cp 255
#a582#3b82213/8
28 07 
        jr z, La58b
#a584#3b8415
04 
        inc b
#a585#3b85318
cd cc a5 
        call La5cc_a_times_64
#a588#3b88317
22 ad 6a 
        ld (L6aad_player_current_x), hl
#a58b#3b8b
La58b:
#a58b#3b8b321
dd 7e 03 
        ld a, (ix + OBJECT_Z)
#a58e#3b8e28
fe ff 
        cp 255
#a590#3b90213/8
28 07 
        jr z, La599
#a592#3b9215
04 
        inc b
#a593#3b93318
cd cc a5 
        call La5cc_a_times_64
#a596#3b96317
22 b1 6a 
        ld (L6ab1_player_current_z), hl
#a599#3b99
La599:
#a599#3b99321
dd 7e 02 
        ld a, (ix + OBJECT_Y)
#a59c#3b9c28
fe ff 
        cp 255
#a59e#3b9e213/8
28 14 
        jr z, La5b4
#a5a0#3ba015
04 
        inc b
#a5a1#3ba115
67 
        ld h, a
#a5a2#3ba2314
3a be 6a 
        ld a, (L6abe_use_eye_player_coordinate)
#a5a5#3ba515
b7 
        or a
#a5a6#3ba6213/8
20 06 
        jr nz, La5ae
#a5a8#3ba8
        ; Adjust player y to be "eye" coordinate.
#a5a8#3ba8314
3a b9 6a 
        ld a, (L6ab9_player_height)
#a5ab#3bab15
3d 
        dec a
#a5ac#3bac15
84 
        add a, h
#a5ad#3bad15
67 
        ld h, a
#a5ae#3bae
La5ae:
#a5ae#3bae318
cd cd a5 
        call La5cd_h_times_64
#a5b1#3bb1317
22 af 6a 
        ld (L6aaf_player_current_y), hl
#a5b4#3bb4
La5b4:
#a5b4#3bb428
3e 03 
        ld a, 3
#a5b6#3bb615
b8 
        cp b
#a5b7#3bb7213/8
20 0c 
        jr nz, La5c5_done
#a5b9#3bb9321
dd 7e 04 
        ld a, (ix + OBJECT_SIZE_X)
#a5bc#3bbc314
32 b6 6a 
        ld (L6ab6_player_pitch_angle), a
#a5bf#3bbf321
dd 7e 05 
        ld a, (ix + OBJECT_SIZE_Y)
#a5c2#3bc2314
32 b7 6a 
        ld (L6ab7_player_yaw_angle), a
#a5c5#3bc5
La5c5_done:
#a5c5#3bc5111
f1 
    pop af
#a5c6#3bc6111
c1 
    pop bc
#a5c7#3bc7111
d1 
    pop de
#a5c8#3bc8111
e1 
    pop hl
#a5c9#3bc9216
dd e1 
    pop ix
#a5cb#3bcb111
c9 
    ret
#a5cc#3bcc
#a5cc#3bcc
#a5cc#3bcc
; --------------------------------
#a5cc#3bcc
; HL = a * 64
#a5cc#3bcc
; input:
#a5cc#3bcc
; - a
#a5cc#3bcc
; - de
#a5cc#3bcc
; output:
#a5cc#3bcc
; - hl = a*64 + de
#a5cc#3bcc
La5cc_a_times_64:
#a5cc#3bcc15
67 
    ld h, a
#a5cd#3bcd
La5cd_h_times_64:
#a5cd#3bcd28
2e 00 
    ld l, 0
#a5cf#3bcf210
cb 3c 
    srl h
#a5d1#3bd1210
cb 1d 
    rr l
#a5d3#3bd3210
cb 3c 
    srl h
#a5d5#3bd5210
cb 1d 
    rr l
#a5d7#3bd7112
19 
    add hl, de
#a5d8#3bd8111
c9 
    ret
#a5d9#3bd9
#a5d9#3bd9
#a5d9#3bd9
; --------------------------------
#a5d9#3bd9
; Attempts a player movement:
#a5d9#3bd9
; Input:
#a5d9#3bd9
; - desired player coordinates in (L7456_player_desired_x, ...)
#a5d9#3bd9
; Output:
#a5d9#3bd9
; - modifies (L6aad_player_current_x, ...)
#a5d9#3bd9
; - a: 1 if movement, 0 otehrwise.
#a5d9#3bd9
La5d9_move_player:
#a5d9#3bd9217
dd e5 
    push ix
#a5db#3bdb112
e5 
    push hl
#a5dc#3bdc112
d5 
    push de
#a5dd#3bdd112
c5 
    push bc
#a5de#3bde314
3a 28 6b 
        ld a, (L6b28_player_radius)
#a5e1#3be115
b7 
        or a
#a5e2#3be2213/8
28 50 
        jr z, La634_target_within_bounds  ; Cannot happen in this game (player ratius is always 10).
#a5e4#3be4317
2a 56 74 
        ld hl, (L7456_player_desired_x)
#a5e7#3be715
7c 
        ld a, h
#a5e8#3be828
fe 7f 
        cp #7f
#a5ea#3bea213/8
28 33 
        jr z, La61f_pop_and_return  ; out of bounds in x
#a5ec#3bec28
fe 9f 
        cp #9f
#a5ee#3bee213/8
28 2f 
        jr z, La61f_pop_and_return  ; out of bounds in x
#a5f0#3bf0422
ed 5b 5a 74 
        ld de, (L745a_player_desired_z)
#a5f4#3bf415
7a 
        ld a, d
#a5f5#3bf528
fe 7f 
        cp #7f
#a5f7#3bf7213/8
28 26 
        jr z, La61f_pop_and_return  ; out of bounds in z
#a5f9#3bf928
fe 9f 
        cp #9f
#a5fb#3bfb213/8
28 22 
        jr z, La61f_pop_and_return  ; out of bounds in z
#a5fd#3bfd15
af 
        xor a
#a5fe#3bfe311
01 c0 1f 
        ld bc, MAX_COORDINATE
#a601#3c01318
cd 23 a6 
        call La623_coordinates_positive_and_small_check
#a604#3c04210
cb 27 
        sla a
#a606#3c06317
2a ad 6a 
        ld hl, (L6aad_player_current_x)
#a609#3c09422
ed 5b b1 6a 
        ld de, (L6ab1_player_current_z)
#a60d#3c0d318
cd 23 a6 
        call La623_coordinates_positive_and_small_check
#a610#3c1015
b7 
        or a  ; both out of bounds
#a611#3c11311
ca cc a8 
        jp z, La8cc_accept_movement  ; if we are already out of bounds, just move
#a614#3c1428
fe 03 
        cp 3  ; both within bounds
#a616#3c16213/8
28 1c 
        jr z, La634_target_within_bounds
#a618#3c1828
fe 01 
        cp 1  ; target within bounds
#a61a#3c1a213/8
28 18 
        jr z, La634_target_within_bounds
#a61c#3c1c
        ; origin within bounds
#a61c#3c1c311
c3 cc a8 
        jp La8cc_accept_movement  ; if target is out of bounds, accept movement
#a61f#3c1f
La61f_pop_and_return:
#a61f#3c1f15
af 
        xor a  ; mark "no movement".
#a620#3c20311
c3 23 a9 
        jp La923_pop_and_return
#a623#3c23
#a623#3c23
; Auxiliary function of La5d9_move_player: checks if some x, z coordinates are within some bounds.
#a623#3c23
; input:
#a623#3c23
; - hl: x
#a623#3c23
; - de: z
#a623#3c23
; - bc: 127*64  (MAX_COORDINATE)
#a623#3c23
; output:
#a623#3c23
; - if the (x, z) coordinates are positive and smaller than bc, a++
#a623#3c23
La623_coordinates_positive_and_small_check:
#a623#3c23
    ; x out of bounds?
#a623#3c23210
cb 7c 
    bit 7, h  ; if x is negative -> return
#a625#3c25112/6
c0 
    ret nz
#a626#3c2615
b7 
    or a
#a627#3c27217
ed 42 
    sbc hl, bc  ; hl -= bc
#a629#3c29112/6
f0 
    ret p  ; if x is too large -> return
#a62a#3c2a
    ; z out of bounds?
#a62a#3c2a210
cb 7a 
    bit 7, d
#a62c#3c2c112/6
c0 
    ret nz  ; if z is negative -> return
#a62d#3c2d15
eb 
    ex de, hl
#a62e#3c2e15
b7 
    or a
#a62f#3c2f217
ed 42 
    sbc hl, bc  ; hl = de - bc
#a631#3c31112/6
f0 
    ret p  ; if z is too large -> return
#a632#3c32
    ; success, coordiantes are positive and small:
#a632#3c3215
3c 
    inc a  ; a++
#a633#3c33111
c9 
    ret
#a634#3c34
#a634#3c34
La634_target_within_bounds:
#a634#3c34
        ; The target coordinates have passed the "La623_coordinates_positive_and_small_check":
#a634#3c3415
af 
        xor a
#a635#3c35314
32 e5 74 
        ld (L74e5_collision_correction_object_shape_type), a
#a638#3c38314
32 e6 74 
        ld (L74e6_movement_involves_falling_flag), a
#a63b#3c3b314
32 eb 74 
        ld (L74eb_closest_object_below_ID), a
#a63e#3c3e15
67 
        ld h, a
#a63f#3c3f15
6f 
        ld l, a
#a640#3c40317
22 e3 74 
        ld (L74e3_player_height_16bits), hl
#a643#3c4317
2b 
        dec hl
#a644#3c44317
22 d2 74 
        ld (L74d0_target_object_climb_coordinates + 2), hl  ; #ffff
#a647#3c4715
47 
        ld b, a  ; b = 0
#a648#3c48314
3a 28 6b 
        ld a, (L6b28_player_radius)
#a64b#3c4b15
4f 
        ld c, a
#a64c#3c4c15
b7 
        or a
#a64d#3c4d213/8
28 01 
        jr z, La650
#a64f#3c4f15
0d 
        dec c  ; bc = radius - 1
#a650#3c50
La650:
#a650#3c50
        ; At this point:
#a650#3c50
        ; - bc = max(0, player radius - 1)
#a650#3c50314
3a be 6a 
        ld a, (L6abe_use_eye_player_coordinate)
#a653#3c5315
b7 
        or a
#a654#3c54213/8
20 21 
        jr nz, La677  ; jump if "eye coordinates":
#a656#3c56
        ; feet coordinates (used when we are checking if we need to fall):
#a656#3c5628
3e 02 
        ld a, 2
#a658#3c58314
32 e6 74 
        ld (L74e6_movement_involves_falling_flag), a
#a65b#3c5b317
2a ad 6a 
        ld hl, (L6aad_player_current_x)
#a65e#3c5e317
22 dc 74 
        ld (L74dc_falling_reference_coordinates), hl
#a661#3c61317
2a af 6a 
        ld hl, (L6aaf_player_current_y)
#a664#3c64317
22 de 74 
        ld (L74dc_falling_reference_coordinates + 2), hl
#a667#3c67317
2a b1 6a 
        ld hl, (L6ab1_player_current_z)
#a66a#3c6a317
22 e0 74 
        ld (L74dc_falling_reference_coordinates + 4), hl
#a66d#3c6d314
3a b9 6a 
        ld a, (L6ab9_player_height)
#a670#3c7015
67 
        ld h, a
#a671#3c71318
cd de a9 
        call La9de_hl_eq_h_times_64
#a674#3c74317
22 e3 74 
        ld (L74e3_player_height_16bits), hl
#a677#3c77
La677:
#a677#3c7715
af 
        xor a  ; initialize whether there is movement or not in any axis.
#a678#3c78317
2a 56 74 
        ld hl, (L7456_player_desired_x)
#a67b#3c7b317
22 ca 74 
        ld (L74ca_movement_target_coordinates_2), hl
#a67e#3c7e317
22 d6 74 
        ld (L74d6_movement_target_coordinates_1), hl
#a681#3c81
        ; Check if we are requesting movement in any axis, and in which direction:
#a681#3c81422
ed 5b ad 6a 
        ld de, (L6aad_player_current_x)
#a685#3c85112
e5 
        push hl
#a686#3c8615
b7 
            or a
#a687#3c87217
ed 52 
            sbc hl, de
#a689#3c89317
22 a6 74 
            ld (L74a6_player_movement_delta), hl
#a68c#3c8c111
e1 
        pop hl
#a68d#3c8d213/8
28 08 
        jr z, La697
#a68f#3c8f210
cb cf 
        set 1, a  ; positive movement on x axis
#a691#3c91311
f2 97 a6 
        jp p, La697
#a694#3c9428
3e 01 
        ld a, 1  ; negative movement on x axis
#a696#3c9615
eb 
        ex de, hl
#a697#3c97
La697:
#a697#3c97
        ; At this point:
#a697#3c97
        ; - bc = max(0, player radius - 1)
#a697#3c97
        ; - hl = max(desired x, player x)
#a697#3c97
        ; - de = min(player x, desired x)
#a697#3c97112
09 
        add hl, bc
#a698#3c98317
22 ac 74 
        ld (L74ac_movement_volume_max_coordinate), hl  ; max x + radius
#a69b#3c9b15
eb 
        ex de, hl
#a69c#3c9c15
b7 
        or a
#a69d#3c9d217
ed 42 
        sbc hl, bc
#a69f#3c9f317
22 b2 74 
        ld (L74b2_movement_volume_min_coordinate), hl  ; min x - radius
#a6a2#3ca2317
2a 58 74 
        ld hl, (L7458_player_desired_y)
#a6a5#3ca5317
22 cc 74 
        ld (L74ca_movement_target_coordinates_2 + 2), hl
#a6a8#3ca8317
22 d8 74 
        ld (L74d6_movement_target_coordinates_1 + 2), hl
#a6ab#3cab422
ed 5b af 6a 
        ld de, (L6aaf_player_current_y)
#a6af#3caf112
e5 
        push hl
#a6b0#3cb015
b7 
            or a
#a6b1#3cb1217
ed 52 
            sbc hl, de
#a6b3#3cb3317
22 a8 74 
            ld (L74a6_player_movement_delta + 2), hl
#a6b6#3cb6111
e1 
        pop hl
#a6b7#3cb7213/8
28 0a 
        jr z, La6c3
#a6b9#3cb9210
cb df 
        set 3, a  ; positive movement on y axis
#a6bb#3cbb311
f2 c3 a6 
        jp p, La6c3
#a6be#3cbe28
e6 f3 
        and #f3
#a6c0#3cc028
f6 04 
        or 4  ; negative movement on y axis
#a6c2#3cc215
eb 
        ex de, hl
#a6c3#3cc3
La6c3:
#a6c3#3cc3112
d5 
        push de
#a6c4#3cc415
57 
            ld d, a
#a6c5#3cc5314
3a be 6a 
            ld a, (L6abe_use_eye_player_coordinate)
#a6c8#3cc815
b7 
            or a
#a6c9#3cc915
7a 
            ld a, d
#a6ca#3cca111
d1 
        pop de
#a6cb#3ccb213/8
20 10 
        jr nz, La6dd
#a6cd#3ccd
        ; Feet coordinates: take into account whole player height.
#a6cd#3ccd17
13 
        inc de
#a6ce#3cce422
ed 53 b4 74 
        ld (L74b2_movement_volume_min_coordinate + 2), de
#a6d2#3cd2422
ed 5b e3 74 
        ld de, (L74e3_player_height_16bits)
#a6d6#3cd6112
19 
        add hl, de
#a6d7#3cd717
2b 
        dec hl
#a6d8#3cd8317
22 ae 74 
        ld (L74ac_movement_volume_max_coordinate + 2), hl
#a6db#3cdb213
18 0b 
        jr La6e8
#a6dd#3cdd
La6dd:
#a6dd#3cdd
        ; Eye coordinates: consider just a cube around the eye coordinates,
#a6dd#3cdd
        ; ignoring player height.
#a6dd#3cdd112
09 
        add hl, bc
#a6de#3cde317
22 ae 74 
        ld (L74ac_movement_volume_max_coordinate + 2), hl
#a6e1#3ce115
eb 
        ex de, hl
#a6e2#3ce215
b7 
        or a
#a6e3#3ce3217
ed 42 
        sbc hl, bc
#a6e5#3ce5317
22 b4 74 
        ld (L74b2_movement_volume_min_coordinate + 2), hl
#a6e8#3ce8
#a6e8#3ce8
La6e8:
#a6e8#3ce8317
2a 5a 74 
        ld hl, (L745a_player_desired_z)
#a6eb#3ceb317
22 ce 74 
        ld (L74ca_movement_target_coordinates_2 + 4), hl
#a6ee#3cee317
22 da 74 
        ld (L74d6_movement_target_coordinates_1 + 4), hl
#a6f1#3cf1422
ed 5b b1 6a 
        ld de, (L6ab1_player_current_z)
#a6f5#3cf5112
e5 
        push hl
#a6f6#3cf615
b7 
            or a
#a6f7#3cf7217
ed 52 
            sbc hl, de
#a6f9#3cf9317
22 aa 74 
            ld (L74a6_player_movement_delta + 4), hl
#a6fc#3cfc111
e1 
        pop hl
#a6fd#3cfd213/8
28 0a 
        jr z, La709
#a6ff#3cff210
cb ef 
        set 5, a  ; positive movement on z axis
#a701#3d01311
f2 09 a7 
        jp p, La709
#a704#3d0428
e6 cf 
        and #cf
#a706#3d0628
f6 10 
        or 16  ; negative movement on z axis
#a708#3d0815
eb 
        ex de, hl
#a709#3d09
La709:
#a709#3d09112
09 
        add hl, bc
#a70a#3d0a317
22 b0 74 
        ld (L74ac_movement_volume_max_coordinate + 4), hl
#a70d#3d0d15
eb 
        ex de, hl
#a70e#3d0e15
b7 
        or a
#a70f#3d0f217
ed 42 
        sbc hl, bc
#a711#3d11317
22 b6 74 
        ld (L74b2_movement_volume_min_coordinate + 4), hl
#a714#3d1415
b7 
        or a
#a715#3d15311
ca 23 a9 
        jp z, La923_pop_and_return  ; if there is no movement in any axis, just return
#a718#3d18314
32 e2 74 
        ld (L74e2_movement_direction_bits), a  ; bits 0,1: movement on x, bits 2,3: movement on y, bits 4,5: movement on z
#a71b#3d1b
#a71b#3d1b314
3a be 6a 
        ld a, (L6abe_use_eye_player_coordinate)
#a71e#3d1e15
b7 
        or a
#a71f#3d1f311
c2 25 a8 
        jp nz, La825_movement_without_falling
#a722#3d22
#a722#3d22
La722_movement_with_falling:
#a722#3d22
        ; Feet coordinates movement, consider falling!
#a722#3d22318
cd 9f aa 
        call Laa9f_find_closest_object_below
#a725#3d25317
2a e7 74 
        ld hl, (L74e7_closest_object_below_distance)
#a728#3d2815
7d 
        ld a, l  ; if we are on top of an object, ignore falling
#a729#3d2915
b4 
        or h
#a72a#3d2a311
c2 25 a8 
        jp nz, La825_movement_without_falling
#a72d#3d2d
#a72d#3d2d
        ; We are falling!
#a72d#3d2d314
3a eb 74 
        ld a, (L74eb_closest_object_below_ID)
#a730#3d3015
b7 
        or a
#a731#3d31213/8
28 52 
        jr z, La785_falling_without_object
#a733#3d33
#a733#3d33
        ; Check if in the target x, z we wanted to be over this object
#a733#3d33
        ; If not, it means the object interrupted x/z movement, and we need to adjust.
#a733#3d33422
dd 2a e9 74 
        ld ix, (L74e9_closest_object_below_ptr)
#a737#3d37321
dd 66 01 
        ld h, (ix + OBJECT_X)
#a73a#3d3a318
cd de a9 
        call La9de_hl_eq_h_times_64
#a73d#3d3d15
af 
        xor a
#a73e#3d3e422
ed 5b 56 74 
        ld de, (L7456_player_desired_x)
#a742#3d42217
ed 52 
        sbc hl, de  ; object x * 64 - desired x
#a744#3d44311
f2 8c a7 
        jp p, La78c_object_below_not_really_below
#a747#3d47321
dd 7e 01 
        ld a, (ix + OBJECT_X)
#a74a#3d4a321
dd 86 04 
        add a, (ix + OBJECT_SIZE_X)
#a74d#3d4d15
67 
        ld h, a
#a74e#3d4e318
cd de a9 
        call La9de_hl_eq_h_times_64
#a751#3d5115
af 
        xor a
#a752#3d52217
ed 52 
        sbc hl, de
#a754#3d54311
fa 8c a7 
        jp m, La78c_object_below_not_really_below
#a757#3d57321
dd 66 03 
        ld h, (ix + OBJECT_Z)
#a75a#3d5a318
cd de a9 
        call La9de_hl_eq_h_times_64
#a75d#3d5d15
af 
        xor a
#a75e#3d5e422
ed 5b 5a 74 
        ld de, (L745a_player_desired_z)
#a762#3d62217
ed 52 
        sbc hl, de
#a764#3d64311
f2 8c a7 
        jp p, La78c_object_below_not_really_below
#a767#3d67321
dd 7e 03 
        ld a, (ix + OBJECT_Z)
#a76a#3d6a321
dd 86 06 
        add a, (ix + OBJECT_SIZE_Z)
#a76d#3d6d15
67 
        ld h, a
#a76e#3d6e318
cd de a9 
        call La9de_hl_eq_h_times_64
#a771#3d7115
af 
        xor a
#a772#3d72217
ed 52 
        sbc hl, de
#a774#3d74311
fa 8c a7 
        jp m, La78c_object_below_not_really_below
#a777#3d77
        
#a777#3d77
        ; Set the new reference coordinates for falling:
#a777#3d77311
21 56 74 
        ld hl, L7456_player_desired_x
#a77a#3d7a311
11 dc 74 
        ld de, L74dc_falling_reference_coordinates
#a77d#3d7d311
01 06 00 
        ld bc, 6
#a780#3d80223/18
ed b0 
        ldir
#a782#3d82
#a782#3d82
        ; Find another object (just in case?) and move on 
#a782#3d82
        ; to regular movement.
#a782#3d82318
cd 9f aa 
        call Laa9f_find_closest_object_below
#a785#3d85
La785_falling_without_object:
#a785#3d8515
af 
        xor a
#a786#3d86314
32 e6 74 
        ld (L74e6_movement_involves_falling_flag), a
#a789#3d89311
c3 25 a8 
        jp La825_movement_without_falling
#a78c#3d8c
#a78c#3d8c
La78c_object_below_not_really_below:
#a78c#3d8c
        ; The object we collided with interrupted us half way to reaching
#a78c#3d8c
        ; the target x, z. We need to cut the movement short:
#a78c#3d8c314
3a e2 74 
        ld a, (L74e2_movement_direction_bits)
#a78f#3d8f210
cb 47 
        bit 0, a
#a791#3d91213/8
28 05 
        jr z, La798
#a793#3d93
        ; negative x movement
#a793#3d93321
dd 66 01 
        ld h, (ix + OBJECT_X)
#a796#3d96213
18 0b 
        jr La7a3
#a798#3d98
La798:
#a798#3d98210
cb 4f 
        bit 1, a
#a79a#3d9a213/8
28 4b 
        jr z, La7e7
#a79c#3d9c
        ; positive x movement
#a79c#3d9c321
dd 7e 01 
        ld a, (ix + OBJECT_X)
#a79f#3d9f321
dd 86 04 
        add a, (ix + OBJECT_SIZE_X)
#a7a2#3da215
67 
        ld h, a
#a7a3#3da3
La7a3:
#a7a3#3da3318
cd de a9 
        call La9de_hl_eq_h_times_64  ; hl = object x2 * 2
#a7a6#3da6317
22 dc 74 
        ld (L74dc_falling_reference_coordinates), hl
#a7a9#3da9318
cd 7b ae 
        call Lae7b_relative_z_proportional_to_relative_x_and_player_movement_direction
#a7ac#3dac317
22 e0 74 
        ld (L74dc_falling_reference_coordinates + 4), hl
#a7af#3daf321
dd 56 03 
        ld d, (ix + OBJECT_Z)
#a7b2#3db2318
cd d3 a9 
        call La9d3_de_eq_d_times_64
#a7b5#3db515
b7 
        or a
#a7b6#3db6112
e5 
        push hl
#a7b7#3db7217
ed 52 
            sbc hl, de
#a7b9#3db9111
e1 
        pop hl
#a7ba#3dba311
fa e7 a7 
        jp m, La7e7
#a7bd#3dbd321
dd 7e 03 
        ld a, (ix + OBJECT_Z)
#a7c0#3dc0321
dd 86 06 
        add a, (ix + OBJECT_SIZE_Z)
#a7c3#3dc315
57 
        ld d, a
#a7c4#3dc4318
cd d3 a9 
        call La9d3_de_eq_d_times_64
#a7c7#3dc715
b7 
        or a
#a7c8#3dc8217
ed 52 
        sbc hl, de
#a7ca#3dca311
f2 e7 a7 
        jp p, La7e7
#a7cd#3dcd317
2a dc 74 
        ld hl, (L74dc_falling_reference_coordinates)
#a7d0#3dd0422
ed 4b 28 6b 
        ld bc, (L6b28_player_radius)
#a7d4#3dd4314
3a e2 74 
        ld a, (L74e2_movement_direction_bits)
#a7d7#3dd7210
cb 47 
        bit 0, a
#a7d9#3dd9213/8
28 05 
        jr z, La7e0
#a7db#3ddb15
b7 
        or a
#a7dc#3ddc217
ed 42 
        sbc hl, bc
#a7de#3dde213
18 01 
        jr La7e1
#a7e0#3de0
La7e0:
#a7e0#3de0112
09 
        add hl, bc
#a7e1#3de1
La7e1:
#a7e1#3de1
        ; we have adjusted the coordinates, try again to see now if we can keep falling:
#a7e1#3de1317
22 dc 74 
        ld (L74dc_falling_reference_coordinates), hl
#a7e4#3de4311
c3 22 a7 
        jp La722_movement_with_falling
#a7e7#3de7
#a7e7#3de7
La7e7:
#a7e7#3de7
        ; Movement in 'x' was not interrupted, try to see if movement in 'z' is the one interrupted:
#a7e7#3de7314
3a e2 74 
        ld a, (L74e2_movement_direction_bits)
#a7ea#3dea210
cb 67 
        bit 4, a
#a7ec#3dec213/8
28 05 
        jr z, La7f3
#a7ee#3dee321
dd 66 03 
        ld h, (ix + OBJECT_Z)
#a7f1#3df1213
18 0c 
        jr La7ff
#a7f3#3df3
La7f3:
#a7f3#3df3210
cb 6f 
        bit 5, a
#a7f5#3df5311
ca 25 a8 
        jp z, La825_movement_without_falling
#a7f8#3df8321
dd 7e 03 
        ld a, (ix + OBJECT_Z)
#a7fb#3dfb321
dd 86 06 
        add a, (ix + OBJECT_SIZE_Z)
#a7fe#3dfe15
67 
        ld h, a
#a7ff#3dff
La7ff:
#a7ff#3dff318
cd de a9 
        call La9de_hl_eq_h_times_64
#a802#3e02317
22 e0 74 
        ld (L74dc_falling_reference_coordinates + 4), hl
#a805#3e05318
cd 96 ae 
        call Lae96_relative_x_proportional_to_relative_z_and_player_movement_direction
#a808#3e08317
22 dc 74 
        ld (L74dc_falling_reference_coordinates), hl
#a80b#3e0b317
2a e0 74 
        ld hl, (L74dc_falling_reference_coordinates + 4)
#a80e#3e0e422
ed 4b 28 6b 
        ld bc, (L6b28_player_radius)
#a812#3e12314
3a e2 74 
        ld a, (L74e2_movement_direction_bits)
#a815#3e15210
cb 67 
        bit 4, a
#a817#3e17213/8
28 05 
        jr z, La81e
#a819#3e1915
b7 
        or a
#a81a#3e1a217
ed 42 
        sbc hl, bc
#a81c#3e1c213
18 01 
        jr La81f
#a81e#3e1e
La81e:
#a81e#3e1e112
09 
        add hl, bc
#a81f#3e1f
La81f:
#a81f#3e1f
        ; we have adjusted the coordinates, try again to see now if we can keep falling:
#a81f#3e1f317
22 e0 74 
        ld (L74dc_falling_reference_coordinates + 4), hl
#a822#3e22311
c3 22 a7 
        jp La722_movement_with_falling
#a825#3e25
#a825#3e25
La825_movement_without_falling:
#a825#3e25
        ; Eye coordinates movement, do not consider falling:
#a825#3e25318
cd 56 ab 
        call Lab56_correct_player_movement_if_collision
#a828#3e28314
3a 28 6b 
        ld a, (L6b28_player_radius)
#a82b#3e2b15
b7 
        or a
#a82c#3e2c28
3e 01 
        ld a, 1
#a82e#3e2e311
ca 23 a9 
        jp z, La923_pop_and_return
#a831#3e31314
3a e6 74 
        ld a, (L74e6_movement_involves_falling_flag)
#a834#3e3415
b7 
        or a
#a835#3e35213/8
20 19 
        jr nz, La850_movement_involved_falling
#a837#3e37
La837:
#a837#3e37
        ; Movement did not involve falling:
#a837#3e37
        ; Set L74d6_movement_target_coordinates_1 as our desired move:
#a837#3e37311
21 d6 74 
        ld hl, L74d6_movement_target_coordinates_1
#a83a#3e3a311
11 56 74 
        ld de, L7456_player_desired_x
#a83d#3e3d311
01 06 00 
        ld bc, 6
#a840#3e40223/18
ed b0 
        ldir
#a842#3e42314
3a 80 74 
        ld a, (L7480_under_pointer_object_ID)
#a845#3e4515
b7 
        or a
#a846#3e46213/8
20 67 
        jr nz, La8af
#a848#3e48314
3a eb 74 
        ld a, (L74eb_closest_object_below_ID)
#a84b#3e4b314
32 80 74 
        ld (L7480_under_pointer_object_ID), a
#a84e#3e4e213
18 5f 
        jr La8af
#a850#3e50
#a850#3e50
La850_movement_involved_falling:
#a850#3e50317
2a ca 74 
        ld hl, (L74ca_movement_target_coordinates_2)
#a853#3e53422
ed 5b cc 74 
        ld de, (L74ca_movement_target_coordinates_2 + 2)
#a857#3e57422
ed 4b ce 74 
        ld bc, (L74ca_movement_target_coordinates_2 + 4)
#a85b#3e5b318
cd e9 a9 
        call La9e9_manhattan_distance_to_player
#a85e#3e5e112
e5 
        push hl
#a85f#3e5f317
2a dc 74 
            ld hl, (L74dc_falling_reference_coordinates)
#a862#3e62422
ed 5b de 74 
            ld de, (L74dc_falling_reference_coordinates + 2)
#a866#3e66422
ed 4b e0 74 
            ld bc, (L74dc_falling_reference_coordinates + 4)
#a86a#3e6a318
cd e9 a9 
            call La9e9_manhattan_distance_to_player
#a86d#3e6d111
d1 
        pop de
#a86e#3e6e15
b7 
        or a
#a86f#3e6f217
ed 52 
        sbc hl, de  ; hl = distance to falling reference - distance to target 2
#a871#3e71311
f2 37 a8 
        jp p, La837  ; target 2 is closer, just go to regular movement without falling
#a874#3e74
        ; Move player down, and if distance is too large, call Lcb78_fall_from_height
#a874#3e74422
ed 5b e7 74 
        ld de, (L74e7_closest_object_below_distance)
#a878#3e78317
2a de 74 
        ld hl, (L74dc_falling_reference_coordinates + 2)
#a87b#3e7b15
af 
        xor a
#a87c#3e7c314
32 76 74 
        ld (L7476_trigger_collision_event_flag), a
#a87f#3e7f217
ed 52 
        sbc hl, de
#a881#3e81317
22 de 74 
        ld (L74dc_falling_reference_coordinates + 2), hl
#a884#3e84317
22 58 74 
        ld (L7458_player_desired_y), hl
#a887#3e87317
2a dc 74 
        ld hl, (L74dc_falling_reference_coordinates)
#a88a#3e8a317
22 56 74 
        ld (L7456_player_desired_x), hl
#a88d#3e8d317
2a e0 74 
        ld hl, (L74dc_falling_reference_coordinates + 4)
#a890#3e90317
22 5a 74 
        ld (L745a_player_desired_z), hl
#a893#3e9315
eb 
        ex de, hl
#a894#3e94112
29 
        add hl, hl
#a895#3e95112
29 
        add hl, hl
#a896#3e96314
3a ba 6a 
        ld a, (L6aba_max_falling_height_without_damage)
#a899#3e9915
bc 
        cp h
#a89a#3e9a311
f2 a2 a8 
        jp p, La8a2  ; jump is fall is acceptable
#a89d#3e9d318
cd 78 cb 
        call Lcb78_fall_from_height
#a8a0#3ea0213
18 2a 
        jr La8cc_accept_movement
#a8a2#3ea2
#a8a2#3ea2
La8a2:
#a8a2#3ea2
        ; Move down without damage
#a8a2#3ea2314
3a eb 74 
        ld a, (L74eb_closest_object_below_ID)
#a8a5#3ea5314
32 80 74 
        ld (L7480_under_pointer_object_ID), a
#a8a8#3ea828
3e 0c 
        ld a, SFX_CLIMB_DROP
#a8aa#3eaa314
32 7a 74 
        ld (L747a_requested_SFX), a
#a8ad#3ead213
18 1d 
        jr La8cc_accept_movement
#a8af#3eaf
La8af:
#a8af#3eaf314
3a be 6a 
        ld a, (L6abe_use_eye_player_coordinate)
#a8b2#3eb215
b7 
        or a
#a8b3#3eb3213/8
20 17 
        jr nz, La8cc_accept_movement
#a8b5#3eb5
        ; Using feet coordinates (when falling/climbing):
#a8b5#3eb5317
2a d2 74 
        ld hl, (L74d0_target_object_climb_coordinates + 2)
#a8b8#3eb8210
cb 7c 
        bit 7, h
#a8ba#3eba213/8
20 10 
        jr nz, La8cc_accept_movement
#a8bc#3ebc
        ; See if we tried to climb to high an altitude:
#a8bc#3ebc422
ed 5b 58 74 
        ld de, (L7458_player_desired_y)
#a8c0#3ec015
b7 
        or a
#a8c1#3ec1217
ed 52 
        sbc hl, de
#a8c3#3ec3112
29 
        add hl, hl
#a8c4#3ec4112
29 
        add hl, hl
#a8c5#3ec5314
3a bb 6a 
        ld a, (L6abb_max_climbable_height)
#a8c8#3ec815
bc 
        cp h
#a8c9#3ec9
        ; If height is acceptable, climb!
#a8c9#3ec9318/11
d4 29 a9 
        call nc, La929_teleport_player_if_no_collision
#a8cc#3ecc
#a8cc#3ecc
La8cc_accept_movement:
#a8cc#3ecc
        ; Actually execute the movement:
#a8cc#3ecc
        ; If player is within bounds, turn on culling, otherwise, turn it off.
#a8cc#3ecc
        ; My guess is that this is to prevent not rendering anything if player
#a8cc#3ecc
        ; is too far.
#a8cc#3ecc
        ; Note: not sure why "La623_coordinates_positive_and_small_check" was
#a8cc#3ecc
        ;       not used for this, as it's the same logic.
#a8cc#3ecc
        ; x within bounds:?
#a8cc#3ecc311
11 c0 1f 
        ld de, MAX_COORDINATE
#a8cf#3ecf317
2a 56 74 
        ld hl, (L7456_player_desired_x)
#a8d2#3ed2210
cb 7c 
        bit 7, h
#a8d4#3ed4213/8
20 13 
        jr nz, La8e9_no_culling
#a8d6#3ed615
b7 
        or a
#a8d7#3ed7217
ed 52 
        sbc hl, de
#a8d9#3ed9311
f2 e9 a8 
        jp p, La8e9_no_culling
#a8dc#3edc
        ; z within bounds:?
#a8dc#3edc317
2a 5a 74 
        ld hl, (L745a_player_desired_z)
#a8df#3edf210
cb 7c 
        bit 7, h
#a8e1#3ee1213/8
20 06 
        jr nz, La8e9_no_culling
#a8e3#3ee315
af 
        xor a  ; culling
#a8e4#3ee4217
ed 52 
        sbc hl, de
#a8e6#3ee6311
fa eb a8 
        jp m, La8eb
#a8e9#3ee9
La8e9_no_culling:
#a8e9#3ee928
3e 01 
        ld a, 1  ; no culling
#a8eb#3eeb
La8eb:
#a8eb#3eeb314
32 bd 6a 
        ld (L6abd_cull_by_rendering_volume_flag), a
#a8ee#3eee
        ; Copy x coordinate, and mark "a = 1" if there is a change:
#a8ee#3eee422
ed 5b 56 74 
        ld de, (L7456_player_desired_x)
#a8f2#3ef2317
2a ad 6a 
        ld hl, (L6aad_player_current_x)
#a8f5#3ef515
af 
        xor a
#a8f6#3ef6217
ed 52 
        sbc hl, de
#a8f8#3ef8213/8
28 05 
        jr z, La8ff
#a8fa#3efa422
ed 53 ad 6a 
        ld (L6aad_player_current_x), de
#a8fe#3efe15
3c 
        inc a
#a8ff#3eff
La8ff:
#a8ff#3eff
        ; Copy y coordinate, and mark "a = 1" if there is a change:
#a8ff#3eff422
ed 5b 58 74 
        ld de, (L7458_player_desired_y)
#a903#3f03317
2a af 6a 
        ld hl, (L6aaf_player_current_y)
#a906#3f0615
b7 
        or a
#a907#3f07217
ed 52 
        sbc hl, de
#a909#3f09213/8
28 06 
        jr z, La911
#a90b#3f0b422
ed 53 af 6a 
        ld (L6aaf_player_current_y), de
#a90f#3f0f28
3e 01 
        ld a, 1
#a911#3f11
La911:
#a911#3f11
        ; Copy z coordinate, and mark "a = 1" if there is a change:
#a911#3f11422
ed 5b 5a 74 
        ld de, (L745a_player_desired_z)
#a915#3f15317
2a b1 6a 
        ld hl, (L6ab1_player_current_z)
#a918#3f1815
b7 
        or a
#a919#3f19217
ed 52 
        sbc hl, de
#a91b#3f1b213/8
28 06 
        jr z, La923_pop_and_return
#a91d#3f1d422
ed 53 b1 6a 
        ld (L6ab1_player_current_z), de
#a921#3f2128
3e 01 
        ld a, 1
#a923#3f23
La923_pop_and_return:
#a923#3f23111
c1 
    pop bc
#a924#3f24111
d1 
    pop de
#a925#3f25111
e1 
    pop hl
#a926#3f26216
dd e1 
    pop ix
#a928#3f28111
c9 
    ret
#a929#3f29
#a929#3f29
#a929#3f29
; --------------------------------
#a929#3f29
; Checks if the player would collide with any visible object if moving to
#a929#3f29
; coordinates (L74d0_target_object_climb_coordinates), and if there is no collision:
#a929#3f29
; - sets the player desired coordinates to (L74d0_target_object_climb_coordinates).
#a929#3f29
; - Sets L7476_trigger_collision_event_flag to 0,
#a929#3f29
; - Plays an SFX.
#a929#3f29
; This is used, for example, to teleport the player on top of a short object,
#a929#3f29
; when colliding with it.
#a929#3f29
La929_teleport_player_if_no_collision:
#a929#3f29422
dd 2a d1 6a 
    ld ix, (L6ad1_current_area_objects)
#a92d#3f2d314
3a d0 6a 
    ld a, (L6ad0_current_area_n_objects)
#a930#3f3015
b7 
    or a
#a931#3f31318/11
c4 53 a9 
    call nz, La953_find_object_with_collision
#a934#3f34422
dd 2a 63 74 
    ld ix, (L7463_global_area_objects)
#a938#3f38314
3a 65 74 
    ld a, (L7465_global_area_n_objects)
#a93b#3f3b15
b7 
    or a
#a93c#3f3c318/11
c4 53 a9 
    call nz, La953_find_object_with_collision
#a93f#3f3f
    ; No collision! Set the desired player coordinates to the target coordinates!
#a93f#3f3f314
32 76 74 
    ld (L7476_trigger_collision_event_flag), a  ; a == 0 here
#a942#3f42311
21 d0 74 
    ld hl, L74d0_target_object_climb_coordinates
#a945#3f45311
11 56 74 
    ld de, L7456_player_desired_x
#a948#3f48311
01 06 00 
    ld bc, 6
#a94b#3f4b223/18
ed b0 
    ldir
#a94d#3f4d28
3e 0c 
    ld a, SFX_CLIMB_DROP
#a94f#3f4f314
32 7a 74 
    ld (L747a_requested_SFX), a
#a952#3f52
La952:
#a952#3f52111
c9 
    ret
#a953#3f53
#a953#3f53
#a953#3f53
; --------------------------------
#a953#3f53
; Checks if there is any object that collides with a vertical line that 
#a953#3f53
; is at coordinates (L74d0_target_object_climb_coordinates), with height (L74e3_player_height_16bits)
#a953#3f53
; Input:
#a953#3f53
; - a: number of objects
#a953#3f53
; - ix: pointer to first object
#a953#3f53
La953_find_object_with_collision:
#a953#3f5315
47 
    ld b, a  ; number of objects
#a954#3f54
La954_object_loop:
#a954#3f54422
dd cb 00 76 
    bit 6, (ix)  ; is the object visible?
#a958#3f58311
c2 c7 a9 
    jp nz, La9c7_next_object  ; if not visible, skip
#a95b#3f5b
#a95b#3f5b
    ; "y" coordinate check: check if (L74d0_target_object_climb_coordinates + 2) is within the object bounding box "x":
#a95b#3f5b321
dd 66 02 
    ld h, (ix + OBJECT_Y)
#a95e#3f5e318
cd de a9 
    call La9de_hl_eq_h_times_64
#a961#3f61422
ed 5b e3 74 
    ld de, (L74e3_player_height_16bits)
#a965#3f6515
b7 
    or a
#a966#3f66217
ed 52 
    sbc hl, de  ; hl = object y * 64 - (L74e3_player_height_16bits)
#a968#3f68422
ed 5b d2 74 
    ld de, (L74d0_target_object_climb_coordinates + 2)  ; y
#a96c#3f6c15
af 
    xor a
#a96d#3f6d217
ed 52 
    sbc hl, de  ; hl = object y * 64 - ((L74e3_player_height_16bits) + (L74d0_target_object_climb_coordinates + 2))
#a96f#3f6f
    ; If (L74e3_player_height_16bits) + (L74d0_target_object_climb_coordinates + 2) < object y * 64, skip
#a96f#3f6f311
f2 c7 a9 
    jp p, La9c7_next_object
#a972#3f72
#a972#3f7215
eb 
    ex de, hl  ; hl = (L74d0_target_object_climb_coordinates + 2)
#a973#3f73321
dd 7e 02 
    ld a, (ix + OBJECT_Y)
#a976#3f76321
dd 86 05 
    add a, (ix + OBJECT_SIZE_Y)
#a979#3f7915
57 
    ld d, a  ; d = object y2 = object y + object size y 
#a97a#3f7a318
cd d3 a9 
    call La9d3_de_eq_d_times_64
#a97d#3f7d15
af 
    xor a
#a97e#3f7e217
ed 52 
    sbc hl, de
#a980#3f80
    ; If (L74d0_target_object_climb_coordinates + 2) > object y2 * 64, skip
#a980#3f80311
f2 c7 a9 
    jp p, La9c7_next_object
#a983#3f83
#a983#3f83
    ; "x" coordinate check: check if (L74d0_target_object_climb_coordinates) is within the object bounding box "x":
#a983#3f83321
dd 56 01 
    ld d, (ix + OBJECT_X)
#a986#3f86318
cd d3 a9 
    call La9d3_de_eq_d_times_64
#a989#3f89317
2a d0 74 
    ld hl, (L74d0_target_object_climb_coordinates)  ; x
#a98c#3f8c15
af 
    xor a
#a98d#3f8d217
ed 52 
    sbc hl, de
#a98f#3f8f
    ; if (L74d0_target_object_climb_coordinates) < object x * 64, skip
#a98f#3f8f311
fa c7 a9 
    jp m, La9c7_next_object
#a992#3f92
#a992#3f92321
dd 66 04 
    ld h, (ix + OBJECT_SIZE_X)
#a995#3f95318
cd de a9 
    call La9de_hl_eq_h_times_64
#a998#3f98112
19 
    add hl, de  ; hl = object x2 * 64
#a999#3f99422
ed 5b d0 74 
    ld de, (L74d0_target_object_climb_coordinates)  ; z
#a99d#3f9d15
af 
    xor a
#a99e#3f9e217
ed 52 
    sbc hl, de
#a9a0#3fa0
    ; if object x2 * 64 < (L74d0_target_object_climb_coordinates), skip
#a9a0#3fa0311
fa c7 a9 
    jp m, La9c7_next_object
#a9a3#3fa3
#a9a3#3fa3
    ; "z" coordinate check: check if (L74d0_target_object_climb_coordinates + 4) is within the object bounding box "z":
#a9a3#3fa3321
dd 56 03 
    ld d, (ix + OBJECT_Z)
#a9a6#3fa6318
cd d3 a9 
    call La9d3_de_eq_d_times_64
#a9a9#3fa9317
2a d4 74 
    ld hl, (L74d0_target_object_climb_coordinates + 4)
#a9ac#3fac15
af 
    xor a
#a9ad#3fad217
ed 52 
    sbc hl, de
#a9af#3faf
    ; if (L74d0_target_object_climb_coordinates + 4) < object z * 64, skip
#a9af#3faf311
fa c7 a9 
    jp m, La9c7_next_object
#a9b2#3fb2
#a9b2#3fb2321
dd 66 06 
    ld h, (ix + OBJECT_SIZE_Z)
#a9b5#3fb5318
cd de a9 
    call La9de_hl_eq_h_times_64
#a9b8#3fb8112
19 
    add hl, de
#a9b9#3fb9422
ed 5b d4 74 
    ld de, (L74d0_target_object_climb_coordinates + 4)
#a9bd#3fbd15
af 
    xor a
#a9be#3fbe217
ed 52 
    sbc hl, de
#a9c0#3fc0
    ; if object z2 * 64 < (L74d0_target_object_climb_coordinates + 4), skip
#a9c0#3fc0311
fa c7 a9 
    jp m, La9c7_next_object
#a9c3#3fc3
#a9c3#3fc3
    ; Collision!
#a9c3#3fc3111
e1 
    pop hl  ; simulate a ret
#a9c4#3fc4311
c3 52 a9 
    jp La952  ; return from La929_teleport_player_if_no_collision
#a9c7#3fc7
La9c7_next_object:
#a9c7#3fc7321
dd 5e 08 
    ld e, (ix + OBJECT_SIZE)
#a9ca#3fca28
16 00 
    ld d, 0
#a9cc#3fcc217
dd 19 
    add ix, de  ; next object
#a9ce#3fce15
05 
    dec b
#a9cf#3fcf311
c2 54 a9 
    jp nz, La954_object_loop
#a9d2#3fd2111
c9 
    ret
#a9d3#3fd3
#a9d3#3fd3
#a9d3#3fd3
; --------------------------------
#a9d3#3fd3
; input:
#a9d3#3fd3
; - d
#a9d3#3fd3
; output:
#a9d3#3fd3
; - de = d * 64
#a9d3#3fd3
La9d3_de_eq_d_times_64:
#a9d3#3fd328
1e 00 
    ld e, 0
#a9d5#3fd5210
cb 3a 
    srl d
#a9d7#3fd7210
cb 1b 
    rr e
#a9d9#3fd9210
cb 3a 
    srl d
#a9db#3fdb210
cb 1b 
    rr e
#a9dd#3fdd111
c9 
    ret
#a9de#3fde
#a9de#3fde
#a9de#3fde
; --------------------------------
#a9de#3fde
; input:
#a9de#3fde
; - h
#a9de#3fde
; output:
#a9de#3fde
; - hl = h * 64
#a9de#3fde
La9de_hl_eq_h_times_64:
#a9de#3fde28
2e 00 
    ld l, 0
#a9e0#3fe0210
cb 3c 
    srl h
#a9e2#3fe2210
cb 1d 
    rr l
#a9e4#3fe4210
cb 3c 
    srl h
#a9e6#3fe6210
cb 1d 
    rr l
#a9e8#3fe8111
c9 
    ret
#a9e9#3fe9
#a9e9#3fe9
#a9e9#3fe9
; --------------------------------
#a9e9#3fe9
; Calculates the Manhattan distance between the current player coordinates and (hl, de, bc)
#a9e9#3fe9
; Input:
#a9e9#3fe9
; - hl: x
#a9e9#3fe9
; - de: y
#a9e9#3fe9
; - bc: z
#a9e9#3fe9
; Output:
#a9e9#3fe9
; - hl = |hl - (L6aad_player_current_x)| + |de - (L6aaf_player_current_y)| + |(L6ab1_player_current_z) - bc|
#a9e9#3fe9
La9e9_manhattan_distance_to_player:
#a9e9#3fe9112
c5 
    push bc
#a9ea#3fea422
ed 4b ad 6a 
        ld bc, (L6aad_player_current_x)
#a9ee#3fee318
cd 04 aa 
        call Laa04_abs_hl_minus_bc
#a9f1#3ff115
eb 
        ex de, hl
#a9f2#3ff2422
ed 4b af 6a 
            ld bc, (L6aaf_player_current_y)
#a9f6#3ff6318
cd 04 aa 
            call Laa04_abs_hl_minus_bc
#a9f9#3ff9112
19 
            add hl, de
#a9fa#3ffa15
eb 
        ex de, hl
#a9fb#3ffb111
c1 
    pop bc
#a9fc#3ffc317
2a b1 6a 
    ld hl, (L6ab1_player_current_z)
#a9ff#3fff318
cd 04 aa 
    call Laa04_abs_hl_minus_bc
#aa02#4002112
19 
    add hl, de  ; hl =  |hl - (L6aad_player_current_x)| + |de - (L6aaf_player_current_y)| + |(L6ab1_player_current_z) - bc|
#aa03#4003111
c9 
    ret
#aa04#4004
#aa04#4004
#aa04#4004
; --------------------------------
#aa04#4004
; Returns the absolute value of "hl - bc"
#aa04#4004
; Input:
#aa04#4004
; - hl
#aa04#4004
; - bc
#aa04#4004
; Output:
#aa04#4004
; - hl
#aa04#4004
Laa04_abs_hl_minus_bc:
#aa04#400415
b7 
    or a
#aa05#4005217
ed 42 
    sbc hl, bc  ; hl -= bc
#aa07#4007112/6
f0 
    ret p  ; if positive, we are done
#aa08#400815
7c 
    ld a, h
#aa09#400915
2f 
    cpl
#aa0a#400a15
67 
    ld h, a
#aa0b#400b15
7d 
    ld a, l
#aa0c#400c15
2f 
    cpl
#aa0d#400d15
6f 
    ld l, a
#aa0e#400e17
23 
    inc hl
#aa0f#400f111
c9 
    ret
#aa10#4010
#aa10#4010
#aa10#4010
; --------------------------------
#aa10#4010
; Check if the correct coordinates due to cropping the player movement after colliding with an object
#aa10#4010
; are a better movement target than L74ca_movement_target_coordinates_2. If they are,
#aa10#4010
; overwrite the target coordinates. 
#aa10#4010
; - This method is always called from "Lab6d_correct_player_movement_if_collision_internal". If the correction is applied, this method will
#aa10#4010
;   directly return from the caller of the caller of "Lab6d_correct_player_movement_if_collision_internal".
#aa10#4010
Laa10_coordiante_corrected_movement_if_better:
#aa10#4010317
2a b8 74 
    ld hl, (L74b8_collision_corrected_coordinates_2)
#aa13#4013422
ed 5b ba 74 
    ld de, (L74b8_collision_corrected_coordinates_2 + 2)
#aa17#4017422
ed 4b bc 74 
    ld bc, (L74b8_collision_corrected_coordinates_2 + 4)  ; hl, de, bc <- x, y, z
#aa1b#401b318
cd e9 a9 
    call La9e9_manhattan_distance_to_player
#aa1e#401e112
e5 
    push hl
#aa1f#401f317
2a ca 74 
        ld hl, (L74ca_movement_target_coordinates_2)
#aa22#4022422
ed 5b cc 74 
        ld de, (L74ca_movement_target_coordinates_2 + 2)
#aa26#4026422
ed 4b ce 74 
        ld bc, (L74ca_movement_target_coordinates_2 + 4)
#aa2a#402a318
cd e9 a9 
        call La9e9_manhattan_distance_to_player
#aa2d#402d111
d1 
    pop de
#aa2e#402e
    ; At this point:
#aa2e#402e
    ; - hl = distance from player to (L74b8_collision_corrected_coordinates_2)
#aa2e#402e
    ; - de = distance from player to (L74ca_movement_target_coordinates_2)
#aa2e#402e15
b7 
    or a
#aa2f#402f217
ed 52 
    sbc hl, de
#aa31#4031311
fa 9e aa 
    jp m, Laa9e_return  ; if player is closer to (L74b8_collision_corrected_coordinates_2), return.
#aa34#4034112
f5 
    push af
#aa35#403528
16 02 
        ld d, 2  ; indicates colliding with a 3d shape
#aa37#4037321
dd 7e 00 
        ld a, (ix + OBJECT_TYPE_AND_FLAGS)
#aa3a#403a28
e6 0f 
        and #0f
#aa3c#403c28
fe 03 
        cp OBJECT_TYPE_RECTANGLE
#aa3e#403e213/8
28 06 
        jr z, Laa46
#aa40#404028
fe 0a 
        cp OBJECT_TYPE_LINE
#aa42#4042213/8
30 02 
        jr nc, Laa46
#aa44#404428
16 01 
        ld d, 1  ; indicates colliding with a 2d shape
#aa46#4046
Laa46:
#aa46#4046111
f1 
    pop af
#aa47#4047213/8
20 1a 
    jr nz, Laa63
#aa49#4049
    ; player is same distance from (L74b8_collision_corrected_coordinates_2) than from (L74ca_movement_target_coordinates_2).
#aa49#4049314
3a e5 74 
    ld a, (L74e5_collision_correction_object_shape_type)
#aa4c#404c15
b7 
    or a
#aa4d#404d213/8
28 14 
    jr z, Laa63
#aa4f#404f15
ba 
    cp d
#aa50#4050213/8
28 04 
    jr z, Laa56
#aa52#4052213/8
30 4a 
    jr nc, Laa9e_return  ; Give preference to collisions with 3d shapes
#aa54#4054213
18 0d 
    jr Laa63
#aa56#4056
Laa56:
#aa56#4056422
ed 4b c0 74 
    ld bc, (L74be_collision_corrected_climb_coordinates + 2)
#aa5a#405a317
2a d2 74 
    ld hl, (L74d0_target_object_climb_coordinates + 2)
#aa5d#405d15
b7 
    or a
#aa5e#405e217
ed 42 
    sbc hl, bc
#aa60#4060311
f2 9e aa 
    jp p, Laa9e_return  ; if this would prevent a climb, stop.
#aa63#4063
Laa63:
#aa63#406315
7a 
    ld a, d
#aa64#4064314
32 e5 74 
    ld (L74e5_collision_correction_object_shape_type), a  ; 1 for 2d shapes, 2 for 3d shape collisions.
#aa67#4067321
dd 7e 07 
    ld a, (ix + OBJECT_ID)
#aa6a#406a314
32 80 74 
    ld (L7480_under_pointer_object_ID), a
#aa6d#406d28
3e 01 
    ld a, 1
#aa6f#406f314
32 76 74 
    ld (L7476_trigger_collision_event_flag), a
#aa72#4072
    ; Successful coordinate adjustment, update target coordinates:
#aa72#4072311
21 be 74 
    ld hl, L74be_collision_corrected_climb_coordinates
#aa75#4075311
11 d0 74 
    ld de, L74d0_target_object_climb_coordinates
#aa78#4078311
01 06 00 
    ld bc, 6
#aa7b#407b223/18
ed b0 
    ldir
#aa7d#407d
#aa7d#407d311
21 c4 74 
    ld hl, L74c4_collision_corrected_coordinates_1
#aa80#4080311
11 d6 74 
    ld de, L74d6_movement_target_coordinates_1
#aa83#408328
0e 06 
    ld c, 6
#aa85#4085223/18
ed b0 
    ldir
#aa87#4087
#aa87#4087311
21 b8 74 
    ld hl, L74b8_collision_corrected_coordinates_2
#aa8a#408a311
11 ca 74 
    ld de, L74ca_movement_target_coordinates_2
#aa8d#408d28
0e 06 
    ld c, 6
#aa8f#408f223/18
ed b0 
    ldir
#aa91#4091
#aa91#4091314
3a 28 6b 
    ld a, (L6b28_player_radius)
#aa94#409415
b7 
    or a
#aa95#4095213/8
20 07 
    jr nz, Laa9e_return
#aa97#4097
    ; Unreachable in this game, as (L6b28_player_radius) is always 10.
#aa97#4097111
e1 
    pop hl  ; ret from this function
#aa98#4098111
e1 
    pop hl  ; undo push af from Lab6d_correct_player_movement_if_collision_internal
#aa99#4099111
e1 
    pop hl  ; ret from this Lab6d_correct_player_movement_if_collision_internal
#aa9a#409a111
e1 
    pop hl  ; ret from this Lab56_correct_player_movement_if_collision
#aa9b#409b311
c3 23 a9 
    jp La923_pop_and_return  ; return from La5d9_move_player
#aa9e#409e
Laa9e_return:
#aa9e#409e111
c9 
    ret
#aa9f#409f
#aa9f#409f
#aa9f#409f
; --------------------------------
#aa9f#409f
; Finds the closest object below the player (using coordinates in "L74dc_falling_reference_coordinates"):
#aa9f#409f
; - It stores the result in:
#aa9f#409f
;   - L74e9_closest_object_below_ptr: pointer to object
#aa9f#409f
;   - L74eb_closest_object_below_ID: ID of object
#aa9f#409f
;   - L74e7_closest_object_below_distance: distance to object.
#aa9f#409f
Laa9f_find_closest_object_below:
#aa9f#409f317
2a de 74 
    ld hl, (L74dc_falling_reference_coordinates + 2)  ; player desired y
#aaa2#40a2317
22 e7 74 
    ld (L74e7_closest_object_below_distance), hl  ; initialize (L74e7_closest_object_below_distance) to player desired y (distance to floor).
#aaa5#40a515
af 
    xor a
#aaa6#40a6314
32 eb 74 
    ld (L74eb_closest_object_below_ID), a  ; initialize found object ID to = 0
#aaa9#40a9422
dd 2a d1 6a 
    ld ix, (L6ad1_current_area_objects)
#aaad#40ad314
3a d0 6a 
    ld a, (L6ad0_current_area_n_objects)
#aab0#40b015
47 
    ld b, a
#aab1#40b115
b7 
    or a
#aab2#40b2318/11
c4 c2 aa 
    call nz, Laac2_find_closest_object_below_internal
#aab5#40b5422
dd 2a 63 74 
    ld ix, (L7463_global_area_objects)
#aab9#40b9314
3a 65 74 
    ld a, (L7465_global_area_n_objects)
#aabc#40bc15
47 
    ld b, a
#aabd#40bd15
b7 
    or a
#aabe#40be318/11
c4 c2 aa 
    call nz, Laac2_find_closest_object_below_internal
#aac1#40c1111
c9 
    ret
#aac2#40c2
#aac2#40c2
#aac2#40c2
; --------------------------------
#aac2#40c2
; Finds the closest object below the player (using coordinates in "L74dc_falling_reference_coordinates"):
#aac2#40c2
; - It stores the result in:
#aac2#40c2
;   - L74e9_closest_object_below_ptr: pointer to object
#aac2#40c2
;   - L74eb_closest_object_below_ID: ID of object
#aac2#40c2
;   - L74e7_closest_object_below_distance: distance to object.
#aac2#40c2
; Input:
#aac2#40c2
; - ix: pointer to the first object.
#aac2#40c2
; - b: number of objects.
#aac2#40c2
Laac2_find_closest_object_below_internal:
#aac2#40c2
Laac2_find_closest_object_below_internal_object_loop:
#aac2#40c2112
c5 
    push bc
#aac3#40c3422
dd cb 00 76 
        bit 6, (ix)  ; If object not visible, skip
#aac7#40c7311
c2 49 ab 
        jp nz, Lab49_next_object
#aaca#40ca
        ; Object is visible:
#aaca#40ca317
2a de 74 
        ld hl, (L74dc_falling_reference_coordinates + 2)  ; current desired y
#aacd#40cd321
dd 7e 02 
        ld a, (ix + OBJECT_Y)
#aad0#40d0321
dd 86 05 
        add a, (ix + OBJECT_SIZE_Y)
#aad3#40d315
57 
        ld d, a  ; d = object y2 = object y + object size y
#aad4#40d4318
cd d3 a9 
        call La9d3_de_eq_d_times_64  ; de = object y2 * 64
#aad7#40d715
af 
        xor a
#aad8#40d8217
ed 52 
        sbc hl, de  ; hl = y - object y2 * 64
#aada#40da15
44 
        ld b, h
#aadb#40db15
4d 
        ld c, l  ; bc = y - object y2 * 64
#aadc#40dc311
fa 49 ab 
        jp m, Lab49_next_object  ; if "y" smaller than object y2, skip
#aadf#40df
#aadf#40df
        ; Check if player desired x collides with object in "x" axis:
#aadf#40df321
dd 66 01 
        ld h, (ix + OBJECT_X)
#aae2#40e2318
cd de a9 
        call La9de_hl_eq_h_times_64
#aae5#40e5422
ed 5b dc 74 
        ld de, (L74dc_falling_reference_coordinates)  ; player desired x
#aae9#40e915
b7 
        or a
#aaea#40ea217
ed 52 
        sbc hl, de  ; hl = object x * 64 - player desired x
#aaec#40ec
        ; if player x < object x, skip 
#aaec#40ec213/8
28 03 
        jr z, Laaf1
#aaee#40ee311
f2 49 ab 
        jp p, Lab49_next_object
#aaf1#40f1
Laaf1:
#aaf1#40f1321
dd 7e 01 
        ld a, (ix + OBJECT_X)
#aaf4#40f4321
dd 86 04 
        add a, (ix + OBJECT_SIZE_X)
#aaf7#40f715
67 
        ld h, a
#aaf8#40f8318
cd de a9 
        call La9de_hl_eq_h_times_64
#aafb#40fb15
af 
        xor a
#aafc#40fc217
ed 52 
        sbc hl, de  ; hl = object x2 - player x
#aafe#40fe
        ; if player x > object x2, skip
#aafe#40fe311
fa 49 ab 
        jp m, Lab49_next_object
#ab01#4101
#ab01#4101
        ; Check if player desired x collides with object in "z" axis:
#ab01#4101321
dd 66 03 
        ld h, (ix + OBJECT_Z)
#ab04#4104318
cd de a9 
        call La9de_hl_eq_h_times_64
#ab07#4107422
ed 5b e0 74 
        ld de, (L74dc_falling_reference_coordinates + 4)  ; player desired z
#ab0b#410b15
b7 
        or a
#ab0c#410c217
ed 52 
        sbc hl, de
#ab0e#410e
        ; if player z < object z, skip 
#ab0e#410e213/8
28 03 
        jr z, Lab13
#ab10#4110311
f2 49 ab 
        jp p, Lab49_next_object
#ab13#4113
Lab13:
#ab13#4113321
dd 7e 03 
        ld a, (ix + OBJECT_Z)
#ab16#4116321
dd 86 06 
        add a, (ix + OBJECT_SIZE_Z)
#ab19#411915
67 
        ld h, a
#ab1a#411a318
cd de a9 
        call La9de_hl_eq_h_times_64
#ab1d#411d15
b7 
        or a
#ab1e#411e217
ed 52 
        sbc hl, de
#ab20#4120
        ; if player z > object z2, skip
#ab20#4120311
fa 49 ab 
        jp m, Lab49_next_object
#ab23#4123
#ab23#4123
        ; We found an object below the player:
#ab23#4123
        ; bc: distance from player to object in "y" axis
#ab23#4123317
2a e7 74 
        ld hl, (L74e7_closest_object_below_distance)
#ab26#412615
b7 
        or a
#ab27#4127217
ed 42 
        sbc hl, bc
#ab29#4129
        ; If the new object is further than the previous one we found, skip:
#ab29#4129311
fa 49 ab 
        jp m, Lab49_next_object
#ab2c#412c422
ed 43 e7 74 
        ld (L74e7_closest_object_below_distance), bc  ; new closest distance in "y"
#ab30#4130
        ; If it's strictly closer than the previous one, record it:
#ab30#4130213/8
20 0d 
        jr nz, Lab3f_new_best
#ab32#4132
        ; If it's the same distance as a previous object, prefer flat objects:
#ab32#4132321
dd 7e 00 
        ld a, (ix + OBJECT_TYPE_AND_FLAGS)
#ab35#413528
e6 0f 
        and #0f
#ab37#413728
fe 03 
        cp OBJECT_TYPE_RECTANGLE
#ab39#4139213/8
28 04 
        jr z, Lab3f_new_best  ; flat rectangles are fine
#ab3b#413b28
fe 0a 
        cp OBJECT_TYPE_LINE
#ab3d#413d213/8
38 0a 
        jr c, Lab49_next_object
#ab3f#413f
Lab3f_new_best:
#ab3f#413f
        ; If it is a rectangle, or another flat shape (line, triangle, etc.),
#ab3f#413f
        ; we store the object pointer and ID:
#ab3f#413f422
dd 22 e9 74 
        ld (L74e9_closest_object_below_ptr), ix
#ab43#4143321
dd 7e 07 
        ld a, (ix + OBJECT_ID)
#ab46#4146314
32 eb 74 
        ld (L74eb_closest_object_below_ID), a
#ab49#4149
#ab49#4149
Lab49_next_object:
#ab49#4149321
dd 5e 08 
        ld e, (ix + OBJECT_SIZE)
#ab4c#414c28
16 00 
        ld d, 0
#ab4e#414e217
dd 19 
        add ix, de
#ab50#4150111
c1 
    pop bc
#ab51#415115
05 
    dec b
#ab52#4152311
c2 c2 aa 
    jp nz, Laac2_find_closest_object_below_internal_object_loop
#ab55#4155111
c9 
    ret
#ab56#4156
#ab56#4156
#ab56#4156
; --------------------------------
#ab56#4156
; Adjusts player movement accounting for collisions:
#ab56#4156
; - see docstring of "Lab6d_correct_player_movement_if_collision_internal"
#ab56#4156
Lab56_correct_player_movement_if_collision:
#ab56#4156422
dd 2a d1 6a 
    ld ix, (L6ad1_current_area_objects)
#ab5a#415a314
3a d0 6a 
    ld a, (L6ad0_current_area_n_objects)
#ab5d#415d15
b7 
    or a
#ab5e#415e318/11
c4 6d ab 
    call nz, Lab6d_correct_player_movement_if_collision_internal
#ab61#4161422
dd 2a 63 74 
    ld ix, (L7463_global_area_objects)
#ab65#4165314
3a 65 74 
    ld a, (L7465_global_area_n_objects)
#ab68#416815
b7 
    or a
#ab69#4169318/11
c4 6d ab 
    call nz, Lab6d_correct_player_movement_if_collision_internal
#ab6c#416c111
c9 
    ret
#ab6d#416d
#ab6d#416d
#ab6d#416d
; --------------------------------
#ab6d#416d
; Adjusts player movement accounting for collisions:
#ab6d#416d
; - Assuming the player wants to move to through the the volume (L74b2_movement_volume_min_coordinate) -> (L74ac_movement_volume_max_coordinate)
#ab6d#416d
;   - this volume comprises the whole movement path, to make sure we do not skip small objects
#ab6d#416d
;     with a large step.
#ab6d#416d
;   - (L74b2_movement_volume_min_coordinate): (x2, y2, z2)   (max position + radius)
#ab6d#416d
;   - (L74ac_movement_volume_max_coordinate): (x1, y1, z1)   (min position - radius)
#ab6d#416d
; - If this new position causes a collision, adjust the position (based on the current movement
#ab6d#416d
;   direction), to find a position that does not collide.
#ab6d#416d
; - The result are updated positions for target movement (the 3 sets of possible target positions
#ab6d#416d
;   are updated).
#ab6d#416d
; - Note: this function is so convoluted, and there are solutions that are so much simpler than this!
#ab6d#416d
;   On top of that, this method prevents "sliding" along walls, which is an expected
#ab6d#416d
;   feature of modern engines. So, I would scrap all that special code.
#ab6d#416d
;   As a consequence, I only annotated the first part, (x collision), as the other two parts
#ab6d#416d
;   (y and z collision are analogous).
#ab6d#416d
; Input:
#ab6d#416d
; - ix: pointer to the first object
#ab6d#416d
; - a: number of objects
#ab6d#416d
Lab6d_correct_player_movement_if_collision_internal:
#ab6d#416d
Lab6d_correct_player_movement_if_collision_internal_object_loop:
#ab6d#416d112
f5 
    push af
#ab6e#416e422
dd cb 00 76 
        bit 6, (ix)  ; check if object is visible
#ab72#4172311
c2 6e ae 
        jp nz, Lae6e_next_object  ; If not visible, skip.
#ab75#4175
#ab75#4175
        ; 'x' axis comparison:
#ab75#4175321
dd 66 01 
        ld h, (ix + OBJECT_X)
#ab78#4178318
cd de a9 
        call La9de_hl_eq_h_times_64
#ab7b#417b422
ed 5b ac 74 
        ld de, (L74ac_movement_volume_max_coordinate)  ; x1
#ab7f#417f15
b7 
        or a
#ab80#4180217
ed 52 
        sbc hl, de  ; hl = object x * 64 - x1
#ab82#4182311
f2 6e ae 
        jp p, Lae6e_next_object  ; if no x collision skip
#ab85#4185
#ab85#4185321
dd 7e 01 
        ld a, (ix + OBJECT_X)
#ab88#4188321
dd 86 04 
        add a, (ix + OBJECT_SIZE_X)
#ab8b#418b15
57 
        ld d, a
#ab8c#418c318
cd d3 a9 
        call La9d3_de_eq_d_times_64
#ab8f#418f317
2a b2 74 
        ld hl, (L74b2_movement_volume_min_coordinate)  ; x2
#ab92#419215
b7 
        or a
#ab93#4193217
ed 52 
        sbc hl, de
#ab95#4195311
f2 6e ae 
        jp p, Lae6e_next_object  ; if no x collision skip
#ab98#4198
#ab98#4198
        ; 'y' axis comparison:
#ab98#4198321
dd 66 02 
        ld h, (ix + OBJECT_Y)
#ab9b#419b318
cd de a9 
        call La9de_hl_eq_h_times_64
#ab9e#419e422
ed 5b ae 74 
        ld de, (L74ac_movement_volume_max_coordinate + 2)  ; y1
#aba2#41a215
b7 
        or a
#aba3#41a3217
ed 52 
        sbc hl, de
#aba5#41a5311
f2 6e ae 
        jp p, Lae6e_next_object  ; if no y collision skip
#aba8#41a8
#aba8#41a8321
dd 7e 02 
        ld a, (ix + OBJECT_Y)
#abab#41ab321
dd 86 05 
        add a, (ix + OBJECT_SIZE_Y)
#abae#41ae15
57 
        ld d, a
#abaf#41af318
cd d3 a9 
        call La9d3_de_eq_d_times_64
#abb2#41b2317
2a b4 74 
        ld hl, (L74b2_movement_volume_min_coordinate + 2)  ; y2
#abb5#41b515
b7 
        or a
#abb6#41b6217
ed 52 
        sbc hl, de
#abb8#41b8311
f2 6e ae 
        jp p, Lae6e_next_object  ; if no y collision skip
#abbb#41bb
#abbb#41bb
        ; 'z' axis comparison:
#abbb#41bb321
dd 66 03 
        ld h, (ix + OBJECT_Z)
#abbe#41be318
cd de a9 
        call La9de_hl_eq_h_times_64
#abc1#41c1422
ed 5b b0 74 
        ld de, (L74ac_movement_volume_max_coordinate + 4)  ; z1
#abc5#41c515
b7 
        or a
#abc6#41c6217
ed 52 
        sbc hl, de
#abc8#41c8311
f2 6e ae 
        jp p, Lae6e_next_object  ; if no z collision skip
#abcb#41cb
#abcb#41cb321
dd 7e 03 
        ld a, (ix + OBJECT_Z)
#abce#41ce321
dd 86 06 
        add a, (ix + OBJECT_SIZE_Z)
#abd1#41d115
57 
        ld d, a
#abd2#41d2318
cd d3 a9 
        call La9d3_de_eq_d_times_64
#abd5#41d5317
2a b6 74 
        ld hl, (L74b2_movement_volume_min_coordinate + 4)  ; z2
#abd8#41d815
b7 
        or a
#abd9#41d9217
ed 52 
        sbc hl, de
#abdb#41db311
f2 6e ae 
        jp p, Lae6e_next_object  ; if no z collision skip
#abde#41de
#abde#41de
        ; Object and the volume defined by (L74b2_movement_volume_min_coordinate) -> (L74ac_movement_volume_max_coordinate) collide! 
#abde#41de422
ed 5b 28 6b 
        ld de, (L6b28_player_radius)
#abe2#41e2314
3a e2 74 
        ld a, (L74e2_movement_direction_bits)
#abe5#41e5210
cb 47 
        bit 0, a  ; negative movement on x?
#abe7#41e7213/8
28 09 
        jr z, Labf2
#abe9#41e9
        ; negative movement on x:
#abe9#41e9321
dd 7e 01 
        ld a, (ix + OBJECT_X)
#abec#41ec321
dd 86 04 
        add a, (ix + OBJECT_SIZE_X)
#abef#41ef15
67 
        ld h, a
#abf0#41f0213
18 10 
        jr Lac02
#abf2#41f2
Labf2:
#abf2#41f2210
cb 4f 
        bit 1, a  ; positive movement on x?
#abf4#41f4311
ca bd ac 
        jp z, Lacbd_y_coordinate_adjust
#abf7#41f7
#abf7#41f7
        ; positive movement on x:
#abf7#41f7321
dd 66 01 
        ld h, (ix + OBJECT_X)
#abfa#41fa
        ; negate the sign of the radius:
#abfa#41fa15
7b 
        ld a, e
#abfb#41fb210
ed 44 
        neg
#abfd#41fd213/8
28 03 
        jr z, Lac02
#abff#41ff15
5f 
        ld e, a
#ac00#420028
16 ff 
        ld d, #ff  ; de = - player_radius
#ac02#4202
Lac02:
#ac02#4202
        ; At this point:
#ac02#4202
        ; - h = object bound with whith player collided
#ac02#4202
        ; - de = amount to add to the bound due to player radius
#ac02#4202318
cd de a9 
        call La9de_hl_eq_h_times_64  ; hl = bound * 64
#ac05#4205112
19 
        add hl, de  ; hl = bound * 64 + radius
#ac06#4206317
22 b8 74 
        ld (L74b8_collision_corrected_coordinates_2), hl  ; limit up to which we can move in x
#ac09#420915
eb 
        ex de, hl
#ac0a#420a317
2a b2 74 
        ld hl, (L74b2_movement_volume_min_coordinate)  ; x2
#ac0d#420d15
b7 
        or a
#ac0e#420e217
ed 52 
        sbc hl, de  ; amount we need to correct the movement (should be negative).
#ac10#4210311
f2 bd ac 
        jp p, Lacbd_y_coordinate_adjust  ; if it is not negative, something weird has happend, and just ignore.
#ac13#4213317
2a ac 74 
        ld hl, (L74ac_movement_volume_max_coordinate)  ; x1
#ac16#421615
b7 
        or a
#ac17#4217217
ed 52 
        sbc hl, de  ; make sure we would not move out of bounds
#ac19#4219311
fa bd ac 
        jp m, Lacbd_y_coordinate_adjust  ; if we are out of bounds, ignore
#ac1c#421c15
eb 
        ex de, hl  ; hl = limit up to which we can move in x
#ac1d#421d318
cd 7b ae 
        call Lae7b_relative_z_proportional_to_relative_x_and_player_movement_direction
#ac20#4220317
22 bc 74 
        ld (L74b8_collision_corrected_coordinates_2 + 4), hl  ; limit z movement proportionally
#ac23#4223317
22 c2 74 
        ld (L74be_collision_corrected_climb_coordinates + 4), hl
#ac26#4226317
22 c8 74 
        ld (L74c4_collision_corrected_coordinates_1 + 4), hl
#ac29#4229321
dd 56 03 
        ld d, (ix + OBJECT_Z)
#ac2c#422c318
cd d3 a9 
        call La9d3_de_eq_d_times_64
#ac2f#422f422
ed 4b 28 6b 
        ld bc, (L6b28_player_radius)
#ac33#423315
eb 
        ex de, hl
#ac34#423415
b7 
        or a
#ac35#4235217
ed 42 
        sbc hl, bc  ; hl = object z * 64 - player radius
#ac37#423715
eb 
        ex de, hl
#ac38#423815
b7 
        or a
#ac39#4239217
ed 52 
        sbc hl, de  ; hl = new z - object z * 64 - player radius
#ac3b#423b314
3a e2 74 
        ld a, (L74e2_movement_direction_bits)
#ac3e#423e311
f2 49 ac 
        jp p, Lac49  ; if this does not result in positive movement in z, we keep going
#ac41#4241
        ; negative z movement as a result of the adjustment:
#ac41#4241210
cb 67 
        bit 4, a  ; negative movement in z?
#ac43#4243311
c2 6e ae 
        jp nz, Lae6e_next_object  ; if we moved negatively in z, ignore this object's collision
#ac46#4246311
c3 bd ac 
        jp Lacbd_y_coordinate_adjust
#ac49#4249
Lac49:
#ac49#4249
        ; here:
#ac49#4249
        ; - de = object z * 64 - player radius
#ac49#4249
        ; - bc = player radius
#ac49#4249321
dd 66 06 
        ld h, (ix + OBJECT_SIZE_Z)
#ac4c#424c318
cd de a9 
        call La9de_hl_eq_h_times_64
#ac4f#424f112
19 
        add hl, de
#ac50#4250112
09 
        add hl, bc
#ac51#4251112
09 
        add hl, bc  ; hl = object z2 * 64 + player radius
#ac52#425215
eb 
        ex de, hl
#ac53#4253317
2a bc 74 
        ld hl, (L74b8_collision_corrected_coordinates_2 + 4)  ; new z we wanted as a result of x collision
#ac56#425615
b7 
        or a
#ac57#4257217
ed 52 
        sbc hl, de  ; hl = new z - (object z2 * 64 + player radius)
#ac59#4259311
fa 64 ac 
        jp m, Lac64  ; this would cause a collision
#ac5c#425c210
cb 6f 
        bit 5, a  ; positive movement in z?
#ac5e#425e311
c2 6e ae 
        jp nz, Lae6e_next_object  ; if we moved positively in z, ignore this object's collision
#ac61#4261311
c3 bd ac 
        jp Lacbd_y_coordinate_adjust
#ac64#4264
Lac64:
#ac64#4264318
cd b1 ae 
        call Laeb1_adjust_y_movement_relative_to_x_movement_limit_due_to_collision
#ac67#4267314
3a e2 74 
        ld a, (L74e2_movement_direction_bits)
#ac6a#426a311
f2 74 ac 
        jp p, Lac74
#ac6d#426d210
cb 57 
        bit 2, a  ; negative movement in y?
#ac6f#426f311
c2 6e ae 
        jp nz, Lae6e_next_object
#ac72#4272213
18 49 
        jr Lacbd_y_coordinate_adjust
#ac74#4274
Lac74:
#ac74#4274321
dd 66 05 
        ld h, (ix + OBJECT_SIZE_Y)
#ac77#4277318
cd de a9 
        call La9de_hl_eq_h_times_64
#ac7a#427a112
19 
        add hl, de
#ac7b#427b15
eb 
        ex de, hl
#ac7c#427c317
2a ba 74 
        ld hl, (L74b8_collision_corrected_coordinates_2 + 2)  ; new adjusted y
#ac7f#427f15
b7 
        or a
#ac80#4280217
ed 52 
        sbc hl, de
#ac82#4282311
fa 8c ac 
        jp m, Lac8c
#ac85#4285210
cb 5f 
        bit 3, a
#ac87#4287311
c2 6e ae 
        jp nz, Lae6e_next_object
#ac8a#428a213
18 31 
        jr Lacbd_y_coordinate_adjust
#ac8c#428c
Lac8c:
#ac8c#428c321
dd 7e 02 
        ld a, (ix + OBJECT_Y)
#ac8f#428f321
dd 86 05 
        add a, (ix + OBJECT_SIZE_Y)
#ac92#429215
67 
        ld h, a
#ac93#4293318
cd de a9 
        call La9de_hl_eq_h_times_64
#ac96#4296317
22 c0 74 
        ld (L74be_collision_corrected_climb_coordinates + 2), hl
#ac99#4299317
2a b8 74 
        ld hl, (L74b8_collision_corrected_coordinates_2)
#ac9c#429c422
ed 4b 28 6b 
        ld bc, (L6b28_player_radius)
#aca0#42a017
03 
        inc bc
#aca1#42a115
b7 
        or a
#aca2#42a2217
ed 42 
        sbc hl, bc
#aca4#42a415
5d 
        ld e, l
#aca5#42a515
54 
        ld d, h
#aca6#42a6112
09 
        add hl, bc
#aca7#42a7112
09 
        add hl, bc
#aca8#42a8314
3a e2 74 
        ld a, (L74e2_movement_direction_bits)
#acab#42ab210
cb 47 
        bit 0, a  ; negative movement in x?
#acad#42ad213/8
20 01 
        jr nz, Lacb0
#acaf#42af15
eb 
        ex de, hl  ; flip the coordinates
#acb0#42b0
Lacb0:
#acb0#42b0422
ed 53 be 74 
        ld (L74be_collision_corrected_climb_coordinates), de
#acb4#42b4317
22 c4 74 
        ld (L74c4_collision_corrected_coordinates_1), hl
#acb7#42b7318
cd 10 aa 
        call Laa10_coordiante_corrected_movement_if_better
#acba#42ba311
c3 6e ae 
        jp Lae6e_next_object
#acbd#42bd
#acbd#42bd
Lacbd_y_coordinate_adjust:
#acbd#42bd422
ed 5b 28 6b 
        ld de, (L6b28_player_radius)
#acc1#42c1314
3a e2 74 
        ld a, (L74e2_movement_direction_bits)
#acc4#42c4210
cb 57 
        bit 2, a
#acc6#42c6213/8
28 09 
        jr z, Lacd1
#acc8#42c8321
dd 7e 02 
        ld a, (ix + 2)
#accb#42cb321
dd 86 05 
        add a, (ix + 5)
#acce#42ce15
67 
        ld h, a
#accf#42cf213
18 10 
        jr Lace1
#acd1#42d1
Lacd1:
#acd1#42d1210
cb 5f 
        bit 3, a
#acd3#42d3311
ca b6 ad 
        jp z, Ladb6
#acd6#42d6321
dd 66 02 
        ld h, (ix + 2)
#acd9#42d915
7b 
        ld a, e
#acda#42da210
ed 44 
        neg
#acdc#42dc213/8
28 03 
        jr z, Lace1
#acde#42de15
5f 
        ld e, a
#acdf#42df28
16 ff 
        ld d, 255
#ace1#42e1
Lace1:
#ace1#42e1318
cd de a9 
        call La9de_hl_eq_h_times_64
#ace4#42e4112
19 
        add hl, de
#ace5#42e5317
22 ba 74 
        ld (L74b8_collision_corrected_coordinates_2 + 2), hl
#ace8#42e815
eb 
        ex de, hl
#ace9#42e9317
2a b4 74 
        ld hl, (L74b2_movement_volume_min_coordinate + 2)
#acec#42ec15
b7 
        or a
#aced#42ed217
ed 52 
        sbc hl, de
#acef#42ef311
f2 b6 ad 
        jp p, Ladb6
#acf2#42f2317
2a ae 74 
        ld hl, (L74ac_movement_volume_max_coordinate + 2)
#acf5#42f515
b7 
        or a
#acf6#42f6217
ed 52 
        sbc hl, de
#acf8#42f8311
fa b6 ad 
        jp m, Ladb6
#acfb#42fb15
eb 
        ex de, hl
#acfc#42fc422
ed 5b af 6a 
        ld de, (L6aaf_player_current_y)
#ad00#430015
af 
        xor a
#ad01#4301217
ed 52 
        sbc hl, de
#ad03#4303422
ed 5b aa 74 
        ld de, (L74a6_player_movement_delta + 4)
#ad07#4307318
cd 5e a1 
        call La15e_de_times_hl_signed
#ad0a#430a422
ed 4b a8 74 
        ld bc, (L74a6_player_movement_delta + 2)
#ad0e#430e318
cd b7 b1 
        call Lb1b7_de_hl_divided_by_bc_signed
#ad11#4311422
ed 4b b1 6a 
        ld bc, (L6ab1_player_current_z)
#ad15#4315112
09 
        add hl, bc
#ad16#4316317
22 bc 74 
        ld (L74b8_collision_corrected_coordinates_2 + 4), hl
#ad19#4319317
22 c8 74 
        ld (L74c4_collision_corrected_coordinates_1 + 4), hl
#ad1c#431c321
dd 56 03 
        ld d, (ix + 3)
#ad1f#431f318
cd d3 a9 
        call La9d3_de_eq_d_times_64
#ad22#4322422
ed 4b 28 6b 
        ld bc, (L6b28_player_radius)
#ad26#432615
eb 
        ex de, hl
#ad27#432715
b7 
        or a
#ad28#4328217
ed 42 
        sbc hl, bc
#ad2a#432a15
eb 
        ex de, hl
#ad2b#432b15
b7 
        or a
#ad2c#432c217
ed 52 
        sbc hl, de
#ad2e#432e314
3a e2 74 
        ld a, (L74e2_movement_direction_bits)
#ad31#4331311
f2 3c ad 
        jp p, Lad3c
#ad34#4334210
cb 67 
        bit 4, a
#ad36#4336311
c2 6e ae 
        jp nz, Lae6e_next_object
#ad39#4339311
c3 b6 ad 
        jp Ladb6
#ad3c#433c
Lad3c:
#ad3c#433c321
dd 66 06 
        ld h, (ix + 6)
#ad3f#433f318
cd de a9 
        call La9de_hl_eq_h_times_64
#ad42#4342112
19 
        add hl, de
#ad43#4343112
09 
        add hl, bc
#ad44#4344112
09 
        add hl, bc
#ad45#434515
eb 
        ex de, hl
#ad46#4346317
2a bc 74 
        ld hl, (L74b8_collision_corrected_coordinates_2 + 4)
#ad49#434915
b7 
        or a
#ad4a#434a217
ed 52 
        sbc hl, de
#ad4c#434c311
fa 57 ad 
        jp m, Lad57
#ad4f#434f210
cb 6f 
        bit 5, a
#ad51#4351311
c2 6e ae 
        jp nz, Lae6e_next_object
#ad54#4354311
c3 b6 ad 
        jp Ladb6
#ad57#4357
Lad57:
#ad57#4357317
2a bc 74 
        ld hl, (L74b8_collision_corrected_coordinates_2 + 4)
#ad5a#435a318
cd 96 ae 
        call Lae96_relative_x_proportional_to_relative_z_and_player_movement_direction
#ad5d#435d317
22 b8 74 
        ld (L74b8_collision_corrected_coordinates_2), hl
#ad60#4360317
22 c4 74 
        ld (L74c4_collision_corrected_coordinates_1), hl
#ad63#4363321
dd 56 01 
        ld d, (ix + 1)
#ad66#4366318
cd d3 a9 
        call La9d3_de_eq_d_times_64
#ad69#4369422
ed 4b 28 6b 
        ld bc, (L6b28_player_radius)
#ad6d#436d15
eb 
        ex de, hl
#ad6e#436e15
b7 
        or a
#ad6f#436f217
ed 42 
        sbc hl, bc
#ad71#437115
eb 
        ex de, hl
#ad72#437215
b7 
        or a
#ad73#4373217
ed 52 
        sbc hl, de
#ad75#4375314
3a e2 74 
        ld a, (L74e2_movement_direction_bits)
#ad78#4378311
f2 82 ad 
        jp p, Lad82
#ad7b#437b210
cb 47 
        bit 0, a
#ad7d#437d311
c2 6e ae 
        jp nz, Lae6e_next_object
#ad80#4380213
18 34 
        jr Ladb6
#ad82#4382
Lad82:
#ad82#4382321
dd 66 04 
        ld h, (ix + 4)
#ad85#4385318
cd de a9 
        call La9de_hl_eq_h_times_64
#ad88#4388112
19 
        add hl, de
#ad89#4389112
09 
        add hl, bc
#ad8a#438a112
09 
        add hl, bc
#ad8b#438b15
eb 
        ex de, hl
#ad8c#438c317
2a b8 74 
        ld hl, (L74b8_collision_corrected_coordinates_2)
#ad8f#438f15
b7 
        or a
#ad90#4390217
ed 52 
        sbc hl, de
#ad92#4392311
fa 9c ad 
        jp m, Lad9c
#ad95#4395210
cb 4f 
        bit 1, a
#ad97#4397311
c2 6e ae 
        jp nz, Lae6e_next_object
#ad9a#439a213
18 1a 
        jr Ladb6
#ad9c#439c
Lad9c:
#ad9c#439c422
ed 5b 28 6b 
        ld de, (L6b28_player_radius)
#ada0#43a0317
2a ba 74 
        ld hl, (L74b8_collision_corrected_coordinates_2 + 2)
#ada3#43a3210
cb 57 
        bit 2, a
#ada5#43a5213/8
28 03 
        jr z, Ladaa
#ada7#43a7112
19 
        add hl, de
#ada8#43a8213
18 03 
        jr Ladad
#adaa#43aa
Ladaa:
#adaa#43aa15
b7 
        or a
#adab#43ab217
ed 52 
        sbc hl, de
#adad#43ad
Ladad:
#adad#43ad317
22 c6 74 
        ld (L74c4_collision_corrected_coordinates_1 + 2), hl
#adb0#43b0318
cd 10 aa 
        call Laa10_coordiante_corrected_movement_if_better
#adb3#43b3311
c3 6e ae 
        jp Lae6e_next_object
#adb6#43b6
Ladb6:
#adb6#43b6422
ed 5b 28 6b 
        ld de, (L6b28_player_radius)
#adba#43ba314
3a e2 74 
        ld a, (L74e2_movement_direction_bits)
#adbd#43bd210
cb 67 
        bit 4, a
#adbf#43bf213/8
28 09 
        jr z, Ladca
#adc1#43c1321
dd 7e 03 
        ld a, (ix + 3)
#adc4#43c4321
dd 86 06 
        add a, (ix + 6)
#adc7#43c715
67 
        ld h, a
#adc8#43c8213
18 10 
        jr Ladda
#adca#43ca
Ladca:
#adca#43ca210
cb 6f 
        bit 5, a
#adcc#43cc311
ca 6e ae 
        jp z, Lae6e_next_object
#adcf#43cf321
dd 66 03 
        ld h, (ix + 3)
#add2#43d215
7b 
        ld a, e
#add3#43d3210
ed 44 
        neg
#add5#43d5213/8
28 03 
        jr z, Ladda
#add7#43d715
5f 
        ld e, a
#add8#43d828
16 ff 
        ld d, 255
#adda#43da
Ladda:
#adda#43da318
cd de a9 
        call La9de_hl_eq_h_times_64
#addd#43dd112
19 
        add hl, de
#adde#43de317
22 bc 74 
        ld (L74b8_collision_corrected_coordinates_2 + 4), hl
#ade1#43e115
eb 
        ex de, hl
#ade2#43e2317
2a b6 74 
        ld hl, (L74b2_movement_volume_min_coordinate + 4)
#ade5#43e515
b7 
        or a
#ade6#43e6217
ed 52 
        sbc hl, de
#ade8#43e8311
f2 6e ae 
        jp p, Lae6e_next_object
#adeb#43eb317
2a b0 74 
        ld hl, (L74ac_movement_volume_max_coordinate + 4)
#adee#43ee15
b7 
        or a
#adef#43ef217
ed 52 
        sbc hl, de
#adf1#43f1311
fa 6e ae 
        jp m, Lae6e_next_object
#adf4#43f415
eb 
        ex de, hl
#adf5#43f5318
cd 96 ae 
        call Lae96_relative_x_proportional_to_relative_z_and_player_movement_direction
#adf8#43f8317
22 b8 74 
        ld (L74b8_collision_corrected_coordinates_2), hl
#adfb#43fb317
22 be 74 
        ld (L74be_collision_corrected_climb_coordinates), hl
#adfe#43fe317
22 c4 74 
        ld (L74c4_collision_corrected_coordinates_1), hl
#ae01#4401321
dd 56 01 
        ld d, (ix + 1)
#ae04#4404318
cd d3 a9 
        call La9d3_de_eq_d_times_64
#ae07#4407422
ed 4b 28 6b 
        ld bc, (L6b28_player_radius)
#ae0b#440b15
eb 
        ex de, hl
#ae0c#440c15
b7 
        or a
#ae0d#440d217
ed 42 
        sbc hl, bc
#ae0f#440f15
eb 
        ex de, hl
#ae10#441015
b7 
        or a
#ae11#4411217
ed 52 
        sbc hl, de
#ae13#4413311
fa 6e ae 
        jp m, Lae6e_next_object
#ae16#4416321
dd 66 04 
        ld h, (ix + 4)
#ae19#4419318
cd de a9 
        call La9de_hl_eq_h_times_64
#ae1c#441c112
19 
        add hl, de
#ae1d#441d112
09 
        add hl, bc
#ae1e#441e112
09 
        add hl, bc
#ae1f#441f15
eb 
        ex de, hl
#ae20#4420317
2a b8 74 
        ld hl, (L74b8_collision_corrected_coordinates_2)
#ae23#442315
b7 
        or a
#ae24#4424217
ed 52 
        sbc hl, de
#ae26#4426311
f2 6e ae 
        jp p, Lae6e_next_object
#ae29#4429318
cd b1 ae 
        call Laeb1_adjust_y_movement_relative_to_x_movement_limit_due_to_collision
#ae2c#442c311
fa 6e ae 
        jp m, Lae6e_next_object
#ae2f#442f321
dd 66 05 
        ld h, (ix + 5)
#ae32#4432318
cd de a9 
        call La9de_hl_eq_h_times_64
#ae35#4435112
19 
        add hl, de
#ae36#443615
eb 
        ex de, hl
#ae37#4437317
2a ba 74 
        ld hl, (L74b8_collision_corrected_coordinates_2 + 2)
#ae3a#443a15
b7 
        or a
#ae3b#443b217
ed 52 
        sbc hl, de
#ae3d#443d311
f2 6e ae 
        jp p, Lae6e_next_object
#ae40#4440321
dd 7e 02 
        ld a, (ix + 2)
#ae43#4443321
dd 86 05 
        add a, (ix + 5)
#ae46#444615
67 
        ld h, a
#ae47#4447318
cd de a9 
        call La9de_hl_eq_h_times_64
#ae4a#444a317
22 c0 74 
        ld (L74be_collision_corrected_climb_coordinates + 2), hl
#ae4d#444d317
2a bc 74 
        ld hl, (L74b8_collision_corrected_coordinates_2 + 4)
#ae50#4450422
ed 4b 28 6b 
        ld bc, (L6b28_player_radius)
#ae54#445417
03 
        inc bc
#ae55#445515
b7 
        or a
#ae56#4456217
ed 42 
        sbc hl, bc
#ae58#445815
5d 
        ld e, l
#ae59#445915
54 
        ld d, h
#ae5a#445a112
09 
        add hl, bc
#ae5b#445b112
09 
        add hl, bc
#ae5c#445c314
3a e2 74 
        ld a, (L74e2_movement_direction_bits)
#ae5f#445f210
cb 67 
        bit 4, a
#ae61#4461213/8
20 01 
        jr nz, Lae64
#ae63#446315
eb 
        ex de, hl
#ae64#4464
Lae64:
#ae64#4464422
ed 53 c2 74 
        ld (L74be_collision_corrected_climb_coordinates + 4), de
#ae68#4468317
22 c8 74 
        ld (L74c4_collision_corrected_coordinates_1 + 4), hl
#ae6b#446b318
cd 10 aa 
        call Laa10_coordiante_corrected_movement_if_better
#ae6e#446e
Lae6e_next_object:
#ae6e#446e
        ; Advance the pointer to the next object:
#ae6e#446e321
dd 5e 08 
        ld e, (ix + OBJECT_SIZE)
#ae71#447128
16 00 
        ld d, 0
#ae73#4473217
dd 19 
        add ix, de
#ae75#4475111
f1 
    pop af
#ae76#447615
3d 
    dec a
#ae77#4477311
c2 6d ab 
    jp nz, Lab6d_correct_player_movement_if_collision_internal_object_loop
#ae7a#447a111
c9 
    ret
#ae7b#447b
#ae7b#447b
#ae7b#447b
; --------------------------------
#ae7b#447b
; Given a "x" coordinate, it calculates a "z" such that (player z - z) is proportional to (player x - x) according
#ae7b#447b
; to the current movement direction of the player.
#ae7b#447b
; Input:
#ae7b#447b
; - hl: x coordinate
#ae7b#447b
; Output:
#ae7b#447b
; - hl: (hl - player x) * (delta z / delta x) + player z
#ae7b#447b
Lae7b_relative_z_proportional_to_relative_x_and_player_movement_direction:
#ae7b#447b422
ed 5b ad 6a 
    ld de, (L6aad_player_current_x)
#ae7f#447f15
af 
    xor a
#ae80#4480217
ed 52 
    sbc hl, de  ; hl -= player x
#ae82#4482422
ed 5b aa 74 
    ld de, (L74a6_player_movement_delta + 4)
#ae86#4486318
cd 5e a1 
    call La15e_de_times_hl_signed  ; hl = (hl - player x) * delta z
#ae89#4489422
ed 4b a6 74 
    ld bc, (L74a6_player_movement_delta)
#ae8d#448d318
cd b7 b1 
    call Lb1b7_de_hl_divided_by_bc_signed  ; hl = ((hl - player x) * delta z) / delta x
#ae90#4490422
ed 4b b1 6a 
    ld bc, (L6ab1_player_current_z)
#ae94#4494112
09 
    add hl, bc  ; hl = (hl - player x) * (delta z / delta x) + player z
#ae95#4495111
c9 
    ret
#ae96#4496
#ae96#4496
#ae96#4496
; --------------------------------
#ae96#4496
; Given a "z" coordinate, it calculates a "x" such that (player x - x) is proportional to (player z - z) according
#ae96#4496
; to the current movement direction of the player.
#ae96#4496
; Input:
#ae96#4496
; - hl: z coordinate
#ae96#4496
; Output:
#ae96#4496
; - hl: (hl - player z) * (delta x / delta z) + player x
#ae96#4496
Lae96_relative_x_proportional_to_relative_z_and_player_movement_direction:
#ae96#4496422
ed 5b b1 6a 
    ld de, (L6ab1_player_current_z)
#ae9a#449a15
af 
    xor a
#ae9b#449b217
ed 52 
    sbc hl, de  ; hl -= player z
#ae9d#449d422
ed 5b a6 74 
    ld de, (L74a6_player_movement_delta)
#aea1#44a1318
cd 5e a1 
    call La15e_de_times_hl_signed  ; hl = (hl - player z) * delta x
#aea4#44a4422
ed 4b aa 74 
    ld bc, (L74a6_player_movement_delta + 4)
#aea8#44a8318
cd b7 b1 
    call Lb1b7_de_hl_divided_by_bc_signed  ; hl = ((hl - player z) * delta x) / delta z
#aeab#44ab422
ed 4b ad 6a 
    ld bc, (L6aad_player_current_x)  ; hl = (hl - player z) * (delta x / delta z) + player x
#aeaf#44af112
09 
    add hl, bc
#aeb0#44b0111
c9 
    ret
#aeb1#44b1
#aeb1#44b1
#aeb1#44b1
; --------------------------------
#aeb1#44b1
; Output:
#aeb1#44b1
; - hl: (actual delta x) * (delta y) / (delta x) + player y + (L74e3_player_height_16bits) - object y
#aeb1#44b1
;       This is used by the caller to see if this would result in a collision in y.
#aeb1#44b1
Laeb1_adjust_y_movement_relative_to_x_movement_limit_due_to_collision:
#aeb1#44b1317
2a b8 74 
    ld hl, (L74b8_collision_corrected_coordinates_2)  ; limit up to which we can move in x
#aeb4#44b4422
ed 5b ad 6a 
    ld de, (L6aad_player_current_x)
#aeb8#44b815
af 
    xor a
#aeb9#44b9217
ed 52 
    sbc hl, de  ; hl = actual delta x = amount of movement allowed in x due to collision
#aebb#44bb422
ed 5b a8 74 
    ld de, (L74a6_player_movement_delta + 2)  ; delta y
#aebf#44bf318
cd 5e a1 
    call La15e_de_times_hl_signed  ; (de, hl) = (actual delta x) * delta y
#aec2#44c2422
ed 4b a6 74 
    ld bc, (L74a6_player_movement_delta)
#aec6#44c6318
cd b7 b1 
    call Lb1b7_de_hl_divided_by_bc_signed  ; (de, hl) = (actual delta x) * (delta y) / (delta x)
#aec9#44c9422
ed 4b af 6a 
    ld bc, (L6aaf_player_current_y)
#aecd#44cd112
09 
    add hl, bc  ; (de, hl) = ((L74b8_collision_corrected_coordinates_2) - player x) * (delta y) / (delta x) + player y
#aece#44ce317
22 ba 74 
    ld (L74b8_collision_corrected_coordinates_2 + 2), hl  ; adjust new target y, proportionally to how much did we cut movement on x
#aed1#44d1317
22 c6 74 
    ld (L74c4_collision_corrected_coordinates_1 + 2), hl
#aed4#44d4321
dd 56 02 
    ld d, (ix + OBJECT_Y)
#aed7#44d7318
cd d3 a9 
    call La9d3_de_eq_d_times_64
#aeda#44da422
ed 4b e3 74 
    ld bc, (L74e3_player_height_16bits)
#aede#44de15
b7 
    or a
#aedf#44df217
ed 4a 
    adc hl, bc  ; hl = (actual delta x) * (delta y) / (delta x) + player y + (L74e3_player_height_16bits)
#aee1#44e115
b7 
    or a
#aee2#44e2217
ed 52 
    sbc hl, de  ; hl = (actual delta x) * (delta y) / (delta x) + player y + (L74e3_player_height_16bits) - object y
#aee4#44e4111
c9 
    ret
#aee5#44e5
#aee5#44e5
#aee5#44e5
; --------------------------------
#aee5#44e5
; Processes the following input key functions:
#aee5#44e5
; - INPUT_CRAWL
#aee5#44e5
; - INPUT_WALK
#aee5#44e5
; - INPUT_RUN
#aee5#44e5
; - INPUT_FORWARD
#aee5#44e5
; - INPUT_BACKWARD
#aee5#44e5
; - INPUT_TURN_LEFT
#aee5#44e5
; - INPUT_TURN_RIGHT
#aee5#44e5
; - INPUT_LOOK_UP
#aee5#44e5
; - INPUT_LOOK_DOWN
#aee5#44e5
; - INPUT_FACE_FORWARD
#aee5#44e5
; - INPUT_U_TURN
#aee5#44e5
Laee5_executes_movement_related_pressed_key_functions:
#aee5#44e5311
01 00 00 
    ld bc, 0
#aee8#44e8311
21 89 6d 
    ld hl, L6d89_text_crawl
#aeeb#44eb28
fe 09 
    cp INPUT_CRAWL
#aeed#44ed213/8
28 11 
    jr z, Laf00_desired_walk_speed_selected
#aeef#44ef311
21 99 6d 
    ld hl, L6d99_text_walk
#aef2#44f215
0c 
    inc c
#aef3#44f328
fe 0a 
    cp INPUT_WALK
#aef5#44f5213/8
28 09 
    jr z, Laf00_desired_walk_speed_selected
#aef7#44f7311
21 a9 6d 
    ld hl, L6da9_text_run
#aefa#44fa15
0c 
    inc c
#aefb#44fb28
fe 0b 
    cp INPUT_RUN
#aefd#44fd311
c2 da af 
    jp nz, Lafda
#af00#4500
Laf00_desired_walk_speed_selected:
#af00#4500314
3a 0b 6b 
    ld a, (L6b0b_selected_movement_mode)
#af03#450315
b9 
    cp c
#af04#4504213/8
20 05 
    jr nz, Laf00_walk_speed_change_needed
#af06#450628
0e 00 
    ld c, 0
#af08#4508311
c3 c1 af 
    jp Lafc1_already_at_correct_walk_speed
#af0b#450b
Laf00_walk_speed_change_needed:
#af0b#450b15
57 
    ld d, a
#af0c#450c311
21 79 6d 
    ld hl, L6d79_text_too_weak
#af0f#450f314
3a 0a 6b 
    ld a, (L6b0a_current_strength)
#af12#451228
fe 03 
    cp 3
#af14#4514213/8
30 06 
    jr nc, Lafc1_strength_at_least_3
#af16#451615
79 
    ld a, c
#af17#451715
b7 
    or a
#af18#4518213/8
28 0b 
    jr z, Laf25_strength_at_least_5
#af1a#451a213
18 49 
    jr Laf65_cannot_change_to_requested_speed
#af1c#451c
Lafc1_strength_at_least_3:
#af1c#451c28
fe 05 
    cp 5
#af1e#451e213/8
30 05 
    jr nc, Laf25_strength_at_least_5
#af20#452015
79 
    ld a, c
#af21#452128
fe 02 
    cp 2
#af23#4523213/8
28 40 
    jr z, Laf65_cannot_change_to_requested_speed
#af25#4525
Laf25_strength_at_least_5:
#af25#4525
    ; We have the required strength for the requested walk speed:
#af25#4525
    ; here: d = current walk speed, c = requested walk speed.
#af25#452515
7a 
    ld a, d
#af26#452615
b7 
    or a
#af27#4527213/8
20 4c 
    jr nz, Laf75_speed_change_is_possible
#af29#4529
#af29#4529
    ; Current speed is "crawling", requested to stand up, check if we have space:
#af29#4529317
2a ad 6a 
    ld hl, (L6aad_player_current_x)
#af2c#452c317
22 56 74 
    ld (L7456_player_desired_x), hl
#af2f#452f317
2a b1 6a 
    ld hl, (L6ab1_player_current_z)
#af32#4532317
22 5a 74 
    ld (L745a_player_desired_z), hl
#af35#4535314
3a bc 6a 
    ld a, (L6abc_current_room_scale)
#af38#453815
58 
    ld e, b  ; b == 0 here
#af39#453915
57 
    ld d, a
#af3a#453a210
cb 3a 
    srl d
#af3c#453c210
cb 1b 
    rr e
#af3e#453e210
cb 3a 
    srl d
#af40#4540210
cb 1b 
    rr e  ; de = (L6abc_current_room_scale) * 64
#af42#4542
#af42#4542317
2a af 6a 
    ld hl, (L6aaf_player_current_y)
#af45#4545112
e5 
    push hl
#af46#4546112
19 
        add hl, de  ; player y + room_scale * 64
#af47#4547317
22 58 74 
        ld (L7458_player_desired_y), hl
#af4a#454a28
3e 01 
        ld a, 1
#af4c#454c314
32 be 6a 
        ld (L6abe_use_eye_player_coordinate), a
#af4f#454f318
cd d9 a5 
        call La5d9_move_player
#af52#455215
af 
        xor a
#af53#4553314
32 be 6a 
        ld (L6abe_use_eye_player_coordinate), a
#af56#4556422
ed 5b 58 74 
        ld de, (L7458_player_desired_y)
#af5a#455a217
ed 52 
        sbc hl, de
#af5c#455c111
e1 
    pop hl
#af5d#455d213/8
28 0a 
    jr z, Laf69_getting_up_is_possible
#af5f#455f
    ; We do not have enough room to get up:
#af5f#455f317
22 af 6a 
    ld (L6aaf_player_current_y), hl
#af62#4562311
21 69 6d 
    ld hl, L6d69_text_not_enough_room
#af65#4565
Laf65_cannot_change_to_requested_speed:
#af65#456528
0e 00 
    ld c, 0
#af67#4567213
18 58 
    jr Lafc1_already_at_correct_walk_speed
#af69#4569
Laf69_getting_up_is_possible:
#af69#4569
    ; Get up from crawling:
#af69#4569311
21 b8 6a 
    ld hl, L6ab8_player_crawling
#af6c#456c112
34 
    inc (hl)
#af6d#456d311
21 b9 6a 
    ld hl, L6ab9_player_height
#af70#4570314
3a bc 6a 
    ld a, (L6abc_current_room_scale)
#af73#457318
86 
    add a, (hl)
#af74#457418
77 
    ld (hl), a
#af75#4575
#af75#4575
Laf75_speed_change_is_possible:
#af75#457515
79 
    ld a, c
#af76#4576314
32 0b 6b 
    ld (L6b0b_selected_movement_mode), a
#af79#4579311
21 99 6d 
    ld hl, L6d99_text_walk
#af7c#457c28
fe 01 
    cp 1
#af7e#457e213/8
28 2a 
    jr z, Lafaa
#af80#4580311
21 a9 6d 
    ld hl, L6da9_text_run
#af83#458315
b7 
    or a
#af84#4584213/8
20 24 
    jr nz, Lafaa
#af86#4586
    ; Switch to crawling, we need to crouch:
#af86#4586311
21 b8 6a 
    ld hl, L6ab8_player_crawling
#af89#4589112
35 
    dec (hl)
#af8a#458a311
21 b9 6a 
    ld hl, L6ab9_player_height
#af8d#458d314
3a bc 6a 
    ld a, (L6abc_current_room_scale)
#af90#459015
57 
    ld d, a
#af91#459118
96 
    sub (hl)
#af92#4592210
ed 44 
    neg
#af94#459418
77 
    ld (hl), a
#af95#4595
#af95#4595
    ; de = (L6abc_current_room_scale) * 64
#af95#459515
59 
    ld e, c  ; c == 0 here
#af96#4596210
cb 3a 
    srl d
#af98#4598210
cb 1b 
    rr e
#af9a#459a210
cb 3a 
    srl d
#af9c#459c210
cb 1b 
    rr e
#af9e#459e317
2a af 6a 
    ld hl, (L6aaf_player_current_y)
#afa1#45a115
b7 
    or a
#afa2#45a2217
ed 52 
    sbc hl, de
#afa4#45a4317
22 af 6a 
    ld (L6aaf_player_current_y), hl
#afa7#45a7311
21 89 6d 
    ld hl, L6d89_text_crawl
#afaa#45aa
Lafaa:
#afaa#45aa15
eb 
    ex de, hl
#afab#45ab311
21 c8 d0 
        ld hl, Ld0c8_speed_when_crawling
#afae#45ae112
09 
        add hl, bc
#afaf#45af18
7e 
        ld a, (hl)
#afb0#45b0314
32 b5 6a 
        ld (L6ab5_current_speed), a
#afb3#45b315
6f 
        ld l, a
#afb4#45b415
60 
        ld h, b
#afb5#45b5314
3a bc 6a 
        ld a, (L6abc_current_room_scale)
#afb8#45b8318
cd 08 a1 
        call La108_a_times_hl_signed
#afbb#45bb317
22 b3 6a 
        ld (L6ab3_current_speed_in_this_room), hl
#afbe#45be15
eb 
    ex de, hl
#afbf#45bf28
0e 14 
    ld c, 20
#afc1#45c1
Lafc1_already_at_correct_walk_speed:
#afc1#45c1
    ; Print the walk speed message, produce an SFX, and set a delay the message to disappear.
#afc1#45c128
3e 2a 
    ld a, 42
#afc3#45c3314
32 a5 74 
    ld (L74a5_interrupt_timer), a
#afc6#45c6416
dd 21 5a 73 
    ld ix, L735a_ui_message_row_pointers
#afca#45ca311
11 00 0f 
    ld de, #0f00
#afcd#45cd318
cd 1c d0 
    call Ld01c_draw_string
#afd0#45d028
3e 03 
    ld a, SFX_MENU_SELECT
#afd2#45d2318
cd ca c4 
    call Lc4ca_play_SFX
#afd5#45d528
06 20 
    ld b, #20  ; set the 6th bit of (L746c_game_flags + 1), which will trigger rewriting the "THE CRYPT" message after a pause
#afd7#45d7311
c3 91 b1 
    jp Lb191_done
#afda#45da
#afda#45da
Lafda:
#afda#45da28
0e 00 
    ld c, 0
#afdc#45dc28
fe 03 
    cp INPUT_FORWARD
#afde#45de213/8
28 05 
    jr z, Lafe5
#afe0#45e028
fe 04 
    cp INPUT_BACKWARD
#afe2#45e2311
c2 a5 b0 
    jp nz, Lb0a5
#afe5#45e5
Lafe5:
#afe5#45e5112
f5 
    push af
#afe6#45e6317
2a b3 6a 
        ld hl, (L6ab3_current_speed_in_this_room)
#afe9#45e928
fe 04 
        cp INPUT_BACKWARD
#afeb#45eb213/8
20 13 
        jr nz, Lb000_move
#afed#45ed
        ; Either backwards or forward+backwards keys pressed simultaneously:
#afed#45ed314
3a 0b 6b 
        ld a, (L6b0b_selected_movement_mode)
#aff0#45f028
fe 02 
        cp 2
#aff2#45f2213/8
20 0c 
        jr nz, Lb000_move
#aff4#45f4
        ; Slow down running to walk speed, since we are pressing backwards:
#aff4#45f4314
3a c9 d0 
        ld a, (Ld0c9_speed_when_walking)
#aff7#45f715
6f 
        ld l, a
#aff8#45f828
26 00 
        ld h, 0
#affa#45fa314
3a bc 6a 
        ld a, (L6abc_current_room_scale)
#affd#45fd318
cd 08 a1 
        call La108_a_times_hl_signed
#b000#4600
Lb000_move:
#b000#4600112
e5 
        push hl
#b001#4601314
3a b7 6a 
            ld a, (L6ab7_player_yaw_angle)
#b004#4604
            ; update in "z":
#b004#4604416
dd 21 c6 73 
            ld ix, L73c6_cosine_sine_table
#b008#460815
5f 
            ld e, a
#b009#460915
51 
            ld d, c
#b00a#460a217
dd 19 
            add ix, de
#b00c#460c217
dd 19 
            add ix, de
#b00e#460e321
dd 7e 01 
            ld a, (ix + 1)  ; cos(yaw)
#b011#4611318
cd 08 a1 
            call La108_a_times_hl_signed
#b014#4614210
cb 25 
            sla l
#b016#4616210
cb 14 
            rl h
#b018#4618210
cb 17 
            rl a
#b01a#461a210
cb 25 
            sla l
#b01c#461c210
cb 14 
            rl h
#b01e#461e210
cb 17 
            rl a
#b020#462015
6c 
            ld l, h
#b021#462115
67 
            ld h, a
#b022#4622
            ; hl = (cos(yaw) * movement speed) / 1024
#b022#4622111
d1 
        pop de
#b023#4623111
f1 
    pop af
#b024#4624112
f5 
    push af
#b025#4625112
d5 
        push de
#b026#462628
16 09 
            ld d, 9  ; eye ui frame
#b028#462828
fe 03 
            cp INPUT_FORWARD
#b02a#462a213/8
28 08 
            jr z, Lb034
#b02c#462c
            ; We are moving backwaards:
#b02c#462c
            ; hl = -hl
#b02c#462c15
7c 
            ld a, h
#b02d#462d15
2f 
            cpl
#b02e#462e15
67 
            ld h, a
#b02f#462f15
7d 
            ld a, l
#b030#463015
2f 
            cpl
#b031#463115
6f 
            ld l, a
#b032#463217
23 
            inc hl
#b033#463315
14 
            inc d  ; change eye ui frame
#b034#4634
Lb034:
#b034#4634318
cd a0 b1 
            call Lb1a0_draw_compass_eye_ui_frame
#b037#4637422
ed 5b b1 6a 
            ld de, (L6ab1_player_current_z)
#b03b#463b112
19 
            add hl, de
#b03c#463c317
22 5a 74 
            ld (L745a_player_desired_z), hl
#b03f#463f111
e1 
        pop hl
#b040#4640
        ; update in "x":
#b040#4640321
dd 7e 00 
        ld a, (ix)  ; sin(yaw)
#b043#4643318
cd 08 a1 
        call La108_a_times_hl_signed
#b046#4646210
cb 25 
        sla l
#b048#4648210
cb 14 
        rl h
#b04a#464a210
cb 17 
        rl a
#b04c#464c210
cb 25 
        sla l
#b04e#464e210
cb 14 
        rl h
#b050#4650210
cb 17 
        rl a
#b052#465215
6c 
        ld l, h
#b053#465315
67 
        ld h, a
#b054#4654
        ; hl = (sin(yaw) * movement speed) / 1024
#b054#4654111
f1 
    pop af
#b055#465528
fe 03 
    cp INPUT_FORWARD
#b057#4657213/8
28 07 
    jr z, Lb060
#b059#4659
    ; We are moving backwards:
#b059#4659
    ; hl = -hl
#b059#465915
7c 
    ld a, h
#b05a#465a15
2f 
    cpl
#b05b#465b15
67 
    ld h, a
#b05c#465c15
7d 
    ld a, l
#b05d#465d15
2f 
    cpl
#b05e#465e15
6f 
    ld l, a
#b05f#465f17
23 
    inc hl
#b060#4660
Lb060:
#b060#4660422
ed 5b ad 6a 
    ld de, (L6aad_player_current_x)
#b064#4664112
19 
    add hl, de
#b065#4665317
22 56 74 
    ld (L7456_player_desired_x), hl
#b068#4668
    ; update in "y":
#b068#4668317
2a af 6a 
    ld hl, (L6aaf_player_current_y)
#b06b#466b317
22 58 74 
    ld (L7458_player_desired_y), hl
#b06e#466e314
3a be 6a 
    ld a, (L6abe_use_eye_player_coordinate)
#b071#467115
b7 
    or a
#b072#4672213/8
20 18 
    jr nz, Lb08c_no_y_adjustment
#b074#4674
    ; subtract player height from player y (this is used in the codebase to,
#b074#4674
    ; move from "eye" coordinate, to "feet" coordinates.)
#b074#4674314
3a b9 6a 
    ld a, (L6ab9_player_height)
#b077#467715
3d 
    dec a
#b078#467815
57 
    ld d, a
#b079#467928
1e 80 
    ld e, 128
#b07b#467b210
cb 3a 
    srl d
#b07d#467d210
cb 1b 
    rr e
#b07f#467f210
cb 3a 
    srl d
#b081#4681210
cb 1b 
    rr e  ; de = ((L6ab9_player_height) - 1) * 64 + 32
#b083#468315
b7 
    or a
#b084#4684217
ed 52 
    sbc hl, de
#b086#4686317
22 af 6a 
    ld (L6aaf_player_current_y), hl
#b089#4689317
22 58 74 
    ld (L7458_player_desired_y), hl
#b08c#468c
#b08c#468c
Lb08c_no_y_adjustment:
#b08c#468c318
cd d9 a5 
    call La5d9_move_player
#b08f#468f15
b7 
    or a
#b090#4690213/8
28 03 
    jr z, Lb095
#b092#4692311
01 34 00 
    ld bc, #34  ; Add flags to L746c_game_flags
#b095#4695
Lb095:
#b095#4695314
3a be 6a 
    ld a, (L6abe_use_eye_player_coordinate)
#b098#469815
b7 
    or a
#b099#4699213/8
20 07 
    jr nz, Lb0a2_no_y_adjustment
#b09b#469b
    ; If we had moved coordinates from eye to feet, bring back player y, to "eye" coordinates:
#b09b#469b317
2a af 6a 
    ld hl, (L6aaf_player_current_y)
#b09e#469e112
19 
    add hl, de
#b09f#469f317
22 af 6a 
    ld (L6aaf_player_current_y), hl
#b0a2#46a2
Lb0a2_no_y_adjustment:
#b0a2#46a2311
c3 8c b1 
    jp Lb18c_done_setting_L747f_player_event_to_1
#b0a5#46a5
#b0a5#46a5
Lb0a5:
#b0a5#46a528
fe 05 
    cp INPUT_TURN_LEFT
#b0a7#46a7213/8
20 14 
    jr nz, Lb0bd
#b0a9#46a9311
21 b7 6a 
    ld hl, L6ab7_player_yaw_angle
#b0ac#46ac311
01 24 00 
    ld bc, #24  ; Add flags to L746c_game_flags
#b0af#46af
    ; Determine rotation speed: if shift is pressed, rotate 90 degrees
#b0af#46af314
3a 72 74 
    ld a, (L7472_symbol_shift_pressed)
#b0b2#46b215
b7 
    or a
#b0b3#46b328
3e 12 
    ld a, FULL_ROTATION_DEGREES / 4
#b0b5#46b5213/8
20 03 
    jr nz, Lb0ba
#b0b7#46b7314
3a ce d0 
    ld a, (Ld0ce_yaw_rotation_speed)
#b0ba#46ba
Lb0ba:
#b0ba#46ba311
c3 68 b1 
    jp Lb168_turn_left
#b0bd#46bd
Lb0bd:
#b0bd#46bd28
fe 06 
    cp INPUT_TURN_RIGHT
#b0bf#46bf213/8
20 14 
    jr nz, Lb0d5_no_turn_right
#b0c1#46c1311
21 b7 6a 
    ld hl, L6ab7_player_yaw_angle
#b0c4#46c4311
01 24 00 
    ld bc, #24  ; Add flags to L746c_game_flags
#b0c7#46c7
    ; Determine rotation speed: if shift is pressed, rotate 90 degrees
#b0c7#46c7314
3a 72 74 
    ld a, (L7472_symbol_shift_pressed)
#b0ca#46ca15
b7 
    or a
#b0cb#46cb28
3e 12 
    ld a, FULL_ROTATION_DEGREES / 4
#b0cd#46cd213/8
20 03 
    jr nz, Lb0d2
#b0cf#46cf314
3a ce d0 
    ld a, (Ld0ce_yaw_rotation_speed)
#b0d2#46d2
Lb0d2:
#b0d2#46d2311
c3 5b b1 
    jp Lb15b_turn_right
#b0d5#46d5
#b0d5#46d5
Lb0d5_no_turn_right:
#b0d5#46d528
fe 0c 
    cp INPUT_FACE_FORWARD
#b0d7#46d7213/8
20 2b 
    jr nz, Lb104_no_face_forward
#b0d9#46d9314
3a b6 6a 
    ld a, (L6ab6_player_pitch_angle)
#b0dc#46dc15
b7 
    or a
#b0dd#46dd311
ca 8c b1 
    jp z, Lb18c_done_setting_L747f_player_event_to_1
#b0e0#46e0
    ; "face forward" UI eye animation:
#b0e0#46e0416
dd 21 50 73 
    ld ix, L7350_compass_eye_ui_row_pointers
#b0e4#46e4311
21 92 77 
    ld hl, L7792_ui_compass_eye_sprites
#b0e7#46e7311
11 00 04 
    ld de, #0400  ; Start with frame 4
#b0ea#46ea
Lb0ea_face_forward_animation_loop:
#b0ea#46ea15
14 
    inc d
#b0eb#46eb318
cd 95 c8 
    call Lc895_draw_sprite_to_ix_ptrs
#b0ee#46ee28
3e 02 
    ld a, 2
#b0f0#46f0314
32 a5 74 
    ld (L74a5_interrupt_timer), a
#b0f3#46f3
Lb0f3_pause_loop:
#b0f3#46f3314
3a a5 74 
    ld a, (L74a5_interrupt_timer)
#b0f6#46f615
b7 
    or a
#b0f7#46f7213/8
20 fa 
    jr nz, Lb0f3_pause_loop
#b0f9#46f928
3e 08 
    ld a, 8
#b0fb#46fb15
ba 
    cp d
#b0fc#46fc213/8
20 ec 
    jr nz, Lb0ea_face_forward_animation_loop
#b0fe#46fe
#b0fe#46fe314
32 2b 6b 
    ld (L6b2b_desired_eye_compass_frame), a
#b101#470115
af 
    xor a
#b102#4702213
18 4e 
    jr Lb152_desired_pitch_set
#b104#4704
#b104#4704
Lb104_no_face_forward:
#b104#470428
fe 07 
    cp INPUT_LOOK_UP
#b106#4706213/8
20 23 
    jr nz, Lb12b
#b108#470828
16 01 
    ld d, 1  ; desired ui eye frame
#b10a#470a318
cd a0 b1 
    call Lb1a0_draw_compass_eye_ui_frame
#b10d#470d
    ; If shift is pressed, go directly to -18 (54) degrees
#b10d#470d314
3a 72 74 
    ld a, (L7472_symbol_shift_pressed)
#b110#471015
b7 
    or a
#b111#4711213/8
20 14 
    jr nz, Lb127
#b113#4713314
3a ce d0 
    ld a, (Ld0ce_yaw_rotation_speed)
#b116#471615
5f 
    ld e, a
#b117#4717314
3a b6 6a 
    ld a, (L6ab6_player_pitch_angle)
#b11a#471a15
93 
    sub e
#b11b#471b213/8
30 02 
    jr nc, Lb11f_no_overflow
#b11d#471d28
c6 48 
    add a, FULL_ROTATION_DEGREES
#b11f#471f
Lb11f_no_overflow:
#b11f#471f28
fe 36 
    cp FULL_ROTATION_DEGREES - FULL_ROTATION_DEGREES / 4
#b121#4721213/8
30 2f 
    jr nc, Lb152_desired_pitch_set
#b123#472328
fe 12 
    cp FULL_ROTATION_DEGREES / 4
#b125#4725213/8
38 2b 
    jr c, Lb152_desired_pitch_set
#b127#4727
Lb127:
#b127#472728
3e 36 
    ld a, FULL_ROTATION_DEGREES - FULL_ROTATION_DEGREES / 4
#b129#4729213
18 27 
    jr Lb152_desired_pitch_set
#b12b#472b
#b12b#472b
Lb12b:
#b12b#472b28
fe 08 
    cp INPUT_LOOK_DOWN
#b12d#472d213/8
20 48 
    jr nz, Lb177
#b12f#472f28
16 02 
    ld d, 2  ; desired ui eye frame
#b131#4731318
cd a0 b1 
    call Lb1a0_draw_compass_eye_ui_frame
#b134#4734
    ; If shift is pressed, go directly to 18 degrees
#b134#4734314
3a 72 74 
    ld a, (L7472_symbol_shift_pressed)
#b137#473715
b7 
    or a
#b138#4738213/8
20 16 
    jr nz, Lb150
#b13a#473a314
3a ce d0 
    ld a, (Ld0ce_yaw_rotation_speed)
#b13d#473d15
5f 
    ld e, a
#b13e#473e314
3a b6 6a 
    ld a, (L6ab6_player_pitch_angle)
#b141#474115
83 
    add a, e
#b142#474228
fe 48 
    cp FULL_ROTATION_DEGREES
#b144#4744213/8
38 02 
    jr c, Lb148
#b146#474628
d6 48 
    sub FULL_ROTATION_DEGREES
#b148#4748
Lb148:
#b148#474828
fe 36 
    cp FULL_ROTATION_DEGREES - FULL_ROTATION_DEGREES / 4
#b14a#474a213/8
30 06 
    jr nc, Lb152_desired_pitch_set
#b14c#474c28
fe 12 
    cp FULL_ROTATION_DEGREES / 4
#b14e#474e213/8
38 02 
    jr c, Lb152_desired_pitch_set
#b150#4750
Lb150:
#b150#475028
3e 12 
    ld a, FULL_ROTATION_DEGREES / 4
#b152#4752
Lb152_desired_pitch_set:
#b152#4752314
32 b6 6a 
    ld (L6ab6_player_pitch_angle), a
#b155#4755311
01 44 00 
    ld bc, #44  ; Add flags to L746c_game_flags
#b158#4758311
c3 8c b1 
    jp Lb18c_done_setting_L747f_player_event_to_1
#b15b#475b
#b15b#475b
Lb15b_turn_right:
#b15b#475b15
5f 
    ld e, a
#b15c#475c28
16 04 
    ld d, 4
#b15e#475e18
7e 
    ld a, (hl)
#b15f#475f15
83 
    add a, e
#b160#476028
fe 48 
    cp 72
#b162#4762213/8
38 0d 
    jr c, Lb171_no_overflow
#b164#476428
d6 48 
    sub 72
#b166#4766213
18 09 
    jr Lb171_no_overflow
#b168#4768
#b168#4768
Lb168_turn_left:
#b168#476815
5f 
    ld e, a
#b169#476928
16 03 
    ld d, 3  ; eye ui frame
#b16b#476b18
7e 
    ld a, (hl)
#b16c#476c15
93 
    sub e
#b16d#476d213/8
30 02 
    jr nc, Lb171_no_overflow
#b16f#476f28
c6 48 
    add a, FULL_ROTATION_DEGREES
#b171#4771
Lb171_no_overflow:
#b171#477118
77 
    ld (hl), a
#b172#4772318
cd a0 b1 
    call Lb1a0_draw_compass_eye_ui_frame
#b175#4775213
18 15 
    jr Lb18c_done_setting_L747f_player_event_to_1
#b177#4777
#b177#4777
Lb177:
#b177#477728
fe 0d 
    cp INPUT_U_TURN
#b179#4779213/8
20 16 
    jr nz, Lb191_done
#b17b#477b311
01 24 00 
    ld bc, FULL_ROTATION_DEGREES / 2
#b17e#477e314
3a b7 6a 
    ld a, (L6ab7_player_yaw_angle)
#b181#478128
c6 24 
    add a, FULL_ROTATION_DEGREES / 2
#b183#478328
fe 48 
    cp FULL_ROTATION_DEGREES
#b185#4785213/8
38 02 
    jr c, Lb189_no_overflow
#b187#478728
d6 48 
    sub FULL_ROTATION_DEGREES
#b189#4789
Lb189_no_overflow:
#b189#4789314
32 b7 6a 
    ld (L6ab7_player_yaw_angle), a
#b18c#478c
Lb18c_done_setting_L747f_player_event_to_1:
#b18c#478c28
3e 01 
    ld a, 1
#b18e#478e314
32 7f 74 
    ld (L747f_player_event), a
#b191#4791
Lb191_done:
#b191#4791314
3a 6c 74 
    ld a, (L746c_game_flags)
#b194#479415
b1 
    or c
#b195#4795314
32 6c 74 
    ld (L746c_game_flags), a
#b198#4798314
3a 6d 74 
    ld a, (L746c_game_flags + 1)
#b19b#479b15
b0 
    or b
#b19c#479c314
32 6d 74 
    ld (L746c_game_flags + 1), a
#b19f#479f111
c9 
    ret
#b1a0#47a0
#b1a0#47a0
#b1a0#47a0
; --------------------------------
#b1a0#47a0
; Draws a frame of the "compass eye" in the game UI.
#b1a0#47a0
; This visualization changes depending on the direction you are turning or moving.
#b1a0#47a0
; Input:
#b1a0#47a0
; - d: frame to draw
#b1a0#47a0
Lb1a0_draw_compass_eye_ui_frame:
#b1a0#47a0217
dd e5 
    push ix
#b1a2#47a2112
e5 
    push hl
#b1a3#47a3416
dd 21 50 73 
        ld ix, L7350_compass_eye_ui_row_pointers  ; ptr to row pointers
#b1a7#47a7311
21 92 77 
        ld hl, L7792_ui_compass_eye_sprites  ; ptr to w, h, mask, size, data
#b1aa#47aa28
1e 00 
        ld e, 0  ; x_offset
#b1ac#47ac318
cd 95 c8 
        call Lc895_draw_sprite_to_ix_ptrs
#b1af#47af15
af 
        xor a
#b1b0#47b0314
32 2b 6b 
        ld (L6b2b_desired_eye_compass_frame), a
#b1b3#47b3111
e1 
    pop hl
#b1b4#47b4216
dd e1 
    pop ix
#b1b6#47b6111
c9 
    ret
#b1b7#47b7
#b1b7#47b7
#b1b7#47b7
; --------------------------------
#b1b7#47b7
; Signed division between (DE,HL) / BC.
#b1b7#47b7
; Result stored in (DE,HL), and remainder in BC
#b1b7#47b7
; Note: division result sometimes is off by 1
#b1b7#47b7
;       (maybe this is ok if these are fixed-point precision numbers with lower bits
#b1b7#47b7
;        dedicated to the fractionary part).
#b1b7#47b7
; Input:
#b1b7#47b7
; - de, hl
#b1b7#47b7
; - bc
#b1b7#47b7
; Output:
#b1b7#47b7
; - de, hl
#b1b7#47b7
; - bc
#b1b7#47b7
Lb1b7_de_hl_divided_by_bc_signed:
#b1b7#47b7112
f5 
    push af
#b1b8#47b815
7c 
        ld a, h
#b1b9#47b915
b5 
        or l
#b1ba#47ba213/8
20 08 
        jr nz, Lb1c4
#b1bc#47bc15
7a 
        ld a, d
#b1bd#47bd15
b3 
        or e
#b1be#47be213/8
20 04 
        jr nz, Lb1c4
#b1c0#47c015
47 
        ld b, a
#b1c1#47c115
4f 
        ld c, a
#b1c2#47c2111
f1 
    pop af
#b1c3#47c3111
c9 
    ret
#b1c4#47c4
Lb1c4:
#b1c4#47c415
d9 
        exx
#b1c5#47c5112
e5 
        push hl
#b1c6#47c6112
d5 
        push de
#b1c7#47c7112
c5 
        push bc
#b1c8#47c828
16 00 
            ld d, 0
#b1ca#47ca15
d9 
            exx
#b1cb#47cb210
cb 7a 
            bit 7, d
#b1cd#47cd213/8
28 15 
            jr z, Lb1e4
#b1cf#47cf15
d9 
            exx
#b1d0#47d015
14 
            inc d
#b1d1#47d115
d9 
            exx
#b1d2#47d215
7a 
            ld a, d
#b1d3#47d315
2f 
            cpl
#b1d4#47d415
57 
            ld d, a
#b1d5#47d515
7b 
            ld a, e
#b1d6#47d615
2f 
            cpl
#b1d7#47d715
5f 
            ld e, a
#b1d8#47d815
7c 
            ld a, h
#b1d9#47d915
2f 
            cpl
#b1da#47da15
67 
            ld h, a
#b1db#47db15
7d 
            ld a, l
#b1dc#47dc15
2f 
            cpl
#b1dd#47dd15
6f 
            ld l, a
#b1de#47de17
23 
            inc hl
#b1df#47df15
7c 
            ld a, h
#b1e0#47e015
b5 
            or l
#b1e1#47e1213/8
20 01 
            jr nz, Lb1e4
#b1e3#47e317
13 
            inc de
#b1e4#47e4
Lb1e4:
#b1e4#47e4210
cb 78 
            bit 7, b
#b1e6#47e6213/8
28 0d 
            jr z, Lb1f5
#b1e8#47e815
78 
            ld a, b
#b1e9#47e915
2f 
            cpl
#b1ea#47ea15
47 
            ld b, a
#b1eb#47eb15
79 
            ld a, c
#b1ec#47ec15
2f 
            cpl
#b1ed#47ed15
4f 
            ld c, a
#b1ee#47ee17
03 
            inc bc
#b1ef#47ef15
d9 
            exx
#b1f0#47f015
7a 
            ld a, d
#b1f1#47f128
ee 01 
            xor 1
#b1f3#47f315
57 
            ld d, a
#b1f4#47f415
d9 
            exx
#b1f5#47f5
Lb1f5:
#b1f5#47f5112
c5 
            push bc
#b1f6#47f615
d9 
                exx
#b1f7#47f7111
c1 
            pop bc
#b1f8#47f8311
21 00 00 
            ld hl, 0
#b1fb#47fb15
d9 
            exx
#b1fc#47fc28
06 20 
            ld b, 32
#b1fe#47fe
Lb1fe:
#b1fe#47fe112
29 
            add hl, hl
#b1ff#47ff210
cb 13 
            rl e
#b201#4801210
cb 12 
            rl d
#b203#4803213/8
38 0a 
            jr c, Lb20f
#b205#4805214/9
10 f7 
            djnz Lb1fe
#b207#4807213
18 47 
            jr Lb250
#b209#4809
Lb209:
#b209#4809217
ed 6a 
            adc hl, hl
#b20b#480b210
cb 13 
            rl e
#b20d#480d210
cb 12 
            rl d
#b20f#480f
Lb20f:
#b20f#480f15
d9 
            exx
#b210#4810217
ed 6a 
            adc hl, hl
#b212#4812217
ed 42 
            sbc hl, bc
#b214#4814213/8
30 01 
            jr nc, Lb217
#b216#4816112
09 
            add hl, bc
#b217#4817
Lb217:
#b217#481715
d9 
            exx
#b218#481815
3f 
            ccf
#b219#4819214/9
10 ee 
            djnz Lb209
#b21b#481b217
ed 6a 
            adc hl, hl
#b21d#481d210
cb 13 
            rl e
#b21f#481f210
cb 12 
            rl d
#b221#482115
d9 
            exx
#b222#4822112
e5 
            push hl
#b223#4823210
cb 28 
                sra b
#b225#4825210
cb 19 
                rr c
#b227#482715
b7 
                or a
#b228#4828217
ed 42 
                sbc hl, bc
#b22a#482a15
d9 
                exx
#b22b#482b111
c1 
            pop bc
#b22c#482c311
fa 35 b2 
            jp m, Lb235
#b22f#482f17
23 
            inc hl
#b230#483015
7d 
            ld a, l
#b231#483115
b4 
            or h
#b232#4832213/8
20 01 
            jr nz, Lb235
#b234#483417
13 
            inc de
#b235#4835
Lb235:
#b235#483515
d9 
            exx
#b236#4836210
cb 42 
            bit 0, d
#b238#4838111
c1 
        pop bc
#b239#4839111
d1 
        pop de
#b23a#483a111
e1 
        pop hl
#b23b#483b15
d9 
        exx
#b23c#483c213/8
28 12 
        jr z, Lb250
#b23e#483e15
7c 
        ld a, h
#b23f#483f15
2f 
        cpl
#b240#484015
67 
        ld h, a
#b241#484115
7d 
        ld a, l
#b242#484215
2f 
        cpl
#b243#484315
6f 
        ld l, a
#b244#484415
7a 
        ld a, d
#b245#484515
2f 
        cpl
#b246#484615
57 
        ld d, a
#b247#484715
7b 
        ld a, e
#b248#484815
2f 
        cpl
#b249#484915
5f 
        ld e, a
#b24a#484a17
23 
        inc hl
#b24b#484b15
7d 
        ld a, l
#b24c#484c15
b4 
        or h
#b24d#484d213/8
20 01 
        jr nz, Lb250
#b24f#484f17
13 
        inc de
#b250#4850
Lb250:
#b250#4850111
f1 
    pop af
#b251#4851111
c9 
    ret
#b252#4852
#b252#4852
#b252#4852
; --------------------------------
#b252#4852
; Set the screen area to a uniform attribute read from "L6add_desired_attribute_color", and sets the border to black.
#b252#4852
Lb252_set_screen_area_attributes:
#b252#4852112
e5 
    push hl
#b253#4853112
d5 
    push de
#b254#4854112
c5 
    push bc
#b255#4855112
f5 
    push af
#b256#485615
af 
        xor a
#b257#4857314
32 66 74 
        ld (L7466_need_attribute_refresh_flag), a  ; Mark that the border has already been set.
#b25a#485a317
2a db 6a 
        ld hl, (L6adb_desired_border_color)  ; Desired border color (only msb used)
#b25d#485d317
22 d7 6a 
        ld (L6ad7_current_border_color), hl
#b260#4860317
2a dd 6a 
        ld hl, (L6add_desired_attribute_color)  ; Desired attribute (only msb used)
#b263#4863317
22 d9 6a 
        ld (L6ad9_current_attribute_color), hl
#b266#4866311
21 84 58 
        ld hl, L5800_VIDEOMEM_ATTRIBUTES + 4 * 32 + 4
#b269#4869314
3a d9 6a 
        ld a, (L6ad9_current_attribute_color)  ; read the color attribute
#b26c#486c311
11 08 00 
        ld de, 8  ; skip 4 rows to the right/left of the viewport
#b26f#486f28
0e 0e 
        ld c, SCREEN_HEIGHT
#b271#4871
        ; Set the attributes of the whole game area to "a"
#b271#4871
Lb271_row_loop:
#b271#487128
06 18 
        ld b, SCREEN_WIDTH
#b273#4873
Lb273_column_loop:
#b273#487318
77 
        ld (hl), a
#b274#487417
23 
        inc hl
#b275#4875214/9
10 fc 
        djnz Lb273_column_loop
#b277#4877112
19 
        add hl, de
#b278#487815
0d 
        dec c
#b279#4879213/8
20 f6 
        jr nz, Lb271_row_loop
#b27b#487b15
af 
        xor a
#b27c#487c314
32 d7 6a 
        ld (L6ad7_current_border_color), a  ; Current border to 0
#b27f#487f212
d3 fe 
        out (ULA_PORT), a  ; black border, and no sound.
#b281#4881111
f1 
    pop af
#b282#4882111
c1 
    pop bc
#b283#4883111
d1 
    pop de
#b284#4884111
e1 
    pop hl
#b285#4885111
c9 
    ret
#b286#4886
#b286#4886
#b286#4886
; --------------------------------
#b286#4886
; Determines whether an object with ID (L7468_focus_object_id) is present
#b286#4886
; in either the current area, or a given area.
#b286#4886
; Input:
#b286#4886
; - a: area ID to check (0 for current area)
#b286#4886
; Output:
#b286#4886
; - a: 0 if object found, 1 if object not found
#b286#4886
; - ix: ptr to the object
#b286#4886
Lb286_find_object_by_id:
#b286#4886112
e5 
    push hl
#b287#4887112
d5 
    push de
#b288#4888112
c5 
    push bc
#b289#488915
b7 
        or a
#b28a#488a213/8
20 25 
        jr nz, Lb2b1_find_area_a
#b28c#488c
        ; We want to check objects in the current area:
#b28c#488c422
dd 2a 63 74 
        ld ix, (L7463_global_area_objects)
#b290#4890314
3a 65 74 
        ld a, (L7465_global_area_n_objects)
#b293#489315
b7 
        or a
#b294#4894213/8
28 12 
        jr z, Lb2a8
#b296#489615
47 
        ld b, a
#b297#489728
16 00 
        ld d, 0
#b299#4899314
3a 68 74 
        ld a, (L7468_focus_object_id)
#b29c#489c
Lb29c_object_in_current_area_loop:
#b29c#489c321
dd be 07 
        cp (ix + OBJECT_ID)
#b29f#489f213/8
28 4d 
        jr z, Lb2ee_object_found
#b2a1#48a1321
dd 5e 08 
        ld e, (ix + OBJECT_SIZE)
#b2a4#48a4217
dd 19 
        add ix, de
#b2a6#48a6214/9
10 f4 
        djnz Lb29c_object_in_current_area_loop
#b2a8#48a8
Lb2a8:
#b2a8#48a8422
dd 2a d1 6a 
        ld ix, (L6ad1_current_area_objects)
#b2ac#48ac314
3a d0 6a 
        ld a, (L6ad0_current_area_n_objects)
#b2af#48af213
18 24 
        jr Lb2d5
#b2b1#48b1
Lb2b1_find_area_a:
#b2b1#48b115
6f 
        ld l, a
#b2b2#48b2314
3a 82 d0 
        ld a, (Ld082_n_areas)
#b2b5#48b515
47 
        ld b, a
#b2b6#48b615
7d 
        ld a, l
#b2b7#48b7311
21 d1 d0 
        ld hl, Ld0d1_area_offsets
#b2ba#48ba
Lb2ba_find_area_loop:
#b2ba#48ba
        ; Get area ptr:
#b2ba#48ba18
5e 
        ld e, (hl)
#b2bb#48bb17
23 
        inc hl
#b2bc#48bc18
56 
        ld d, (hl)
#b2bd#48bd17
23 
        inc hl
#b2be#48be416
dd 21 82 d0 
        ld ix, Ld082_n_areas
#b2c2#48c2217
dd 19 
        add ix, de
#b2c4#48c4321
dd be 02 
        cp (ix + AREA_ID)
#b2c7#48c7213/8
28 04 
        jr z, Lb2cd_area_found
#b2c9#48c9214/9
10 ef 
        djnz Lb2ba_find_area_loop
#b2cb#48cb213
18 1d 
        jr Lb2ea_object_not_found
#b2cd#48cd
Lb2cd_area_found:
#b2cd#48cd321
dd 7e 01 
        ld a, (ix + AREA_N_OBJECTS)
#b2d0#48d0311
11 08 00 
        ld de, AREA_HEADER_SIZE
#b2d3#48d3217
dd 19 
        add ix, de
#b2d5#48d5
Lb2d5:
#b2d5#48d515
b7 
        or a
#b2d6#48d6213/8
28 12 
        jr z, Lb2ea_object_not_found
#b2d8#48d815
47 
        ld b, a
#b2d9#48d928
16 00 
        ld d, 0
#b2db#48db314
3a 68 74 
        ld a, (L7468_focus_object_id)
#b2de#48de
Lb2de:
#b2de#48de321
dd be 07 
        cp (ix + OBJECT_ID)
#b2e1#48e1213/8
28 0b 
        jr z, Lb2ee_object_found
#b2e3#48e3321
dd 5e 08 
        ld e, (ix + OBJECT_SIZE)
#b2e6#48e6217
dd 19 
        add ix, de
#b2e8#48e8214/9
10 f4 
        djnz Lb2de
#b2ea#48ea
Lb2ea_object_not_found:
#b2ea#48ea28
3e 01 
        ld a, 1
#b2ec#48ec213
18 01 
        jr Lb2ef_done
#b2ee#48ee
Lb2ee_object_found:
#b2ee#48ee15
af 
        xor a
#b2ef#48ef
Lb2ef_done:
#b2ef#48ef111
c1 
    pop bc
#b2f0#48f0111
d1 
    pop de
#b2f1#48f1111
e1 
    pop hl
#b2f2#48f2111
c9 
    ret
#b2f3#48f3
#b2f3#48f3
#b2f3#48f3
; --------------------------------
#b2f3#48f3
; Pointers to the different animation frames of the "throw rock" animation:
#b2f3#48f3
Lb2f3_rock_animation_frames:
#b2f3#48f32
    dw L7f1e_stone_viewport_sprite_size2 + 1
#b2f5#48f52
    dw L7fee_stone_viewport_sprite_size3 + 1
#b2f7#48f72
    dw L909c_stone_viewport_sprite_size4 + 1
#b2f9#48f9
#b2f9#48f9
#b2f9#48f9
; --------------------------------
#b2f9#48f9
; Processes the following input key functions:
#b2f9#48f9
; - INPUT_SWITCH_BETWEEN_MOVEMENT_AND_POINTER
#b2f9#48f9
; - INPUT_MOVEMENT_POINTER_ON_OFF
#b2f9#48f9
; - INPUT_MOVE_POINTER_LEFT
#b2f9#48f9
; - INPUT_MOVE_POINTER_RIGHT
#b2f9#48f9
; - INPUT_MOVE_POINTER_UP
#b2f9#48f9
; - INPUT_MOVE_POINTER_DOWN
#b2f9#48f9
; - INPUT_THROW_ROCK
#b2f9#48f9
; - INPUT_ACTION
#b2f9#48f9
Lb2f9_execute_pressed_key_function:
#b2f9#48f928
fe 1e 
    cp INPUT_SWITCH_BETWEEN_MOVEMENT_AND_POINTER
#b2fb#48fb213/8
20 43 
    jr nz, Lb340_no_movement_pointer_toggle
#b2fd#48fd
    ; Toogle movement <-> pointer:
#b2fd#48fd28
3e 09 
    ld a, 9
#b2ff#48ff314
32 a5 74 
    ld (L74a5_interrupt_timer), a
#b302#4902
    ; Toogle the movement/pointer mode flag:
#b302#4902314
3a 1c 6b 
    ld a, (L6b1c_movement_or_pointer)
#b305#490515
2f 
    cpl
#b306#4906314
32 1c 6b 
    ld (L6b1c_movement_or_pointer), a
#b309#490915
b7 
    or a
#b30a#490a314
3a 20 6b 
    ld a, (L6b20_display_movement_pointer_flag)
#b30d#490d311
21 88 7d 
    ld hl, L7d88_action_pointer_viewport_sprite
#b310#4910213/8
20 13 
    jr nz, Lb325_switch_to_pointer
#b312#4912
    ; Switched to movement:
#b312#4912318
cd 14 cd 
    call Lcd14_restore_view_port_background_after_drawing_sprite
#b315#491515
b7 
    or a
#b316#4916318/11
c4 37 b5 
    call nz, Lb537_redraw_with_center_pointer
#b319#491928
3e 60 
    ld a, 96
#b31b#491b314
32 1a 6b 
    ld (L6b1a_pointer_x), a
#b31e#491e28
3e 38 
    ld a, 56
#b320#4920314
32 1b 6b 
    ld (L6b1b_pointer_y), a
#b323#4923213
18 30 
    jr Lb355_play_sfx_and_return
#b325#4925
Lb325_switch_to_pointer:
#b325#4925
    ; Switched to pointer:
#b325#492515
b7 
    or a
#b326#4926318/11
c4 37 b5 
    call nz, Lb537_redraw_with_center_pointer
#b329#492928
3e 60 
    ld a, 96
#b32b#492b314
32 1a 6b 
    ld (L6b1a_pointer_x), a
#b32e#492e28
d6 04 
    sub 4
#b330#493018
77 
    ld (hl), a  ; pointer sprite x
#b331#493128
3e 38 
    ld a, 56
#b333#4933314
32 1b 6b 
    ld (L6b1b_pointer_y), a
#b336#493617
23 
    inc hl
#b337#493728
d6 04 
    sub 4
#b339#493918
77 
    ld (hl), a  ; pointer sprite y
#b33a#493a17
2b 
    dec hl
#b33b#493b318
cd 19 cc 
    call Lcc19_draw_viewport_sprite_with_offset
#b33e#493e213
18 15 
    jr Lb355_play_sfx_and_return
#b340#4940
#b340#4940
Lb340_no_movement_pointer_toggle:
#b340#494028
fe 15 
    cp INPUT_MOVEMENT_POINTER_ON_OFF
#b342#4942213/8
20 1f 
    jr nz, Lb363_no_movement_pointer_on_off
#b344#4944
    ; Movement pointer toggle:
#b344#4944
    ; If we are in pointer mode, ignore:
#b344#4944314
3a 1c 6b 
    ld a, (L6b1c_movement_or_pointer)
#b347#494715
b7 
    or a
#b348#4948311
c2 36 b5 
    jp nz, Lb536_execute_pressed_key_function_done
#b34b#494b314
3a 20 6b 
    ld a, (L6b20_display_movement_pointer_flag)
#b34e#494e15
2f 
    cpl
#b34f#494f314
32 20 6b 
    ld (L6b20_display_movement_pointer_flag), a
#b352#4952318
cd 37 b5 
    call Lb537_redraw_with_center_pointer
#b355#4955
Lb355_play_sfx_and_return:
#b355#495528
3e 03 
    ld a, SFX_MENU_SELECT
#b357#4957318
cd ca c4 
    call Lc4ca_play_SFX
#b35a#495a
Lb35a_pause_loop:
#b35a#495a314
3a a5 74 
    ld a, (L74a5_interrupt_timer)
#b35d#495d15
b7 
    or a
#b35e#495e213/8
20 fa 
    jr nz, Lb35a_pause_loop
#b360#4960311
c3 36 b5 
    jp Lb536_execute_pressed_key_function_done
#b363#4963
#b363#4963
Lb363_no_movement_pointer_on_off:
#b363#496315
47 
    ld b, a
#b364#4964314
3a 1c 6b 
    ld a, (L6b1c_movement_or_pointer)
#b367#496715
b7 
    or a
#b368#496815
78 
    ld a, b
#b369#4969311
ca 64 b4 
    jp z, Lb464_movement_mode_functions
#b36c#496c
    ; Pointer mode:
#b36c#496c311
21 88 7d 
    ld hl, L7d88_action_pointer_viewport_sprite
#b36f#496f28
fe 18 
    cp INPUT_MOVE_POINTER_LEFT
#b371#4971213/8
20 13 
    jr nz, Lb386_no_pointer_move_left
#b373#4973
    ; Move pointer left:
#b373#4973318
cd 14 cd 
    call Lcd14_restore_view_port_background_after_drawing_sprite
#b376#4976314
3a 1a 6b 
    ld a, (L6b1a_pointer_x)
#b379#497928
d6 02 
    sub 2
#b37b#497b15
b7 
    or a  ; OPTIMIZATION: unnecessary, as "sub 2" already does this test
#b37c#497c213/8
28 04 
    jr z, Lb382_hit_left_border
#b37e#497e28
fe ff 
    cp -1
#b380#4980213/8
20 16 
    jr nz, Lb398_assign_pointer_x_position
#b382#4982
Lb382_hit_left_border:
#b382#498228
3e 01 
    ld a, 1
#b384#4984213
18 12 
    jr Lb398_assign_pointer_x_position
#b386#4986
Lb386_no_pointer_move_left:
#b386#498628
fe 17 
    cp INPUT_MOVE_POINTER_RIGHT
#b388#4988213/8
20 16 
    jr nz, Lb386_no_pointer_horizontal_movement
#b38a#498a
    ; Move pointer right:
#b38a#498a318
cd 14 cd 
    call Lcd14_restore_view_port_background_after_drawing_sprite
#b38d#498d314
3a 1a 6b 
    ld a, (L6b1a_pointer_x)
#b390#499028
c6 02 
    add a, 2
#b392#499228
fe c0 
    cp 192
#b394#4994213/8
38 02 
    jr c, Lb398_assign_pointer_x_position
#b396#4996
    ; Reached the right border:
#b396#499628
3e c0 
    ld a, 192
#b398#4998
Lb398_assign_pointer_x_position:
#b398#4998314
32 1a 6b 
    ld (L6b1a_pointer_x), a
#b39b#499b28
d6 04 
    sub 4
#b39d#499d18
77 
    ld (hl), a  ; hl = L7d88_action_pointer_viewport_sprite
#b39e#499e213
18 31 
    jr Lb3d1_pointer_movement_pause
#b3a0#49a0
Lb386_no_pointer_horizontal_movement:
#b3a0#49a028
fe 1a 
    cp INPUT_MOVE_POINTER_UP
#b3a2#49a2213/8
20 10 
    jr nz, Lb3b4_no_pointer_movement_no_pointer_move_up
#b3a4#49a4318
cd 14 cd 
    call Lcd14_restore_view_port_background_after_drawing_sprite
#b3a7#49a7314
3a 1b 6b 
    ld a, (L6b1b_pointer_y)
#b3aa#49aa28
c6 02 
    add a, 2
#b3ac#49ac28
fe 6f 
    cp 111
#b3ae#49ae213/8
38 19 
    jr c, Lb3c9
#b3b0#49b028
3e 6f 
    ld a, 111
#b3b2#49b2213
18 15 
    jr Lb3c9
#b3b4#49b4
Lb3b4_no_pointer_movement_no_pointer_move_up:
#b3b4#49b428
fe 19 
    cp INPUT_MOVE_POINTER_DOWN
#b3b6#49b6213/8
20 27 
    jr nz, Lb3df_no_pointer_movement
#b3b8#49b8318
cd 14 cd 
    call Lcd14_restore_view_port_background_after_drawing_sprite
#b3bb#49bb314
3a 1b 6b 
    ld a, (L6b1b_pointer_y)
#b3be#49be28
d6 02 
    sub 2
#b3c0#49c028
fe ff 
    cp 255
#b3c2#49c2213/8
28 04 
    jr z, Lb3c8
#b3c4#49c428
fe fe 
    cp 254
#b3c6#49c6213/8
20 01 
    jr nz, Lb3c9
#b3c8#49c8
Lb3c8:
#b3c8#49c815
af 
    xor a
#b3c9#49c9
Lb3c9:
#b3c9#49c9314
32 1b 6b 
    ld (L6b1b_pointer_y), a
#b3cc#49cc17
23 
    inc hl  ; hl was L7d88_action_pointer_viewport_sprite
#b3cd#49cd28
d6 04 
    sub 4
#b3cf#49cf18
77 
    ld (hl), a
#b3d0#49d017
2b 
    dec hl
#b3d1#49d1
Lb3d1_pointer_movement_pause:
#b3d1#49d1318
cd 19 cc 
    call Lcc19_draw_viewport_sprite_with_offset
#b3d4#49d4311
21 e8 03 
    ld hl, 1000  ; Wait for a 1000 iterations of the loop below
#b3d7#49d7
Lb3d7_pause_loop:
#b3d7#49d717
2b 
    dec hl
#b3d8#49d815
7c 
    ld a, h
#b3d9#49d915
b5 
    or l
#b3da#49da213/8
20 fb 
    jr nz, Lb3d7_pause_loop
#b3dc#49dc311
c3 36 b5 
    jp Lb536_execute_pressed_key_function_done
#b3df#49df
#b3df#49df
Lb3df_no_pointer_movement:
#b3df#49df28
fe 16 
    cp INPUT_THROW_ROCK
#b3e1#49e1311
c2 64 b4 
    jp nz, Lb464_movement_mode_functions
#b3e4#49e4
    ; Throw a rock at the current pointer position:
#b3e4#49e428
3e 05 
    ld a, SFX_THROW_ROCK_OR_LAND
#b3e6#49e6318
cd ca c4 
    call Lc4ca_play_SFX
#b3e9#49e9
    ; Start the rock at the bottom-center of the screen.
#b3e9#49e928
16 60 
    ld d, SCREEN_WIDTH * 8 / 2
#b3eb#49eb28
1e 00 
    ld e, 0  ; 
#b3ed#49ed311
21 e1 7e 
    ld hl, L7ee0_stone_viewport_sprite_size1 + 1
#b3f0#49f018
73 
    ld (hl), e  ; y
#b3f1#49f117
2b 
    dec hl
#b3f2#49f218
72 
    ld (hl), d  ; x
#b3f3#49f3318
cd 19 cc 
    call Lcc19_draw_viewport_sprite_with_offset
#b3f6#49f6314
3a 1a 6b 
    ld a, (L6b1a_pointer_x)
#b3f9#49f915
47 
    ld b, a
#b3fa#49fa15
92 
    sub d
#b3fb#49fb15
57 
    ld d, a  ; d = (L6b1a_pointer_x) - rock x
#b3fc#49fc314
3a 1b 6b 
    ld a, (L6b1b_pointer_y)
#b3ff#49ff15
4f 
    ld c, a
#b400#4a0015
93 
    sub e
#b401#4a0115
5f 
    ld e, a  ; e = (L6b1a_pointer_y) - rock y
#b402#4a02416
dd 21 f3 b2 
    ld ix, Lb2f3_rock_animation_frames
#b406#4a06311
21 e0 7e 
    ld hl, L7ee0_stone_viewport_sprite_size1
#b409#4a0928
3e 03 
    ld a, 3
#b40b#4a0b
Lb40b_throw_rock_animation_loop:
#b40b#4a0b112
f5 
    push af
#b40c#4a0c28
3e 02 
        ld a, 2
#b40e#4a0e314
32 a5 74 
        ld (L74a5_interrupt_timer), a
#b411#4a11
Lb411_wait_loop:  ; OPTIMIZATION: this "wait for interrupt" occurs so many times in the code, that a small function would save a lot of bytes.
#b411#4a11314
3a a5 74 
        ld a, (L74a5_interrupt_timer)
#b414#4a1415
b7 
        or a
#b415#4a15213/8
20 fa 
        jr nz, Lb411_wait_loop
#b417#4a17
        ; Remove the stone gfx 
#b417#4a17318
cd 14 cd 
        call Lcd14_restore_view_port_background_after_drawing_sprite
#b41a#4a1a210
cb 2a 
        sra d  ; x: Amount we want to move the rock to (1/2 the remaining distance to the player pointer)
#b41c#4a1c210
cb 2b 
        sra e  ; y
#b41e#4a1e321
dd 66 01 
        ld h, (ix + 1)  ; get the pointer to the next rock sprite (it gets smaller at each frame)
#b421#4a21321
dd 6e 00 
        ld l, (ix)
#b424#4a24212
dd 23 
        inc ix
#b426#4a26212
dd 23 
        inc ix
#b428#4a2815
79 
        ld a, c
#b429#4a2915
93 
        sub e
#b42a#4a2a18
77 
        ld (hl), a  ; Set new "y" coordinate
#b42b#4a2b111
f1 
    pop af
#b42c#4a2c112
f5 
    push af
#b42d#4a2d15
3d 
        dec a
#b42e#4a2e18
96 
        sub (hl)
#b42f#4a2f210
ed 44 
        neg
#b431#4a3118
77 
        ld (hl), a  ; Correct the "y" coordinate since each animation frame is smaller than the previous
#b432#4a3217
2b 
        dec hl
#b433#4a3315
78 
        ld a, b
#b434#4a3415
92 
        sub d
#b435#4a3518
77 
        ld (hl), a  ; Set the new "x" coordinate
#b436#4a36111
f1 
    pop af
#b437#4a37112
f5 
    push af
#b438#4a3815
3d 
        dec a
#b439#4a3918
96 
        sub (hl)
#b43a#4a3a210
ed 44 
        neg
#b43c#4a3c18
77 
        ld (hl), a  ; Correct the "x" coordinate since each animation frame is smaller than the previous
#b43d#4a3d318
cd 19 cc 
        call Lcc19_draw_viewport_sprite_with_offset
#b440#4a40111
f1 
    pop af
#b441#4a4115
3d 
    dec a
#b442#4a42213/8
20 c7 
    jr nz, Lb40b_throw_rock_animation_loop
#b444#4a44318
cd 14 cd 
    call Lcd14_restore_view_port_background_after_drawing_sprite
#b447#4a47318
cd 07 b6 
    call Lb607_find_object_under_pointer
#b44a#4a4a28
3e 04 
    ld a, 4  ; value to set to L747f_player_event
#b44c#4a4c311
21 e2 6a 
    ld hl, L6adf_game_boolean_variables + 3
#b44f#4a4f214
cb 6e 
    bit 5, (hl)
#b451#4a51213/8
28 0e 
    jr z, Lb461
#b453#4a5315
6f 
    ld l, a  ; l = 4
#b454#4a54314
3a cf 6a 
    ld a, (L6acf_current_area_id)
#b457#4a5728
fe 15 
    cp 21  ; "THE TUBE" area
#b459#4a59213/8
28 05 
    jr z, Lb460
#b45b#4a5b28
fe 10 
    cp 16  ; "LIFT SHAFT" area
#b45d#4a5d213/8
28 01 
    jr z, Lb460
#b45f#4a5f15
2c 
    inc l  ; l = 5 (value to set to L747f_player_event)
#b460#4a60
Lb460:
#b460#4a6015
7d 
    ld a, l
#b461#4a61
Lb461:
#b461#4a61311
c3 33 b5 
    jp Lb533_done_setting_L747f_player_event_to_a
#b464#4a64
#b464#4a64
Lb464_movement_mode_functions:
#b464#4a64
    ; Movement mode:
#b464#4a6428
fe 1b 
    cp INPUT_ACTION
#b466#4a66311
c2 36 b5 
    jp nz, Lb536_execute_pressed_key_function_done
#b469#4a69318
cd 07 b6 
    call Lb607_find_object_under_pointer
#b46c#4a6c314
3a 80 74 
    ld a, (L7480_under_pointer_object_ID)
#b46f#4a6f15
b7 
    or a
#b470#4a70311
ca 36 b5 
    jp z, Lb536_execute_pressed_key_function_done
#b473#4a73
    ; Player requested to interact with an object:
#b473#4a73314
32 68 74 
    ld (L7468_focus_object_id), a
#b476#4a7615
af 
    xor a  ; area ID = check current area
#b477#4a77318
cd 86 b2 
    call Lb286_find_object_by_id  ; look for the object in (L7468_focus_object_id)
#b47a#4a7a15
b7 
    or a
#b47b#4a7b311
c2 36 b5 
    jp nz, Lb536_execute_pressed_key_function_done
#b47e#4a7e
    ; object found (pointer in "ix")
#b47e#4a7e416
fd 21 ad 6a 
    ld iy, L6aad_player_current_x
#b482#4a8215
47 
    ld b, a
#b483#4a8315
4f 
    ld c, a  ; bc = 0 (accumulates manhattan distance to object center)
#b484#4a8428
16 03 
    ld d, 3
#b486#4a86
    ; 3 iterations, one for "x", onr for "y", one for "z":
#b486#4a86
Lb486_coordinate_loop:
#b486#4a86314
3a bc 6a 
    ld a, (L6abc_current_room_scale)
#b489#4a8915
67 
    ld h, a
#b48a#4a8a15
87 
    add a, a
#b48b#4a8b15
87 
    add a, a
#b48c#4a8c15
84 
    add a, h  ; a = room scale * 5
#b48d#4a8d321
dd 6e 04 
    ld l, (ix + OBJECT_SIZE_X)
#b490#4a9015
bd 
    cp l
#b491#4a91311
da 36 b5 
    jp c, Lb536_execute_pressed_key_function_done
#b494#4a94
    ; Only interact with objects of size room scale * 5 or less
#b494#4a94
    ; Note: why?! Maybe a shortcut since all large objects are not interact-able?
#b494#4a94
    ; room scale * 8 >= object size x
#b494#4a94112
d5 
    push de
#b495#4a9528
26 00 
        ld h, 0
#b497#4a9715
54 
        ld d, h
#b498#4a98112
29 
        add hl, hl
#b499#4a99112
29 
        add hl, hl
#b49a#4a9a112
29 
        add hl, hl
#b49b#4a9b112
29 
        add hl, hl
#b49c#4a9c112
29 
        add hl, hl
#b49d#4a9d15
eb 
        ex de, hl  ; de = object size * 32 (half width of object)
#b49e#4a9e321
dd 6e 01 
        ld l, (ix + OBJECT_X)
#b4a1#4aa1112
29 
        add hl, hl
#b4a2#4aa2112
29 
        add hl, hl
#b4a3#4aa3112
29 
        add hl, hl
#b4a4#4aa4112
29 
        add hl, hl
#b4a5#4aa5112
29 
        add hl, hl
#b4a6#4aa6112
29 
        add hl, hl
#b4a7#4aa7112
19 
        add hl, de  ; hl = object position * 64 + object size * 32  (object center)
#b4a8#4aa8321
fd 5e 00 
        ld e, (iy)
#b4ab#4aab321
fd 56 01 
        ld d, (iy + 1)  ; de = player position
#b4ae#4aae15
b7 
        or a
#b4af#4aaf217
ed 52 
        sbc hl, de  ; hl = (object position * 64 + object size * 32) - player position
#b4b1#4ab1311
f2 bb b4 
        jp p, Lb4bb
#b4b4#4ab4
        ; if negative, get absolute value of distance:
#b4b4#4ab415
7c 
        ld a, h
#b4b5#4ab515
2f 
        cpl
#b4b6#4ab615
67 
        ld h, a
#b4b7#4ab715
7d 
        ld a, l
#b4b8#4ab815
2f 
        cpl
#b4b9#4ab915
6f 
        ld l, a
#b4ba#4aba17
23 
        inc hl
#b4bb#4abb
Lb4bb:
#b4bb#4abb112
09 
        add hl, bc
#b4bc#4abc15
44 
        ld b, h
#b4bd#4abd15
4d 
        ld c, l  ; add the distance to the object in the accumulator "bc"
#b4be#4abe212
dd 23 
        inc ix
#b4c0#4ac0212
fd 23 
        inc iy
#b4c2#4ac2212
fd 23 
        inc iy
#b4c4#4ac4111
d1 
    pop de
#b4c5#4ac515
15 
    dec d
#b4c6#4ac6213/8
20 be 
    jr nz, Lb486_coordinate_loop
#b4c8#4ac815
60 
    ld h, b
#b4c9#4ac915
69 
    ld l, c
#b4ca#4aca314
3a bc 6a 
    ld a, (L6abc_current_room_scale)
#b4cd#4acd28
fe 02 
    cp 2
#b4cf#4acf213/8
38 06 
    jr c, Lb4d7
#b4d1#4ad115
5f 
    ld e, a
#b4d2#4ad215
af 
    xor a
#b4d3#4ad315
57 
    ld d, a
#b4d4#4ad4
    ; (a, hl) = distance
#b4d4#4ad4
    ; de = room scale
#b4d4#4ad4318
cd cc a1 
    call La1cc_a_hl_divided_by_de_signed  ; (a, hl) = distance normalized by room scale
#b4d7#4ad7
Lb4d7:
#b4d7#4ad7311
11 2c 01 
    ld de, 300
#b4da#4ada15
af 
    xor a
#b4db#4adb217
ed 52 
    sbc hl, de  ; hl = normalized distance - 300
#b4dd#4add311
21 29 6d 
    ld hl, L6d29_text_out_of_reach
#b4e0#4ae0311
f2 18 b5 
    jp p, Lb518_display_message
#b4e3#4ae315
47 
    ld b, a
#b4e4#4ae4311
11 fd ff 
    ld de, -3
#b4e7#4ae7217
dd 19 
    add ix, de  ; undo the offsetting the loop above had done to ix
#b4e9#4ae9321
dd 7e 00 
    ld a, (ix + OBJECT_TYPE_AND_FLAGS)
#b4ec#4aec28
e6 0f 
    and #0f
#b4ee#4aee15
4f 
    ld c, a  ; c = object type
#b4ef#4aef311
21 2c 6b 
    ld hl, L6b2c_expected_object_size_by_type
#b4f2#4af2112
09 
    add hl, bc
#b4f3#4af318
4e 
    ld c, (hl)
#b4f4#4af4321
dd 7e 08 
    ld a, (ix + OBJECT_SIZE)
#b4f7#4af715
91 
    sub c
#b4f8#4af8213/8
28 1b 
    jr z, Lb515_no_effect
#b4fa#4afa15
3d 
    dec a
#b4fb#4afb
#b4fb#4afb
    ; This loop iterates over the rules stored in the object, and if any
#b4fb#4afb
    ; is ready to fire, it terminates, setting a 2 in L747f_player_event.
#b4fb#4afb
Lb4fb_rule_loop:
#b4fb#4afb217
dd 09 
    add ix, bc  ; ix = pointer to the rule data.
#b4fd#4afd15
57 
    ld d, a  ; left over size - 1
#b4fe#4afe321
dd 7e 00 
    ld a, (ix)  ; rule type and flags
#b501#4b0115
4f 
    ld c, a
#b502#4b0228
e6 c0 
    and #c0  ; keep flags
#b504#4b0428
fe c0 
    cp #c0  ; if it is ready to fire
#b506#4b06213/8
28 29 
    jr z, Lb531_done_setting_L747f_player_event_to_2
#b508#4b08
    ; Ignore rule, move to the next
#b508#4b0815
79 
    ld a, c
#b509#4b0928
e6 3f 
    and #3f
#b50b#4b0b15
4f 
    ld c, a
#b50c#4b0c311
21 3c 6b 
    ld hl, L6b3c_rule_size_by_type
#b50f#4b0f112
09 
    add hl, bc
#b510#4b1018
4e 
    ld c, (hl)
#b511#4b1115
7a 
    ld a, d
#b512#4b1215
91 
    sub c
#b513#4b13213/8
30 e6 
    jr nc, Lb4fb_rule_loop
#b515#4b15
#b515#4b15
    ; We exhausted all the rules, no effect:
#b515#4b15
Lb515_no_effect:
#b515#4b15311
21 39 6d 
    ld hl, L6d39_text_no_effect
#b518#4b18
Lb518_display_message:
#b518#4b1828
3e 2a 
    ld a, 42
#b51a#4b1a314
32 a5 74 
    ld (L74a5_interrupt_timer), a
#b51d#4b1d416
dd 21 5a 73 
    ld ix, L735a_ui_message_row_pointers
#b521#4b21311
11 00 0f 
    ld de, #0f00
#b524#4b24318
cd 1c d0 
    call Ld01c_draw_string
#b527#4b27314
3a 6d 74 
    ld a, (L746c_game_flags + 1)
#b52a#4b2a28
f6 20 
    or #20
#b52c#4b2c314
32 6d 74 
    ld (L746c_game_flags + 1), a
#b52f#4b2f213
18 05 
    jr Lb536_execute_pressed_key_function_done
#b531#4b31
Lb531_done_setting_L747f_player_event_to_2:
#b531#4b3128
3e 02 
    ld a, 2
#b533#4b33
Lb533_done_setting_L747f_player_event_to_a:
#b533#4b33314
32 7f 74 
    ld (L747f_player_event), a
#b536#4b36
Lb536_execute_pressed_key_function_done:
#b536#4b36111
c9 
    ret
#b537#4b37
#b537#4b37
#b537#4b37
; --------------------------------
#b537#4b37
; Draws the center movement pointer in the screen, and then redraws the whole viewport.
#b537#4b37
; It adds a small delay, to allow for the SFX of toggling movement to pointer.
#b537#4b37
Lb537_redraw_with_center_pointer:
#b537#4b37112
e5 
    push hl
#b538#4b3828
3e 09 
        ld a, 9
#b53a#4b3a314
32 a5 74 
        ld (L74a5_interrupt_timer), a
#b53d#4b3d318
cd 8c cd 
        call Lcd8c_draw_movement_center_pointer
#b540#4b40318
cd 46 9d 
        call L9d46_render_3d_view
#b543#4b43318
cd 98 a2 
        call La298_render_buffer_render
#b546#4b46111
e1 
    pop hl
#b547#4b47111
c9 
    ret
#b548#4b48
#b548#4b48
#b548#4b48
; --------------------------------
#b548#4b48
; If we are in pointer mode, draw the pointer, otherwise, do nothing.
#b548#4b48
Lb548_draw_pointer_if_pointer_mode:
#b548#4b48112
e5 
    push hl
#b549#4b49112
f5 
    push af
#b54a#4b4a314
3a 1c 6b 
        ld a, (L6b1c_movement_or_pointer)
#b54d#4b4d15
b7 
        or a
#b54e#4b4e213/8
28 14 
        jr z, Lb564_movement
#b550#4b50311
21 88 7d 
        ld hl, L7d88_action_pointer_viewport_sprite
#b553#4b53314
3a 1a 6b 
        ld a, (L6b1a_pointer_x)
#b556#4b5628
d6 06 
        sub 6
#b558#4b5818
77 
        ld (hl), a
#b559#4b5917
23 
        inc hl
#b55a#4b5a314
3a 1b 6b 
        ld a, (L6b1b_pointer_y)
#b55d#4b5d28
d6 06 
        sub 6
#b55f#4b5f18
77 
        ld (hl), a
#b560#4b6017
2b 
        dec hl
#b561#4b61318
cd 19 cc 
        call Lcc19_draw_viewport_sprite_with_offset
#b564#4b64
Lb564_movement:
#b564#4b64111
f1 
    pop af
#b565#4b65111
e1 
    pop hl
#b566#4b66111
c9 
    ret
#b567#4b67
#b567#4b67
#b567#4b67
; --------------------------------
#b567#4b67
; Determines the order in which the pixels are drawn during the fade-in effect.
#b567#4b67
Lb567_fade_in_current_pixel_ordering:
#b567#4b672
    dw Lb569_fade_in_pixel_orderingss
#b569#4b69
Lb569_fade_in_pixel_orderingss:
#b569#4b694
    db 0, 2, 1, 3
#b56d#4b6d4
    db 1, 3, 0, 2
#b571#4b714
    db 3, 1, 2, 0
#b575#4b754
    db 2, 0, 3, 1
#b579#4b79
#b579#4b79
#b579#4b79
; --------------------------------
#b579#4b79
; Draws the render buffer to the video memory with a fade-in effect.
#b579#4b79
Lb579_render_buffer_fade_in:
#b579#4b79217
dd e5 
    push ix
#b57b#4b7b217
fd e5 
    push iy
#b57d#4b7d112
e5 
    push hl
#b57e#4b7e112
d5 
    push de
#b57f#4b7f112
c5 
    push bc
#b580#4b80112
f5 
    push af
#b581#4b8128
3e 04 
        ld a, 4  ; The fade-in has 4 steps (at each step 1/4th of the pixels are drawn).
#b583#4b83
Lb583_fade_in_loop:
#b583#4b83112
f5 
        push af
#b584#4b8415
3d 
            dec a
#b585#4b85210
cb 27 
            sla a
#b587#4b87210
cb 27 
            sla a
#b589#4b8915
4f 
            ld c, a
#b58a#4b8a28
06 00 
            ld b, 0  ; bc = (a - 1) * 4
#b58c#4b8c311
21 69 b5 
            ld hl, Lb569_fade_in_pixel_orderingss
#b58f#4b8f112
09 
            add hl, bc
#b590#4b90317
22 67 b5 
            ld (Lb567_fade_in_current_pixel_ordering), hl
#b593#4b93416
dd 21 5c 72 
            ld ix, L725c_videomem_row_pointers
#b597#4b9728
3e 70 
            ld a, SCREEN_HEIGHT * 8
#b599#4b99112
f5 
            push af
#b59a#4b9a311
21 bc 5c 
                ld hl, L5cbc_render_buffer
#b59d#4b9d422
fd 2a 67 b5 
                ld iy, (Lb567_fade_in_current_pixel_ordering)
#b5a1#4ba128
e6 03 
                and 3
#b5a3#4ba3213/8
28 04 
                jr z, Lb5a9
#b5a5#4ba5
                ; a = 4 - a
#b5a5#4ba528
d6 04 
                sub 4
#b5a7#4ba7210
ed 44 
                neg
#b5a9#4ba9
Lb5a9:
#b5a9#4ba915
4f 
                ld c, a
#b5aa#4baa217
fd 09 
                add iy, bc
#b5ac#4bac
Lb5ac_row_loop:
#b5ac#4bac112
e5 
                push hl
#b5ad#4bad321
dd 5e 00 
                    ld e, (ix)
#b5b0#4bb0321
dd 56 01 
                    ld d, (ix + 1)  ; de = video memory pointer where to draw this row
#b5b3#4bb3
                    ; We will copy pixels from "hl" (render buffer) to "de" (video memory)
#b5b3#4bb3212
dd 23 
                    inc ix
#b5b5#4bb5212
dd 23 
                    inc ix  ; next pointer
#b5b7#4bb7321
fd 4e 00 
                    ld c, (iy)
#b5ba#4bba28
06 00 
                    ld b, 0
#b5bc#4bbc112
09 
                    add hl, bc
#b5bd#4bbd15
eb 
                    ex de, hl
#b5be#4bbe112
09 
                        add hl, bc
#b5bf#4bbf15
eb 
                    ex de, hl
#b5c0#4bc028
06 06 
                    ld b, SCREEN_WIDTH / 4
#b5c2#4bc228
3e 00 
                    ld a, 0
#b5c4#4bc4321
fd be 00 
                    cp (iy)
#b5c7#4bc7213/8
28 04 
                    jr z, Lb5cd_column_loop
#b5c9#4bc9311
fa cd b5 
                    jp m, Lb5cd_column_loop
#b5cc#4bcc15
04 
                    inc b  ; In this corner case, we need to draw 7 bytes, instead of 6
#b5cd#4bcd
Lb5cd_column_loop:
#b5cd#4bcd
                    ; copy one out of each 4 bytes:
#b5cd#4bcd18
7e 
                    ld a, (hl)
#b5ce#4bce18
12 
                    ld (de), a
#b5cf#4bcf17
23 
                    inc hl
#b5d0#4bd017
23 
                    inc hl
#b5d1#4bd117
23 
                    inc hl
#b5d2#4bd217
23 
                    inc hl
#b5d3#4bd317
13 
                    inc de
#b5d4#4bd417
13 
                    inc de
#b5d5#4bd517
13 
                    inc de
#b5d6#4bd617
13 
                    inc de
#b5d7#4bd7214/9
10 f4 
                    djnz Lb5cd_column_loop
#b5d9#4bd9311
01 18 00 
                    ld bc, SCREEN_WIDTH
#b5dc#4bdc111
e1 
                pop hl
#b5dd#4bdd112
09 
                add hl, bc
#b5de#4bde111
f1 
            pop af
#b5df#4bdf15
3d 
            dec a
#b5e0#4be0213/8
28 0d 
            jr z, Lb5ef_fade_in_step_done
#b5e2#4be2112
f5 
            push af
#b5e3#4be3212
fd 23 
                inc iy
#b5e5#4be528
e6 03 
                and 3
#b5e7#4be7213/8
20 c3 
                jr nz, Lb5ac_row_loop
#b5e9#4be9
                ; Every four loops, reset iy to Lb569_fade_in_pixel_orderingss
#b5e9#4be9422
fd 2a 67 b5 
                ld iy, (Lb567_fade_in_current_pixel_ordering)
#b5ed#4bed213
18 bd 
                jr Lb5ac_row_loop
#b5ef#4bef
Lb5ef_fade_in_step_done:
#b5ef#4bef111
f1 
        pop af
#b5f0#4bf015
3d 
        dec a
#b5f1#4bf1213/8
20 90 
        jr nz, Lb583_fade_in_loop
#b5f3#4bf3314
3a 7a 74 
        ld a, (L747a_requested_SFX)
#b5f6#4bf615
b7 
        or a
#b5f7#4bf7318/11
c4 ca c4 
        call nz, Lc4ca_play_SFX
#b5fa#4bfa15
af 
        xor a
#b5fb#4bfb314
32 7a 74 
        ld (L747a_requested_SFX), a
#b5fe#4bfe111
f1 
    pop af
#b5ff#4bff111
c1 
    pop bc
#b600#4c00111
d1 
    pop de
#b601#4c01111
e1 
    pop hl
#b602#4c02216
fd e1 
    pop iy
#b604#4c04216
dd e1 
    pop ix
#b606#4c06111
c9 
    ret
#b607#4c07
#b607#4c07
#b607#4c07
; --------------------------------
#b607#4c07
; Finds the object that is direcly under the player pointer,
#b607#4c07
; and stores its ID in (L7480_under_pointer_object_ID).
#b607#4c07
; Output:
#b607#4c07
; - (L7480_under_pointer_object_ID): ID of the object clicked. Since this is reset each game loop,
#b607#4c07
;   the method assumes it is 0 at start.
#b607#4c07
Lb607_find_object_under_pointer:
#b607#4c07217
dd e5 
    push ix
#b609#4c09217
fd e5 
    push iy
#b60b#4c0b112
e5 
    push hl
#b60c#4c0c112
d5 
    push de
#b60d#4c0d112
c5 
    push bc
#b60e#4c0e112
f5 
    push af
#b60f#4c0f416
fd 21 54 67 
        ld iy, L6754_current_room_object_projected_data
#b613#4c13314
3a 6b 74 
        ld a, (L746b_n_objects_to_draw)
#b616#4c1615
b7 
        or a
#b617#4c17311
ca ca b7 
        jp z, Lb7ca_return
#b61a#4c1a
        ; Since objects are drawn first to last, when checking what is under the 
#b61a#4c1a
        ; player pointer, we should check starting from the last object (the one drawn
#b61a#4c1a
        ; on top). Hence, we get the pointer to the last object first:
#b61a#4c1a15
47 
        ld b, a  ; number of objects in screen
#b61b#4c1b15
6f 
        ld l, a
#b61c#4c1c15
2d 
        dec l
#b61d#4c1d28
26 00 
        ld h, 0
#b61f#4c1f112
29 
        add hl, hl
#b620#4c20112
29 
        add hl, hl
#b621#4c2115
eb 
        ex de, hl
#b622#4c22217
fd 19 
        add iy, de  ; iy = pointer to the last object projected in screen
#b624#4c24
Lb624_object_loop:
#b624#4c24112
c5 
        push bc
#b625#4c25321
fd 6e 00 
            ld l, (iy)
#b628#4c28321
fd 66 01 
            ld h, (iy + 1)  ; Pointer to the projected vertex data
#b62b#4c2b18
4e 
            ld c, (hl)  ; object ID
#b62c#4c2c17
23 
            inc hl
#b62d#4c2d18
7e 
            ld a, (hl)  ; number of faces
#b62e#4c2e15
b7 
            or a
#b62f#4c2f311
ca c0 b7 
            jp z, Lb7c0_next_object
#b632#4c32
#b632#4c32210
cb 7f 
            bit 7, a  ; Check if the object covers the whole screen
#b634#4c34311
c2 b4 b7 
            jp nz, Lb7b4_object_under_pointer_found
#b637#4c3715
47 
            ld b, a  ; b = number of faces
#b638#4c3817
23 
            inc hl
#b639#4c39112
e5 
            push hl
#b63a#4c3a216
dd e1 
            pop ix  ; ix = pointer fo face data
#b63c#4c3c
Lb63c_face_loop:
#b63c#4c3c112
c5 
            push bc
#b63d#4c3d422
dd 22 fa 74 
                ld (L74fa_object_under_pointer__current_face), ix  ; save the pointer to the face data
#b641#4c41321
dd 7e 00 
                ld a, (ix)
#b644#4c44212
dd 23 
                inc ix
#b646#4c4628
e6 0f 
                and #0f
#b648#4c4815
6f 
                ld l, a  ; l = number of vertices in this face
#b649#4c4928
16 00 
                ld d, 0
#b64b#4c4b15
42 
                ld b, d
#b64c#4c4c314
3a 1a 6b 
                ld a, (L6b1a_pointer_x)
#b64f#4c4f15
5f 
                ld e, a
#b650#4c50314
3a 1b 6b 
                ld a, (L6b1b_pointer_y)
#b653#4c5315
4f 
                ld c, a
#b654#4c5415
af 
                xor a
#b655#4c55
                ; This check if the pointer (x, y) are inside of the bounding
#b655#4c55
                ; box defined by the points of the face.
#b655#4c55
Lb655_face_vertex_loop:
#b655#4c55112
e5 
                push hl
#b656#4c56
                    ; At this point:
#b656#4c56
                    ; - a: accumulates the checks being done
#b656#4c56
                    ; - de: pointer x
#b656#4c56
                    ; - bc: pointer y 
#b656#4c56321
dd 6e 00 
                    ld l, (ix)  ; vertex screen x
#b659#4c5928
26 00 
                    ld h, 0
#b65b#4c5b15
b7 
                    or a
#b65c#4c5c217
ed 52 
                    sbc hl, de  ; vertex x - pointer x
#b65e#4c5e213/8
28 0b 
                    jr z, Lb66b_x_match
#b660#4c60311
f2 67 b6 
                    jp p, Lb667
#b663#4c63
                    ; pointer to the left:
#b663#4c6328
f6 01 
                    or #01
#b665#4c65213
18 06 
                    jr Lb66d_y_check
#b667#4c67
Lb667:
#b667#4c67
                    ; pointer to the right:
#b667#4c6728
f6 02 
                    or #02
#b669#4c69213
18 02 
                    jr Lb66d_y_check
#b66b#4c6b
Lb66b_x_match:
#b66b#4c6b28
f6 04 
                    or #04
#b66d#4c6d
Lb66d_y_check:
#b66d#4c6d321
dd 6e 01 
                    ld l, (ix + 1)  ; vertex screen y
#b670#4c7028
26 00 
                    ld h, 0
#b672#4c7215
b7 
                    or a
#b673#4c73217
ed 42 
                    sbc hl, bc  ; vertex y - pointer y
#b675#4c75213/8
28 0b 
                    jr z, Lb682_y_match
#b677#4c77311
f2 7e b6 
                    jp p, Lb67e
#b67a#4c7a28
f6 08 
                    or #08
#b67c#4c7c213
18 06 
                    jr Lb684
#b67e#4c7e
Lb67e:
#b67e#4c7e28
f6 10 
                    or #10
#b680#4c80213
18 02 
                    jr Lb684
#b682#4c82
Lb682_y_match:
#b682#4c8228
f6 20 
                    or #20
#b684#4c84
Lb684:
#b684#4c84212
dd 23 
                    inc ix  ; next vertex:
#b686#4c86212
dd 23 
                    inc ix
#b688#4c88111
e1 
                pop hl
#b689#4c8915
2d 
                dec l
#b68a#4c8a213/8
20 c9 
                jr nz, Lb655_face_vertex_loop
#b68c#4c8c
                ; If the pointer was to the left of some and to the right of some points,
#b68c#4c8c
                ; and above of some and below some, that means it's inside the bounding box.
#b68c#4c8c210
cb 6f 
                bit 5, a
#b68e#4c8e213/8
20 0a 
                jr nz, Lb69a_check_y  ; if same x coordinate than a point, match for sure
#b690#4c90210
cb 67 
                bit 4, a
#b692#4c92311
ca bb b7 
                jp z, Lb7bb_next_face
#b695#4c95210
cb 5f 
                bit 3, a
#b697#4c97311
ca bb b7 
                jp z, Lb7bb_next_face
#b69a#4c9a
                ; Left of some and right of some:
#b69a#4c9a
Lb69a_check_y:
#b69a#4c9a210
cb 57 
                bit 2, a
#b69c#4c9c213/8
20 0a 
                jr nz, Lb6a8_pointer_inside_face_bounding_box  ; if same y coordiante than a point, match for sure
#b69e#4c9e210
cb 4f 
                bit 1, a
#b6a0#4ca0311
ca bb b7 
                jp z, Lb7bb_next_face
#b6a3#4ca3210
cb 47 
                bit 0, a
#b6a5#4ca5311
ca bb b7 
                jp z, Lb7bb_next_face
#b6a8#4ca8
#b6a8#4ca8
Lb6a8_pointer_inside_face_bounding_box:
#b6a8#4ca8
                ; Checks have succeeded, and we are within the bounding box of the
#b6a8#4ca8
                ; projected face!
#b6a8#4ca8
                ; Make a copy of the vertices of the current face:
#b6a8#4ca8317
2a fa 74 
                ld hl, (L74fa_object_under_pointer__current_face)
#b6ab#4cab18
7e 
                ld a, (hl)
#b6ac#4cac28
e6 0f 
                and #0f  ; a = number of vertices in this face
#b6ae#4cae17
23 
                inc hl
#b6af#4caf311
11 82 74 
                ld de, L7482_object_under_pointer__current_face_vertices
#b6b2#4cb215
4f 
                ld c, a
#b6b3#4cb3210
cb 21 
                sla c
#b6b5#4cb528
06 00 
                ld b, 0
#b6b7#4cb7223/18
ed b0 
                ldir
#b6b9#4cb9
#b6b9#4cb9
                ; Check if the face is just a line (2 vertexes):
#b6b9#4cb928
fe 02 
                cp 2
#b6bb#4cbb15
47 
                ld b, a
#b6bc#4cbc213/8
20 03 
                jr nz, Lb6c1_duplicate_first_vertex
#b6be#4cbe15
05 
                dec b
#b6bf#4cbf213
18 0a 
                jr Lb6cb_vertex_copy_finished
#b6c1#4cc1
Lb6c1_duplicate_first_vertex:
#b6c1#4cc1
                ; We copy over the first vertex at the end of the face. So, we have "number of sedges + 1" vertices.
#b6c1#4cc1317
2a fa 74 
                ld hl, (L74fa_object_under_pointer__current_face)
#b6c4#4cc417
23 
                inc hl
#b6c5#4cc518
7e 
                ld a, (hl)
#b6c6#4cc618
12 
                ld (de), a
#b6c7#4cc717
23 
                inc hl
#b6c8#4cc817
13 
                inc de
#b6c9#4cc918
7e 
                ld a, (hl)
#b6ca#4cca18
12 
                ld (de), a
#b6cb#4ccb
Lb6cb_vertex_copy_finished:
#b6cb#4ccb
                ; At this point:
#b6cb#4ccb
                ; b = number of edges in the face (b == 1 for lines).
#b6cb#4ccb
                ; iy = pointer to the object we are chacking
#b6cb#4ccb217
fd e5 
                push iy
#b6cd#4ccd416
fd 21 82 74 
                    ld iy, L7482_object_under_pointer__current_face_vertices
#b6d1#4cd115
af 
                    xor a
#b6d2#4cd2314
32 fc 74 
                    ld (L74fc_object_under_pointer__projected_xs_at_pointer_y), a
#b6d5#4cd5
Lb6d5_face_edge_loop:
#b6d5#4cd5112
c5 
                    push bc
#b6d6#4cd6314
3a 1b 6b 
                        ld a, (L6b1b_pointer_y)
#b6d9#4cd915
5f 
                        ld e, a
#b6da#4cda28
16 00 
                        ld d, 0  ; de = pointer y
#b6dc#4cdc321
fd 6e 01 
                        ld l, (iy + 1)
#b6df#4cdf15
62 
                        ld h, d  ; hl = vertex y
#b6e0#4ce0
#b6e0#4ce015
af 
                        xor a
#b6e1#4ce1217
ed 52 
                        sbc hl, de
#b6e3#4ce3213/8
28 1f 
                        jr z, Lb704_y_match
#b6e5#4ce5311
f2 ec b6 
                        jp p, Lb6ec_vertex_higher_than_pointer
#b6e8#4ce828
f6 01 
                        or 1  ; vertex 1 lower than pointer
#b6ea#4cea213
18 02 
                        jr Lb6ee
#b6ec#4cec
Lb6ec_vertex_higher_than_pointer:
#b6ec#4cec28
f6 02 
                        or 2  ; vertex 1 higher than pointer
#b6ee#4cee
Lb6ee:
#b6ee#4cee321
fd 6e 03 
                        ld l, (iy + 3)
#b6f1#4cf115
62 
                        ld h, d  ; hl = next vertex y
#b6f2#4cf215
b7 
                        or a
#b6f3#4cf3217
ed 52 
                        sbc hl, de
#b6f5#4cf5213/8
28 0d 
                        jr z, Lb704_y_match
#b6f7#4cf7311
f2 fe b6 
                        jp p, Lb6fe
#b6fa#4cfa28
f6 01 
                        or 1  ; vertex 2 lower than pointer
#b6fc#4cfc213
18 02 
                        jr Lb700
#b6fe#4cfe
Lb6fe:
#b6fe#4cfe28
f6 02 
                        or 2  ; vertex 2 higher than pointer
#b700#4d00
Lb700:
#b700#4d0028
fe 03 
                        cp 3  ; if a == 3, pointer y is in between the two vertices y coordinates.
#b702#4d02213/8
20 78 
                        jr nz, Lb77c_next_edge
#b704#4d04
Lb704_y_match:
#b704#4d04321
fd 7e 01 
                        ld a, (iy + 1)  ; vertex y
#b707#4d07321
fd be 03 
                        cp (iy + 3)  ; next vertex y
#b70a#4d0a311
c2 13 b7 
                        jp nz, Lb713_pointer_within_vertical_span_of_segment
#b70d#4d0d
                        ; horizontal segment.
#b70d#4d0d
                        ; BUG? This determines collision too fast, as we have only checked "y",
#b70d#4d0d
                        ; but "x" has not been checked. It could be a horizontal segment that
#b70d#4d0d
                        ; does not intersect with the player pointer!
#b70d#4d0d
                        ; I think the problem is that hirizontal segments imply infinite slope
#b70d#4d0d
                        ; in the code below, and the programmers did not want to add another
#b70d#4d0d
                        ; special case to handle this. So, they added this shortcut, which might
#b70d#4d0d
                        ; some times fail.
#b70d#4d0d111
c1 
                    pop bc
#b70e#4d0e216
fd e1 
                pop iy
#b710#4d10311
c3 b3 b7 
                jp Lb7b3_object_under_pointer_found_pop
#b713#4d13
#b713#4d13
Lb713_pointer_within_vertical_span_of_segment:
#b713#4d13
                        ; At this point, we know that the pointer "y" is within the "y" coordinages of the
#b713#4d13
                        ; two vertices defining this segment:
#b713#4d13321
fd 7e 00 
                        ld a, (iy)
#b716#4d16321
fd be 02 
                        cp (iy + 2)
#b719#4d19213/8
28 4d 
                        jr z, Lb768  ; if it's a vertical segment
#b71b#4d1b321
fd 6e 02 
                        ld l, (iy + 2)
#b71e#4d1e28
26 00 
                        ld h, 0  ; hl = next vertex x
#b720#4d2015
5f 
                        ld e, a
#b721#4d2115
54 
                        ld d, h  ; de = vertex x
#b722#4d2215
b7 
                        or a
#b723#4d23217
ed 52 
                        sbc hl, de
#b725#4d2515
eb 
                        ex de, hl  ; de = next vertex x - vertex x
#b726#4d26321
fd 6e 03 
                        ld l, (iy + 3)
#b729#4d2928
26 00 
                        ld h, 0  ; hl = next vertex y
#b72b#4d2b321
fd 4e 01 
                        ld c, (iy + 1)
#b72e#4d2e15
44 
                        ld b, h  ; bc = vertex y
#b72f#4d2f15
b7 
                        or a
#b730#4d30217
ed 42 
                        sbc hl, bc  ; hl = next vertex y - vertex y
#b732#4d3215
7c 
                        ld a, h
#b733#4d3315
65 
                        ld h, l
#b734#4d3415
68 
                        ld l, b  ; 0
#b735#4d35210
cb 2f 
                        sra a
#b737#4d37210
cb 1c 
                        rr h
#b739#4d39210
cb 1d 
                        rr l  ; (a, hl) = 128 * (next vertex y - vertex y)
#b73b#4d3b
                        ; compute the edge slope (times 128)
#b73b#4d3b318
cd cc a1 
                        call La1cc_a_hl_divided_by_de_signed  ; (a, hl) = 128 * (next vertex y - vertex y) / (next vertex x - vertex x)
#b73e#4d3e112
e5 
                        push hl
#b73f#4d3f321
fd 7e 00 
                            ld a, (iy)  ; vertex x
#b742#4d42318
cd 08 a1 
                            call La108_a_times_hl_signed  ; (a, hl) = vertex x * 128 * slope
#b745#4d45112
e5 
                            push hl
#b746#4d46112
f5 
                            push af
#b747#4d47314
3a 1b 6b 
                                ld a, (L6b1b_pointer_y)
#b74a#4d4a28
26 00 
                                ld h, 0
#b74c#4d4c15
6f 
                                ld l, a  ; hl = pointer y
#b74d#4d4d15
54 
                                ld d, h
#b74e#4d4e321
fd 5e 01 
                                ld e, (iy + 1)  ; de = vertex y
#b751#4d5115
b7 
                                or a
#b752#4d52217
ed 52 
                                sbc hl, de  ; hl = pointer y - vertex y
#b754#4d5415
44 
                                ld b, h
#b755#4d5515
65 
                                ld h, l
#b756#4d5628
2e 00 
                                ld l, 0
#b758#4d58210
cb 28 
                                sra b
#b75a#4d5a210
cb 1c 
                                rr h
#b75c#4d5c210
cb 1d 
                                rr l  ; (b, hl) = 128 * (pointer y - vertex y)
#b75e#4d5e15
eb 
                                ex de, hl  ; (b, de) = 128 * (pointer y - vertex y)
#b75f#4d5f111
f1 
                            pop af
#b760#4d60111
e1 
                            pop hl
#b761#4d61
                            ; 24 bit addition:
#b761#4d61112
19 
                            add hl, de
#b762#4d6215
88 
                            adc a, b  ; (a, hl) = vertex x * 128 * slope + 128 * (pointer y - vertex y)
#b763#4d63111
d1 
                        pop de
#b764#4d64318
cd cc a1 
                        call La1cc_a_hl_divided_by_de_signed
#b767#4d67
                        ; OPTIMIZATION: the calculation above can be greatly simplified (see my derivation below for a simpler way to do the same calculation).
#b767#4d6715
7d 
                        ld a, l  ; a = (vertex x * 128 * slope + 128 * (pointer y - vertex y)) / 128 * slope
#b768#4d68
                                 ; a = (vertex x * slope + (pointer y - vertex y)) / slope
#b768#4d68
                                 ; a = vertex x + (pointer y - vertex y) / slope
#b768#4d68
Lb768:
#b768#4d68
                        ; Write "a" (vertex x at the "y" coordinate of the pointer) to the next position in "L74fc_object_under_pointer__projected_xs_at_pointer_y"
#b768#4d68
                        ; Only up to 5 values can be stored.
#b768#4d6815
4f 
                        ld c, a
#b769#4d69314
3a fc 74 
                        ld a, (L74fc_object_under_pointer__projected_xs_at_pointer_y)
#b76c#4d6c15
3c 
                        inc a
#b76d#4d6d28
fe 06 
                        cp 6
#b76f#4d6f213/8
28 0b 
                        jr z, Lb77c_next_edge
#b771#4d71314
32 fc 74 
                        ld (L74fc_object_under_pointer__projected_xs_at_pointer_y), a  ; increment the counter of number of points saved.
#b774#4d74311
21 fc 74 
                        ld hl, L74fc_object_under_pointer__projected_xs_at_pointer_y
#b777#4d7728
16 00 
                        ld d, 0
#b779#4d7915
5f 
                        ld e, a
#b77a#4d7a112
19 
                        add hl, de
#b77b#4d7b18
71 
                        ld (hl), c  ; save the point
#b77c#4d7c
Lb77c_next_edge:
#b77c#4d7c212
fd 23 
                        inc iy
#b77e#4d7e212
fd 23 
                        inc iy
#b780#4d80111
c1 
                    pop bc
#b781#4d8115
05 
                    dec b
#b782#4d82311
c2 d5 b6 
                    jp nz, Lb6d5_face_edge_loop
#b785#4d85216
fd e1 
                pop iy
#b787#4d87
#b787#4d87
                ; At this point we have a list of "x coordinates" in the array, corresponding
#b787#4d87
                ; edges intersecting the "y" coordinate of the pointer. If we see that the
#b787#4d87
                ; pointer "x" matches any, or is left of some and right of some others, then 
#b787#4d87
                ; we know we have clicked on this object's face.
#b787#4d87314
3a fc 74 
                ld a, (L74fc_object_under_pointer__projected_xs_at_pointer_y)
#b78a#4d8a15
b7 
                or a
#b78b#4d8b213/8
28 2e 
                jr z, Lb7bb_next_face
#b78d#4d8d15
47 
                ld b, a
#b78e#4d8e311
21 fd 74 
                ld hl, L74fc_object_under_pointer__projected_xs_at_pointer_y + 1
#b791#4d91314
3a 1a 6b 
                ld a, (L6b1a_pointer_x)
#b794#4d9428
16 00 
                ld d, 0
#b796#4d9615
5f 
                ld e, a  ; de = pointer x
#b797#4d9715
af 
                xor a
#b798#4d98
Lb798_coordinate_loop:
#b798#4d9818
4e 
                ld c, (hl)
#b799#4d99112
e5 
                push hl
#b79a#4d9a15
69 
                    ld l, c
#b79b#4d9b28
26 00 
                    ld h, 0
#b79d#4d9d15
b7 
                    or a
#b79e#4d9e217
ed 52 
                    sbc hl, de  ; edge x - pointer x
#b7a0#4da0111
e1 
                pop hl
#b7a1#4da1213/8
28 10 
                jr z, Lb7b3_object_under_pointer_found_pop  ; match!
#b7a3#4da3311
f2 aa b7 
                jp p, Lb7aa
#b7a6#4da628
f6 01 
                or 1  ; pointer above
#b7a8#4da8213
18 02 
                jr Lb7ac
#b7aa#4daa
Lb7aa:
#b7aa#4daa28
f6 02 
                or 2  ; pointer below
#b7ac#4dac
Lb7ac:
#b7ac#4dac17
23 
                inc hl
#b7ad#4dad214/9
10 e9 
                djnz Lb798_coordinate_loop
#b7af#4daf28
fe 03 
                cp 3  ; if a == 3 here, we have clicked on this object's face!
#b7b1#4db1213/8
20 08 
                jr nz, Lb7bb_next_face
#b7b3#4db3
Lb7b3_object_under_pointer_found_pop:
#b7b3#4db3111
c1 
            pop bc
#b7b4#4db4
Lb7b4_object_under_pointer_found:
#b7b4#4db415
79 
            ld a, c
#b7b5#4db5314
32 80 74 
            ld (L7480_under_pointer_object_ID), a
#b7b8#4db8111
c1 
        pop bc
#b7b9#4db9213
18 0f 
        jr Lb7ca_return
#b7bb#4dbb
Lb7bb_next_face:
#b7bb#4dbb111
c1 
            pop bc
#b7bc#4dbc15
05 
            dec b
#b7bd#4dbd311
c2 3c b6 
            jp nz, Lb63c_face_loop
#b7c0#4dc0
Lb7c0_next_object:
#b7c0#4dc0
            ; Advance to the next object (in reverse order):
#b7c0#4dc0311
01 fc ff 
            ld bc, -4
#b7c3#4dc3217
fd 09 
            add iy, bc
#b7c5#4dc5111
c1 
        pop bc
#b7c6#4dc615
05 
        dec b
#b7c7#4dc7311
c2 24 b6 
        jp nz, Lb624_object_loop
#b7ca#4dca
Lb7ca_return:
#b7ca#4dca111
f1 
    pop af
#b7cb#4dcb111
c1 
    pop bc
#b7cc#4dcc111
d1 
    pop de
#b7cd#4dcd111
e1 
    pop hl
#b7ce#4dce216
fd e1 
    pop iy
#b7d0#4dd0216
dd e1 
    pop ix
#b7d2#4dd2111
c9 
    ret
#b7d3#4dd3
#b7d3#4dd3
#b7d3#4dd3
; --------------------------------
#b7d3#4dd3
; Auxiliary variables for Lb7e2_execute_script:
#b7d3#4dd3
Lb7d3:  ; Unused?
#b7d3#4dd32
    db #16, #00
#b7d5#4dd5
Lb7d5:  ; Unused? (only written to, never read)
#b7d5#4dd51
    db #5f
#b7d6#4dd6
Lb7d6_skip_rule_flag:  ; rules (except types 44 and 45) will be skipped if this is != 0.
#b7d6#4dd61
    db #19
#b7d7#4dd71
    db #71
#b7d8#4dd8
Lb7d8_current_rule_type:
#b7d8#4dd81
    db #fd
#b7d9#4dd99
    db #67, #1b, #62, #60, #6c, #61, #6c, #a5, #62  ; Unused?
#b7e2#4de2
#b7e2#4de2
#b7e2#4de2
; --------------------------------
#b7e2#4de2
; Executes a script.
#b7e2#4de2
; Input:
#b7e2#4de2
; - a: script size
#b7e2#4de2
; - ix: script pointer (skipping the size byte).
#b7e2#4de2
Lb7e2_execute_script:
#b7e2#4de2217
dd e5 
    push ix
#b7e4#4de4217
fd e5 
    push iy
#b7e6#4de6112
e5 
    push hl
#b7e7#4de7112
d5 
    push de
#b7e8#4de8112
c5 
    push bc
#b7e9#4de9112
f5 
    push af
#b7ea#4dea15
4f 
        ld c, a  ; c = rule size (in bytes)
#b7eb#4deb15
af 
        xor a
#b7ec#4dec314
32 71 74 
        ld (L7471_event_rule_found), a
#b7ef#4def314
32 d5 b7 
        ld (Lb7d5), a
#b7f2#4df2314
32 d6 b7 
        ld (Lb7d6_skip_rule_flag), a
#b7f5#4df5
Lb7f5_rule_loop:
#b7f5#4df5112
c5 
        push bc
#b7f6#4df6314
3a 7f 74 
            ld a, (L747f_player_event)
#b7f9#4df915
67 
            ld h, a  ; h = event
#b7fa#4dfa321
dd 7e 00 
            ld a, (ix)  ; rule type
#b7fd#4dfd15
47 
            ld b, a
#b7fe#4dfe28
e6 3f 
            and #3f  ; remove flags
#b800#4e00314
32 d8 b7 
            ld (Lb7d8_current_rule_type), a
#b803#4e0315
6f 
            ld l, a  ; l = rule type without flags
#b804#4e0415
78 
            ld a, b
#b805#4e0528
e6 c0 
            and #c0  ; a = flags of rule type
#b807#4e07
                     ; The flags determine which event will a rule match with:
#b807#4e07
                     ; - #00: movement
#b807#4e07
                     ; - #40: timer
#b807#4e07
                     ; - #80: stone throwing
#b807#4e07
                     ; - #c0: interact
#b807#4e0728
fe 40 
            cp #40
#b809#4e09213/8
20 06 
            jr nz, Lb811
#b80b#4e0b
            ; Flags are #40: only consider timer events
#b80b#4e0b210
cb 5c 
            bit 3, h  ; check if it was a timer event.
#b80d#4e0d213/8
20 1b 
            jr nz, Lb82a_condition_matches_event
#b80f#4e0f213
18 12 
            jr Lb823_next_rule
#b811#4e11
#b811#4e11
Lb811:
#b811#4e1128
fe 80 
            cp #80
#b813#4e13213/8
20 06 
            jr nz, Lb81b
#b815#4e15
            ; Flags are #80: only consider stone throwing events
#b815#4e15210
cb 54 
            bit 2, h  ; throwing stone event
#b817#4e17213/8
20 11 
            jr nz, Lb82a_condition_matches_event
#b819#4e19213
18 08 
            jr Lb823_next_rule
#b81b#4e1b
#b81b#4e1b
Lb81b:
#b81b#4e1b28
fe c0 
            cp #c0
#b81d#4e1d213/8
20 07 
            jr nz, Lb826
#b81f#4e1f
            ; Flags are #c0:  ; only consider interact events
#b81f#4e1f210
cb 4c 
            bit 1, h  ; interact event
#b821#4e21213/8
20 07 
            jr nz, Lb82a_condition_matches_event
#b823#4e23
Lb823_next_rule:
#b823#4e23311
c3 e8 bb 
            jp Lbbe8_next_rule
#b826#4e26
#b826#4e26
Lb826:
#b826#4e26
            ; Flags are #00:  ; only consider movement events
#b826#4e26210
cb 44 
            bit 0, h  ; movement event
#b828#4e28213/8
28 f9 
            jr z, Lb823_next_rule
#b82a#4e2a
#b82a#4e2a
Lb82a_condition_matches_event:
#b82a#4e2a28
3e 01 
            ld a, 1
#b82c#4e2c314
32 71 74 
            ld (L7471_event_rule_found), a
#b82f#4e2f15
7d 
            ld a, l  ; rule type
#b830#4e3028
fe 2d 
            cp RULE_TYPE_UNSET_SKIP_RULE
#b832#4e32213/8
20 03 
            jr nz, Lb837
#b834#4e34
#b834#4e34
            ; Note: (for a potential future cleaned version). The following code
#b834#4e34
            ;       is a very large "switch" statement for each rule type. It would
#b834#4e34
            ;       have been much cleaner to have a jump table here.
#b834#4e34
#b834#4e34
            ; Rule type 45 (#2d): continue executing next rule.
#b834#4e3415
af 
            xor a
#b835#4e35213
18 09 
            jr Lb840
#b837#4e37
Lb837:
#b837#4e3728
fe 2c 
            cp RULE_TYPE_FLIP_SKIP_RULE
#b839#4e39213/8
20 0b 
            jr nz, Lb846
#b83b#4e3b
#b83b#4e3b
            ; Rule type 44 (#2c): flip "continue executing" flag.
#b83b#4e3b314
3a d6 b7 
            ld a, (Lb7d6_skip_rule_flag)
#b83e#4e3e28
ee 01 
            xor 1
#b840#4e40
Lb840:
#b840#4e40314
32 d6 b7 
            ld (Lb7d6_skip_rule_flag), a
#b843#4e43
Lb843_next_rule:
#b843#4e43311
c3 e8 bb 
            jp Lbbe8_next_rule
#b846#4e46
#b846#4e46
Lb846:
#b846#4e4615
47 
            ld b, a
#b847#4e47314
3a d6 b7 
            ld a, (Lb7d6_skip_rule_flag)
#b84a#4e4a15
b7 
            or a
#b84b#4e4b213/8
20 f6 
            jr nz, Lb843_next_rule  ; skip this rule
#b84d#4e4d
#b84d#4e4d15
78 
            ld a, b  ; rule type
#b84e#4e4e28
fe 01 
            cp RULE_TYPE_ADD_TO_SCORE
#b850#4e50213/8
20 0f 
            jr nz, Lb861
#b852#4e52
#b852#4e52
            ; Rule type 1 (#01): Gain points
#b852#4e52321
dd 5e 01 
            ld e, (ix + 1)
#b855#4e55321
dd 56 02 
            ld d, (ix + 2)
#b858#4e58321
dd 46 03 
            ld b, (ix + 3)
#b85b#4e5b318
cd 0c bc 
            call Lbc0c_add_de_to_score
#b85e#4e5e311
c3 e8 bb 
            jp Lbbe8_next_rule
#b861#4e61
#b861#4e61
Lb861:
#b861#4e6128
fe 13 
            cp RULE_TYPE_STRENGTH_UPDATE
#b863#4e63213/8
20 24 
            jr nz, Lb889
#b865#4e65
#b865#4e65
            ; Rule type 19 (#13): Strength update
#b865#4e65311
21 0a 6b 
            ld hl, L6b0a_current_strength
#b868#4e6815
f3 
            di
#b869#4e6918
7e 
            ld a, (hl)  ; Get the current strength
#b86a#4e6a321
dd 56 01 
            ld d, (ix + 1)  ; Get the amount to add (possible negative)
#b86d#4e6d210
cb 7a 
            bit 7, d
#b86f#4e6f213/8
20 09 
            jr nz, Lb87a_subtract_strength
#b871#4e7115
82 
            add a, d
#b872#4e72
            ; Make sure we do not overflow:
#b872#4e7228
fe 18 
            cp MAX_STRENGTH
#b874#4e74213/8
38 0e 
            jr c, Lb884
#b876#4e7628
3e 18 
            ld a, MAX_STRENGTH
#b878#4e78213
18 0a 
            jr Lb884
#b87a#4e7a
Lb87a_subtract_strength:
#b87a#4e7a15
82 
            add a, d
#b87b#4e7b311
f2 84 b8 
            jp p, Lb884
#b87e#4e7e
            ; If strength reaches 0, game over!
#b87e#4e7e28
3e 02 
            ld a, GAME_OVER_REASON_YOU_COLLAPSE
#b880#4e80314
32 79 74 
            ld (L7479_current_game_state), a
#b883#4e8315
af 
            xor a
#b884#4e84
Lb884:
#b884#4e8418
77 
            ld (hl), a  ; write the strength back
#b885#4e8515
fb 
            ei
#b886#4e86311
c3 e8 bb 
            jp Lbbe8_next_rule
#b889#4e89
#b889#4e89
Lb889:
#b889#4e89
            ; Rule types 3, 4, 5, 16, 30, 31 (#03, #04, #05, #10, #1e, #1f):
#b889#4e8928
fe 03 
            cp RULE_TYPE_TOGGLE_OBJECT_VISIBILITY
#b88b#4e8b213/8
28 15 
            jr z, Lb8a2
#b88d#4e8d28
fe 04 
            cp RULE_TYPE_MAKE_OBJECT_VISIBILE
#b88f#4e8f213/8
28 11 
            jr z, Lb8a2
#b891#4e9128
fe 05 
            cp RULE_TYPE_MAKE_OBJECT_INVISIBILE
#b893#4e93213/8
28 0d 
            jr z, Lb8a2
#b895#4e9528
fe 10 
            cp RULE_TYPE_DESTROY_OBJECT
#b897#4e97213/8
28 09 
            jr z, Lb8a2
#b899#4e9928
fe 1e 
            cp RULE_TYPE_END_RULE_IF_OBJECT_INVISIBLE
#b89b#4e9b213/8
28 05 
            jr z, Lb8a2
#b89d#4e9d28
fe 1f 
            cp RULE_TYPE_END_RULE_IF_OBJECT_VISIBLE
#b89f#4e9f311
c2 8a b9 
            jp nz, Lb98a
#b8a2#4ea2
Lb8a2:
#b8a2#4ea2321
dd 7e 01 
            ld a, (ix + 1)  ; Get the new focus object ID
#b8a5#4ea5314
32 68 74 
            ld (L7468_focus_object_id), a
#b8a8#4ea815
af 
            xor a
#b8a9#4ea9217
dd e5 
            push ix
#b8ab#4eab318
cd 86 b2 
                call Lb286_find_object_by_id
#b8ae#4eae15
b7 
                or a
#b8af#4eaf213/8
20 0b 
                jr nz, Lb8bc  ; If the object was not found, next rule skipping.
#b8b1#4eb1314
3a d8 b7 
                ld a, (Lb7d8_current_rule_type)
#b8b4#4eb428
fe 1e 
                cp RULE_TYPE_END_RULE_IF_OBJECT_INVISIBLE
#b8b6#4eb6213/8
20 0c 
                jr nz, Lb8c4
#b8b8#4eb8
#b8b8#4eb8
                ; Rule 30 (#1e): end rule if object is invisible
#b8b8#4eb8
                ; Check if the object is invisible: (bit 6 = 1 -> invisible)
#b8b8#4eb8
                ; - if object is visible, we will go to next rule,
#b8b8#4eb8
                ; - otherwise, we will go to next rule, but skipping.
#b8b8#4eb8422
dd cb 00 76 
                bit 6, (ix)
#b8bc#4ebc
Lb8bc:
#b8bc#4ebc216
dd e1 
            pop ix
#b8be#4ebe311
ca e8 bb 
            jp z, Lbbe8_next_rule
#b8c1#4ec1311
c3 e3 bb 
            jp Lbbe3_next_rule_skipping
#b8c4#4ec4
#b8c4#4ec4
Lb8c4:
#b8c4#4ec428
fe 1f 
                cp RULE_TYPE_END_RULE_IF_OBJECT_VISIBLE
#b8c6#4ec6213/8
20 0c 
                jr nz, Lb8d4
#b8c8#4ec8
#b8c8#4ec8
                ; Rule 31 (#1e): end rule if object is visible
#b8c8#4ec8
                ; Check if the object is hideen: (bit 6 = 1 -> invisible)
#b8c8#4ec8
                ; - if object is invisible, we will go to next rule,
#b8c8#4ec8
                ; - otherwise, we will go to next rule, but skipping.
#b8c8#4ec8422
dd cb 00 76 
                bit 6, (ix)
#b8cc#4ecc216
dd e1 
            pop ix
#b8ce#4ece311
c2 e8 bb 
            jp nz, Lbbe8_next_rule
#b8d1#4ed1311
c3 e3 bb 
            jp Lbbe3_next_rule_skipping
#b8d4#4ed4
#b8d4#4ed4
Lb8d4:
#b8d4#4ed4422
dd cb 00 6e 
                bit 5, (ix)
#b8d8#4ed8311
c2 85 b9 
                jp nz, Lb985_next_rule
#b8db#4edb
                ; If object is not "destroyed" (bit 5), continue:
#b8db#4edb111
e1 
            pop hl  ; Recover the pointer to the original object
#b8dc#4edc112
e5 
            push hl
#b8dd#4edd214
cb 76 
                bit 6, (hl)  ; check if the original object is visible
#b8df#4edf213/8
20 05 
                jr nz, Lb8e6  ; jump if already visible
#b8e1#4ee1311
21 77 74 
                ld hl, L7477_render_buffer_effect
#b8e4#4ee4211
36 01 
                ld (hl), 1  ; fade in effect
#b8e6#4ee6
Lb8e6:
#b8e6#4ee628
fe 10 
                cp RULE_TYPE_DESTROY_OBJECT
#b8e8#4ee8213/8
20 06 
                jr nz, Lb8f0
#b8ea#4eea
#b8ea#4eea
                ; Rule 16 (#10): destroy object
#b8ea#4eea425
dd cb 00 ee 
                set 5, (ix)  ; set object as destroyed
#b8ee#4eee213
18 3a 
                jr Lb92a_make_object_invisible
#b8f0#4ef0
#b8f0#4ef0
Lb8f0:
#b8f0#4ef028
fe 03 
                cp RULE_TYPE_TOGGLE_OBJECT_VISIBILITY
#b8f2#4ef2213/8
20 08 
                jr nz, Lb8fc
#b8f4#4ef4
#b8f4#4ef4
                ; Rule 3 (#03): Toggle object visibility
#b8f4#4ef4422
dd cb 00 76 
                bit 6, (ix)
#b8f8#4ef8213/8
20 06 
                jr nz, Lb900_make_object_visible  ; make object visible
#b8fa#4efa213
18 2e 
                jr Lb92a_make_object_invisible  ; make object invisible
#b8fc#4efc
#b8fc#4efc
Lb8fc:
#b8fc#4efc28
fe 04 
                cp RULE_TYPE_MAKE_OBJECT_VISIBILE
#b8fe#4efe213/8
20 2a 
                jr nz, Lb92a_make_object_invisible
#b900#4f00
#b900#4f00
                ; Rule 4 (#04): make object visible
#b900#4f00
Lb900_make_object_visible:
#b900#4f00422
dd cb 00 76 
                bit 6, (ix)
#b904#4f04311
ca 85 b9 
                jp z, Lb985_next_rule
#b907#4f07425
dd cb 00 b6 
                res 6, (ix)  ; make object visible
#b90b#4f0b321
dd 7e 00 
                ld a, (ix)
#b90e#4f0e28
e6 0f 
                and #0f
#b910#4f1028
fe 02 
                cp OBJECT_TYPE_SPIRIT
#b912#4f12213/8
20 06 
                jr nz, Lb91a
#b914#4f14
                ; Object just appeared!
#b914#4f14311
21 69 74 
                ld hl, L7469_n_spirits_found_in_current_area
#b917#4f17112
34 
                inc (hl)
#b918#4f18213
18 2b 
                jr Lb945
#b91a#4f1a
#b91a#4f1a
Lb91a:
#b91a#4f1a425
dd cb 00 e6 
                set 4, (ix)
#b91e#4f1e28
3e 01 
                ld a, 1
#b920#4f20314
32 74 74 
                ld (L7474_check_if_object_crushed_player_flag), a
#b923#4f23311
21 6c 74 
                ld hl, L746c_game_flags
#b926#4f26217
cb d6 
                set 2, (hl)
#b928#4f28213
18 5b 
                jr Lb985_next_rule
#b92a#4f2a
#b92a#4f2a
Lb92a_make_object_invisible:
#b92a#4f2a
                ; Rule 5 (#05): Make object invisible
#b92a#4f2a422
dd cb 00 76 
                bit 6, (ix)  ; if already invisible, next rule
#b92e#4f2e213/8
20 55 
                jr nz, Lb985_next_rule
#b930#4f30425
dd cb 00 f6 
                set 6, (ix)  ; make object invisible
#b934#4f34321
dd 7e 00 
                ld a, (ix)
#b937#4f3728
e6 0f 
                and #0f
#b939#4f3928
fe 02 
                cp OBJECT_TYPE_SPIRIT
#b93b#4f3b213/8
20 0f 
                jr nz, Lb94c
#b93d#4f3d
                ; A spirit was destroyed:
#b93d#4f3d311
21 69 74 
                ld hl, L7469_n_spirits_found_in_current_area
#b940#4f4018
7e 
                ld a, (hl)
#b941#4f4115
b7 
                or a
#b942#4f42213/8
28 41 
                jr z, Lb985_next_rule
#b944#4f44112
35 
                dec (hl)  ; decrease number of spirits
#b945#4f45
Lb945:
#b945#4f45311
21 6d 74 
                ld hl, L746c_game_flags + 1
#b948#4f48217
cb e6 
                set 4, (hl)  ; refresh spirit meter flag
#b94a#4f4a213
18 39 
                jr Lb985_next_rule
#b94c#4f4c
#b94c#4f4c
Lb94c:
#b94c#4f4c
                ; Object just disappeared, check if player needs to fall, and
#b94c#4f4c
                ; remove the object from the projected objects buffers:
#b94c#4f4c28
3e 01 
                ld a, 1
#b94e#4f4e314
32 75 74 
                ld (L7475_call_Lcba4_check_for_player_falling_flag), a
#b951#4f51416
fd 21 54 67 
                ld iy, L6754_current_room_object_projected_data
#b955#4f55314
3a 6b 74 
                ld a, (L746b_n_objects_to_draw)
#b958#4f5815
b7 
                or a
#b959#4f59213/8
28 2a 
                jr z, Lb985_next_rule
#b95b#4f5b15
47 
                ld b, a
#b95c#4f5c311
11 04 00 
                ld de, 4
#b95f#4f5f314
3a 68 74 
                ld a, (L7468_focus_object_id)
#b962#4f62
Lb962_object_rule:
#b962#4f62321
fd 6e 00 
                ld l, (iy)
#b965#4f65321
fd 66 01 
                ld h, (iy + 1)
#b968#4f6818
4e 
                ld c, (hl)
#b969#4f6915
b9 
                cp c  ; is it the disappeared object?
#b96a#4f6a213/8
28 06 
                jr z, Lb972_focus_object_is_on_camera
#b96c#4f6c217
fd 19 
                add iy, de  ; next object
#b96e#4f6e214/9
10 f2 
                djnz Lb962_object_rule
#b970#4f70
                ; The disappeared object is not on camera
#b970#4f70213
18 13 
                jr Lb985_next_rule
#b972#4f72
#b972#4f72
Lb972_focus_object_is_on_camera:
#b972#4f7217
23 
                inc hl
#b973#4f73214
cb 7e 
                bit 7, (hl)  ; Check if the disappeared object covered the whole screen
#b975#4f75213/8
28 07 
                jr z, Lb97e
#b977#4f77314
3a 81 74 
                ld a, (L7481_n_objects_covering_the_whole_screen)
#b97a#4f7a15
3d 
                dec a
#b97b#4f7b314
32 81 74 
                ld (L7481_n_objects_covering_the_whole_screen), a
#b97e#4f7e
Lb97e:
#b97e#4f7e211
36 00 
                ld (hl), 0  ; remove it from the projected objects list.
#b980#4f80311
21 6d 74 
                ld hl, L746c_game_flags + 1
#b983#4f83217
cb de 
                set 3, (hl)  ; re-render flag
#b985#4f85
Lb985_next_rule:
#b985#4f85216
dd e1 
            pop ix
#b987#4f87311
c3 e8 bb 
            jp Lbbe8_next_rule
#b98a#4f8a
#b98a#4f8a
Lb98a:
#b98a#4f8a
            ; Rule types 6, 7, 8, 17, 32, 33 (#06, #07, #08, #11, #20, #21):
#b98a#4f8a
            ; same as above, but have an extra argument to specify the object area.
#b98a#4f8a28
fe 06 
            cp RULE_TYPE_TOGGLE_OBJECT_FROM_AREA_VISIBILITY
#b98c#4f8c213/8
28 14 
            jr z, Lb9a2
#b98e#4f8e28
fe 07 
            cp RULE_TYPE_MAKE_OBJECT_FROM_AREA_VISIBILE
#b990#4f90213/8
28 10 
            jr z, Lb9a2
#b992#4f9228
fe 08 
            cp RULE_TYPE_MAKE_OBJECT_FROM_AREA_INVISIBILE
#b994#4f94213/8
28 0c 
            jr z, Lb9a2
#b996#4f9628
fe 11 
            cp RULE_TYPE_DESTROY_OBJECT_FROM_AREA
#b998#4f98213/8
28 08 
            jr z, Lb9a2
#b99a#4f9a28
fe 20 
            cp RULE_TYPE_END_RULE_IF_OBJECT_FROM_AREA_INVISIBLE
#b99c#4f9c213/8
28 04 
            jr z, Lb9a2
#b99e#4f9e28
fe 21 
            cp RULE_TYPE_END_RULE_IF_OBJECT_FROM_AREA_VISIBLE
#b9a0#4fa0213/8
20 63 
            jr nz, Lba05
#b9a2#4fa2
Lb9a2:
#b9a2#4fa2321
dd 7e 02 
            ld a, (ix + 2)  ; object ID
#b9a5#4fa5314
32 68 74 
            ld (L7468_focus_object_id), a
#b9a8#4fa8321
dd 7e 01 
            ld a, (ix + 1)  ; area ID
#b9ab#4fab217
dd e5 
            push ix
#b9ad#4fad318
cd 86 b2 
                call Lb286_find_object_by_id
#b9b0#4fb015
b7 
                or a
#b9b1#4fb1213/8
20 4d 
                jr nz, Lba00_next_rule_pop
#b9b3#4fb3314
3a d8 b7 
                ld a, (Lb7d8_current_rule_type)
#b9b6#4fb628
fe 20 
                cp RULE_TYPE_END_RULE_IF_OBJECT_FROM_AREA_INVISIBLE
#b9b8#4fb8213/8
20 0c 
                jr nz, Lb9c6
#b9ba#4fba
#b9ba#4fba
                ; Rule type 32 (#20): end rule if object is invisible (from another area)
#b9ba#4fba
                ; Check if the object is invisible: (bit 6 = 1 -> invisible)
#b9ba#4fba
                ; - if object is visible, we will go to next rule,
#b9ba#4fba
                ; - otherwise, we will go to next rule, but skipping.
#b9ba#4fba422
dd cb 00 76 
                bit 6, (ix)
#b9be#4fbe216
dd e1 
            pop ix
#b9c0#4fc0311
ca e8 bb 
            jp z, Lbbe8_next_rule
#b9c3#4fc3311
c3 e3 bb 
            jp Lbbe3_next_rule_skipping
#b9c6#4fc6
#b9c6#4fc6
Lb9c6:
#b9c6#4fc628
fe 21 
                cp RULE_TYPE_END_RULE_IF_OBJECT_FROM_AREA_VISIBLE
#b9c8#4fc8213/8
20 0c 
                jr nz, Lb9d6
#b9ca#4fca
#b9ca#4fca
                ; Rule type 33 (#21): end rule if object is visible (from another area)
#b9ca#4fca
                ; Check if the object is hideen: (bit 6 = 1 -> invisible)
#b9ca#4fca
                ; - if object is invisible, we will go to next rule,
#b9ca#4fca
                ; - otherwise, we will go to next rule, but skipping.
#b9ca#4fca422
dd cb 00 76 
                bit 6, (ix)
#b9ce#4fce216
dd e1 
            pop ix
#b9d0#4fd0311
c2 e8 bb 
            jp nz, Lbbe8_next_rule
#b9d3#4fd3311
c3 e3 bb 
            jp Lbbe3_next_rule_skipping
#b9d6#4fd6
#b9d6#4fd6
Lb9d6:
#b9d6#4fd6422
dd cb 00 6e 
                bit 5, (ix)
#b9da#4fda213/8
20 24 
                jr nz, Lba00_next_rule_pop
#b9dc#4fdc
                ; If object is not "destroyed" (bit 5), continue:
#b9dc#4fdc28
fe 11 
                cp RULE_TYPE_DESTROY_OBJECT_FROM_AREA
#b9de#4fde213/8
20 06 
                jr nz, Lb9e6
#b9e0#4fe0
#b9e0#4fe0
                ; Rule type 17 (#11): destroy object (from another area)
#b9e0#4fe0425
dd cb 00 ee 
                set 5, (ix)
#b9e4#4fe4213
18 16 
                jr Lb9fc_make_object_invisible
#b9e6#4fe6
#b9e6#4fe6
Lb9e6:
#b9e6#4fe628
fe 06 
                cp RULE_TYPE_TOGGLE_OBJECT_FROM_AREA_VISIBILITY
#b9e8#4fe8213/8
20 08 
                jr nz, Lb9f2
#b9ea#4fea
#b9ea#4fea
                ; Rule type 6 (#06): Toggle object visibility (from another area)
#b9ea#4fea422
dd cb 00 76 
                bit 6, (ix)
#b9ee#4fee213/8
20 06 
                jr nz, Lb9f6_make_object_visible  ; make object visible
#b9f0#4ff0213
18 0a 
                jr Lb9fc_make_object_invisible  ; make object invisible
#b9f2#4ff2
#b9f2#4ff2
Lb9f2:
#b9f2#4ff228
fe 07 
                cp RULE_TYPE_MAKE_OBJECT_FROM_AREA_VISIBILE
#b9f4#4ff4213/8
20 06 
                jr nz, Lb9fc_make_object_invisible
#b9f6#4ff6
Lb9f6_make_object_visible:
#b9f6#4ff6
#b9f6#4ff6
                ; Rule type 7 (#07): make object visible (from another area) 
#b9f6#4ff6425
dd cb 00 b6 
                res 6, (ix)
#b9fa#4ffa213
18 04 
                jr Lba00_next_rule_pop
#b9fc#4ffc
#b9fc#4ffc
Lb9fc_make_object_invisible:
#b9fc#4ffc
#b9fc#4ffc
                ; Rule type 8 (#08): make object invisible (from another area) 
#b9fc#4ffc425
dd cb 00 f6 
                set 6, (ix)
#ba00#5000
Lba00_next_rule_pop:
#ba00#5000216
dd e1 
            pop ix
#ba02#5002311
c3 e8 bb 
            jp Lbbe8_next_rule
#ba05#5005
#ba05#5005
Lba05:
#ba05#5005
            ; Rule types 9, 10, 11, 20, 46, 47 (#09, #0a, #0b, #14, #2d, #2f):
#ba05#5005
            ; Deal with game variables.
#ba05#500528
fe 09 
            cp RULE_TYPE_INCREMENT_VARIABLE
#ba07#5007213/8
28 14 
            jr z, Lba1d
#ba09#500928
fe 0a 
            cp RULE_TYPE_DECREMENT_VARIABLE
#ba0b#500b213/8
28 10 
            jr z, Lba1d
#ba0d#500d28
fe 0b 
            cp RULE_TYPE_END_RULE_IF_VARIABLE_DIFFERENT
#ba0f#500f213/8
28 0c 
            jr z, Lba1d
#ba11#501128
fe 14 
            cp RULE_TYPE_SET_VARIABLE
#ba13#5013213/8
28 08 
            jr z, Lba1d
#ba15#501528
fe 2e 
            cp RULE_TYPE_END_RULE_IF_VARIABLE_LARGER
#ba17#5017213/8
28 04 
            jr z, Lba1d
#ba19#501928
fe 2f 
            cp RULE_TYPE_END_RULE_IF_VARIABLE_LOWER
#ba1b#501b213/8
20 40 
            jr nz, Lba5d
#ba1d#501d
Lba1d:
#ba1d#501d321
dd 5e 01 
            ld e, (ix + 1)  ; Variable index
#ba20#502015
1d 
            dec e
#ba21#502128
16 00 
            ld d, 0
#ba23#5023311
21 ee 6a 
            ld hl, L6aee_game_variables
#ba26#5026112
19 
            add hl, de  ; Get pointer to variable
#ba27#5027
#ba27#502728
fe 09 
            cp RULE_TYPE_INCREMENT_VARIABLE
#ba29#5029213/8
20 03 
            jr nz, Lba2e
#ba2b#502b
#ba2b#502b
            ; Rule type 9 (#09): increment variable
#ba2b#502b112
34 
            inc (hl)
#ba2c#502c213
18 2c 
            jr Lba5a_next_rule
#ba2e#502e
#ba2e#502e
Lba2e:
#ba2e#502e28
fe 0a 
            cp RULE_TYPE_DECREMENT_VARIABLE
#ba30#5030213/8
20 03 
            jr nz, Lba35
#ba32#5032
#ba32#5032
            ; Rule type 10 (#0a): decrement variable
#ba32#5032112
35 
            dec (hl)
#ba33#5033213
18 25 
            jr Lba5a_next_rule
#ba35#5035
#ba35#5035
Lba35:
#ba35#5035321
dd 5e 02 
            ld e, (ix + 2)  ; get value
#ba38#503828
fe 14 
            cp RULE_TYPE_SET_VARIABLE
#ba3a#503a213/8
20 03 
            jr nz, Lba3f
#ba3c#503c
#ba3c#503c
            ; Rule type 20 (#14): set variable to value
#ba3c#503c18
73 
            ld (hl), e
#ba3d#503d213
18 1b 
            jr Lba5a_next_rule
#ba3f#503f
#ba3f#503f
Lba3f:
#ba3f#503f28
fe 0b 
            cp RULE_TYPE_END_RULE_IF_VARIABLE_DIFFERENT
#ba41#5041213/8
20 06 
            jr nz, Lba49
#ba43#5043
#ba43#5043
            ; Rule type 11 (#0b): if variable != value, skip rest of script.
#ba43#504315
7b 
            ld a, e
#ba44#504418
be 
            cp (hl)
#ba45#5045213/8
20 10 
            jr nz, Lba57_next_rule_skipping
#ba47#5047213
18 11 
            jr Lba5a_next_rule
#ba49#5049
#ba49#5049
Lba49:
#ba49#504928
fe 2e 
            cp RULE_TYPE_END_RULE_IF_VARIABLE_LARGER
#ba4b#504b213/8
20 06 
            jr nz, Lba53
#ba4d#504d
#ba4d#504d
            ; Rule type 46 (#2e): if variable > value, skip rest of script.
#ba4d#504d15
7b 
            ld a, e
#ba4e#504e18
be 
            cp (hl)
#ba4f#504f213/8
38 09 
            jr c, Lba5a_next_rule
#ba51#5051213
18 04 
            jr Lba57_next_rule_skipping
#ba53#5053
#ba53#5053
Lba53:
#ba53#5053
            ; Rule type 47 (#2f): if variable < value, skip rest of script.
#ba53#505318
7e 
            ld a, (hl)
#ba54#505415
bb 
            cp e
#ba55#5055213/8
38 03 
            jr c, Lba5a_next_rule
#ba57#5057
Lba57_next_rule_skipping:
#ba57#5057311
c3 e3 bb 
            jp Lbbe3_next_rule_skipping
#ba5a#505a
#ba5a#505a
Lba5a_next_rule:
#ba5a#505a311
c3 e8 bb 
            jp Lbbe8_next_rule
#ba5d#505d
#ba5d#505d
Lba5d:
#ba5d#505d
            ; Rule types 12, 13, 14, 29 (#0c, #0d, #0e, #1d):
#ba5d#505d
            ; Operations on boolean variables (used for storing collected keys in this game):
#ba5d#505d28
fe 0c 
            cp RULE_TYPE_SET_BOOLEAN_TRUE
#ba5f#505f213/8
28 0c 
            jr z, Lba6d
#ba61#506128
fe 0d 
            cp RULE_TYPE_SET_BOOLEAN_FALSE
#ba63#5063213/8
28 08 
            jr z, Lba6d
#ba65#506528
fe 0e 
            cp RULE_TYPE_END_RULE_IF_BOOLEAN_DIFFERENT
#ba67#5067213/8
28 04 
            jr z, Lba6d
#ba69#506928
fe 1d 
            cp RULE_TYPE_TOGGLE_BOOLEAN
#ba6b#506b213/8
20 49 
            jr nz, Lbab6
#ba6d#506d
Lba6d:
#ba6d#506d15
5f 
            ld e, a  ; save the rule type for later
#ba6e#506e311
21 df 6a 
            ld hl, L6adf_game_boolean_variables
#ba71#5071321
dd 7e 01 
            ld a, (ix + 1)  ; bit we want to modify
#ba74#507415
3d 
            dec a
#ba75#5075
            ; Get to the correct byte of the boolean variables:
#ba75#5075
Lba75_byte_loop:
#ba75#507528
fe 08 
            cp 8
#ba77#5077213/8
38 05 
            jr c, Lba7e_byte_found
#ba79#507928
d6 08 
            sub 8  ; next byte
#ba7b#507b17
23 
            inc hl
#ba7c#507c213
18 f7 
            jr Lba75_byte_loop
#ba7e#507e
#ba7e#507e
Lba7e_byte_found:
#ba7e#507e28
16 01 
            ld d, 1  ; mask
#ba80#508015
b7 
            or a
#ba81#5081213/8
28 05 
            jr z, Lba88
#ba83#5083
            ; Generate a one-hot bit mask for the target bit (in "d"):
#ba83#508315
47 
            ld b, a
#ba84#5084
Lba84_bit_mask_loop:
#ba84#5084210
cb 22 
            sla d
#ba86#5086214/9
10 fc 
            djnz Lba84_bit_mask_loop
#ba88#5088
Lba88:
#ba88#508815
7b 
            ld a, e  ; restore the rule type
#ba89#508918
5e 
            ld e, (hl)
#ba8a#508a28
fe 1d 
            cp RULE_TYPE_TOGGLE_BOOLEAN
#ba8c#508c213/8
20 06 
            jr nz, Lba94
#ba8e#508e
#ba8e#508e
            ; Rule type 29 (#1d): toggle bit
#ba8e#508e15
7a 
            ld a, d
#ba8f#508f15
a3 
            and e
#ba90#5090213/8
28 06 
            jr z, Lba98_set_bit
#ba92#5092213
18 0d 
            jr Lbaa1_reset_bit
#ba94#5094
#ba94#5094
Lba94:
#ba94#509428
fe 0c 
            cp RULE_TYPE_SET_BOOLEAN_TRUE
#ba96#5096213/8
20 05 
            jr nz, Lba9d
#ba98#5098
#ba98#5098
Lba98_set_bit:
#ba98#5098
            ; Rule type 12 (#0c): set bit
#ba98#509815
7a 
            ld a, d
#ba99#509915
b3 
            or e
#ba9a#509a18
77 
            ld (hl), a
#ba9b#509b213
18 16 
            jr Lbab3
#ba9d#509d
#ba9d#509d
Lba9d:
#ba9d#509d28
fe 0d 
            cp RULE_TYPE_SET_BOOLEAN_FALSE
#ba9f#509f213/8
20 06 
            jr nz, Lbaa7
#baa1#50a1
#baa1#50a1
Lbaa1_reset_bit:
#baa1#50a1
            ; Rule type 13 (#0d): reset bit
#baa1#50a115
7a 
            ld a, d
#baa2#50a215
2f 
            cpl
#baa3#50a315
a3 
            and e
#baa4#50a418
77 
            ld (hl), a
#baa5#50a5213
18 0c 
            jr Lbab3
#baa7#50a7
#baa7#50a7
Lbaa7:
#baa7#50a7
            ; Rule type 14 (#0e): end script if bit is different than expected value
#baa7#50a715
7a 
            ld a, d
#baa8#50a815
a3 
            and e
#baa9#50a9213/8
28 02 
            jr z, Lbaad
#baab#50ab28
3e 01 
            ld a, 1
#baad#50ad
Lbaad:
#baad#50ad321
dd be 02 
            cp (ix + 2)  ; exected value
#bab0#50b0311
c2 e3 bb 
            jp nz, Lbbe3_next_rule_skipping
#bab3#50b3
Lbab3:
#bab3#50b3311
c3 e8 bb 
            jp Lbbe8_next_rule
#bab6#50b6
#bab6#50b6
Lbab6:
#bab6#50b628
fe 0f 
            cp RULE_TYPE_PLAY_SFX
#bab8#50b8213/8
28 18 
            jr z, Lbad2_play_sfx
#baba#50ba28
fe 1c 
            cp RULE_TYPE_REQUEST_SFX_NEXT_FRAME
#babc#50bc213/8
20 1d 
            jr nz, Lbadb
#babe#50be
#babe#50be
            ; Rule type 28 (#1c): request SFX to be played in next frame.
#babe#50be317
2a 6c 74 
            ld hl, (L746c_game_flags)
#bac1#50c1
            ; If a re-render or re-projection is requested, schedule
#bac1#50c1
            ; the SFX to play afterwards. Otherwise, play now (as there will be no timing difference):
#bac1#50c1210
cb 55 
            bit 2, l
#bac3#50c3213/8
20 04 
            jr nz, Lbac9_request_sfx
#bac5#50c5210
cb 5c 
            bit 3, h
#bac7#50c7213/8
28 09 
            jr z, Lbad2_play_sfx
#bac9#50c9
Lbac9_request_sfx:
#bac9#50c9321
dd 7e 01 
            ld a, (ix + 1)
#bacc#50cc314
32 7a 74 
            ld (L747a_requested_SFX), a
#bacf#50cf311
c3 e8 bb 
            jp Lbbe8_next_rule
#bad2#50d2
#bad2#50d2
Lbad2_play_sfx:
#bad2#50d2
            ; Rule type 15 (#0f): play SFX.
#bad2#50d2321
dd 7e 01 
            ld a, (ix + 1)  ; SFX ID
#bad5#50d5318
cd ca c4 
            call Lc4ca_play_SFX
#bad8#50d8311
c3 e8 bb 
            jp Lbbe8_next_rule
#badb#50db
#badb#50db
Lbadb:
#badb#50db28
fe 12 
            cp RULE_TYPE_TELEPORT
#badd#50dd213/8
20 57 
            jr nz, Lbb36
#badf#50df
#badf#50df
            ; Rule type 18 (#12): Teleport to a new area
#badf#50df314
3a cf 6a 
            ld a, (L6acf_current_area_id)
#bae2#50e2314
32 70 74 
            ld (L7470_previous_area_id), a
#bae5#50e528
3e 07 
            ld a, SFX_GAME_START
#bae7#50e7314
32 7a 74 
            ld (L747a_requested_SFX), a
#baea#50ea321
dd 7e 01 
            ld a, (ix + 1)  ; Get target area
#baed#50ed314
32 cf 6a 
            ld (L6acf_current_area_id), a
#baf0#50f015
67 
            ld h, a
#baf1#50f1321
dd 7e 02 
            ld a, (ix + 2)  ; Get object that determines position to go to
#baf4#50f4314
32 67 74 
            ld (L7467_player_starting_position_object_id), a
#baf7#50f7318
cd 63 a5 
            call La563_load_and_reset_new_area
#bafa#50fa15
7c 
            ld a, h  ; requested area ID to go to
#bafb#50fb311
21 e3 6a 
            ld hl, L6ae3_visited_areas
#bafe#50fe
#bafe#50fe
            ; Get to the byte containing the bit representing the target area.
#bafe#50fe
Lbafe_byte_loop:
#bafe#50fe28
fe 08 
            cp 8
#bb00#5100213/8
38 05 
            jr c, Lbb07
#bb02#510217
23 
            inc hl
#bb03#510328
d6 08 
            sub 8
#bb05#5105213
18 f7 
            jr Lbafe_byte_loop
#bb07#5107
#bb07#5107
Lbb07:
#bb07#5107
            ; Get a one-hot bit mask for the bit representing this area.
#bb07#510728
0e 01 
            ld c, 1
#bb09#510915
47 
            ld b, a
#bb0a#510a15
b7 
            or a
#bb0b#510b213/8
28 04 
            jr z, Lbb11
#bb0d#510d
Lbb0d_bit_mask_loop:
#bb0d#510d
#bb0d#510d210
cb 21 
            sla c
#bb0f#510f214/9
10 fc 
            djnz Lbb0d_bit_mask_loop
#bb11#5111
Lbb11:
#bb11#5111
#bb11#511118
7e 
            ld a, (hl)
#bb12#511215
a1 
            and c
#bb13#5113213/8
20 09 
            jr nz, Lbb1e_area_already_visited
#bb15#5115
            ; New area visited, mark it as visited, and
#bb15#5115
            ; add 25000 points!
#bb15#511518
7e 
            ld a, (hl)
#bb16#511615
b1 
            or c
#bb17#511718
77 
            ld (hl), a
#bb18#5118311
11 a8 61 
            ld de, 25000
#bb1b#511b318
cd 0c bc 
            call Lbc0c_add_de_to_score
#bb1e#511e
Lbb1e_area_already_visited:
#bb1e#511e311
21 fc ff 
            ld hl, #fffc  ; redraw everything
#bb21#5121314
3a e2 6a 
            ld a, (L6adf_game_boolean_variables + 3)
#bb24#5124
            ; Check if game complete flag is set, to play the
#bb24#5124
            ; escaped SFX:
#bb24#5124210
cb 77 
            bit 6, a
#bb26#5126213/8
28 08 
            jr z, Lbb30
#bb28#512828
3e 0d 
            ld a, SFX_OPEN_ESCAPED
#bb2a#512a314
32 7a 74 
            ld (L747a_requested_SFX), a
#bb2d#512d311
21 04 00 
            ld hl, #0004  ; reproject
#bb30#5130
Lbb30:
#bb30#5130317
22 6c 74 
            ld (L746c_game_flags), hl
#bb33#5133311
c3 e8 bb 
            jp Lbbe8_next_rule
#bb36#5136
#bb36#5136
Lbb36:
#bb36#513628
fe 22 
            cp RULE_TYPE_SHOW_MESSAGE
#bb38#5138311
c2 87 bb 
            jp nz, Lbb87
#bb3b#513b
#bb3b#513b
            ; Rule type 34 (#22): Display text message
#bb3b#513b217
dd e5 
            push ix
#bb3d#513d321
dd 7e 01 
                ld a, (ix + 1)  ; text message to display
#bb40#514015
47 
                ld b, a
#bb41#5141311
21 c9 6c 
                ld hl, L6cc9_text_overpowered  ; The first text message (ignoring " PRESS ANY KEY ")
#bb44#514415
05 
                dec b
#bb45#5145213/8
28 06 
                jr z, Lbb4d
#bb47#5147311
11 10 00 
                ld de, 16  ; size of text messages.
#bb4a#514a
Lbb4a_text_message_ptr_loop:
#bb4a#514a112
19 
                add hl, de
#bb4b#514b214/9
10 fd 
                djnz Lbb4a_text_message_ptr_loop
#bb4d#514d
Lbb4d:
#bb4d#514d416
dd 21 5a 73 
                ld ix, L735a_ui_message_row_pointers
#bb51#5151311
11 00 0f 
                ld de, #0f00
#bb54#5154318
cd 1c d0 
                call Ld01c_draw_string
#bb57#5157314
3a 79 74 
                ld a, (L7479_current_game_state)
#bb5a#515a15
b7 
                or a
#bb5b#515b213/8
20 0c 
                jr nz, Lbb69
#bb5d#515d28
3e 32 
                ld a, 50  ; wait 50 interrupts before refreshing the text.
#bb5f#515f314
32 a5 74 
                ld (L74a5_interrupt_timer), a
#bb62#516228
3e 20 
                ld a, 32  ; request refreshing the room name.
#bb64#5164311
21 6d 74 
                ld hl, L746c_game_flags + 1
#bb67#516718
b6 
                or (hl)
#bb68#516818
77 
                ld (hl), a
#bb69#5169
Lbb69:
#bb69#5169216
dd e1 
            pop ix
#bb6b#516b311
c3 e8 bb 
            jp Lbbe8_next_rule
#bb6e#516e
#bb6e#516e
    ; Unreachable code?
#bb6e#516e112
c5 
    push bc
#bb6f#516f321
dd 5e 00 
    ld e, (ix)
#bb72#5172321
dd 56 01 
    ld d, (ix + 1)
#bb75#5175212
dd 23 
    inc ix
#bb77#5177212
dd 23 
    inc ix
#bb79#5179218
ed a0 
    ldi
#bb7b#517b28
06 16 
    ld b, 22
#bb7d#517d18
7e 
    ld a, (hl)
#bb7e#517e17
23 
    inc hl
#bb7f#517f
Lbb7f:
#bb7f#517f18
12 
    ld (de), a
#bb80#518017
13 
    inc de
#bb81#5181214/9
10 fc 
    djnz Lbb7f
#bb83#5183218
ed a0 
    ldi
#bb85#5185111
c1 
    pop bc
#bb86#5186111
c9 
    ret
#bb87#5187
#bb87#5187
Lbb87:
#bb87#518728
fe 23 
            cp RULE_TYPE_RENDER_EFFECT
#bb89#5189213/8
20 09 
            jr nz, Lbb94
#bb8b#518b
#bb8b#518b
            ; Rule type 35 (#23): trigger rendere effect (fade-in, gate open/closing, etc.)
#bb8b#518b321
dd 7e 01 
            ld a, (ix + 1)
#bb8e#518e314
32 77 74 
            ld (L7477_render_buffer_effect), a
#bb91#5191311
c3 e8 bb 
            jp Lbbe8_next_rule
#bb94#5194
#bb94#5194
Lbb94:
#bb94#519428
fe 1a 
            cp RULE_TYPE_REDRAW
#bb96#5196213/8
20 0b 
            jr nz, Lbba3
#bb98#5198
#bb98#5198
            ; Rule type 26 (#1a): triggers a whole redraw.
#bb98#5198318
cd aa 83 
            call L83aa_redraw_whole_screen
#bb9b#519b311
21 00 00 
            ld hl, 0
#bb9e#519e317
22 6c 74 
            ld (L746c_game_flags), hl
#bba1#51a1213
18 45 
            jr Lbbe8_next_rule
#bba3#51a3
#bba3#51a3
Lbba3:
#bba3#51a328
fe 1b 
            cp RULE_TYPE_PAUSE
#bba5#51a5213/8
20 0e 
            jr nz, Lbbb5
#bba7#51a7
#bba7#51a7
            ; Rule type 27 (#1b): creates a small pause
#bba7#51a7321
dd 7e 01 
            ld a, (ix + 1)  ; number of interrupts to pause for
#bbaa#51aa314
32 a5 74 
            ld (L74a5_interrupt_timer), a
#bbad#51ad
Lbbad_pause_loop:
#bbad#51ad314
3a a5 74 
            ld a, (L74a5_interrupt_timer)
#bbb0#51b015
b7 
            or a
#bbb1#51b1213/8
20 fa 
            jr nz, Lbbad_pause_loop
#bbb3#51b3213
18 33 
            jr Lbbe8_next_rule
#bbb5#51b5
#bbb5#51b5
Lbbb5:
#bbb5#51b528
fe 30 
            cp RULE_TYPE_SELECT_OBJECT
#bbb7#51b7213/8
20 4a 
            jr nz, Lbc03_return
#bbb9#51b9111
c1 
        pop bc
#bbba#51ba
#bbba#51ba
        ; Rule type 48 (#30): select object
#bbba#51ba
        ; Changes the focus object to a new one, and executes rules from that object instead.
#bbba#51ba321
dd 7e 01 
        ld a, (ix + 1)  ; object ID
#bbbd#51bd314
32 68 74 
        ld (L7468_focus_object_id), a
#bbc0#51c015
af 
        xor a
#bbc1#51c1318
cd 86 b2 
        call Lb286_find_object_by_id
#bbc4#51c415
b7 
        or a
#bbc5#51c5213/8
20 3c 
        jr nz, Lbc03_return
#bbc7#51c7
        ; Object found:
#bbc7#51c715
57 
        ld d, a  ; d = 0
#bbc8#51c8321
dd 7e 00 
        ld a, (ix)
#bbcb#51cb28
e6 0f 
        and #0f
#bbcd#51cd416
fd 21 2c 6b 
        ld iy, L6b2c_expected_object_size_by_type
#bbd1#51d115
5f 
        ld e, a
#bbd2#51d2217
fd 19 
        add iy, de
#bbd4#51d4321
fd 5e 00 
        ld e, (iy)
#bbd7#51d7321
dd 7e 08 
        ld a, (ix + OBJECT_SIZE)
#bbda#51da15
93 
        sub e
#bbdb#51db213/8
28 26 
        jr z, Lbc03_return
#bbdd#51dd15
4f 
        ld c, a  ; c = number of bytes left of rules
#bbde#51de217
dd 19 
        add ix, de  ; ix = pointer to the rule data in the new object
#bbe0#51e0311
c3 f5 b7 
        jp Lb7f5_rule_loop
#bbe3#51e3
#bbe3#51e3
Lbbe3_next_rule_skipping:
#bbe3#51e3
            ; Turns on skipping (the rest of rules will be skipped, unless a special rule reverting this is found):
#bbe3#51e328
3e 01 
            ld a, 1
#bbe5#51e5314
32 d6 b7 
            ld (Lb7d6_skip_rule_flag), a
#bbe8#51e8
Lbbe8_next_rule:
#bbe8#51e8314
3a d8 b7 
            ld a, (Lb7d8_current_rule_type)  ; get rule type without flags
#bbeb#51eb311
21 3c 6b 
            ld hl, L6b3c_rule_size_by_type
#bbee#51ee15
5f 
            ld e, a
#bbef#51ef28
16 00 
            ld d, 0
#bbf1#51f1112
19 
            add hl, de
#bbf2#51f218
5e 
            ld e, (hl)
#bbf3#51f3217
dd 19 
            add ix, de  ; skip to the next rule
#bbf5#51f515
7b 
            ld a, e
#bbf6#51f6111
c1 
        pop bc
#bbf7#51f715
b7 
        or a  ; If the rule size is 0, return (end of sequence marker)
#bbf8#51f8213/8
28 09 
        jr z, Lbc03_return
#bbfa#51fa15
91 
        sub c
#bbfb#51fb210
ed 44 
        neg
#bbfd#51fd15
4f 
        ld c, a  ; updates the number of bytes left
#bbfe#51fe213/8
28 03 
        jr z, Lbc03_return
#bc00#5200311
f2 f5 b7 
        jp p, Lb7f5_rule_loop
#bc03#5203
Lbc03_return:
#bc03#5203111
f1 
    pop af
#bc04#5204111
c1 
    pop bc
#bc05#5205111
d1 
    pop de
#bc06#5206111
e1 
    pop hl
#bc07#5207216
fd e1 
    pop iy
#bc09#5209216
dd e1 
    pop ix
#bc0b#520b111
c9 
    ret
#bc0c#520c
#bc0c#520c
#bc0c#520c
; --------------------------------
#bc0c#520c
; Adds points to the current score
#bc0c#520c
; Input:
#bc0c#520c
; - (b, de): points
#bc0c#520c
Lbc0c_add_de_to_score:
#bc0c#520c317
2a eb 6a 
    ld hl, (L6aeb_score)
#bc0f#520f314
3a ed 6a 
    ld a, (L6aeb_score + 2)
#bc12#5212112
19 
    add hl, de
#bc13#521315
88 
    adc a, b
#bc14#5214317
22 eb 6a 
    ld (L6aeb_score), hl
#bc17#5217314
32 ed 6a 
    ld (L6aeb_score + 2), a
#bc1a#521a111
c9 
    ret
#bc1b#521b
#bc1b#521b
#bc1b#521b
; --------------------------------
#bc1b#521b
; Converts a 32bit number (de, hl) into a decimal string.
#bc1b#521b
; Input:
#bc1b#521b
; - de, hl: number to convert to decimal
#bc1b#521b
; - a: number of digits
#bc1b#521b
Lbc1b_integer_to_ascii:
#bc1b#521b217
dd e5 
    push ix
#bc1d#521d112
e5 
    push hl
#bc1e#521e112
d5 
    push de
#bc1f#521f112
c5 
    push bc
#bc20#5220112
f5 
    push af
#bc21#522115
4f 
        ld c, a
#bc22#522228
06 00 
        ld b, 0
#bc24#5224217
dd 09 
        add ix, bc
#bc26#522615
47 
        ld b, a
#bc27#5227
Lbc27:
#bc27#5227112
c5 
        push bc
#bc28#5228212
dd 2b 
            dec ix
#bc2a#522a311
01 0a 00 
            ld bc, 10
#bc2d#522d318
cd b7 b1 
            call Lb1b7_de_hl_divided_by_bc_signed
#bc30#523015
79 
            ld a, c
#bc31#523128
fe 05 
            cp 5
#bc33#5233311
fa 40 bc 
            jp m, Lbc40
#bc36#5236311
01 00 00 
            ld bc, 0
#bc39#523915
b7 
            or a
#bc3a#523a217
ed 42 
            sbc hl, bc
#bc3c#523c17
2b 
            dec hl
#bc3d#523d213/8
20 01 
            jr nz, Lbc40
#bc3f#523f17
1b 
            dec de
#bc40#5240
Lbc40:
#bc40#524028
c6 30 
            add a, 48
#bc42#5242321
dd 77 00 
            ld (ix), a
#bc45#5245111
c1 
        pop bc
#bc46#5246214/9
10 df 
    djnz Lbc27
#bc48#5248111
f1 
    pop af
#bc49#5249111
c1 
    pop bc
#bc4a#524a111
d1 
    pop de
#bc4b#524b111
e1 
    pop hl
#bc4c#524c216
dd e1 
    pop ix
#bc4e#524e111
c9 
    ret
#bc4f#524f
#bc4f#524f
#bc4f#524f
; --------------------------------
#bc4f#524f
; Temporary variables for "Lbc52_update_UI":
#bc4f#524f
Lbc4f_current_eye_compass_frame:
#bc4f#524f1
    db #00
#bc50#5250
Lbc50_current_rendered_spirit_meter:
#bc50#52501
    db #00
#bc51#5251
Lbc51_current_rendered_strength:
#bc51#52511
    db #00
#bc52#5252
#bc52#5252
#bc52#5252
; --------------------------------
#bc52#5252
; Updates the UI elements (keys, eye compass, strength, spirit counter).
#bc52#5252
Lbc52_update_UI:
#bc52#5252
    ; Part 1: Update keys UI:
#bc52#5252314
3a 6d 74 
    ld a, (L746c_game_flags + 1)
#bc55#5255210
cb 7f 
    bit 7, a
#bc57#5257213/8
28 30 
    jr z, Lbc89_no_key_redraw
#bc59#5259311
21 cc 76 
    ld hl, L76cc_ui_key_bg_sprite  ; calculate sufficient pixel row pointers for the height of this sprite
#bc5c#525c318
cd 4f ca 
    call Lca4f_calculate_pixel_row_pointers
#bc5f#525f416
dd 21 64 66 
    ld ix, L6664_row_pointers
#bc63#5263311
11 00 00 
    ld de, 0
#bc66#5266318
cd 95 c8 
    call Lc895_draw_sprite_to_ix_ptrs
#bc69#5269
#bc69#5269314
3a 0c 6b 
    ld a, (L6b0c_num_collected_keys)
#bc6c#526c15
b7 
    or a
#bc6d#526d213/8
28 0f 
    jr z, Lbc7e_no_keys
#bc6f#526f15
47 
    ld b, a
#bc70#5270311
21 25 77 
    ld hl, L7725_ui_key_sprite
#bc73#5273311
11 22 00 
    ld de, 34  ; x_offset of the first key.
#bc76#5276
Lbc76_draw_ui_keys_loop:
#bc76#5276318
cd 95 c8 
    call Lc895_draw_sprite_to_ix_ptrs
#bc79#527915
1d 
    dec e
#bc7a#527a15
1d 
    dec e
#bc7b#527b15
1d 
    dec e
#bc7c#527c214/9
10 f8 
    djnz Lbc76_draw_ui_keys_loop
#bc7e#527e
#bc7e#527e
Lbc7e_no_keys:
#bc7e#527e311
21 cc 76 
    ld hl, L76cc_ui_key_bg_sprite
#bc81#5281416
fd 21 98 73 
    ld iy, L7398_key_count_ui_row_pointers
#bc85#528515
af 
    xor a
#bc86#5286318
cd 70 ca 
    call Lca70_draw_sprite_from_ix_to_iy
#bc89#5289
#bc89#5289
Lbc89_no_key_redraw:
#bc89#5289
    ; Check if a new key was just taken, and update the inventory:
#bc89#5289314
3a 0d 6b 
    ld a, (L6b0d_new_key_taken)
#bc8c#528c15
b7 
    or a
#bc8d#528d213/8
28 47 
    jr z, Lbcd6_no_new_key  ; if (L6b0d_new_key_taken) == 0 (no new key), skip
#bc8f#528f15
5f 
    ld e, a
#bc90#529015
1d 
    dec e
#bc91#529115
af 
    xor a
#bc92#5292314
32 0d 6b 
    ld (L6b0d_new_key_taken), a
#bc95#529515
7b 
    ld a, e  ; a = (L6b0d_new_key_taken) - 1
#bc96#529628
fe 0a 
    cp 10
#bc98#5298213/8
30 3c 
    jr nc, Lbcd6_no_new_key  ; if (L6b0d_new_key_taken) - 1 >= 0, skip
#bc9a#529a311
21 df 6a 
    ld hl, L6adf_game_boolean_variables
#bc9d#529d28
fe 08 
    cp 8
#bc9f#529f213/8
38 03 
    jr c, Lbca4  ; if (L6b0d_new_key_taken) - 1 >= 8, hl = L6adf_game_boolean_variables + 1
#bca1#52a128
d6 08 
    sub 8
#bca3#52a317
23 
    inc hl
#bca4#52a4
Lbca4:
#bca4#52a4
    ; Calculate (in "c') the one-hot mask corresponding to (L6b0d_new_key_taken) - 1
#bca4#52a428
0e 01 
    ld c, 1
#bca6#52a615
47 
    ld b, a
#bca7#52a715
b7 
    or a
#bca8#52a8213/8
28 04 
    jr z, Lbcae
#bcaa#52aa
Lbcaa_bit_mask_loop:
#bcaa#52aa210
cb 21 
    sla c
#bcac#52ac214/9
10 fc 
    djnz Lbcaa_bit_mask_loop
#bcae#52ae
Lbcae:
#bcae#52ae18
7e 
    ld a, (hl)  ; Check if the corresponding bit was already set
#bcaf#52af15
a1 
    and c
#bcb0#52b0213/8
20 24 
    jr nz, Lbcd6_no_new_key  ; If already set, skip
#bcb2#52b215
79 
    ld a, c
#bcb3#52b318
b6 
    or (hl)
#bcb4#52b418
77 
    ld (hl), a  ; Set the bit corresponding to (L6b0d_new_key_taken) - 1
#bcb5#52b5
    ; Increment the # of collected keys:
#bcb5#52b5314
3a 0c 6b 
    ld a, (L6b0c_num_collected_keys)
#bcb8#52b815
4f 
    ld c, a
#bcb9#52b915
3c 
    inc a
#bcba#52ba314
32 0c 6b 
    ld (L6b0c_num_collected_keys), a
#bcbd#52bd311
21 0f 6b 
    ld hl, L6b0f_collected_keys
#bcc0#52c0112
09 
    add hl, bc
#bcc1#52c118
73 
    ld (hl), e  ; Add the new key to the inventory.
#bcc2#52c2
    ; Update the UI with the new key:
#bcc2#52c2
    ; OPTIMIZATION: if "adding a key" to the inventory were done at the beginning of the function,
#bcc2#52c2
    ; there would be no need for the code below, as can be made to be drawn with the code above.
#bcc2#52c2311
21 25 77 
    ld hl, L7725_ui_key_sprite
#bcc5#52c5416
dd 21 98 73 
    ld ix, L7398_key_count_ui_row_pointers
#bcc9#52c928
16 00 
    ld d, 0
#bccb#52cb15
79 
    ld a, c
#bccc#52cc15
87 
    add a, a
#bccd#52cd15
81 
    add a, c
#bcce#52ce210
ed 44 
    neg
#bcd0#52d028
c6 22 
    add a, 34
#bcd2#52d215
5f 
    ld e, a
#bcd3#52d3318
cd 95 c8 
    call Lc895_draw_sprite_to_ix_ptrs
#bcd6#52d6
#bcd6#52d6
Lbcd6_no_new_key:
#bcd6#52d6
    ; Part 2: Update compass eye UI:
#bcd6#52d6314
3a 2b 6b 
    ld a, (L6b2b_desired_eye_compass_frame)
#bcd9#52d915
57 
    ld d, a
#bcda#52da314
3a 4f bc 
    ld a, (Lbc4f_current_eye_compass_frame)
#bcdd#52dd15
ba 
    cp d
#bcde#52de213/8
20 07 
    jr nz, Lbce7
#bce0#52e0314
3a 6c 74 
    ld a, (L746c_game_flags)
#bce3#52e328
e6 60 
    and #60
#bce5#52e5213/8
28 2f 
    jr z, Lbd16_eye_compass_done
#bce7#52e7
Lbce7:
#bce7#52e7416
dd 21 50 73 
    ld ix, L7350_compass_eye_ui_row_pointers
#bceb#52eb311
21 92 77 
    ld hl, L7792_ui_compass_eye_sprites
#bcee#52ee28
1e 00 
    ld e, 0
#bcf0#52f015
7a 
    ld a, d
#bcf1#52f128
fe 08 
    cp 8
#bcf3#52f3213/8
20 1a 
    jr nz, Lbd0f
#bcf5#52f528
16 07 
    ld d, 7
#bcf7#52f7
Lbcf7:
#bcf7#52f7
    ; Special case for eye frame 8, which requires an animation from 8 to 5:
#bcf7#52f715
15 
    dec d
#bcf8#52f8318
cd 95 c8 
    call Lc895_draw_sprite_to_ix_ptrs
#bcfb#52fb28
3e 02 
    ld a, 2
#bcfd#52fd314
32 a5 74 
    ld (L74a5_interrupt_timer), a
#bd00#5300
    ; animation delay:
#bd00#5300
Lbd00_pause_loop:
#bd00#5300314
3a a5 74 
    ld a, (L74a5_interrupt_timer)
#bd03#530315
b7 
    or a
#bd04#5304213/8
20 fa 
    jr nz, Lbd00_pause_loop
#bd06#530628
3e 05 
    ld a, 5
#bd08#530815
ba 
    cp d
#bd09#5309213/8
20 ec 
    jr nz, Lbcf7
#bd0b#530b
    ; Back to frame 0:
#bd0b#530b15
af 
    xor a
#bd0c#530c314
32 2b 6b 
    ld (L6b2b_desired_eye_compass_frame), a
#bd0f#530f
Lbd0f:
#bd0f#530f314
32 4f bc 
    ld (Lbc4f_current_eye_compass_frame), a
#bd12#531215
57 
    ld d, a
#bd13#5313318
cd 95 c8 
    call Lc895_draw_sprite_to_ix_ptrs
#bd16#5316
#bd16#5316
Lbd16_eye_compass_done:
#bd16#5316
    ; Part 3: Update strength UI:
#bd16#5316314
3a 0a 6b 
    ld a, (L6b0a_current_strength)
#bd19#531915
57 
    ld d, a
#bd1a#531a314
3a 51 bc 
    ld a, (Lbc51_current_rendered_strength)
#bd1d#531d15
ba 
    cp d
#bd1e#531e311
ca f8 bd 
    jp z, Lbdf8_strength_done
#bd21#532115
7a 
    ld a, d
#bd22#5322314
32 51 bc 
    ld (Lbc51_current_rendered_strength), a
#bd25#532528
fe 03 
    cp 3
#bd27#5327213/8
30 30 
    jr nc, Lbd59_strength_3_or_higher
#bd29#5329
    ; Strength < 3:
#bd29#5329314
3a 0b 6b 
    ld a, (L6b0b_selected_movement_mode)
#bd2c#532c15
b7 
    or a
#bd2d#532d213/8
28 4f 
    jr z, Lbd7e_done_handling_strength
#bd2f#532f
    ; If we are not crawling, but strength is < 3, switch to crawling:
#bd2f#532f
    ; This makes the player crouch for crawling:
#bd2f#532f311
21 b8 6a 
    ld hl, L6ab8_player_crawling
#bd32#5332112
35 
    dec (hl)
#bd33#5333314
3a b9 6a 
    ld a, (L6ab9_player_height)
#bd36#5336311
21 bc 6a 
    ld hl, L6abc_current_room_scale
#bd39#533918
96 
    sub (hl)
#bd3a#533a314
32 b9 6a 
    ld (L6ab9_player_height), a
#bd3d#533d18
46 
    ld b, (hl)
#bd3e#533e18
56 
    ld d, (hl)
#bd3f#533f28
1e 00 
    ld e, 0
#bd41#5341210
cb 3a 
    srl d
#bd43#5343210
cb 1b 
    rr e
#bd45#5345210
cb 3a 
    srl d
#bd47#5347210
cb 1b 
    rr e
#bd49#5349317
2a af 6a 
    ld hl, (L6aaf_player_current_y)
#bd4c#534c15
af 
    xor a
#bd4d#534d217
ed 52 
    sbc hl, de
#bd4f#534f317
22 af 6a 
    ld (L6aaf_player_current_y), hl
#bd52#5352
    ; This changes the player movement speed to crawling:
#bd52#5352314
3a c8 d0 
    ld a, (Ld0c8_speed_when_crawling)
#bd55#535515
6f 
    ld l, a
#bd56#535615
af 
    xor a
#bd57#5357213
18 15 
    jr Lbd6e_change_movement_mode
#bd59#5359
Lbd59_strength_3_or_higher:
#bd59#535928
fe 05 
    cp 5
#bd5b#535b213/8
30 21 
    jr nc, Lbd7e_done_handling_strength
#bd5d#535d
    ; Strength 3 or 4
#bd5d#535d314
3a 0b 6b 
    ld a, (L6b0b_selected_movement_mode)
#bd60#536028
fe 02 
    cp 2
#bd62#5362213/8
20 1a 
    jr nz, Lbd7e_done_handling_strength
#bd64#5364
    ; If we are running, but at low strength, switch to walking:
#bd64#5364314
3a bc 6a 
    ld a, (L6abc_current_room_scale)
#bd67#536715
47 
    ld b, a
#bd68#5368314
3a c9 d0 
    ld a, (Ld0c9_speed_when_walking)
#bd6b#536b15
6f 
    ld l, a
#bd6c#536c28
3e 01 
    ld a, 1
#bd6e#536e
Lbd6e_change_movement_mode:
#bd6e#536e314
32 0b 6b 
    ld (L6b0b_selected_movement_mode), a
#bd71#537115
7d 
    ld a, l
#bd72#5372314
32 b5 6a 
    ld (L6ab5_current_speed), a
#bd75#537528
26 00 
    ld h, 0
#bd77#537715
78 
    ld a, b
#bd78#5378318
cd 08 a1 
    call La108_a_times_hl_signed  ; hl = hl * a
#bd7b#537b317
22 b3 6a 
    ld (L6ab3_current_speed_in_this_room), hl
#bd7e#537e
Lbd7e_done_handling_strength:
#bd7e#537e311
21 05 78 
    ld hl, L7805_ui_strength_bg_sprite
#bd81#5381318
cd 4f ca 
    call Lca4f_calculate_pixel_row_pointers
#bd84#5384416
dd 21 64 66 
    ld ix, L6664_row_pointers
#bd88#5388311
11 00 00 
    ld de, 0
#bd8b#538b318
cd 95 c8 
    call Lc895_draw_sprite_to_ix_ptrs  ; Draw strength background
#bd8e#538e28
1e 0c 
    ld e, 6 * 2  ; Move 6 pixels down
#bd90#5390217
dd 19 
    add ix, de
#bd92#5392314
3a 0a 6b 
    ld a, (L6b0a_current_strength)
#bd95#539528
fe 04 
    cp 4
#bd97#5397213/8
30 09 
    jr nc, Lbda2_bar_y_coordinate_set
#bd99#5399
    ; If strength <= 4:
#bd99#5399
    ;   move 4 - (L6b0a_current_strength) pixels down, since the smaller weights are smaller in diameter
#bd99#539928
d6 04 
    sub 4
#bd9b#539b210
ed 44 
    neg
#bd9d#539d15
5f 
    ld e, a
#bd9e#539e217
dd 19 
    add ix, de
#bda0#53a0217
dd 19 
    add ix, de
#bda2#53a2
Lbda2_bar_y_coordinate_set:
#bda2#53a2311
21 91 78 
    ld hl, L7891_ui_strength_bar_sprite
#bda5#53a515
5a 
    ld e, d  ; e = 0
#bda6#53a6318
cd 95 c8 
    call Lc895_draw_sprite_to_ix_ptrs  ; draw "bar" (the bar that holds the weights)
#bda9#53a9
#bda9#53a9311
21 b1 78 
    ld hl, L78b1_ui_strength_weight_sprite
#bdac#53ac311
11 f4 ff 
    ld de, -6 * 2
#bdaf#53af217
dd 19 
    add ix, de  ; move back up 6 pixels to draw the weights
#bdb1#53b1311
11 05 00 
    ld de, 5  ; x_offset = 5, frame = 0
#bdb4#53b428
0e 3d 
    ld c, 61  ; Distance in pixels between the furthest appart discs.
#bdb6#53b6314
3a 0a 6b 
    ld a, (L6b0a_current_strength)
#bdb9#53b915
47 
    ld b, a
#bdba#53ba15
b7 
    or a
#bdbb#53bb213/8
20 05 
    jr nz, Lbdc2_non_zero_strength
#bdbd#53bd28
3e 02 
    ld a, GAME_OVER_REASON_YOU_COLLAPSE
#bdbf#53bf314
32 79 74 
    ld (L7479_current_game_state), a
#bdc2#53c2
Lbdc2_non_zero_strength:
#bdc2#53c215
78 
    ld a, b
#bdc3#53c3210
cb 38 
    srl b
#bdc5#53c5210
cb 38 
    srl b
#bdc7#53c715
04 
    inc b  ; (b = (L6b0a_current_strength) / 4 + 1)
#bdc8#53c828
e6 03 
    and 3
#bdca#53ca213/8
28 1b 
    jr z, Lbde7_no_smaller_disc
#bdcc#53cc
    ; Calculate the sprite to be used for the very first disc:
#bdcc#53cc28
d6 04 
    sub 4
#bdce#53ce210
ed 44 
    neg
#bdd0#53d015
82 
    add a, d
#bdd1#53d115
57 
    ld d, a  ; Sprite to use for the very first disc (which might be smaller)
#bdd2#53d2
    ; Loop that draws each of the individual weight discs in the strength visualization:
#bdd2#53d2
Lbdd2_individual_weight_loop:
#bdd2#53d2318
cd 95 c8 
    call Lc895_draw_sprite_to_ix_ptrs  ; Draw left disc.
#bdd5#53d515
79 
    ld a, c
#bdd6#53d628
d6 03 
    sub 3  ; Each disc is 3 pixels wide
#bdd8#53d815
4f 
    ld c, a
#bdd9#53d915
83 
    add a, e  ; Move x_offset to the right disc
#bdda#53da15
5f 
    ld e, a
#bddb#53db318
cd 95 c8 
    call Lc895_draw_sprite_to_ix_ptrs  ; Draw right disc.
#bdde#53de15
79 
    ld a, c
#bddf#53df28
d6 03 
    sub 3  ; Each disc is 3 pixels wide
#bde1#53e115
4f 
    ld c, a
#bde2#53e215
7b 
    ld a, e  ; Move x_offset to the left disc again
#bde3#53e315
91 
    sub c
#bde4#53e415
5f 
    ld e, a
#bde5#53e528
16 00 
    ld d, 0  ; Each subsequent disc is a large one
#bde7#53e7
Lbde7_no_smaller_disc:
#bde7#53e7214/9
10 e9 
    djnz Lbdd2_individual_weight_loop
#bde9#53e9416
dd 21 64 66 
    ld ix, L6664_row_pointers
#bded#53ed416
fd 21 7a 73 
    ld iy, L737a_strength_ui_row_pointers
#bdf1#53f1311
21 05 78 
    ld hl, L7805_ui_strength_bg_sprite  ; Only used to determine the width * height to copy.
#bdf4#53f415
af 
    xor a
#bdf5#53f5318
cd 70 ca 
    call Lca70_draw_sprite_from_ix_to_iy  ; Copy the recently drawn strength visual to video memory.
#bdf8#53f8
#bdf8#53f8
Lbdf8_strength_done:
#bdf8#53f8
    ; Part 4: Update spirit meter UI:
#bdf8#53f8314
3a 1f 6b 
    ld a, (L6b1f_current_spirit_meter)
#bdfb#53fb15
57 
    ld d, a
#bdfc#53fc314
3a 50 bc 
    ld a, (Lbc50_current_rendered_spirit_meter)
#bdff#53ff15
ba 
    cp d
#be00#5400213/8
20 07 
    jr nz, Lbe09_redraw_spirit_meter
#be02#5402
    ; If the desired and rendered values are the same, only redraw if
#be02#5402
    ; The re-render flag is set:
#be02#5402314
3a 6d 74 
    ld a, (L746c_game_flags + 1)
#be05#540528
e6 10 
    and #10
#be07#5407213/8
28 4c 
    jr z, Lbe55
#be09#5409
Lbe09_redraw_spirit_meter:
#be09#5409
    ; The position of the spirit meter is computed based on some non trivial formula, specifically:
#be09#5409
    ; - There is a concept of "sprit time", T, ('L6b1f_current_spirit_meter'), that starts at 32, and
#be09#5409
    ;   increments by one each 120 seconds.
#be09#5409
    ; - There is also a number of spirits that must be killed, N, ('Ld0cb_n_sprits_that_must_be_killed')
#be09#5409
    ; - And the # of spirits actually killed, n, (starts at 0).
#be09#5409
    ; - The position of the spirit meter is = T * (N - n) / N
#be09#5409
    ; - If this position reaches 'SPIRIT_METER_MAX' (64), the game is over.
#be09#540915
7a 
    ld a, d
#be0a#540a314
32 50 bc 
    ld (Lbc50_current_rendered_spirit_meter), a
#be0d#540d311
21 38 77 
    ld hl, L7738_ui_spirit_meter_bg_sprite
#be10#5410318
cd 4f ca 
    call Lca4f_calculate_pixel_row_pointers
#be13#5413416
dd 21 64 66 
    ld ix, L6664_row_pointers
#be17#5417311
11 08 00 
    ld de, 8  ; x_offset = 8, frame to draw = 0
#be1a#541a318
cd 95 c8 
    call Lc895_draw_sprite_to_ix_ptrs
#be1d#541d314
3a cb d0 
    ld a, (Ld0cb_n_sprits_that_must_be_killed)
#be20#542015
5f 
    ld e, a
#be21#542115
b7 
    or a
#be22#5422213/8
28 1f 
    jr z, Lbe43_draw_spirit_indicator
#be24#5424311
21 09 6b 
    ld hl, L6b09_number_of_spirits_destroyed
#be27#542718
96 
    sub (hl)
#be28#542815
6f 
    ld l, a  ; l = (Ld0cb_n_sprits_that_must_be_killed) - (L6b09_number_of_spirits_destroyed)
#be29#5429314
3a 50 bc 
    ld a, (Lbc50_current_rendered_spirit_meter)
#be2c#542c15
67 
    ld h, a
#be2d#542d318
cd 53 a2 
    call La253_h_times_l_signed  ; hl = (Lbc50_current_rendered_spirit_meter) * ((Ld0cb_n_sprits_that_must_be_killed) - (L6b09_number_of_spirits_destroyed))
#be30#543015
af 
    xor a
#be31#543115
57 
    ld d, a
#be32#5432318
cd cc a1 
    call La1cc_a_hl_divided_by_de_signed  ; (a, hl) = (a, hl) / de
#be35#543515
7d 
    ld a, l
#be36#543628
fe 40 
    cp SPIRIT_METER_MAX
#be38#5438213/8
38 05 
    jr c, Lbe3f
#be3a#543a
    ; spirit meter reached its maximum, game over!
#be3a#543a28
3e 01 
    ld a, GAME_OVER_REASON_OVERPOWERED
#be3c#543c314
32 79 74 
    ld (L7479_current_game_state), a
#be3f#543f
Lbe3f:
#be3f#543f15
2c 
    inc l
#be40#544028
16 00 
    ld d, 0  ; frame 0 (there is only one frame here)
#be42#544215
5d 
    ld e, l  ; x_offset (# of spirits left)
#be43#5443
Lbe43_draw_spirit_indicator:
#be43#5443
    ; Draw the sprite indicator with offset "e":
#be43#5443311
21 7d 77 
    ld hl, L777d_ui_spirit_meter_indicator_sprite
#be46#5446318
cd 95 c8 
    call Lc895_draw_sprite_to_ix_ptrs
#be49#5449311
21 38 77 
    ld hl, L7738_ui_spirit_meter_bg_sprite  ; Only used to get the width * height
#be4c#544c416
fd 21 6a 73 
    ld iy, L736a_spirit_count_ui_row_pointers
#be50#545028
3e 01 
    ld a, 1  ; Skip the left-most byte when drawing (as that is occluded in the UI).
#be52#5452318
cd 70 ca 
    call Lca70_draw_sprite_from_ix_to_iy
#be55#5455
Lbe55:
#be55#5455111
c9 
    ret
#be56#5456
#be56#5456
#be56#5456
; --------------------------------
#be56#5456
Lbe56_interrupt_noise_status:
#be56#54561
    db #00  ; When there is a spirit in the room, the game produces a constant noise.
#be57#5457
Lbe57_spirit_effect_attribute_cycle:
#be57#5457
    ; #42: 01 000 010 : red
#be57#5457
    ; #42: 01 000 011 : magenta
#be57#5457
    ; #42: 01 000 110 ; yellow
#be57#54575
    db #42, #42, #43, #43, #46
#be5c#545c
Lbe5c_random_eyes_1_timer:
#be5c#545c2
    db #9d, #00
#be5e#545e
Lbe5e_random_eyes_2_timer:
#be5e#545e2
    db #87, #00
#be60#5460
Lbe60_waving_flag_timer:
#be60#54601
    db #07
#be61#5461
Lbe61_spirit_effect_timer:
#be61#54611
    db #0a
#be62#5462
Lbe62_waving_flag_frame:
#be62#54621
    db #02
#be63#5463
Lbe63_hud_random_eyes_status:
#be63#54631
    db #03
#be64#5464
Lbe64_time_unit1:  ; changes once per second, and counts from 5 to 1
#be64#54641
    db #01
#be65#5465
Lbe65_time_unit3:  ; changes once per second, and counts from 120 to 1
#be65#54651
    db #01
#be66#5466
#be66#5466
#be66#5466
; --------------------------------
#be66#5466
; Interrupt routine, does the following tasks:
#be66#5466
; - Updates the background color of the viewport in case a fade-out was triggered.
#be66#5466
; - Updates the HUD animations (eyes, waving flag).
#be66#5466
; - Updates all the timers.
#be66#5466
Lbe66_interrupt_routine:
#be66#546615
f3 
    di
#be67#5467112
e5 
    push hl
#be68#5468112
c5 
    push bc
#be69#5469112
f5 
    push af
#be6a#546a311
21 7c 74 
        ld hl, L747c_within_interrupt_flag
#be6d#546d217
cb fe 
        set 7, (hl)  ; Mark we are within the interrupt
#be6f#546f311
21 a5 74 
        ld hl, L74a5_interrupt_timer
#be72#5472
        ; Drecrease (L74a5_interrupt_timer) if it's not 0:
#be72#547215
af 
        xor a
#be73#547318
be 
        cp (hl)
#be74#5474213/8
28 01 
        jr z, Lbe77_already_zero
#be76#5476112
35 
        dec (hl)
#be77#5477
Lbe77_already_zero:
#be77#5477
        ; Checks whether we need to change attributes due to a fade out:
#be77#547715
3c 
        inc a  ; a = 1
#be78#5478314
32 78 74 
        ld (L7478_interrupt_executed_flag), a  ; Some functions set this to 0, and wait for the interrupt to execute by waiting for this to be 1
#be7b#547b311
21 61 be 
        ld hl, Lbe61_spirit_effect_timer
#be7e#547e314
3a 79 74 
        ld a, (L7479_current_game_state)
#be81#548115
b7 
        or a
#be82#5482213/8
20 06 
        jr nz, Lbe8a
#be84#5484
        ; We are in a menu, or ga,e over, do not apply the spirit effect
#be84#5484314
3a 2a 6b 
        ld a, (L6b2a_spirit_in_room)
#be87#548715
b7 
        or a
#be88#5488213/8
20 07 
        jr nz, Lbe91_spirit_in_room_effect
#be8a#548a
Lbe8a:
#be8a#548a18
7e 
        ld a, (hl)  ; hl = Lbe61_spirit_effect_timer
#be8b#548b28
fe 0a 
        cp 10
#be8d#548d213/8
28 2a 
        jr z, Lbeb9_no_attribute_change
#be8f#548f213
18 03 
        jr Lbe94_fade_out_finished
#be91#5491
Lbe91_spirit_in_room_effect:
#be91#5491112
35 
        dec (hl)
#be92#5492213/8
20 07 
        jr nz, Lbe9b
#be94#5494
Lbe94_fade_out_finished:
#be94#5494211
36 0a 
        ld (hl), 10
#be96#5496314
3a d9 6a 
        ld a, (L6ad9_current_attribute_color)
#be99#5499213
18 0a 
        jr Lbea5_attribute_decided
#be9b#549b
Lbe9b:
#be9b#549b18
4e 
        ld c, (hl)
#be9c#549c210
cb 39 
        srl c  ; Offset in the fade out table is (Lbe61_spirit_effect_timer)/2
#be9e#549e28
06 00 
        ld b, 0
#bea0#54a0311
21 57 be 
        ld hl, Lbe57_spirit_effect_attribute_cycle
#bea3#54a3112
09 
        add hl, bc
#bea4#54a418
7e 
        ld a, (hl)  ; Get the desired attribute byte
#bea5#54a5
Lbea5_attribute_decided:
#bea5#54a5
        ; Change the attributes of the whole viewport to "a":
#bea5#54a5311
21 84 58 
        ld hl, L5800_VIDEOMEM_ATTRIBUTES + 4 * 32 + 4
#bea8#54a8112
d5 
        push de
#bea9#54a9311
11 08 00 
            ld de, 8  ; skip 4 rows to the right/left of the viewport
#beac#54ac28
0e 0e 
            ld c, SCREEN_HEIGHT
#beae#54ae
Lbeae_attribute_change_row_loop:
#beae#54ae28
06 18 
            ld b, SCREEN_WIDTH
#beb0#54b0
Lbeb0_attribute_change_column_loop:
#beb0#54b018
77 
            ld (hl), a
#beb1#54b117
23 
            inc hl
#beb2#54b2214/9
10 fc 
            djnz Lbeb0_attribute_change_column_loop
#beb4#54b4112
19 
            add hl, de
#beb5#54b515
0d 
            dec c
#beb6#54b6213/8
20 f6 
            jr nz, Lbeae_attribute_change_row_loop
#beb8#54b8111
d1 
        pop de
#beb9#54b9
#beb9#54b9
Lbeb9_no_attribute_change:
#beb9#54b9
        ; Randomly display eyes in one of the windows in the HUD:
#beb9#54b9317
2a 5c be 
        ld hl, (Lbe5c_random_eyes_1_timer)
#bebc#54bc17
2b 
        dec hl
#bebd#54bd15
7c 
        ld a, h
#bebe#54be15
b5 
        or l
#bebf#54bf213/8
20 28 
        jr nz, Lbee9_no_eyes1
#bec1#54c1
        ; Update eyes:
#bec1#54c1314
3a 63 be 
        ld a, (Lbe63_hud_random_eyes_status)
#bec4#54c4210
cb 47 
        bit 0, a
#bec6#54c6213/8
20 14 
        jr nz, Lbedc_add_eyes
#bec8#54c828
f6 01 
        or 1
#beca#54ca314
32 63 be 
        ld (Lbe63_hud_random_eyes_status), a
#becd#54cd311
21 a2 4c 
        ld hl, L4000_VIDEOMEM_PATTERNS + #0ca2  ; (2, 108)
#bed0#54d0211
36 0e 
        ld (hl), #0e  ; remove eyes
#bed2#54d2
        ; Randomize the amount of time until the next time we draw the eyes:
#bed2#54d2211
ed 5f 
        ld a, r
#bed4#54d415
6f 
        ld l, a
#bed5#54d528
26 00 
        ld h, 0
#bed7#54d7112
29 
        add hl, hl
#bed8#54d815
24 
        inc h
#bed9#54d915
24 
        inc h
#beda#54da213
18 0d 
        jr Lbee9_no_eyes1
#bedc#54dc
Lbedc_add_eyes:
#bedc#54dc28
e6 fe 
        and 254
#bede#54de314
32 63 be 
        ld (Lbe63_hud_random_eyes_status), a
#bee1#54e1311
21 a2 4c 
        ld hl, L4000_VIDEOMEM_PATTERNS + #0ca2  ; (2, 108)
#bee4#54e4211
36 ae 
        ld (hl), #ae  ; draw eyes
#bee6#54e6311
21 0f 00 
        ld hl, 15  ; keep the eyes on for 15 interrupts
#bee9#54e9
Lbee9_no_eyes1:
#bee9#54e9317
22 5c be 
        ld (Lbe5c_random_eyes_1_timer), hl
#beec#54ec
#beec#54ec317
2a 5e be 
        ld hl, (Lbe5e_random_eyes_2_timer)
#beef#54ef17
2b 
        dec hl
#bef0#54f015
7c 
        ld a, h
#bef1#54f115
b5 
        or l
#bef2#54f2213/8
20 28 
        jr nz, Lbf1c_no_eyes2
#bef4#54f4
        ; Update eyes:
#bef4#54f4314
3a 63 be 
        ld a, (Lbe63_hud_random_eyes_status)
#bef7#54f7210
cb 4f 
        bit 1, a
#bef9#54f9213/8
20 14 
        jr nz, Lbf0f_add_eyes
#befb#54fb28
f6 02 
        or 2
#befd#54fd314
32 63 be 
        ld (Lbe63_hud_random_eyes_status), a
#bf00#5500311
21 bd 47 
        ld hl, L4000_VIDEOMEM_PATTERNS + #07bd  ; (29, 47)
#bf03#5503211
36 e0 
        ld (hl), #e0  ; remove eyes
#bf05#5505
        ; Randomize the amount of time until the next time we draw the eyes:
#bf05#5505211
ed 5f 
        ld a, r
#bf07#550715
6f 
        ld l, a
#bf08#550828
26 00 
        ld h, 0
#bf0a#550a112
29 
        add hl, hl
#bf0b#550b15
24 
        inc h
#bf0c#550c15
24 
        inc h
#bf0d#550d213
18 0d 
        jr Lbf1c_no_eyes2
#bf0f#550f
Lbf0f_add_eyes:
#bf0f#550f28
e6 fd 
        and #fd
#bf11#5511314
32 63 be 
        ld (Lbe63_hud_random_eyes_status), a
#bf14#5514311
21 bd 47 
        ld hl, L4000_VIDEOMEM_PATTERNS + #07bd  ; (29, 47)
#bf17#5517211
36 ea 
        ld (hl), #ea  ; draw eyes
#bf19#5519311
21 0f 00 
        ld hl, 15  ; keep the eyes on for 15 interrupts
#bf1c#551c
Lbf1c_no_eyes2:
#bf1c#551c317
22 5e be 
        ld (Lbe5e_random_eyes_2_timer), hl
#bf1f#551f
#bf1f#551f
        ; Update the waving flag in the HUD:
#bf1f#551f311
21 60 be 
        ld hl, Lbe60_waving_flag_timer
#bf22#5522112
35 
        dec (hl)
#bf23#5523213/8
20 1e 
        jr nz, Lbf43_no_flag_update
#bf25#5525211
36 08 
        ld (hl), 8
#bf27#5527314
3a 62 be 
        ld a, (Lbe62_waving_flag_frame)
#bf2a#552a15
3c 
        inc a
#bf2b#552b28
e6 03 
        and 3
#bf2d#552d314
32 62 be 
        ld (Lbe62_waving_flag_frame), a
#bf30#5530112
d5 
        push de
#bf31#5531217
dd e5 
        push ix
#bf33#5533416
dd 21 b4 73 
            ld ix, L73b4_waving_flag_row_pointers
#bf37#5537311
21 12 7a 
            ld hl, L7a12_waving_flag_gfx_properties
#bf3a#553a15
57 
            ld d, a
#bf3b#553b28
1e 00 
            ld e, 0
#bf3d#553d318
cd 95 c8 
            call Lc895_draw_sprite_to_ix_ptrs  ; draws one frame of the waving flag
#bf40#5540216
dd e1 
        pop ix
#bf42#5542111
d1 
        pop de
#bf43#5543
Lbf43_no_flag_update:
#bf43#5543
#bf43#5543314
3a 79 74 
        ld a, (L7479_current_game_state)
#bf46#554615
b7 
        or a
#bf47#5547213/8
20 56 
        jr nz, Lbf9f_time_update_done
#bf49#5549314
3a 2a 6b 
        ld a, (L6b2a_spirit_in_room)
#bf4c#554c15
b7 
        or a
#bf4d#554d213/8
28 12 
        jr z, Lbf61_no_interrupt_sound
#bf4f#554f
        ; There is a spirit in the room and we need to produce sound:
#bf4f#554f314
3a d7 6a 
        ld a, (L6ad7_current_border_color)
#bf52#555215
67 
        ld h, a
#bf53#5553314
3a 56 be 
        ld a, (Lbe56_interrupt_noise_status)
#bf56#555628
ee 10 
        xor 16
#bf58#5558314
32 56 be 
        ld (Lbe56_interrupt_noise_status), a
#bf5b#555b15
b4 
        or h
#bf5c#555c28
f6 08 
        or 8
#bf5e#555e212
d3 fe 
        out (ULA_PORT), a
#bf60#556015
af 
        xor a
#bf61#5561
Lbf61_no_interrupt_sound:
#bf61#5561
#bf61#5561
        ; Update the internal game time:
#bf61#5561311
21 1d 6b 
        ld hl, L6b1d_time_interrupts
#bf64#5564112
35 
        dec (hl)
#bf65#5565311
c2 9f bf 
        jp nz, Lbf9f_time_update_done
#bf68#5568211
36 32 
        ld (hl), 50
#bf6a#556a311
21 0e 6b 
        ld hl, L6b0e_lightning_time_seconds_countdown
#bf6d#556d18
be 
        cp (hl)  ; Compare with 0, as a == 0 at this point.
#bf6e#556e213/8
28 01 
        jr z, Lbf71_zero_seconds
#bf70#5570112
35 
        dec (hl)
#bf71#5571
Lbf71_zero_seconds:
#bf71#5571311
21 64 be 
        ld hl, Lbe64_time_unit1
#bf74#5574112
35 
        dec (hl)
#bf75#5575213/8
20 10 
        jr nz, Lbf87_no_strength_decrease
#bf77#5577211
36 05 
        ld (hl), 5
#bf79#5579311
21 2a 6b 
        ld hl, L6b2a_spirit_in_room
#bf7c#557c
        ; If there is a spirit in the room, decrease strength by 1 each 5 seconds:
#bf7c#557c15
af 
        xor a
#bf7d#557d18
be 
        cp (hl)
#bf7e#557e213/8
28 07 
        jr z, Lbf87_no_strength_decrease
#bf80#5580311
21 0a 6b 
        ld hl, L6b0a_current_strength
#bf83#558318
be 
        cp (hl)
#bf84#5584213/8
28 0d 
        jr z, Lbf93_current_strength_zero
#bf86#5586112
35 
        dec (hl)  ; decrease strength
#bf87#5587
Lbf87_no_strength_decrease:
#bf87#5587311
21 65 be 
        ld hl, Lbe65_time_unit3
#bf8a#558a112
35 
        dec (hl)
#bf8b#558b213/8
20 06 
        jr nz, Lbf93_time_unit3_zero
#bf8d#558d211
36 78 
        ld (hl), 120
#bf8f#558f311
21 1f 6b 
        ld hl, L6b1f_current_spirit_meter
#bf92#5592112
34 
        inc (hl)
#bf93#5593
Lbf93_current_strength_zero:
#bf93#5593
Lbf93_time_unit3_zero:
#bf93#5593311
21 1e 6b 
        ld hl, L6b1e_time_unit5
#bf96#5596112
35 
        dec (hl)
#bf97#5597213/8
20 06 
        jr nz, Lbf9f_time_update_done
#bf99#5599211
36 0a 
        ld (hl), 10
#bf9b#559b311
21 22 6b 
        ld hl, L6b22_time_unit6
#bf9e#559e112
34 
        inc (hl)
#bf9f#559f
Lbf9f_time_update_done:
#bf9f#559f311
21 7c 74 
        ld hl, L747c_within_interrupt_flag
#bfa2#55a2217
cb be 
        res 7, (hl)  ; Mark the interrupt has finished.
#bfa4#55a4111
f1 
    pop af
#bfa5#55a5111
c1 
    pop bc
#bfa6#55a6111
e1 
    pop hl
#bfa7#55a715
fb 
    ei
#bfa8#55a8216
ed 4d 
    reti
#bfaa#55aa
#bfaa#55aa
#bfaa#55aa
; --------------------------------
#bfaa#55aa
; When reading the keyboard, if the keys read are the same as
#bfaa#55aa
; in the previous cycle, and this counter is == 0, we will try
#bfaa#55aa
; to read the keyboard again.
#bfaa#55aa
Ld0cf_keyboard_first_key_repeat:
#bfaa#55aa1
    db 0
#bfab#55ab
Lbfab_previous_number_of_pressed_keys:
#bfab#55ab1
    db 0
#bfac#55ac
Lbfac_keyboard_layout:
#bfac#55ac5
    db 127, "ZXCV"
#bfb1#55b15
    db "ASDFG"
#bfb6#55b65
    db "QWERT"
#bfbb#55bb5
    db "12345"
#bfc0#55c05
    db "09876"
#bfc5#55c55
    db "POIUY"
#bfca#55ca5
    db 13, "LKJH"
#bfcf#55cf5
    db " ", 27, "MNB"
#bfd4#55d4
#bfd4#55d4
#bfd4#55d4
; --------------------------------
#bfd4#55d4
; Reads input from keyboard and joysticks.
#bfd4#55d4
; In addition to the register/flags outputs below, it also fills a set of RAM
#bfd4#55d4
; buffers with all the keys currently being held pressed, and how many of them
#bfd4#55d4
; are there currently pressed.
#bfd4#55d4
; Output:
#bfd4#55d4
;  - carry flag: any key pressed
#bfd4#55d4
;  - a: pressed key
#bfd4#55d4
Lbfd4_read_keyboard_and_joystick_input:
#bfd4#55d4217
dd e5 
    push ix
#bfd6#55d6112
e5 
    push hl
#bfd7#55d7112
d5 
    push de
#bfd8#55d8112
c5 
    push bc
#bfd9#55d9
Lbfd9_read_keyboard_and_joystick_input_internal:
#bfd9#55d9311
21 f2 74 
        ld hl, L74f2_keyboard_input
#bfdc#55dc311
01 fe fe 
        ld bc, #fe00 + ULA_PORT  ; start reading the top keyboard half-row
#bfdf#55df
Lbfdf_keyboard_read_loop:
#bfdf#55df214
ed 78 
        in a, (c)  ; Read the status of one keyboard half-row
#bfe1#55e115
2f 
        cpl
#bfe2#55e228
e6 1f 
        and 31
#bfe4#55e418
77 
        ld (hl), a  ; Store it in L74f2_keyboard_input
#bfe5#55e517
23 
        inc hl
#bfe6#55e6210
cb 00 
        rlc b  ; Next half-row
#bfe8#55e8213/8
38 f5 
        jr c, Lbfdf_keyboard_read_loop
#bfea#55ea
#bfea#55ea15
af 
        xor a
#bfeb#55eb314
32 9f 74 
        ld (L749f_number_of_pressed_keys), a
#bfee#55ee314
32 72 74 
        ld (L7472_symbol_shift_pressed), a
#bff1#55f1311
11 a0 74 
        ld de, L74a0_pressed_keys_buffer
#bff4#55f4311
21 f2 74 
        ld hl, L74f2_keyboard_input
#bff7#55f728
06 08 
        ld b, 8  ; Number of keyboard half-rows
#bff9#55f9
Lbff9_keyboard_row_loop:
#bff9#55f918
7e 
        ld a, (hl)
#bffa#55fa
Lbffa_keyboard_row_loop_internal:
#bffa#55fa15
b7 
        or a
#bffb#55fb213/8
28 46 
        jr z, Lc043_next_row  ; If nothing pressed in that row
#bffd#55fd112
d5 
        push de
#bffe#55fe112
c5 
            push bc
#bfff#55ff28
06 08 
                ld b, 8
#c001#560115
4f 
                ld c, a
#c002#560215
af 
                xor a
#c003#560328
1e fe 
                ld e, 254
#c005#5605
                ; Here we know for sure a key was pressed, we loop
#c005#5605
                ; through the bits to find the one of the pressed key.
#c005#5605
Lc005_find_pressed_key_loop:
#c005#5605210
cb 39 
                srl c
#c007#5607213/8
38 05 
                jr c, Lc00e_key_pressed  ; key pressed found
#c009#560915
3c 
                inc a
#c00a#560a210
cb 23 
                sla e
#c00c#560c214/9
10 f7 
                djnz Lc005_find_pressed_key_loop
#c00e#560e
Lc00e_key_pressed:
#c00e#560e111
c1 
            pop bc
#c00f#560f15
4f 
            ld c, a  ; Index of the pressed key
#c010#561028
3e 08 
            ld a, 8
#c012#561215
90 
            sub b  ; 8 - half-row index
#c013#561315
57 
            ld d, a
#c014#561415
87 
            add a, a
#c015#561515
87 
            add a, a
#c016#561615
82 
            add a, d
#c017#561715
81 
            add a, c  ; a = half-row * 5 + key index
#c018#561815
4b 
            ld c, e
#c019#561915
5f 
            ld e, a
#c01a#561a28
16 00 
            ld d, 0
#c01c#561c416
dd 21 ac bf 
            ld ix, Lbfac_keyboard_layout
#c020#5620217
dd 19 
            add ix, de  ; ix = key corresponding to this position
#c022#5622321
dd 7e 00 
            ld a, (ix)
#c025#5625111
d1 
        pop de
#c026#562628
fe 1b 
        cp 27  ; symbol shift key code
#c028#5628213/8
20 07 
        jr nz, Lc031_its_not_symbol_shift
#c02a#562a112
f5 
        push af
#c02b#562b28
3e 01 
            ld a, 1
#c02d#562d314
32 72 74 
            ld (L7472_symbol_shift_pressed), a
#c030#5630111
f1 
        pop af
#c031#5631
Lc031_its_not_symbol_shift:
#c031#563118
12 
        ld (de), a  ; store the key pressed 
#c032#5632314
3a 9f 74 
        ld a, (L749f_number_of_pressed_keys)
#c035#563515
3c 
        inc a
#c036#5636314
32 9f 74 
        ld (L749f_number_of_pressed_keys), a
#c039#563928
fe 05 
        cp MAX_PRESSED_KEYS
#c03b#563b213/8
28 57 
        jr z, Lc094_done_reading_keys
#c03d#563d
        ; continue reading keys in this half-row, ignoring the ones
#c03d#563d
        ; we have already checked:
#c03d#563d17
13 
        inc de
#c03e#563e18
7e 
        ld a, (hl)
#c03f#563f15
a1 
        and c
#c040#564018
77 
        ld (hl), a
#c041#5641213
18 b7 
        jr Lbffa_keyboard_row_loop_internal
#c043#5643
Lc043_next_row:
#c043#564317
23 
        inc hl
#c044#5644214/9
10 b3 
        djnz Lbff9_keyboard_row_loop
#c046#5646
#c046#5646314
3a 83 76 
        ld a, (L7683_control_mode)
#c049#564928
fe 02 
        cp CONTROL_MODE_KEMPSTON_JOYSTICK
#c04b#564b213/8
20 3c 
        jr nz, Lc089_control_mode_not_kempston
#c04d#564d
        ; kemptson joystick controls:
#c04d#564d311
01 1f 00 
        ld bc, 31
#c050#5650214
ed 78 
        in a, (c)  ; read kempston joystick status
#c052#565215
47 
        ld b, a
#c053#565328
3e 95 
        ld a, 149
#c055#5655210
cb 60 
        bit 4, b
#c057#5657318/11
c4 78 c0 
        call nz, Lc078_accumulate_key_subroutine
#c05a#565a28
3e 91 
        ld a, 145
#c05c#565c210
cb 58 
        bit 3, b
#c05e#565e318/11
c4 78 c0 
        call nz, Lc078_accumulate_key_subroutine
#c061#566128
3e 92 
        ld a, 146
#c063#5663210
cb 50 
        bit 2, b
#c065#5665318/11
c4 78 c0 
        call nz, Lc078_accumulate_key_subroutine
#c068#566828
3e 93 
        ld a, 147
#c06a#566a210
cb 48 
        bit 1, b
#c06c#566c318/11
c4 78 c0 
        call nz, Lc078_accumulate_key_subroutine
#c06f#566f28
3e 94 
        ld a, 148
#c071#5671210
cb 40 
        bit 0, b
#c073#5673318/11
c4 78 c0 
        call nz, Lc078_accumulate_key_subroutine
#c076#5676213
18 11 
        jr Lc089_control_mode_not_kempston
#c078#5678
#c078#5678
; This is an auxiliary function defined inside of the key reading function:
#c078#5678
Lc078_accumulate_key_subroutine:
#c078#567818
12 
    ld (de), a
#c079#5679314
3a 9f 74 
    ld a, (L749f_number_of_pressed_keys)
#c07c#567c15
3c 
    inc a
#c07d#567d314
32 9f 74 
    ld (L749f_number_of_pressed_keys), a
#c080#568028
fe 05 
    cp MAX_PRESSED_KEYS
#c082#5682213/8
28 02 
    jr z, Lc086
#c084#568417
13 
    inc de
#c085#5685111
c9 
    ret
#c086#5686
#c086#5686
Lc086:
#c086#5686111
c1 
        pop bc  ; remove the return address from the stack (as there was a "call Lc078" to get here)
#c087#5687213
18 0b 
        jr Lc094_done_reading_keys
#c089#5689
#c089#5689
Lc089_control_mode_not_kempston:
#c089#5689314
3a 9f 74 
        ld a, (L749f_number_of_pressed_keys)
#c08c#568c15
b7 
        or a
#c08d#568d213/8
20 05 
        jr nz, Lc094_done_reading_keys
#c08f#568f
        ; No keys pressed
#c08f#568f314
32 ab bf 
        ld (Lbfab_previous_number_of_pressed_keys), a
#c092#5692213
18 56 
        jr Lc0ea_pop_bc_de_hl_ix_and_return
#c094#5694
Lc094_done_reading_keys:
#c094#569415
47 
        ld b, a
#c095#5695314
3a ab bf 
        ld a, (Lbfab_previous_number_of_pressed_keys)
#c098#569815
b8 
        cp b
#c099#5699213/8
20 24 
        jr nz, Lc0bf_keys_pressed_different_than_before
#c09b#569b
        ; Same number of keys pressed as before:
#c09b#569b311
21 a0 74 
        ld hl, L74a0_pressed_keys_buffer
#c09e#569e311
11 ec 74 
        ld de, L74ec_previous_pressed_keys_buffer
#c0a1#56a1
        ; Compare the current pressed keys to the previous ones:
#c0a1#56a1
Lc0a1_compare_keys_to_previous_loop:
#c0a1#56a118
1a 
        ld a, (de)
#c0a2#56a218
be 
        cp (hl)
#c0a3#56a3213/8
20 1a 
        jr nz, Lc0bf_keys_pressed_different_than_before  ; At least one key is different
#c0a5#56a517
13 
        inc de
#c0a6#56a617
23 
        inc hl
#c0a7#56a7214/9
10 f8 
        djnz Lc0a1_compare_keys_to_previous_loop
#c0a9#56a9314
3a aa bf 
        ld a, (Ld0cf_keyboard_first_key_repeat)
#c0ac#56ac15
b7 
        or a
#c0ad#56ad213/8
20 2a 
        jr nz, Lc0d9_not_first_keyboard_read_attempt
#c0af#56af15
3c 
        inc a
#c0b0#56b0314
32 aa bf 
        ld (Ld0cf_keyboard_first_key_repeat), a
#c0b3#56b3
        ; If we have the same keys pressed as before,
#c0b3#56b3
        ; and (Ld0cf_keyboard_first_key_repeat) == 0, we check the keyboard again.
#c0b3#56b3314
3a cf d0 
        ld a, (Ld0cf_keyboard_hold_delays)  ; First key press delay
#c0b6#56b6314
32 f1 74 
        ld (L74f1), a  ; Note: I believe this is unused (written, but never read)
#c0b9#56b9314
32 a5 74 
        ld (L74a5_interrupt_timer), a
#c0bc#56bc311
c3 d9 bf 
        jp Lbfd9_read_keyboard_and_joystick_input_internal
#c0bf#56bf
Lc0bf_keys_pressed_different_than_before:
#c0bf#56bf15
af 
        xor a
#c0c0#56c0314
32 aa bf 
        ld (Ld0cf_keyboard_first_key_repeat), a
#c0c3#56c315
47 
        ld b, a
#c0c4#56c4314
3a 9f 74 
        ld a, (L749f_number_of_pressed_keys)
#c0c7#56c7314
32 ab bf 
        ld (Lbfab_previous_number_of_pressed_keys), a
#c0ca#56ca15
4f 
        ld c, a
#c0cb#56cb311
21 a0 74 
        ld hl, L74a0_pressed_keys_buffer
#c0ce#56ce311
11 ec 74 
        ld de, L74ec_previous_pressed_keys_buffer
#c0d1#56d1223/18
ed b0 
        ldir
#c0d3#56d3314
3a a0 74 
        ld a, (L74a0_pressed_keys_buffer)  ; return the first key pressed
#c0d6#56d615
37 
        scf  ; mark that there is a key being pressed
#c0d7#56d7213
18 11 
        jr Lc0ea_pop_bc_de_hl_ix_and_return
#c0d9#56d9
Lc0d9_not_first_keyboard_read_attempt:
#c0d9#56d9314
3a a5 74 
        ld a, (L74a5_interrupt_timer)
#c0dc#56dc15
b7 
        or a
#c0dd#56dd311
c2 d9 bf 
        jp nz, Lbfd9_read_keyboard_and_joystick_input_internal
#c0e0#56e0314
3a d0 d0 
        ld a, (Ld0cf_keyboard_hold_delays + 1)  ; non-first repeat keyboard delay
#c0e3#56e3314
32 a5 74 
        ld (L74a5_interrupt_timer), a
#c0e6#56e6314
3a a0 74 
        ld a, (L74a0_pressed_keys_buffer)  ; return the first key pressed
#c0e9#56e915
37 
        scf  ; mark that there is a key being pressed
#c0ea#56ea
Lc0ea_pop_bc_de_hl_ix_and_return:
#c0ea#56ea111
c1 
    pop bc
#c0eb#56eb111
d1 
    pop de
#c0ec#56ec111
e1 
    pop hl
#c0ed#56ed216
dd e1 
    pop ix
#c0ef#56ef111
c9 
    ret
#c0f0#56f0
#c0f0#56f0
#c0f0#56f0
; --------------------------------
#c0f0#56f0
; Gets the initial area pointers, and initializes the following variables accordingly:
#c0f0#56f0
; - L746e_global_rules_ptr
#c0f0#56f0
; - L7465_global_area_n_objects
#c0f0#56f0
; - L7463_global_area_objects
#c0f0#56f0
Lc0f0_get_initial_area_pointers:
#c0f0#56f0217
dd e5 
    push ix
#c0f2#56f2112
e5 
    push hl
#c0f3#56f3112
d5 
    push de
#c0f4#56f4112
c5 
    push bc
#c0f5#56f5112
f5 
    push af
#c0f6#56f6311
11 82 d0 
        ld de, Ld082_area_reference_start
#c0f9#56f9317
2a c6 d0 
        ld hl, (Ld0c6_global_rules_offset)
#c0fc#56fc112
19 
        add hl, de
#c0fd#56fd317
22 6e 74 
        ld (L746e_global_rules_ptr), hl
#c100#5700314
3a ca d0 
        ld a, (Ld0ca_speed_when_running)
#c103#5703314
32 b5 6a 
        ld (L6ab5_current_speed), a
#c106#570615
af 
        xor a
#c107#5707314
32 be 6a 
        ld (L6abe_use_eye_player_coordinate), a
#c10a#570a314
32 bd 6a 
        ld (L6abd_cull_by_rendering_volume_flag), a  ; turn on volume culling
#c10d#570d314
3a 82 d0 
        ld a, (Ld082_n_areas)
#c110#571015
47 
        ld b, a
#c111#571128
3e ff 
        ld a, #ff
#c113#5713311
21 d1 d0 
        ld hl, Ld0d1_area_offsets
#c116#5716
Lc116_find_area_loop:
#c116#571618
5e 
        ld e, (hl)
#c117#571717
23 
        inc hl
#c118#571818
56 
        ld d, (hl)
#c119#571917
23 
        inc hl
#c11a#571a416
dd 21 82 d0 
        ld ix, Ld082_area_reference_start
#c11e#571e217
dd 19 
        add ix, de
#c120#5720321
dd be 02 
        cp (ix + AREA_ID)
#c123#5723213/8
28 08 
        jr z, Lc12d_area_found
#c125#5725214/9
10 ef 
        djnz Lc116_find_area_loop
#c127#572715
af 
        xor a
#c128#5728314
32 65 74 
        ld (L7465_global_area_n_objects), a
#c12b#572b213
18 0f 
        jr Lc13c_area_not_found
#c12d#572d
Lc12d_area_found:
#c12d#572d321
dd 7e 01 
        ld a, (ix + AREA_N_OBJECTS)
#c130#5730314
32 65 74 
        ld (L7465_global_area_n_objects), a
#c133#5733311
11 08 00 
        ld de, AREA_HEADER_SIZE
#c136#5736217
dd 19 
        add ix, de
#c138#5738422
dd 22 63 74 
        ld (L7463_global_area_objects), ix
#c13c#573c
Lc13c_area_not_found:
#c13c#573c111
f1 
    pop af
#c13d#573d111
c1 
    pop bc
#c13e#573e111
d1 
    pop de
#c13f#573f111
e1 
    pop hl
#c140#5740216
dd e1 
    pop ix
#c142#5742111
c9 
    ret
#c143#5743
#c143#5743
#c143#5743
; --------------------------------
#c143#5743
; Searches the area with ID (L6acf_current_area_id), loads it into the 
#c143#5743
; game variables, and resets all the necessary state.
#c143#5743
Lc143_load_and_reset_current_area:
#c143#5743217
dd e5 
    push ix
#c145#5745112
e5 
    push hl
#c146#5746112
d5 
    push de
#c147#5747112
c5 
    push bc
#c148#5748112
f5 
    push af
#c149#574915
af 
        xor a
#c14a#574a314
32 21 6b 
        ld (L6b21_time_unit6_previous), a
#c14d#574d314
32 22 6b 
        ld (L6b22_time_unit6), a
#c150#575015
3c 
        inc a
#c151#5751314
32 75 74 
        ld (L7475_call_Lcba4_check_for_player_falling_flag), a
#c154#5754314
32 66 74 
        ld (L7466_need_attribute_refresh_flag), a
#c157#5757314
32 77 74 
        ld (L7477_render_buffer_effect), a  ; fade in effect
#c15a#575a314
3a 82 d0 
        ld a, (Ld082_n_areas)
#c15d#575d15
47 
        ld b, a
#c15e#575e314
3a cf 6a 
        ld a, (L6acf_current_area_id)
#c161#5761311
21 d1 d0 
        ld hl, Ld0d1_area_offsets
#c164#5764
Lc164_find_area_loop:
#c164#576418
5e 
        ld e, (hl)
#c165#576517
23 
        inc hl
#c166#576618
56 
        ld d, (hl)
#c167#576717
23 
        inc hl
#c168#5768416
dd 21 82 d0 
        ld ix, Ld082_n_areas
#c16c#576c217
dd 19 
        add ix, de
#c16e#576e321
dd be 02 
        cp (ix + AREA_ID)
#c171#5771213/8
28 05 
        jr z, Lc178_area_found
#c173#5773214/9
10 ef 
        djnz Lc164_find_area_loop
#c175#5775311
c3 f3 c1 
        jp Lc1f3_done
#c178#5778
Lc178_area_found:
#c178#5778321
dd 7e 00 
        ld a, (ix + AREA_FLAGS)
#c17b#577b314
32 19 6b 
        ld (L6b19_current_area_flags), a
#c17e#577e321
dd 7e 01 
        ld a, (ix + AREA_N_OBJECTS)
#c181#5781314
32 d0 6a 
        ld (L6ad0_current_area_n_objects), a
#c184#5784321
dd 5e 03 
        ld e, (ix + AREA_RULES_OFFSET)
#c187#5787321
dd 56 04 
        ld d, (ix + AREA_RULES_OFFSET + 1)
#c18a#578a217
dd e5 
        push ix
#c18c#578c217
dd 19 
            add ix, de
#c18e#578e422
dd 22 d5 6a 
            ld (L6ad5_current_area_rules), ix
#c192#5792216
dd e1 
        pop ix
#c194#5794321
dd 7e 05 
        ld a, (ix + AREA_SCALE)
#c197#5797314
32 bc 6a 
        ld (L6abc_current_room_scale), a
#c19a#579a15
47 
        ld b, a
#c19b#579b314
3a b5 6a 
        ld a, (L6ab5_current_speed)
#c19e#579e15
6f 
        ld l, a
#c19f#579f28
26 00 
        ld h, 0
#c1a1#57a115
78 
        ld a, b
#c1a2#57a2318
cd 08 a1 
        call La108_a_times_hl_signed
#c1a5#57a5317
22 b3 6a 
        ld (L6ab3_current_speed_in_this_room), hl
#c1a8#57a815
68 
        ld l, b
#c1a9#57a9314
3a cc d0 
        ld a, (Ld0cc_max_failling_height_in_room_units)
#c1ac#57ac15
67 
        ld h, a
#c1ad#57ad318
cd 53 a2 
        call La253_h_times_l_signed
#c1b0#57b015
7d 
        ld a, l
#c1b1#57b1314
32 ba 6a 
        ld (L6aba_max_falling_height_without_damage), a
#c1b4#57b415
68 
        ld l, b
#c1b5#57b5314
3a cd d0 
        ld a, (Ld0cd_max_climbable_height_in_room_units)
#c1b8#57b815
67 
        ld h, a
#c1b9#57b9318
cd 53 a2 
        call La253_h_times_l_signed
#c1bc#57bc15
7d 
        ld a, l
#c1bd#57bd314
32 bb 6a 
        ld (L6abb_max_climbable_height), a
#c1c0#57c015
68 
        ld l, b
#c1c1#57c1314
3a b8 6a 
        ld a, (L6ab8_player_crawling)
#c1c4#57c415
67 
        ld h, a
#c1c5#57c5318
cd 53 a2 
        call La253_h_times_l_signed
#c1c8#57c815
7d 
        ld a, l
#c1c9#57c9314
32 b9 6a 
        ld (L6ab9_player_height), a
#c1cc#57cc28
16 00 
        ld d, 0
#c1ce#57ce321
dd 7e 06 
        ld a, (ix + AREA_ATTRIBUTE)
#c1d1#57d1314
32 dd 6a 
        ld (L6add_desired_attribute_color), a
#c1d4#57d4321
dd 6e 07 
        ld l, (ix + AREA_NAME)
#c1d7#57d715
62 
        ld h, d
#c1d8#57d828
1e 08 
        ld e, 8
#c1da#57da217
dd 19 
        add ix, de  ; ix += 8 (skip header)
#c1dc#57dc422
dd 22 d1 6a 
        ld (L6ad1_current_area_objects), ix
#c1e0#57e0112
29 
        add hl, hl
#c1e1#57e1112
29 
        add hl, hl
#c1e2#57e2112
29 
        add hl, hl
#c1e3#57e3112
29 
        add hl, hl
#c1e4#57e4311
11 49 6f 
        ld de, L6f49_area_names
#c1e7#57e7112
19 
        add hl, de  ; hl = #6f49 + (ix + 7) * 16
#c1e8#57e8311
11 bf 6a 
        ld de, L6abf_current_area_name_string
#c1eb#57eb311
01 10 00 
        ld bc, 16
#c1ee#57ee223/18
ed b0 
        ldir
#c1f0#57f0318
cd 1c c8 
        call Lc81c_reset_global_area_objects
#c1f3#57f3
Lc1f3_done:
#c1f3#57f3111
f1 
    pop af
#c1f4#57f4111
c1 
    pop bc
#c1f5#57f5111
d1 
    pop de
#c1f6#57f6111
e1 
    pop hl
#c1f7#57f7216
dd e1 
    pop ix
#c1f9#57f9111
c9 
    ret
#c1fa#57fa
#c1fa#57fa
#c1fa#57fa
; --------------------------------
#c1fa#57fa
Lc1fa_text_spaces:
#c1fa#57fa24
    db 0, "                       "
#c212#5812
Lc212:
#c212#58121
    db 103  ; Number of rows to compute pointers for.
#c213#5813
Lc213_last_described_key:
#c213#58131
    db 0  ; Last key for which description message was shown.
#c214#5814
Lc214_key_description_message_indexes:
#c214#5814
    ; These index the "L6cb9_game_text" array.
#c214#581410
    db #34, #36, #3a, #3d, #41, #47, #4b, #4d, #4f, #50
#c21e#581e
Lc21e:
#c21e#581e2
    dw #0f00
#c220#5820
Lc220:  ; Note: I believe this is unused (written, but never read)
#c220#58202
    dw #0d00
#c222#5822
Lc222_text_dash:
#c222#58222
    db #00, "-"
#c224#5824
#c224#5824
#c224#5824
; --------------------------------
#c224#5824
; Load/Save/Quit menu
#c224#5824
Lc224_load_save_quit_menu:
#c224#5824
    ; If the number of keys pressed is != 1, just return:
#c224#5824314
3a 9f 74 
    ld a, (L749f_number_of_pressed_keys)
#c227#582728
fe 01 
    cp 1
#c229#5829311
c2 9a c3 
    jp nz, Lc39a_return
#c22c#582c
#c22c#582c28
3e 06 
    ld a, 6
#c22e#582e314
32 79 74 
    ld (L7479_current_game_state), a
#c231#5831
#c231#5831
    ; Clear the render buffer:
#c231#5831311
21 bc 5c 
    ld hl, L5cbc_render_buffer
#c234#583415
54 
    ld d, h
#c235#583515
5d 
    ld e, l
#c236#583617
13 
    inc de
#c237#5837211
36 00 
    ld (hl), 0
#c239#5839311
01 97 0a 
    ld bc, (SCREEN_HEIGHT * 8 + 1) * SCREEN_WIDTH - 1
#c23c#583c223/18
ed b0 
    ldir
#c23e#583e
#c23e#583e311
21 11 c2 
    ld hl, Lc212 - 1  ; Compute pointers for 103 rows
#c241#5841318
cd 4f ca 
    call Lca4f_calculate_pixel_row_pointers
#c244#5844318
cd 9b c3 
    call Lc39b_update_number_of_collected_keys_text
#c247#5847318
cd cb c3 
    call Lc3cb_update_number_of_spirits_destroyed_text
#c24a#584a318
cd b8 c3 
    call Lc3b8_update_score_text
#c24d#584d311
21 1a 72 
    ld hl, L721a_text_asterisks
#c250#5850416
dd 21 76 66 
    ld ix, L6664_row_pointers + 9 * 2
#c254#5854311
11 0b 13 
    ld de, #130b  ; length 19, offset 11
#c257#5857318
cd 1c d0 
    call Ld01c_draw_string
#c25a#585a416
dd 21 24 67 
    ld ix, L6664_row_pointers + 96 * 2
#c25e#585e318
cd 1c d0 
    call Ld01c_draw_string
#c261#5861311
21 1f 7d 
    ld hl, L7d1f_text_save_load_quit
#c264#5864416
dd 21 94 66 
    ld ix, L6664_row_pointers + 24 * 2
#c268#5868311
11 06 14 
    ld de, #1406
#c26b#586b318
cd 1c d0 
    call Ld01c_draw_string
#c26e#586e311
21 34 7d 
    ld hl, L7d34_text_keys
#c271#5871416
dd 21 be 66 
    ld ix, L6664_row_pointers + 45 * 2
#c275#5875311
11 0d 04 
    ld de, #040d
#c278#5878318
cd 1c d0 
    call Ld01c_draw_string
#c27b#587b311
21 4a 7d 
    ld hl, L7d4a_text_collected
#c27e#587e422
ed 5b 1e c2 
    ld de, (49694)
#c282#5882318
cd 1c d0 
    call Ld01c_draw_string
#c285#5885311
21 39 7d 
    ld hl, L7d39_text_spirits
#c288#5888416
dd 21 d4 66 
    ld ix, L6664_row_pointers + 56 * 2
#c28c#588c311
11 04 07 
    ld de, #0704
#c28f#588f318
cd 1c d0 
    call Ld01c_draw_string
#c292#5892311
21 5a 7d 
    ld hl, L7d5a_text_destroyed
#c295#5895422
ed 5b 20 c2 
    ld de, (49696)
#c299#5899318
cd 1c d0 
    call Ld01c_draw_string
#c29c#589c311
21 41 7d 
    ld hl, L7d41_text_strength
#c29f#589f416
dd 21 ea 66 
    ld ix, L6664_row_pointers + 67 * 2
#c2a3#58a3311
11 0d 08 
    ld de, #080d
#c2a6#58a6318
cd 1c d0 
    call Ld01c_draw_string
#c2a9#58a9311
11 0b 00 
    ld de, 11  ; size of each strength text
#c2ac#58ac311
21 c9 71 
    ld hl, L71c9_text_status_array
#c2af#58af
    ; Strength text is "(L6b0a_current_strength - 1) / 4"
#c2af#58af314
3a 0a 6b 
    ld a, (L6b0a_current_strength)
#c2b2#58b215
3d 
    dec a
#c2b3#58b3
Lc2b3_strength_text_loop:
#c2b3#58b328
d6 04 
    sub 4
#c2b5#58b5213/8
38 03 
    jr c, Lc2ba
#c2b7#58b7112
19 
    add hl, de
#c2b8#58b8213
18 f9 
    jr Lc2b3_strength_text_loop
#c2ba#58ba
Lc2ba:
#c2ba#58ba311
11 67 09 
    ld de, #0967
#c2bd#58bd318
cd 1c d0 
    call Ld01c_draw_string  ; Draw current strength
#c2c0#58c0311
21 6a 7d 
    ld hl, L7d6a_text_score
#c2c3#58c3416
dd 21 00 67 
    ld ix, L6664_row_pointers + 78 * 2
#c2c7#58c7311
11 23 0f 
    ld de, #0f23
#c2ca#58ca318
cd 1c d0 
    call Ld01c_draw_string
#c2cd#58cd
#c2cd#58cd15
af 
    xor a
#c2ce#58ce314
32 13 c2 
    ld (Lc213_last_described_key), a
#c2d1#58d1
    ; Clear the row pointers:
#c2d1#58d1311
21 64 66 
    ld hl, L6664_row_pointers
#c2d4#58d415
54 
    ld d, h
#c2d5#58d515
5d 
    ld e, l
#c2d6#58d617
13 
    inc de
#c2d7#58d718
77 
    ld (hl), a
#c2d8#58d8311
01 ef 00 
    ld bc, 240 - 1
#c2db#58db223/18
ed b0 
    ldir
#c2dd#58dd
#c2dd#58dd
    ; Set the attributes to grey:
#c2dd#58dd314
3a d9 6a 
    ld a, (L6ad9_current_attribute_color)
#c2e0#58e015
5f 
    ld e, a
#c2e1#58e128
3e 07 
    ld a, 7  ; attribute to set the screen area to
#c2e3#58e3314
32 dd 6a 
    ld (L6add_desired_attribute_color), a
#c2e6#58e6318
cd 52 b2 
    call Lb252_set_screen_area_attributes
#c2e9#58e9
#c2e9#58e915
7b 
    ld a, e
#c2ea#58ea314
32 dd 6a 
    ld (L6add_desired_attribute_color), a  ; Save the color attribute we had before entering in this screen.
#c2ed#58ed28
3e 01 
    ld a, 1
#c2ef#58ef314
32 66 74 
    ld (L7466_need_attribute_refresh_flag), a  ; Set the flag on, so attributes are refreshed after exiting this screen.
#c2f2#58f2318
cd 79 b5 
    call Lb579_render_buffer_fade_in
#c2f5#58f5
#c2f5#58f5
    ; Menu main loop:
#c2f5#58f5
Lc2f5_wait_for_input_loop:
#c2f5#58f5318
cd d4 bf 
    call Lbfd4_read_keyboard_and_joystick_input
#c2f8#58f8213/8
30 fb 
    jr nc, Lc2f5_wait_for_input_loop
#c2fa#58fa311
11 06 01 
    ld de, #0106
#c2fd#58fd28
fe 53 
    cp "S"
#c2ff#58ff213/8
28 06 
    jr z, Lc307
#c301#590128
fe 4c 
    cp "L"
#c303#5903213/8
20 2b 
    jr nz, Lc330_no_load_or_save
#c305#590528
1e 45 
    ld e, 69
#c307#5907
Lc307:
#c307#5907
    ; These calls draw directly to video memory, instead of to the draw buffer:
#c307#5907311
21 22 c2 
    ld hl, Lc222_text_dash
#c30a#590a416
dd 21 96 72 
    ld ix, L725c_videomem_row_pointers + 29 * 2
#c30e#590e318
cd 15 d0 
    call Ld015_draw_string_without_erasing
#c311#5911311
21 fa c1 
    ld hl, Lc1fa_text_spaces
#c314#5914311
11 04 14 
    ld de, #1404
#c317#5917416
dd 21 b6 72 
    ld ix, L725c_videomem_row_pointers + 45 * 2
#c31b#591b311
01 16 00 
    ld bc, 22
#c31e#591e112
f5 
    push af
#c31f#591f
        ; Clear 4 lines of text (drawing spaces over them):
#c31f#591f28
3e 04 
        ld a, 4
#c321#5921
Lc321_clear_loop:
#c321#5921318
cd 1c d0 
        call Ld01c_draw_string
#c324#5924217
dd 09 
        add ix, bc
#c326#592615
3d 
        dec a
#c327#5927213/8
20 f8 
        jr nz, Lc321_clear_loop
#c329#5929111
f1 
    pop af
#c32a#592a318
cd 32 81 
    call L8132_load_or_save_to_tape
#c32d#592d311
c3 97 c3 
    jp Lc397
#c330#5930
Lc330_no_load_or_save:
#c330#593028
fe 4b 
    cp "K"  ; press 'K' to show descriptions of keys collected
#c332#5932213/8
20 46 
    jr nz, Lc37a_K_not_pressed
#c334#5934314
3a 0c 6b 
    ld a, (L6b0c_num_collected_keys)
#c337#593715
b7 
    or a
#c338#5938213/8
28 bb 
    jr z, Lc2f5_wait_for_input_loop  ; If there are no collected keys, ignore.
#c33a#593a416
dd 21 b6 72 
    ld ix, L725c_videomem_row_pointers + 45 * 2
#c33e#593e311
21 13 c2 
    ld hl, Lc213_last_described_key
#c341#594118
5e 
    ld e, (hl)
#c342#594215
3d 
    dec a
#c343#594318
be 
    cp (hl)
#c344#5944213/8
38 1a 
    jr c, Lc360  ; Circle around to show the first key again.
#c346#5946112
34 
    inc (hl)  ; Show next key:
#c347#594728
16 00 
    ld d, 0
#c349#5949311
21 0f 6b 
    ld hl, L6b0f_collected_keys
#c34c#594c112
19 
    add hl, de
#c34d#594d18
5e 
    ld e, (hl)
#c34e#594e311
21 14 c2 
    ld hl, Lc214_key_description_message_indexes
#c351#5951112
19 
    add hl, de
#c352#595218
46 
    ld b, (hl)
#c353#5953
    ; Get the pointer to the b-th text message in L6cb9_game_text:
#c353#5953311
21 b9 6c 
    ld hl, L6cb9_game_text
#c356#595628
1e 10 
    ld e, 16
#c358#5958
Lc358_get_text_ptr_loop:
#c358#5958112
19 
    add hl, de
#c359#5959214/9
10 fd 
    djnz Lc358_get_text_ptr_loop
#c35b#595b
#c35b#595b311
11 39 0f 
    ld de, #0f39
#c35e#595e213
18 09 
    jr Lc369
#c360#5960
Lc360:
#c360#5960211
36 00 
    ld (hl), 0
#c362#5962311
21 4a 7d 
    ld hl, L7d4a_text_collected
#c365#5965422
ed 5b 1e c2 
    ld de, (Lc21e)
#c369#5969
Lc369:
#c369#5969318
cd 1c d0 
    call Ld01c_draw_string
#c36c#596c28
3e 19 
    ld a, 25  ; wait for 25 interrupts to prevent cycling through keys too fast.
#c36e#596e314
32 a5 74 
    ld (L74a5_interrupt_timer), a
#c371#5971
Lc371_pause_loop:
#c371#5971314
3a a5 74 
    ld a, (L74a5_interrupt_timer)
#c374#597415
b7 
    or a
#c375#5975213/8
20 fa 
    jr nz, Lc371_pause_loop
#c377#5977311
c3 f5 c2 
    jp Lc2f5_wait_for_input_loop
#c37a#597a
Lc37a_K_not_pressed:
#c37a#597a112
f5 
    push af
#c37b#597b28
3e 0b 
        ld a, 11
#c37d#597d314
32 a5 74 
        ld (L74a5_interrupt_timer), a
#c380#5980318
cd 46 9d 
        call L9d46_render_3d_view
#c383#5983318
cd 52 b2 
        call Lb252_set_screen_area_attributes
#c386#5986318
cd 79 b5 
        call Lb579_render_buffer_fade_in
#c389#5989318
cd 48 b5 
        call Lb548_draw_pointer_if_pointer_mode
#c38c#598c111
f1 
    pop af
#c38d#598d
#c38d#598d28
fe 51 
    cp "Q"  ; press 'Q' to quite the game
#c38f#598f213/8
28 09 
    jr z, Lc39a_return
#c391#5991
    ; Any other key, goes back to the game
#c391#5991
Lc391_pause_loop:
#c391#5991314
3a a5 74 
    ld a, (L74a5_interrupt_timer)
#c394#599415
b7 
    or a
#c395#5995213/8
20 fa 
    jr nz, Lc391_pause_loop
#c397#5997
Lc397:
#c397#5997314
32 79 74 
    ld (L7479_current_game_state), a  ; set current game state to 0 (normal play).
#c39a#599a
Lc39a_return:
#c39a#599a111
c9 
    ret
#c39b#599b
#c39b#599b
#c39b#599b
; --------------------------------
#c39b#599b
; Updates the "XX COLLECTED" keys text with the actual number.
#c39b#599b
Lc39b_update_number_of_collected_keys_text:
#c39b#599b311
21 4c 7d 
    ld hl, L7d4a_text_collected + 2
#c39e#599e211
36 20 
    ld (hl), " "
#c3a0#59a028
16 39 
    ld d, 57
#c3a2#59a2314
3a 0c 6b 
    ld a, (L6b0c_num_collected_keys)
#c3a5#59a528
fe 0a 
    cp 10
#c3a7#59a7213/8
38 06 
    jr c, Lc3af_less_than_10
#c3a9#59a928
16 39 
    ld d, 57
#c3ab#59ab211
36 31 
    ld (hl), "1"
#c3ad#59ad28
d6 0a 
    sub 10
#c3af#59af
Lc3af_less_than_10:
#c3af#59af28
c6 30 
    add a, "0"
#c3b1#59b117
23 
    inc hl
#c3b2#59b218
77 
    ld (hl), a
#c3b3#59b315
7a 
    ld a, d
#c3b4#59b4314
32 1e c2 
    ld (Lc21e), a  ; Update the x_offset at which to draw the key description messages
#c3b7#59b7111
c9 
    ret
#c3b8#59b8
#c3b8#59b8
#c3b8#59b8
; --------------------------------
#c3b8#59b8
; Updates the "SCORE  XXXXXXX " string with the actual score.
#c3b8#59b8
Lc3b8_update_score_text:
#c3b8#59b8416
dd 21 72 7d 
    ld ix, L7d6a_text_score + 8  ; position of the number in the score string
#c3bc#59bc317
2a eb 6a 
    ld hl, (L6aeb_score)  ; lower 2 btes of the score
#c3bf#59bf314
3a ed 6a 
    ld a, (L6aeb_score + 2)  ; higher byte of the score
#c3c2#59c215
5f 
    ld e, a
#c3c3#59c328
16 00 
    ld d, 0
#c3c5#59c528
3e 07 
    ld a, 7  ; number of digits
#c3c7#59c7318
cd 1b bc 
    call Lbc1b_integer_to_ascii
#c3ca#59ca111
c9 
    ret
#c3cb#59cb
#c3cb#59cb
#c3cb#59cb
; --------------------------------
#c3cb#59cb
; Updates the " XX DESTROYED  " string with the actual number of spirits destroyed.
#c3cb#59cb
Lc3cb_update_number_of_spirits_destroyed_text:
#c3cb#59cb311
21 5c 7d 
    ld hl, L7d5a_text_destroyed + 2
#c3ce#59ce211
36 20 
    ld (hl), 32
#c3d0#59d028
16 43 
    ld d, 67
#c3d2#59d2314
3a 09 6b 
    ld a, (L6b09_number_of_spirits_destroyed)
#c3d5#59d528
0e 30 
    ld c, "0"  ; first digit
#c3d7#59d7
Lc3d7:
#c3d7#59d728
fe 0a 
    cp 10
#c3d9#59d9213/8
38 07 
    jr c, Lc3e2_tenths_found
#c3db#59db28
d6 0a 
    sub 10
#c3dd#59dd28
16 43 
    ld d, 67
#c3df#59df15
0c 
    inc c  ; first digit += 1
#c3e0#59e0213
18 f5 
    jr Lc3d7
#c3e2#59e2
Lc3e2_tenths_found:
#c3e2#59e228
c6 30 
    add a, "0"
#c3e4#59e417
23 
    inc hl
#c3e5#59e518
77 
    ld (hl), a  ; write tenths
#c3e6#59e615
7a 
    ld a, d
#c3e7#59e7314
32 20 c2 
    ld (Lc220), a  ; update position where to draw (but this is unused).
#c3ea#59ea15
79 
    ld a, c
#c3eb#59eb28
fe 30 
    cp "0"
#c3ed#59ed112/6
c8 
    ret z
#c3ee#59ee17
2b 
    dec hl
#c3ef#59ef18
77 
    ld (hl), a  ; write units
#c3f0#59f0111
c9 
    ret
#c3f1#59f1
#c3f1#59f1
#c3f1#59f1
; --------------------------------
#c3f1#59f1
; Unused?
#c3f1#59f13
    db #00, #00, #0d
#c3f4#59f4
#c3f4#59f4
#c3f4#59f4
; --------------------------------
#c3f4#59f4
; Reads a filename from keyboard input.
#c3f4#59f4
; Output:
#c3f4#59f4
; - a: name length.
#c3f4#59f4
; - hl: pointer to the edited name.
#c3f4#59f4
Lc3f4_read_filename:
#c3f4#59f4217
dd e5 
    push ix
#c3f6#59f6217
fd e5 
    push iy
#c3f8#59f8112
d5 
    push de
#c3f9#59f9112
c5 
    push bc
#c3fa#59fa317
2a cf d0 
        ld hl, (Ld0cf_keyboard_hold_delays)  ; Save previous keyboard delays
#c3fd#59fd112
e5 
        push hl
#c3fe#59fe311
21 23 05 
            ld hl, #0523  ; 35 interrupts delay for first repeat, 5 interrupts delay for subsequent repeats
#c401#5a01317
22 cf d0 
            ld (Ld0cf_keyboard_hold_delays), hl
#c404#5a04416
dd 21 bc 72 
            ld ix, L725c_videomem_row_pointers + 48 * 2
#c408#5a0828
3e 23 
            ld a, "#"  ; Cursor character.
#c40a#5a0a314
32 0c 72 
            ld (L720b_text_input_buffer + 1), a
#c40d#5a0d
            ; Clear the input buffer to all spaces:
#c40d#5a0d311
11 0d 72 
            ld de, L720b_text_input_buffer + 2
#c410#5a1028
06 0c 
            ld b, FILENAME_BUFFER_SIZE
#c412#5a1228
3e 20 
            ld a, " "
#c414#5a14
Lc414_clear_input_buffer_loop:
#c414#5a1418
12 
            ld (de), a
#c415#5a1517
13 
            inc de
#c416#5a16214/9
10 fc 
            djnz Lc414_clear_input_buffer_loop
#c418#5a18
#c418#5a18
            ; Draws the "filename :   " and input buffer texts to screen:
#c418#5a18311
21 7a 7d 
            ld hl, L7d7a_text_filename
#c41b#5a1b28
06 02 
            ld b, 2
#c41d#5a1d
Lc41d_draw_filename_and_input_buffer_loop:
#c41d#5a1d311
11 27 0d 
            ld de, #0d27
#c420#5a20318
cd 1c d0 
            call Ld01c_draw_string
#c423#5a23
#c423#5a23311
11 14 00 
            ld de, 10 * 2
#c426#5a26217
dd 19 
            add ix, de  ; move 10 pixels down
#c428#5a28311
21 0b 72 
            ld hl, L720b_text_input_buffer
#c42b#5a2b214/9
10 f0 
            djnz Lc41d_draw_filename_and_input_buffer_loop
#c42d#5a2d
#c42d#5a2d311
11 ec ff 
            ld de, -2 * 10
#c430#5a30217
dd 19 
            add ix, de  ; move back 10 pixels up
#c432#5a32416
fd 21 0c 72 
            ld iy, L720b_text_input_buffer + 1
#c436#5a36311
21 0b 72 
            ld hl, L720b_text_input_buffer
#c439#5a39311
11 27 0d 
            ld de, #0d27
#c43c#5a3c28
06 00 
            ld b, 0  ; Current editing position
#c43e#5a3e
Lc43e_wait_for_player_input_loop:
#c43e#5a3e318
cd d4 bf 
            call Lbfd4_read_keyboard_and_joystick_input
#c441#5a41213/8
30 fb 
            jr nc, Lc43e_wait_for_player_input_loop
#c443#5a4328
fe 7f 
            cp 127  ; "delete"
#c445#5a45213/8
20 1f 
            jr nz, Lc466_not_delete
#c447#5a47
            ; Check if this was produced by SHIFT + '0':
#c447#5a47314
3a 9f 74 
            ld a, (L749f_number_of_pressed_keys)
#c44a#5a4a28
fe 02 
            cp 2  ; Check if 2 keys re pressed simultaneously.
#c44c#5a4c213/8
20 f0 
            jr nz, Lc43e_wait_for_player_input_loop
#c44e#5a4e314
3a a1 74 
            ld a, (L74a0_pressed_keys_buffer + 1)
#c451#5a5128
fe 30 
            cp "0"
#c453#5a53213/8
20 e9 
            jr nz, Lc43e_wait_for_player_input_loop
#c455#5a5515
78 
            ld a, b
#c456#5a5615
b7 
            or a  ; If we are at the beginning of the string, we cannot delete.
#c457#5a57213/8
28 e5 
            jr z, Lc43e_wait_for_player_input_loop
#c459#5a59
            ; Delete last character:
#c459#5a5915
05 
            dec b
#c45a#5a5a421
fd 36 00 20 
            ld (iy), " "
#c45e#5a5e212
fd 2b 
            dec iy
#c460#5a60421
fd 36 00 23 
            ld (iy), "#"
#c464#5a64213
18 3d 
            jr Lc4a3_redraw_input_buffer
#c466#5a66
Lc466_not_delete:
#c466#5a6628
fe 1b 
            cp 27  ; symbol shift pressed
#c468#5a68213/8
20 12 
            jr nz, Lc47c_no_symbol_shift
#c46a#5a6a
            ; Check if it's shift + 'M' -> '.'
#c46a#5a6a314
3a 9f 74 
            ld a, (L749f_number_of_pressed_keys)
#c46d#5a6d28
fe 02 
            cp 2
#c46f#5a6f213/8
20 cd 
            jr nz, Lc43e_wait_for_player_input_loop
#c471#5a71314
3a a1 74 
            ld a, (L74a0_pressed_keys_buffer + 1)
#c474#5a7428
fe 4d 
            cp "M"
#c476#5a76213/8
20 c6 
            jr nz, Lc43e_wait_for_player_input_loop
#c478#5a7828
3e 2e 
            ld a, "."
#c47a#5a7a213
18 17 
            jr Lc493_type_character
#c47c#5a7c
Lc47c_no_symbol_shift:
#c47c#5a7c15
4f 
            ld c, a
#c47d#5a7d314
3a 9f 74 
            ld a, (L749f_number_of_pressed_keys)
#c480#5a8028
fe 01 
            cp 1
#c482#5a82213/8
20 ba 
            jr nz, Lc43e_wait_for_player_input_loop
#c484#5a8415
79 
            ld a, c
#c485#5a8528
fe 0d 
            cp 13  ; enter
#c487#5a87213/8
28 1f 
            jr z, Lc4a8_done_editing
#c489#5a8928
fe 20 
            cp " "  ; ignore anything below a space
#c48b#5a8b311
fa 3e c4 
            jp m, Lc43e_wait_for_player_input_loop
#c48e#5a8e28
fe 5b 
            cp "Z" + 1  ; ignore anything above 'Z'
#c490#5a90311
f2 3e c4 
            jp p, Lc43e_wait_for_player_input_loop
#c493#5a93
Lc493_type_character:
#c493#5a93
            ; Make sure we do not overflow the buffer:
#c493#5a9315
4f 
            ld c, a
#c494#5a9415
78 
            ld a, b
#c495#5a9528
fe 0c 
            cp FILENAME_BUFFER_SIZE
#c497#5a97213/8
28 a5 
            jr z, Lc43e_wait_for_player_input_loop
#c499#5a99
            ; Add a character:
#c499#5a9915
04 
            inc b
#c49a#5a9a321
fd 71 00 
            ld (iy), c
#c49d#5a9d212
fd 23 
            inc iy
#c49f#5a9f421
fd 36 00 23 
            ld (iy), "#"
#c4a3#5aa3
Lc4a3_redraw_input_buffer:
#c4a3#5aa3318
cd 1c d0 
            call Ld01c_draw_string
#c4a6#5aa6213
18 96 
            jr Lc43e_wait_for_player_input_loop
#c4a8#5aa8
Lc4a8_done_editing:
#c4a8#5aa8421
fd 36 00 20 
            ld (iy), " "  ; Replace cursor by space.
#c4ac#5aac318
cd 1c d0 
            call Ld01c_draw_string
#c4af#5aaf111
e1 
        pop hl
#c4b0#5ab0317
22 cf d0 
        ld (Ld0cf_keyboard_hold_delays), hl  ; Resore previous keyboard delays
#c4b3#5ab315
78 
        ld a, b
#c4b4#5ab4311
21 0c 72 
        ld hl, L720b_text_input_buffer + 1
#c4b7#5ab7111
c1 
    pop bc
#c4b8#5ab8111
d1 
    pop de
#c4b9#5ab9216
fd e1 
    pop iy
#c4bb#5abb216
dd e1 
    pop ix
#c4bd#5abd111
c9 
    ret
#c4be#5abe
#c4be#5abe
#c4be#5abe
; --------------------------------
#c4be#5abe
; Play SFX state
#c4be#5abe
Lc4be:
#c4be#5abe2
    dw 0
#c4c0#5ac0
Lc3c0:
#c4c0#5ac02
    dw 0
#c4c2#5ac2
Lc4c2:
#c4c2#5ac21
    db 0
#c4c3#5ac3
Lc4c3:
#c4c3#5ac32
    db 0, 0
#c4c5#5ac5
Lc4c5:
#c4c5#5ac52
    dw 0
#c4c7#5ac7
Lc4c7:
#c4c7#5ac73
    db 0, 0, 0
#c4ca#5aca
#c4ca#5aca
#c4ca#5aca
; --------------------------------
#c4ca#5aca
; Plays an SFX
#c4ca#5aca
; Input:
#c4ca#5aca
; - a: SFX ID
#c4ca#5aca
Lc4ca_play_SFX:
#c4ca#5aca217
dd e5 
    push ix
#c4cc#5acc217
fd e5 
    push iy
#c4ce#5ace112
e5 
    push hl
#c4cf#5acf112
d5 
    push de
#c4d0#5ad0112
c5 
    push bc
#c4d1#5ad1112
f5 
    push af
#c4d2#5ad215
f3 
        di
#c4d3#5ad315
3d 
        dec a
#c4d4#5ad4210
cb 27 
        sla a
#c4d6#5ad6210
cb 27 
        sla a
#c4d8#5ad815
5f 
        ld e, a
#c4d9#5ad928
16 00 
        ld d, 0  ; de = (a - 1) * 4  (offset of the SFX in the SFX table)
#c4db#5adb311
21 bf 75 
        ld hl, L75bf_SFX_table
#c4de#5ade112
19 
        add hl, de
#c4df#5adf18
5e 
        ld e, (hl)
#c4e0#5ae017
23 
        inc hl
#c4e1#5ae118
4e 
        ld c, (hl)
#c4e2#5ae217
23 
        inc hl
#c4e3#5ae318
46 
        ld b, (hl)
#c4e4#5ae4422
ed 43 be c4 
        ld (Lc4be), bc
#c4e8#5ae817
23 
        inc hl
#c4e9#5ae918
7e 
        ld a, (hl)
#c4ea#5aea416
dd 21 c2 c4 
        ld ix, Lc4c2
#c4ee#5aee321
dd 77 00 
        ld (ix), a
#c4f1#5af1311
21 fb 75 
        ld hl, L75fb_SFX_data
#c4f4#5af4112
19 
        add hl, de
#c4f5#5af5112
19 
        add hl, de
#c4f6#5af6112
19 
        add hl, de
#c4f7#5af7112
19 
        add hl, de
#c4f8#5af818
7e 
        ld a, (hl)
#c4f9#5af917
23 
        inc hl
#c4fa#5afa210
cb 7f 
        bit 7, a
#c4fc#5afc311
c2 83 c5 
        jp nz, Lc583
#c4ff#5aff321
dd 77 04 
        ld (ix + 4), a
#c502#5b02317
22 c0 c4 
        ld (Lc3c0), hl
#c505#5b05421
dd 36 05 00 
        ld (ix + 5), 0
#c509#5b09
Lc509:
#c509#5b0918
46 
        ld b, (hl)
#c50a#5b0a321
dd 70 01 
        ld (ix + 1), b
#c50d#5b0d17
23 
        inc hl
#c50e#5b0e18
7e 
        ld a, (hl)
#c50f#5b0f321
dd 77 02 
        ld (ix + 2), a
#c512#5b1217
23 
        inc hl
#c513#5b1318
7e 
        ld a, (hl)
#c514#5b14321
dd 77 03 
        ld (ix + 3), a
#c517#5b17
Lc517:
#c517#5b17321
dd 7e 03 
        ld a, (ix + 3)
#c51a#5b1a311
21 d0 00 
        ld hl, 208
#c51d#5b1d318
cd 08 a1 
        call La108_a_times_hl_signed
#c520#5b20422
ed 5b be c4 
        ld de, (Lc4be)
#c524#5b24318
cd cc a1 
        call La1cc_a_hl_divided_by_de_signed
#c527#5b2717
23 
        inc hl
#c528#5b28112
e5 
        push hl
#c529#5b29317
2a be c4 
            ld hl, (Lc4be)
#c52c#5b2c28
3e 07 
            ld a, 7
#c52e#5b2e318
cd 08 a1 
            call La108_a_times_hl_signed
#c531#5b31311
11 1e 00 
            ld de, 30
#c534#5b3415
b7 
            or a
#c535#5b35217
ed 52 
            sbc hl, de
#c537#5b37311
f2 3d c5 
            jp p, Lc53d
#c53a#5b3a311
21 01 00 
            ld hl, 1
#c53d#5b3d
Lc53d:
#c53d#5b3d111
d1 
        pop de
#c53e#5b3e217
dd e5 
        push ix
#c540#5b40112
c5 
        push bc
#c541#5b41318
cd 43 c6 
            call Lc643_play_sfx_beep
#c544#5b44111
c1 
        pop bc
#c545#5b45216
dd e1 
        pop ix
#c547#5b47317
2a be c4 
        ld hl, (Lc4be)
#c54a#5b4a28
16 00 
        ld d, 0
#c54c#5b4c321
dd 5e 02 
        ld e, (ix + 2)
#c54f#5b4f210
cb 7b 
        bit 7, e
#c551#5b51213/8
28 01 
        jr z, Lc554
#c553#5b5315
15 
        dec d
#c554#5b54
Lc554:
#c554#5b54112
19 
        add hl, de
#c555#5b5515
7c 
        ld a, h
#c556#5b5628
e6 0f 
        and 15
#c558#5b5815
67 
        ld h, a
#c559#5b59317
22 be c4 
        ld (Lc4be), hl
#c55c#5b5c214/9
10 b9 
        djnz Lc517
#c55e#5b5e325
dd 34 05 
        inc (ix + 5)
#c561#5b61321
dd 7e 05 
        ld a, (ix + 5)
#c564#5b64321
dd be 04 
        cp (ix + 4)
#c567#5b67213/8
20 0f 
        jr nz, Lc578
#c569#5b69325
dd 35 00 
        dec (ix)
#c56c#5b6c311
ca 39 c6 
        jp z, Lc639
#c56f#5b6f317
2a c0 c4 
        ld hl, (Lc3c0)
#c572#5b72421
dd 36 05 00 
        ld (ix + 5), 0
#c576#5b76213
18 91 
        jr Lc509
#c578#5b78
Lc578:
#c578#5b78317
2a c0 c4 
        ld hl, (Lc3c0)
#c57b#5b7b28
16 00 
        ld d, 0
#c57d#5b7d15
5f 
        ld e, a
#c57e#5b7e112
19 
        add hl, de
#c57f#5b7f112
19 
        add hl, de
#c580#5b80112
19 
        add hl, de
#c581#5b81213
18 86 
        jr Lc509
#c583#5b83
Lc583:
#c583#5b83311
11 c3 c4 
        ld de, Lc4c3
#c586#5b86311
01 07 00 
        ld bc, 7
#c589#5b89223/18
ed b0 
        ldir
#c58b#5b8b28
e6 7f 
        and 127
#c58d#5b8d28
fe 01 
        cp 1
#c58f#5b8f213/8
28 35 
        jr z, Lc5c6
#c591#5b9128
fe 02 
        cp 2
#c593#5b93213/8
28 56 
        jr z, Lc5eb
#c595#5b95314
3a c2 c4 
        ld a, (Lc4c2)
#c598#5b9815
47 
        ld b, a
#c599#5b9928
3e 00 
        ld a, 0
#c59b#5b9b
Lc59b:
#c59b#5b9b112
c5 
        push bc
#c59c#5b9c422
ed 4b c3 c4 
            ld bc, (Lc4c3)
#c5a0#5ba028
26 00 
            ld h, 0
#c5a2#5ba2
Lc5a2:
#c5a2#5ba2212
d3 fe 
            out (ULA_PORT), a
#c5a4#5ba428
ee 10 
            xor 16
#c5a6#5ba6112
f5 
            push af
#c5a7#5ba715
af 
                xor a
#c5a8#5ba815
6f 
                ld l, a
#c5a9#5ba915
55 
                ld d, l
#c5aa#5baa15
5c 
                ld e, h
#c5ab#5bab217
ed 52 
                sbc hl, de
#c5ad#5bad217
ed 52 
                sbc hl, de
#c5af#5baf15
59 
                ld e, c
#c5b0#5bb0112
19 
                add hl, de
#c5b1#5bb115
7d 
                ld a, l
#c5b2#5bb215
94 
                sub h
#c5b3#5bb3213/8
38 01 
                jr c, Lc5b6
#c5b5#5bb515
3d 
                dec a
#c5b6#5bb6
Lc5b6:
#c5b6#5bb615
67 
                ld h, a
#c5b7#5bb7
Lc5b7:
#c5b7#5bb715
3d 
                dec a
#c5b8#5bb8213/8
20 fd 
                jr nz, Lc5b7
#c5ba#5bba111
f1 
            pop af
#c5bb#5bbb214/9
10 e5 
            djnz Lc5a2
#c5bd#5bbd111
c1 
        pop bc
#c5be#5bbe214/9
10 db 
        djnz Lc59b
#c5c0#5bc028
3e 00 
        ld a, 0
#c5c2#5bc2212
d3 fe 
        out (ULA_PORT), a  ; black border, and no sound.
#c5c4#5bc4213
18 73 
        jr Lc639
#c5c6#5bc6
Lc5c6:
#c5c6#5bc6321
dd 46 00 
        ld b, (ix)
#c5c9#5bc9
Lc5c9:
#c5c9#5bc9112
c5 
        push bc
#c5ca#5bca422
ed 5b c3 c4 
            ld de, (Lc4c3)
#c5ce#5bce317
2a be c4 
            ld hl, (Lc4be)
#c5d1#5bd1
Lc5d1:
#c5d1#5bd1112
d5 
            push de
#c5d2#5bd2422
ed 5b c5 c4 
                ld de, (Lc4c5)
#c5d6#5bd6112
e5 
                push hl
#c5d7#5bd7318
cd 43 c6 
                    call Lc643_play_sfx_beep
#c5da#5bda111
e1 
                pop hl
#c5db#5bdb422
ed 5b c7 c4 
                ld de, (Lc4c7)
#c5df#5bdf112
19 
                add hl, de
#c5e0#5be0111
d1 
            pop de
#c5e1#5be117
1b 
            dec de
#c5e2#5be215
7b 
            ld a, e
#c5e3#5be315
b2 
            or d
#c5e4#5be4213/8
20 eb 
            jr nz, Lc5d1
#c5e6#5be6111
c1 
        pop bc
#c5e7#5be7214/9
10 e0 
        djnz Lc5c9
#c5e9#5be9213
18 4e 
        jr Lc639
#c5eb#5beb
Lc5eb:
#c5eb#5beb321
dd 7e 04 
        ld a, (ix + 4)
#c5ee#5bee311
11 41 10 
        ld de, #1041  ; "ld c, b; djnz ..."
#c5f1#5bf1311
21 fe 00 
        ld hl, #00fe  ; "... -3; nop"
#c5f4#5bf415
b7 
        or a
#c5f5#5bf5213/8
28 0c 
        jr z, Lc603
#c5f7#5bf728
1e 43 
        ld e, 67
#c5f9#5bf928
fe 02 
        cp 2
#c5fb#5bfb213/8
28 06 
        jr z, Lc603
#c5fd#5bfd311
11 45 05 
        ld de, #0545  ; "ld b, l; dec b"
#c600#5c00311
21 20 fd 
        ld hl, #fd20  ; "jr nz, -3"
#c603#5c03
Lc603:
#c603#5c03422
ed 53 29 c6 
        ld (Lc629_self_modifying), de
#c607#5c07317
22 2b c6 
        ld (Lc62b_self_modifying), hl
#c60a#5c0a321
dd 56 00 
        ld d, (ix)
#c60d#5c0d321
dd 5e 01 
        ld e, (ix + 1)
#c610#5c10321
dd 4e 02 
        ld c, (ix + 2)
#c613#5c13321
dd 66 03 
        ld h, (ix + 3)
#c616#5c1628
2e ff 
        ld l, 255
#c618#5c1828
3e 00 
        ld a, 0
#c61a#5c1a
Lc61a:
#c61a#5c1a28
f6 18 
        or 24
#c61c#5c1c212
d3 fe 
        out (ULA_PORT), a
#c61e#5c1e15
41 
        ld b, c
#c61f#5c1f
Lc61f:
#c61f#5c1f214/9
10 fe 
        djnz Lc61f
#c621#5c2115
44 
        ld b, h
#c622#5c22
Lc622:
#c622#5c22214/9
10 fe 
        djnz Lc622
#c624#5c2428
e6 0f 
        and 15
#c626#5c26212
d3 fe 
        out (ULA_PORT), a
#c628#5c2817
1b 
        dec de
#c629#5c29
Lc629_self_modifying:
#c629#5c2915
00 
        nop
#c62a#5c2a15
00 
        nop
#c62b#5c2b
Lc62b_self_modifying:
#c62b#5c2b15
00 
        nop
#c62c#5c2c15
00 
        nop
#c62d#5c2d15
47 
        ld b, a
#c62e#5c2e314
3a c7 c4 
        ld a, (Lc4c7)
#c631#5c3115
81 
        add a, c
#c632#5c3215
4f 
        ld c, a
#c633#5c3315
7a 
        ld a, d
#c634#5c3415
b3 
        or e
#c635#5c3515
6f 
        ld l, a
#c636#5c3615
78 
        ld a, b
#c637#5c37213/8
20 e1 
        jr nz, Lc61a
#c639#5c39
Lc639:
#c639#5c39111
f1 
    pop af
#c63a#5c3a15
fb 
    ei
#c63b#5c3b111
c1 
    pop bc
#c63c#5c3c111
d1 
    pop de
#c63d#5c3d111
e1 
    pop hl
#c63e#5c3e216
fd e1 
    pop iy
#c640#5c40216
dd e1 
    pop ix
#c642#5c42111
c9 
    ret
#c643#5c43
#c643#5c43
#c643#5c43
; --------------------------------
#c643#5c43
; Plays a "beep" (used in the play SFX function to generate the different SFX).
#c643#5c43
; Input:
#c643#5c43
; - h: duration of the beep
#c643#5c43
; - l: frequency of the beep
#c643#5c43
Lc643_play_sfx_beep:
#c643#5c4315
7d 
    ld a, l
#c644#5c44210
cb 3d 
    srl l
#c646#5c46210
cb 3d 
    srl l
#c648#5c4815
2f 
    cpl
#c649#5c4928
e6 03 
    and 3
#c64b#5c4b15
4f 
    ld c, a
#c64c#5c4c28
06 00 
    ld b, 0  ; bc = (255 - l) & #03
#c64e#5c4e416
dd 21 58 c6 
    ld ix, Lc658_pause
#c652#5c52217
dd 09 
    add ix, bc  ; set the exact amount of "nops" we will execute in each loop
#c654#5c5428
3e 00 
    ld a, 0
#c656#5c5628
f6 08 
    or 8  ; OPTIMIZATION: these two instructions are the same as ld a, 8
#c658#5c58
Lc658_pause:
#c658#5c5815
00 
    nop
#c659#5c5915
00 
    nop
#c65a#5c5a15
00 
    nop
#c65b#5c5b15
04 
    inc b
#c65c#5c5c15
0c 
    inc c
#c65d#5c5d
Lc65d_pause_loop:
#c65d#5c5d15
0d 
    dec c
#c65e#5c5e213/8
20 fd 
    jr nz, Lc65d_pause_loop
#c660#5c6028
0e 3f 
    ld c, 63
#c662#5c6215
05 
    dec b
#c663#5c63311
c2 5d c6 
    jp nz, Lc65d_pause_loop
#c666#5c6628
ee 10 
    xor 16  ; alternate between sound and no sound
#c668#5c68212
d3 fe 
    out (ULA_PORT), a  ; produce sound
#c66a#5c6a15
44 
    ld b, h
#c66b#5c6b15
4f 
    ld c, a
#c66c#5c6c210
cb 67 
    bit 4, a
#c66e#5c6e213/8
20 09 
    jr nz, Lc679
#c670#5c7015
7a 
    ld a, d
#c671#5c7115
b3 
    or e
#c672#5c72213/8
28 09 
    jr z, Lc67d
#c674#5c7415
79 
    ld a, c
#c675#5c7515
4d 
    ld c, l
#c676#5c7617
1b 
    dec de
#c677#5c77210
dd e9 
    jp ix  ; jumps back to Lc658_pause (+0, +1, +2, or +3)
#c679#5c79
Lc679:
#c679#5c7915
4d 
    ld c, l
#c67a#5c7a15
0c 
    inc c
#c67b#5c7b210
dd e9 
    jp ix  ; jumps back to Lc658_pause (+0, +1, +2, or +3)
#c67d#5c7d
Lc67d:
#c67d#5c7d111
c9 
    ret  ; OPTIMIZATION: remove, and make the jump here just ret z
#c67e#5c7e
#c67e#5c7e
#c67e#5c7e
; --------------------------------
#c67e#5c7e
; Title screen text positions and strings:
#c67e#5c7e
Lc67e_title_screen_text_attributes:
#c67e#5c7e
    ; Each block is:
#c67e#5c7e
    ; - string ptr., pointer to buffer ptr.
#c67e#5c7e
    ; - x offset (pixel), length
#c67e#5c7e4
    dw Lc6ae, L6664_row_pointers + 8 * 2
#c682#5c822
    db #1b, 15
#c684#5c84
Lc684:
#c684#5c844
    dw Lc6be, L6664_row_pointers + 28 * 2
#c688#5c882
    db 16, 10
#c68a#5c8a
Lc68a:
#c68a#5c8a4
    dw Lc6c9, L6664_row_pointers + 38 * 2
#c68e#5c8e2
    db 16, 19
#c690#5c90
Lc690:
#c690#5c904
    dw Lc6dd, L6664_row_pointers + 48 * 2
#c694#5c942
    db 16, 19
#c696#5c96
Lc696:
#c696#5c964
    dw Lc6f1, L6664_row_pointers + 58 * 2
#c69a#5c9a2
    db 16, 17
#c69c#5c9c
Lc69c:
#c69c#5c9c4
    dw Lc703, L6664_row_pointers + 78 * 2
#c6a0#5ca02
    db 7, 20
#c6a2#5ca2
Lc6a2:
#c6a2#5ca24
    dw Lc718, L6664_row_pointers + 94 * 2
#c6a6#5ca62
    db 25, 16
#c6a8#5ca8
Lc6a8:
#c6a8#5ca84
    dw Lc72b, L6664_row_pointers + 28 * 2
#c6ac#5cac2
    db 4, 1
#c6ae#5cae
#c6ae#5cae
Lc6ae:
#c6ae#5cae16
    db 0, "CONTROL OPTIONS"
#c6be#5cbe
Lc6be:
#c6be#5cbe11
    db 0, "1 KEYBOARD"
#c6c9#5cc9
Lc6c9:
#c6c9#5cc920
    db 0, "2 SINCLAIR JOYSTICK"
#c6dd#5cdd
Lc6dd:
#c6dd#5cdd20
    db 0, "3 KEMPSTON JOYSTICK"
#c6f1#5cf1
Lc6f1:
#c6f1#5cf118
    db 0, "4 CURSOR JOYSTICK"
#c703#5d03
Lc703:
#c703#5d0321
    db 0, "ENTER: BEGIN MISSION"
#c718#5d18
Lc718:
#c718#5d1817
    db 0, "% 1990 INCENTIVE"
#c729#5d29
Lc729_text_space:
#c729#5d292
    db 0, " "
#c72b#5d2b
Lc72b:
#c72b#5d2b2
    db 0, "@"
#c72d#5d2d
#c72d#5d2d1
    db 103  ; # of pixel rows to calculate pointers for in the title screen
#c72e#5d2e
#c72e#5d2e
#c72e#5d2e
; --------------------------------
#c72e#5d2e
; Title screen loop
#c72e#5d2e
Lc72e_title_screen_loop:
#c72e#5d2e217
dd e5 
    push ix
#c730#5d30112
e5 
    push hl
#c731#5d31112
d5 
    push de
#c732#5d32112
c5 
    push bc
#c733#5d33112
f5 
    push af
#c734#5d34
        ; Clear the render buffer:
#c734#5d34311
21 bc 5c 
        ld hl, L5cbc_render_buffer
#c737#5d3715
54 
        ld d, h
#c738#5d3815
5d 
        ld e, l
#c739#5d3917
13 
        inc de
#c73a#5d3a211
36 00 
        ld (hl), 0
#c73c#5d3c311
01 97 0a 
        ld bc, (SCREEN_HEIGHT * 8 + 1) * SCREEN_WIDTH - 1
#c73f#5d3f223/18
ed b0 
        ldir
#c741#5d41311
21 2c c7 
        ld hl, Lc72b + 1
#c744#5d44318
cd 4f ca 
        call Lca4f_calculate_pixel_row_pointers
#c747#5d4728
3e 07 
        ld a, 7  ; draw 7 strings
#c749#5d49311
21 7e c6 
        ld hl, Lc67e_title_screen_text_attributes
#c74c#5d4c
Lc74c_title_screen_draw_loop:
#c74c#5d4c18
4e 
        ld c, (hl)
#c74d#5d4d17
23 
        inc hl
#c74e#5d4e18
46 
        ld b, (hl)  ; string ptr.
#c74f#5d4f17
23 
        inc hl
#c750#5d5018
5e 
        ld e, (hl)
#c751#5d5117
23 
        inc hl
#c752#5d5218
56 
        ld d, (hl)  ; buffer ptr.
#c753#5d5317
23 
        inc hl
#c754#5d54112
d5 
        push de
#c755#5d55216
dd e1 
        pop ix  ; ix = buffer ptr (where to draw the string).
#c757#5d5718
5e 
        ld e, (hl)  ; x offset
#c758#5d5817
23 
        inc hl
#c759#5d5918
56 
        ld d, (hl)  ; string length
#c75a#5d5a17
23 
        inc hl
#c75b#5d5b112
e5 
        push hl
#c75c#5d5c15
60 
            ld h, b
#c75d#5d5d15
69 
            ld l, c  ; hl = string ptr
#c75e#5d5e318
cd 1c d0 
            call Ld01c_draw_string
#c761#5d61111
e1 
        pop hl
#c762#5d6215
3d 
        dec a
#c763#5d63213/8
20 e7 
        jr nz, Lc74c_title_screen_draw_loop
#c765#5d65
#c765#5d65
        ; Clear the pixel row pointers:
#c765#5d65311
21 64 66 
        ld hl, L6664_row_pointers
#c768#5d6815
54 
        ld d, h
#c769#5d6915
5d 
        ld e, l
#c76a#5d6a17
13 
        inc de
#c76b#5d6b18
77 
        ld (hl), a
#c76c#5d6c311
01 ef 00 
        ld bc, 10 * SCREEN_WIDTH - 1
#c76f#5d6f223/18
ed b0 
        ldir
#c771#5d71
#c771#5d71
        ; Set the color attributes of the title screen:
#c771#5d7128
3e 07 
        ld a, 7
#c773#5d73311
21 84 58 
        ld hl, L5800_VIDEOMEM_ATTRIBUTES + 4 * 32 + 4
#c776#5d76311
11 08 00 
        ld de, 8  ; skip 4 rows to the right/left of the viewport
#c779#5d7928
0e 0e 
        ld c, SCREEN_HEIGHT
#c77b#5d7b
Lc77b_title_attributes_y_loop:
#c77b#5d7b28
06 18 
        ld b, SCREEN_WIDTH
#c77d#5d7d
Lc77d_title_attributes_x_loop:
#c77d#5d7d18
77 
        ld (hl), a
#c77e#5d7e17
23 
        inc hl
#c77f#5d7f214/9
10 fc 
        djnz Lc77d_title_attributes_x_loop
#c781#5d81112
19 
        add hl, de
#c782#5d8215
0d 
        dec c
#c783#5d83213/8
20 f6 
        jr nz, Lc77b_title_attributes_y_loop
#c785#5d85
#c785#5d85318
cd 79 b5 
        call Lb579_render_buffer_fade_in
#c788#5d88311
01 f8 0b 
        ld bc, L725c_videomem_row_pointers - L6664_row_pointers
#c78b#5d8b422
ed 5b ac c6 
        ld de, (Lc6a8 + 4)  ; x, y of the arrow
#c78f#5d8f213
18 31 
        jr Lc7c2_title_screen_arrow
#c791#5d91
Lc791_title_loop:
#c791#5d91318
cd d4 bf 
        call Lbfd4_read_keyboard_and_joystick_input
#c794#5d94213/8
30 fb 
        jr nc, Lc791_title_loop
#c796#5d9628
fe 0d 
        cp 13  ; ENTER KEY
#c798#5d98213/8
28 51 
        jr z, Lc7eb_title_enter_pressed
#c79a#5d9a28
fe 31 
        cp "1"
#c79c#5d9c311
fa 91 c7 
        jp m, Lc791_title_loop
#c79f#5d9f28
fe 35 
        cp "5"
#c7a1#5da1311
f2 91 c7 
        jp p, Lc791_title_loop
#c7a4#5da428
d6 31 
        sub "1"
#c7a6#5da615
6f 
        ld l, a  ; l = 0, 1, 2, or 3 for the control mode
#c7a7#5da7314
3a 83 76 
        ld a, (L7683_control_mode)
#c7aa#5daa15
bd 
        cp l
#c7ab#5dab213/8
28 e4 
        jr z, Lc791_title_loop  ; if we have not changed the mode, just loop back
#c7ad#5dad15
7d 
        ld a, l
#c7ae#5dae314
32 83 76 
        ld (L7683_control_mode), a  ; set current control mode
#c7b1#5db1422
dd 2a aa c6 
        ld ix, (Lc6a8 + 2)  ; pointer where to draw
#c7b5#5db5217
dd 09 
        add ix, bc
#c7b7#5db7311
21 29 c7 
        ld hl, Lc729_text_space
#c7ba#5dba318
cd 1c d0 
        call Ld01c_draw_string
#c7bd#5dbd28
3e 03 
        ld a, SFX_MENU_SELECT
#c7bf#5dbf318
cd ca c4 
        call Lc4ca_play_SFX
#c7c2#5dc2
Lc7c2_title_screen_arrow:
#c7c2#5dc2314
3a 83 76 
        ld a, (L7683_control_mode)
#c7c5#5dc5317
2a 86 c6 
        ld hl, (Lc684 + 2)  ; keyboard string
#c7c8#5dc815
b7 
        or a
#c7c9#5dc9213/8
28 0f 
        jr z, Lc7da
#c7cb#5dcb317
2a 8c c6 
        ld hl, (Lc68a + 2)  ; sinclair joystick string
#c7ce#5dce15
3d 
        dec a
#c7cf#5dcf213/8
28 09 
        jr z, Lc7da
#c7d1#5dd1317
2a 92 c6 
        ld hl, (Lc690 + 2)  ; kempston joystick string
#c7d4#5dd415
3d 
        dec a
#c7d5#5dd5213/8
28 03 
        jr z, Lc7da
#c7d7#5dd7317
2a 98 c6 
        ld hl, (Lc696 + 2)  ; cursor joystick string
#c7da#5dda
Lc7da:
#c7da#5dda317
22 aa c6 
        ld (Lc6a8 + 2), hl
#c7dd#5ddd422
dd 2a aa c6 
        ld ix, (Lc6a8 + 2)  ; pointer where to draw
#c7e1#5de1217
dd 09 
        add ix, bc  ; Go from "L6664_row_pointers" to "L725c_videomem_row_pointers".
#c7e3#5de3311
21 2b c7 
        ld hl, Lc72b  ; arrow string
#c7e6#5de6318
cd 1c d0 
        call Ld01c_draw_string
#c7e9#5de9213
18 a6 
        jr Lc791_title_loop
#c7eb#5deb
#c7eb#5deb
Lc7eb_title_enter_pressed:
#c7eb#5deb
        ; Adjust the input mapping, depending on the control mode:
#c7eb#5deb311
11 09 00 
        ld de, 9
#c7ee#5dee311
21 84 76 
        ld hl, L7684_input_mapping
#c7f1#5df1314
3a 83 76 
        ld a, (L7683_control_mode)
#c7f4#5df428
fe 01 
        cp CONTROL_MODE_SINCLAIR_JOYSTICK
#c7f6#5df6213/8
20 0d 
        jr nz, Lc805_no_sinclair_joystick
#c7f8#5df8211
36 39 
        ld (hl), "9"  ; up
#c7fa#5dfa112
19 
        add hl, de
#c7fb#5dfb211
36 38 
        ld (hl), "8"  ; down
#c7fd#5dfd112
19 
        add hl, de
#c7fe#5dfe211
36 36 
        ld (hl), "6"  ; left
#c800#5e00112
19 
        add hl, de
#c801#5e01211
36 37 
        ld (hl), "7"  ; right
#c803#5e03213
18 0b 
        jr Lc810
#c805#5e05
Lc805_no_sinclair_joystick:
#c805#5e05211
36 37 
        ld (hl), "7"  ; up
#c807#5e07112
19 
        add hl, de
#c808#5e08211
36 36 
        ld (hl), "6"  ; down
#c80a#5e0a112
19 
        add hl, de
#c80b#5e0b211
36 35 
        ld (hl), "5"  ; left
#c80d#5e0d112
19 
        add hl, de
#c80e#5e0e211
36 38 
        ld (hl), "8"  ; right
#c810#5e10
Lc810:
#c810#5e1028
3e 03 
        ld a, SFX_MENU_SELECT
#c812#5e12318
cd ca c4 
        call Lc4ca_play_SFX
#c815#5e15111
f1 
    pop af
#c816#5e16111
c1 
    pop bc
#c817#5e17111
d1 
    pop de
#c818#5e18111
e1 
    pop hl
#c819#5e19216
dd e1 
    pop ix
#c81b#5e1b111
c9 
    ret
#c81c#5e1c
#c81c#5e1c
#c81c#5e1c
; --------------------------------
#c81c#5e1c
; Resets the state of all the objects in the current area.
#c81c#5e1c
Lc81c_reset_global_area_objects:
#c81c#5e1c217
dd e5 
    push ix
#c81e#5e1e112
e5 
    push hl
#c81f#5e1f112
d5 
    push de
#c820#5e20112
c5 
    push bc
#c821#5e21112
f5 
    push af
#c822#5e22314
3a 65 74 
        ld a, (L7465_global_area_n_objects)
#c825#5e2515
b7 
        or a
#c826#5e26213/8
28 4c 
        jr z, Lc874_done
#c828#5e2828
16 00 
        ld d, 0
#c82a#5e2a422
dd 2a 63 74 
        ld ix, (L7463_global_area_objects)
#c82e#5e2e15
47 
        ld b, a
#c82f#5e2f
Lc82f_object_reset_loop:
#c82f#5e2f
        ; Reset object flags:
#c82f#5e2f321
dd 7e 00 
        ld a, (ix + OBJECT_TYPE_AND_FLAGS)
#c832#5e3228
e6 8f 
        and #8f
#c834#5e3428
f6 40 
        or #40
#c836#5e36321
dd 77 00 
        ld (ix + OBJECT_TYPE_AND_FLAGS), a
#c839#5e39321
dd 5e 08 
        ld e, (ix + OBJECT_SIZE)
#c83c#5e3c217
dd 19 
        add ix, de
#c83e#5e3e214/9
10 ef 
        djnz Lc82f_object_reset_loop
#c840#5e40
#c840#5e4028
3e ff 
        ld a, #ff
#c842#5e42314
32 68 74 
        ld (L7468_focus_object_id), a
#c845#5e4515
af 
        xor a
#c846#5e46318
cd 86 b2 
        call Lb286_find_object_by_id
#c849#5e4915
b7 
        or a
#c84a#5e4a213/8
20 28 
        jr nz, Lc874_done
#c84c#5e4c
        ; Object with ID #ff found!
#c84c#5e4c
        ; This is the "global room structure of the area":
#c84c#5e4c217
dd e5 
        push ix
#c84e#5e4e111
e1 
        pop hl  ; hl = object ptr
#c84f#5e4f321
dd 7e 08 
        ld a, (ix + OBJECT_SIZE)
#c852#5e5228
d6 03 
        sub 3
#c854#5e5415
47 
        ld b, a
#c855#5e5528
0e 00 
        ld c, 0  ; bc = number of rooms
#c857#5e57
        ; Each byte except for 0, 7 and 8 (hence the "sub 3" above) in this object represents an object ID:
#c857#5e57
Lc857_reset_objects_in_room_structure_loop:
#c857#5e5717
23 
        inc hl
#c858#5e5818
7e 
        ld a, (hl)
#c859#5e5915
b7 
        or a
#c85a#5e5a213/8
28 0e 
        jr z, Lc86a_skip_object
#c85c#5e5c314
32 68 74 
        ld (L7468_focus_object_id), a
#c85f#5e5f15
af 
        xor a
#c860#5e60318
cd 86 b2 
        call Lb286_find_object_by_id
#c863#5e6315
b7 
        or a
#c864#5e64213/8
20 04 
        jr nz, Lc86a_skip_object
#c866#5e66
        ; Reset the state of the object pointed to in the global state:
#c866#5e66425
dd cb 00 b6 
        res 6, (ix + OBJECT_TYPE_AND_FLAGS)
#c86a#5e6a
Lc86a_skip_object:
#c86a#5e6a15
0c 
        inc c
#c86b#5e6b15
79 
        ld a, c
#c86c#5e6c28
fe 06 
        cp 6
#c86e#5e6e213/8
20 02 
        jr nz, Lc872
#c870#5e70
        ; skip object ID and size
#c870#5e7017
23 
        inc hl
#c871#5e7117
23 
        inc hl
#c872#5e72
Lc872:
#c872#5e72214/9
10 e3 
        djnz Lc857_reset_objects_in_room_structure_loop
#c874#5e74
Lc874_done:
#c874#5e74111
f1 
    pop af
#c875#5e75111
c1 
    pop bc
#c876#5e76111
d1 
    pop de
#c877#5e77111
e1 
    pop hl
#c878#5e78216
dd e1 
    pop ix
#c87a#5e7a111
c9 
    ret
#c87b#5e7b
#c87b#5e7b
#c87b#5e7b
; --------------------------------
#c87b#5e7b
; Clears the render buffer, and then fades-in to this new version, effectively
#c87b#5e7b
; achieving a fade-out to black effect.
#c87b#5e7b
Lc87b_fade_out:
#c87b#5e7b112
e5 
    push hl
#c87c#5e7c112
d5 
    push de
#c87d#5e7d112
c5 
    push bc
#c87e#5e7e
        ; Clear the render buffer:
#c87e#5e7e311
21 bc 5c 
        ld hl, L5cbc_render_buffer
#c881#5e8115
54 
        ld d, h
#c882#5e8215
5d 
        ld e, l
#c883#5e8317
13 
        inc de
#c884#5e84211
36 00 
        ld (hl), 0
#c886#5e86311
01 97 0a 
        ld bc, (SCREEN_HEIGHT * 8 + 1) * SCREEN_WIDTH - 1
#c889#5e89223/18
ed b0 
        ldir
#c88b#5e8b
        ; Fade-in to this new black buffer:
#c88b#5e8b318
cd 79 b5 
        call Lb579_render_buffer_fade_in
#c88e#5e8e111
c1 
    pop bc
#c88f#5e8f111
d1 
    pop de
#c890#5e90111
e1 
    pop hl
#c891#5e91111
c9 
    ret
#c892#5e92
#c892#5e92
#c892#5e92
; --------------------------------
#c892#5e92
; Draw sprite local variables:
#c892#5e92
Lc892_draw_sprite_and_mask:  ; The "and-mask" to use for dropping pixels in the last byte of each row
#c892#5e921
    db #ff  ; in case the sprite width is not a multiple of 8 pixels.
#c893#5e93
Lc893_draw_sprite_within_byte_offset:
#c893#5e931
    db #04
#c894#5e94
Lc894_mode3_tmp_storage:
#c894#5e941
    db #00
#c895#5e95
#c895#5e95
#c895#5e95
; --------------------------------
#c895#5e95
; Draws a sprite to video memory. It contains 3 alternative drawing routines:
#c895#5e95
; - mode 1 (easy): sprite is aligned to the horizontal 8-pixel grid.
#c895#5e95
; - mode 2 (shifted): sprite data needs to be shifted, as the z coordinate
#c895#5e95
;                     is not aligned to the 8-pixel grid.
#c895#5e95
; - mode 3 (over-write): in this mode, the sprite does not erase the background
#c895#5e95
;                        (only the 1s are added, but the 0s do not erase the background).
#c895#5e95
; Note: the and-mask is only applied to the last byte in each row. This is used to copy
#c895#5e95
;       graphics that have a width in pixels that is not a multiple of 8.
#c895#5e95
; Input:
#c895#5e95
; - hl: pointer to attributes: width, height, and-mask, frame size, sprite data
#c895#5e95
; - d: frame to draw (most significant bit determines drawing mode)
#c895#5e95
; - e: x_offset
#c895#5e95
; - ix: Pointer to the sequence of row pointers where to draw each row.
#c895#5e95
Lc895_draw_sprite_to_ix_ptrs:
#c895#5e95217
dd e5 
    push ix
#c897#5e97217
fd e5 
    push iy
#c899#5e99112
e5 
    push hl
#c89a#5e9a112
d5 
    push de
#c89b#5e9b112
c5 
    push bc
#c89c#5e9c112
f5 
    push af
#c89d#5e9d15
f3 
        di  ; Disable interrupts while drawing
#c89e#5e9e18
4e 
        ld c, (hl)  ; Width of buffer to draw in bytes
#c89f#5e9f17
23 
        inc hl
#c8a0#5ea018
46 
        ld b, (hl)  ; Height of buffer to draw in bytes
#c8a1#5ea1112
c5 
        push bc
#c8a2#5ea2112
d5 
        push de
#c8a3#5ea315
42 
            ld b, d
#c8a4#5ea417
23 
            inc hl
#c8a5#5ea518
7e 
            ld a, (hl)  ; We read the and mask (for the last byte)
#c8a6#5ea6314
32 92 c8 
            ld (Lc892_draw_sprite_and_mask), a
#c8a9#5ea917
23 
            inc hl
#c8aa#5eaa18
5e 
            ld e, (hl)  ; Frame size (low byte)
#c8ab#5eab17
23 
            inc hl
#c8ac#5eac18
56 
            ld d, (hl)  ; Frame size (high byte)
#c8ad#5ead17
23 
            inc hl
#c8ae#5eae210
cb b8 
            res 7, b
#c8b0#5eb015
78 
            ld a, b
#c8b1#5eb1
            ; Get the pointer to the sprite:
#c8b1#5eb115
b7 
            or a
#c8b2#5eb2213/8
28 03 
            jr z, Lc8b7_ptr_set
#c8b4#5eb4
Lc8b4_ptr_loop:
#c8b4#5eb4112
19 
            add hl, de
#c8b5#5eb5214/9
10 fd 
            djnz Lc8b4_ptr_loop
#c8b7#5eb7
Lc8b7_ptr_set:
#c8b7#5eb7111
d1 
        pop de
#c8b8#5eb8111
c1 
        pop bc
#c8b9#5eb9
        ; If the "x_offset" is not a multiple of 8, use drawing mode 2
#c8b9#5eb915
7b 
        ld a, e
#c8ba#5eba28
e6 07 
        and 7
#c8bc#5ebc213/8
20 37 
        jr nz, Lc8f5_drawing_mode2
#c8be#5ebe
        ; If we explicitly called for drawing mode 3, go to mode 2 first,
#c8be#5ebe
        ; as the check for mode 3 is there:
#c8be#5ebe210
cb 7a 
        bit 7, d
#c8c0#5ec0213/8
20 33 
        jr nz, Lc8f5_drawing_mode2
#c8c2#5ec2
#c8c2#5ec2
        ; Drawing mode 1: Simple case, bytes can be copied directly
#c8c2#5ec2
        ;                 (sprite aligned with the horizontal 8 pixel grid).
#c8c2#5ec215
7b 
        ld a, e  ; Translate the pixel offset into a byte offset
#c8c3#5ec3210
cb 3f 
        srl a
#c8c5#5ec5210
cb 3f 
        srl a
#c8c7#5ec7210
cb 3f 
        srl a
#c8c9#5ec9
Lc8c9_mode1_draw_loop:
#c8c9#5ec9112
c5 
        push bc
#c8ca#5eca112
f5 
        push af
#c8cb#5ecb
            ; Add the drawing address "(ix)" to the pixel offset "a":
#c8cb#5ecb321
dd 86 00 
            add a, (ix)
#c8ce#5ece15
5f 
            ld e, a
#c8cf#5ecf321
dd 7e 01 
            ld a, (ix + 1)
#c8d2#5ed228
ce 00 
            adc a, 0
#c8d4#5ed415
57 
            ld d, a
#c8d5#5ed5
#c8d5#5ed5212
dd 23 
            inc ix
#c8d7#5ed7212
dd 23 
            inc ix  ; To get the next row pointer
#c8d9#5ed915
0d 
            dec c  ; Copy "c - 1" bytes (hl) -> (de)
#c8da#5eda213/8
28 04 
            jr z, Lc8e0_skip_copy
#c8dc#5edc28
06 00 
            ld b, 0
#c8de#5ede223/18
ed b0 
            ldir
#c8e0#5ee0
Lc8e0_skip_copy:
#c8e0#5ee0
            ; For the last byte of each row, we apply the "and mask":
#c8e0#5ee0314
3a 92 c8 
            ld a, (Lc892_draw_sprite_and_mask)  ; restore the and mask
#c8e3#5ee315
4f 
            ld c, a
#c8e4#5ee418
a6 
            and (hl)  ; "and" with the last byte in the row
#c8e5#5ee515
47 
            ld b, a
#c8e6#5ee615
79 
            ld a, c
#c8e7#5ee715
2f 
            cpl  ; invert "and mask" 
#c8e8#5ee815
eb 
            ex de, hl
#c8e9#5ee918
a6 
                and (hl)  ; "and" with the byte in the destination
#c8ea#5eea15
b0 
                or b  ; add the masked-byte from source
#c8eb#5eeb18
77 
                ld (hl), a  ; write result
#c8ec#5eec15
eb 
            ex de, hl
#c8ed#5eed17
23 
            inc hl  ; next byte
#c8ee#5eee111
f1 
        pop af
#c8ef#5eef111
c1 
        pop bc
#c8f0#5ef0214/9
10 d7 
        djnz Lc8c9_mode1_draw_loop
#c8f2#5ef2311
c3 3e ca 
        jp Lca3e_draw_complete
#c8f5#5ef5
#c8f5#5ef5
Lc8f5_drawing_mode2:
#c8f5#5ef5
        ; Drawing mode 2:
#c8f5#5ef5
        ; "a" contains the x_offset % 8 here:
#c8f5#5ef5314
32 93 c8 
        ld (Lc893_draw_sprite_within_byte_offset), a
#c8f8#5ef815
7b 
        ld a, e  ; Translate the pixel offset into a byte offset
#c8f9#5ef9210
cb 3f 
        srl a
#c8fb#5efb210
cb 3f 
        srl a
#c8fd#5efd210
cb 3f 
        srl a
#c8ff#5eff210
cb 7a 
        bit 7, d  ; Check if drawing mode 3 is requested:
#c901#5f01311
c2 b7 c9 
        jp nz, Ld015_drawing_mode3
#c904#5f04
Lc904_mode2_row_loop:
#c904#5f04112
c5 
        push bc
#c905#5f05112
f5 
        push af
#c906#5f06
            ; Add the drawing address "(ix)" to the pixel offset "a":
#c906#5f06321
dd 86 00 
            add a, (ix)
#c909#5f0915
5f 
            ld e, a
#c90a#5f0a321
dd 7e 01 
            ld a, (ix + 1)
#c90d#5f0d28
ce 00 
            adc a, 0
#c90f#5f0f15
57 
            ld d, a
#c910#5f10
#c910#5f10212
dd 23 
            inc ix
#c912#5f12212
dd 23 
            inc ix  ; To get the next row pointer
#c914#5f14112
d5 
            push de
#c915#5f15216
fd e1 
            pop iy  ; iy = address where to draw.
#c917#5f1728
16 00 
            ld d, 0
#c919#5f1918
5e 
            ld e, (hl)  ; Read the byte to draw
#c91a#5f1a314
3a 93 c8 
            ld a, (Lc893_draw_sprite_within_byte_offset)
#c91d#5f1d15
47 
            ld b, a
#c91e#5f1e28
3e 80 
            ld a, #80  ; "a" will contain the "and mask" to use
#c920#5f20
Lc920_shift_byte_loop:
#c920#5f20210
cb 3b 
            srl e
#c922#5f22210
cb 2f 
            sra a
#c924#5f24214/9
10 fa 
            djnz Lc920_shift_byte_loop
#c926#5f2615
87 
            add a, a  ; we have shifted "a" one extra position to the right (since it started at #80),
#c927#5f27
                      ; so, we correct this by shifting it 1 bit to the left.
#c927#5f2715
0d 
            dec c  ; Check if this sprite is just 1 byte wide
#c928#5f28213/8
20 19 
            jr nz, Lc943_mode2_wider_than_one_byte
#c92a#5f2a
            ; This is the last byte in this row:
#c92a#5f2a15
4f 
            ld c, a
#c92b#5f2b314
3a 93 c8 
            ld a, (Lc893_draw_sprite_within_byte_offset)
#c92e#5f2e15
47 
            ld b, a
#c92f#5f2f
            ; we not also shift the "and mask":
#c92f#5f2f314
3a 92 c8 
            ld a, (Lc892_draw_sprite_and_mask)
#c932#5f3215
2f 
            cpl
#c933#5f33
Lc933_mode2_and_mask_shift_loop:
#c933#5f33210
cb 3f 
            srl a
#c935#5f35214/9
10 fc 
            djnz Lc933_mode2_and_mask_shift_loop
#c937#5f3715
b1 
            or c  ; we add the "and mask" we computed above
#c938#5f38
            ; draw the byte ("iy" contains the address in video memory, and "e" the byte to draw)
#c938#5f38321
fd a6 00 
            and (iy)
#c93b#5f3b15
b3 
            or e
#c93c#5f3c321
fd 77 00 
            ld (iy), a
#c93f#5f3f212
fd 23 
            inc iy
#c941#5f41213
18 44 
            jr Lc987_mode2_draw_second_part_of_last_byte
#c943#5f43
#c943#5f43
Lc943_mode2_wider_than_one_byte:
#c943#5f43
            ; At this point: a = shifted "and mask" of the first part of the byte
#c943#5f43
            ;                e = shifted first part of the byte
#c943#5f43
            ;                c = width - 1
#c943#5f43
            ; Draw the first part of the byte of the first sprite:
#c943#5f43321
fd a6 00 
            and (iy)
#c946#5f4615
b3 
            or e
#c947#5f47321
fd 77 00 
            ld (iy), a
#c94a#5f4a212
fd 23 
            inc iy
#c94c#5f4c15
0d 
            dec c  ; Check if this is the second to last byte in the row
#c94d#5f4d213/8
28 15 
            jr z, Lc964_mode2_second_to_last_byte
#c94f#5f4f
Lc94f_mode2_inner_byte_loop:
#c94f#5f4f18
56 
            ld d, (hl)
#c950#5f5017
23 
            inc hl
#c951#5f5118
5e 
            ld e, (hl)
#c952#5f52314
3a 93 c8 
            ld a, (Lc893_draw_sprite_within_byte_offset)
#c955#5f5515
47 
            ld b, a
#c956#5f56
            ; Given the byte to draw, and the next one, shift both together to obtain the actual byte
#c956#5f56
            ; that we need to draw in the current video memory position:
#c956#5f56
Lc956_mode2_byte_to_draw_shift_loop:
#c956#5f56210
cb 3a 
            srl d
#c958#5f58210
cb 1b 
            rr e
#c95a#5f5a214/9
10 fa 
            djnz Lc956_mode2_byte_to_draw_shift_loop
#c95c#5f5c
            ; Draw it directly, no need for an "and mask", as we are within the sprite:
#c95c#5f5c321
fd 73 00 
            ld (iy), e
#c95f#5f5f212
fd 23 
            inc iy
#c961#5f6115
0d 
            dec c
#c962#5f62213/8
20 eb 
            jr nz, Lc94f_mode2_inner_byte_loop
#c964#5f64
#c964#5f64
Lc964_mode2_second_to_last_byte:
#c964#5f64
            ; Draw the left-over part of the sprite:
#c964#5f6418
56 
            ld d, (hl)
#c965#5f6517
23 
            inc hl
#c966#5f66314
3a 92 c8 
            ld a, (Lc892_draw_sprite_and_mask)
#c969#5f6918
a6 
            and (hl)
#c96a#5f6a15
5f 
            ld e, a
#c96b#5f6b314
3a 93 c8 
            ld a, (Lc893_draw_sprite_within_byte_offset)
#c96e#5f6e15
47 
            ld b, a
#c96f#5f6f
Lc96f_mode2_and_mask_shift_loop:
#c96f#5f6f210
cb 3a 
            srl d
#c971#5f71210
cb 1b 
            rr e
#c973#5f73214/9
10 fa 
            djnz Lc96f_mode2_and_mask_shift_loop
#c975#5f7515
47 
            ld b, a
#c976#5f76314
3a 92 c8 
            ld a, (Lc892_draw_sprite_and_mask)
#c979#5f7915
2f 
            cpl
#c97a#5f7a
Lc97a_mode2_and_mask_shift_loop2:
#c97a#5f7a210
cb 3f 
            srl a
#c97c#5f7c214/9
10 fc 
            djnz Lc97a_mode2_and_mask_shift_loop2
#c97e#5f7e321
fd a6 00 
            and (iy)
#c981#5f8115
b3 
            or e
#c982#5f82321
fd 77 00 
            ld (iy), a
#c985#5f85212
fd 23 
            inc iy
#c987#5f87
#c987#5f87
Lc987_mode2_draw_second_part_of_last_byte:
#c987#5f87
            ; The "second part of the byte" is the part that overlaps with the following byte, once
#c987#5f87
            ; we shift it "x_offset % 8" pixels to the right.
#c987#5f87
            ; Get the "and mask":
#c987#5f87314
3a 92 c8 
            ld a, (Lc892_draw_sprite_and_mask)
#c98a#5f8a15
57 
            ld d, a
#c98b#5f8b314
3a 93 c8 
            ld a, (Lc893_draw_sprite_within_byte_offset)
#c98e#5f8e15
47 
            ld b, a
#c98f#5f8f28
1e 00 
            ld e, 0
#c991#5f91
            ; Shift the and mask to obtain the mask we need for the second part of the byte:
#c991#5f91
Lc991_mode2_and_mask_shift_loop2:
#c991#5f91210
cb 3a 
            srl d
#c993#5f93210
cb 1b 
            rr e
#c995#5f95214/9
10 fa 
            djnz Lc991_mode2_and_mask_shift_loop2
#c997#5f9715
47 
            ld b, a
#c998#5f9815
7b 
            ld a, e
#c999#5f9915
2f 
            cpl
#c99a#5f9a321
fd a6 00 
            and (iy)  ; Apply the "and mask" to the byte currently in video memory
#c99d#5f9d15
4f 
            ld c, a
#c99e#5f9e18
56 
            ld d, (hl)  ; Get the byte to draw again
#c99f#5f9f17
23 
            inc hl
#c9a0#5fa028
1e 00 
            ld e, 0
#c9a2#5fa2
            ; Shift the byte to the right to obtain only the second part:
#c9a2#5fa2
Lc9a2_get_second_part_of_byte_loop:
#c9a2#5fa2210
cb 3a 
            srl d
#c9a4#5fa4210
cb 1b 
            rr e
#c9a6#5fa6214/9
10 fa 
            djnz Lc9a2_get_second_part_of_byte_loop
#c9a8#5fa815
7b 
            ld a, e
#c9a9#5fa915
b1 
            or c
#c9aa#5faa321
fd 77 00 
            ld (iy), a  ; Draw the second part of the byte.
#c9ad#5fad111
f1 
        pop af
#c9ae#5fae111
c1 
        pop bc
#c9af#5faf214/9
10 03 
        djnz Lc9b4
#c9b1#5fb1311
c3 3e ca 
        jp Lca3e_draw_complete
#c9b4#5fb4
Lc9b4:  ; Auxiliary label, since the target of "djnz" is further than 128 bytes
#c9b4#5fb4
        ; OPTIMIZATION: this can be done faster replacing the "djnz" by just "dec b; jp z, Lc904_mode2_row_loop"
#c9b4#5fb4311
c3 04 c9 
        jp Lc904_mode2_row_loop
#c9b7#5fb7
#c9b7#5fb7
Ld015_drawing_mode3:
#c9b7#5fb7112
c5 
        push bc
#c9b8#5fb8112
f5 
        push af
#c9b9#5fb9
            ; Add the drawing address "(ix)" to the pixel offset "a":
#c9b9#5fb9321
dd 86 00 
            add a, (ix)
#c9bc#5fbc15
5f 
            ld e, a
#c9bd#5fbd321
dd 7e 01 
            ld a, (ix + 1)
#c9c0#5fc028
ce 00 
            adc a, 0
#c9c2#5fc215
57 
            ld d, a
#c9c3#5fc3
#c9c3#5fc3212
dd 23 
            inc ix
#c9c5#5fc5212
dd 23 
            inc ix  ; To get the next row pointer
#c9c7#5fc7112
d5 
            push de
#c9c8#5fc8216
fd e1 
            pop iy  ; iy = address where to draw.
#c9ca#5fca
#c9ca#5fca28
06 ff 
            ld b, #ff  ; Used to insert 1s from the left when rotating the inverted version of the byte to draw
#c9cc#5fcc15
af 
            xor a
#c9cd#5fcd314
32 94 c8 
            ld (Lc894_mode3_tmp_storage), a
#c9d0#5fd0
Lc9d0_mode3_byte_loop:
#c9d0#5fd018
56 
            ld d, (hl)  ; Read the byte to draw.
#c9d1#5fd115
7a 
            ld a, d
#c9d2#5fd215
2f 
            cpl
#c9d3#5fd315
5f 
            ld e, a
#c9d4#5fd415
50 
            ld d, b  ; d = #ff
#c9d5#5fd515
43 
            ld b, e  ; b, e = inverted version of the byte to draw
#c9d6#5fd6112
c5 
            push bc
#c9d7#5fd7314
3a 93 c8 
                ld a, (Lc893_draw_sprite_within_byte_offset)
#c9da#5fda15
b7 
                or a
#c9db#5fdb213/8
28 07 
                jr z, Lc9e4_no_shift_necessary
#c9dd#5fdd15
47 
                ld b, a
#c9de#5fde
                ; shifts the inverted byte to draw to the right, inserting 1s from the left:
#c9de#5fde
Lc9de_mode3_inverted_shift_loop:
#c9de#5fde210
cb 3a 
                srl d
#c9e0#5fe0210
cb 1b 
                rr e
#c9e2#5fe2214/9
10 fa 
                djnz Lc9de_mode3_inverted_shift_loop
#c9e4#5fe4
Lc9e4_no_shift_necessary:
#c9e4#5fe415
4b 
                ld c, e
#c9e5#5fe5314
3a 94 c8 
                ld a, (Lc894_mode3_tmp_storage)
#c9e8#5fe815
57 
                ld d, a
#c9e9#5fe918
7e 
                ld a, (hl)
#c9ea#5fea314
32 94 c8 
                ld (Lc894_mode3_tmp_storage), a  ; Store the byte to draw temporarily
#c9ed#5fed17
23 
                inc hl
#c9ee#5fee15
5f 
                ld e, a
#c9ef#5fef314
3a 93 c8 
                ld a, (Lc893_draw_sprite_within_byte_offset)
#c9f2#5ff215
b7 
                or a
#c9f3#5ff3213/8
28 07 
                jr z, Lc9fc_no_shift_necessary
#c9f5#5ff515
47 
                ld b, a
#c9f6#5ff6
                ; shifts the byte to draw to the right, inserting 0s from the left:
#c9f6#5ff6
Lc9f6_mode3_shift_loop:
#c9f6#5ff6210
cb 3a 
                srl d
#c9f8#5ff8210
cb 1b 
                rr e
#c9fa#5ffa214/9
10 fa 
                djnz Lc9f6_mode3_shift_loop
#c9fc#5ffc
Lc9fc_no_shift_necessary:
#c9fc#5ffc15
79 
                ld a, c
#c9fd#5ffd321
fd a6 00 
                and (iy)  ; We keep the part of the background that corresponds to bits == 0 in the sprite to draw
#ca00#600015
b3 
                or e  ; We add the sprite to draw (only adding the 1s, keeping the background in the 0s)
#ca01#6001321
fd 77 00 
                ld (iy), a  ; Draw
#ca04#6004212
fd 23 
                inc iy
#ca06#6006111
c1 
            pop bc
#ca07#600715
0d 
            dec c
#ca08#6008213/8
20 c6 
            jr nz, Lc9d0_mode3_byte_loop
#ca0a#600a15
50 
            ld d, b
#ca0b#600b28
1e ff 
            ld e, #ff
#ca0d#600d314
3a 93 c8 
            ld a, (Lc893_draw_sprite_within_byte_offset)
#ca10#601015
b7 
            or a
#ca11#6011213/8
28 07 
            jr z, Lca1a
#ca13#601315
47 
            ld b, a
#ca14#6014
Lca14:
#ca14#6014210
cb 3a 
            srl d
#ca16#6016210
cb 1b 
            rr e
#ca18#6018214/9
10 fa 
            djnz Lca14
#ca1a#601a
Lca1a:
#ca1a#601a15
4b 
            ld c, e
#ca1b#601b17
2b 
            dec hl
#ca1c#601c18
56 
            ld d, (hl)
#ca1d#601d17
23 
            inc hl
#ca1e#601e28
1e 00 
            ld e, 0
#ca20#6020314
3a 93 c8 
            ld a, (Lc893_draw_sprite_within_byte_offset)
#ca23#602315
b7 
            or a
#ca24#6024213/8
28 07 
            jr z, Lca2d
#ca26#602615
47 
            ld b, a
#ca27#6027
Lca27:
#ca27#6027210
cb 3a 
            srl d
#ca29#6029210
cb 1b 
            rr e
#ca2b#602b214/9
10 fa 
            djnz Lca27
#ca2d#602d
Lca2d:
#ca2d#602d15
79 
            ld a, c
#ca2e#602e321
fd a6 00 
            and (iy)
#ca31#603115
b3 
            or e
#ca32#6032321
fd 77 00 
            ld (iy), a
#ca35#6035111
f1 
        pop af
#ca36#6036111
c1 
        pop bc
#ca37#6037214/9
10 02 
        djnz Lca3b
#ca39#6039213
18 03 
        jr Lca3e_draw_complete
#ca3b#603b
Lca3b:
#ca3b#603b311
c3 b7 c9 
        jp Ld015_drawing_mode3
#ca3e#603e
Lca3e_draw_complete:
#ca3e#603e
        ; If we are not within the interrupt, reenable them
#ca3e#603e314
3a 7c 74 
        ld a, (L747c_within_interrupt_flag)
#ca41#604128
e6 80 
        and 128
#ca43#6043213/8
20 01 
        jr nz, Lca46_no_interrupt_reeneable
#ca45#604515
fb 
        ei
#ca46#6046
Lca46_no_interrupt_reeneable:
#ca46#6046111
f1 
    pop af
#ca47#6047111
c1 
    pop bc
#ca48#6048111
d1 
    pop de
#ca49#6049111
e1 
    pop hl
#ca4a#604a216
fd e1 
    pop iy
#ca4c#604c216
dd e1 
    pop ix
#ca4e#604e111
c9 
    ret
#ca4f#604f
#ca4f#604f
#ca4f#604f
; --------------------------------
#ca4f#604f
; Calculate render buffer pixel row pointers, and writes them to "L6664_row_pointers"
#ca4f#604f
; Input:
#ca4f#604f
; - hl: (hl + 1) contains the number of rows to calculate
#ca4f#604f
Lca4f_calculate_pixel_row_pointers:
#ca4f#604f112
e5 
    push hl
#ca50#6050112
d5 
    push de
#ca51#6051112
c5 
    push bc
#ca52#6052112
f5 
    push af
#ca53#605317
23 
        inc hl
#ca54#605418
46 
        ld b, (hl)
#ca55#6055311
21 64 66 
        ld hl, L6664_row_pointers
#ca58#6058311
11 bc 5c 
        ld de, L5cbc_render_buffer
#ca5b#605b
Lca5b:
#ca5b#605b18
73 
        ld (hl), e
#ca5c#605c17
23 
        inc hl
#ca5d#605d18
72 
        ld (hl), d
#ca5e#605e17
23 
        inc hl
#ca5f#605f
        ; de += SCREEN_WIDTH
#ca5f#605f15
7b 
        ld a, e
#ca60#606028
c6 18 
        add a, SCREEN_WIDTH
#ca62#606215
5f 
        ld e, a
#ca63#606315
7a 
        ld a, d
#ca64#606428
ce 00 
        adc a, 0
#ca66#606615
57 
        ld d, a
#ca67#6067214/9
10 f2 
        djnz Lca5b
#ca69#6069111
f1 
    pop af
#ca6a#606a111
c1 
    pop bc
#ca6b#606b111
d1 
    pop de
#ca6c#606c111
e1 
    pop hl
#ca6d#606d111
c9 
    ret
#ca6e#606e
#ca6e#606e
#ca6e#606e
; --------------------------------
#ca6e#606e
; Temporary data for method Lca70_draw_sprite_from_ix_to_iy
#ca6e#606e
Lca6e_x_offset_tmp:
#ca6e#606e2
    dw 0
#ca70#6070
#ca70#6070
#ca70#6070
; --------------------------------
#ca70#6070
; Draws a sprite from pointers in "iy" to pointers in "ix" with an offset
#ca70#6070
; Input:
#ca70#6070
; - hl: ptr to sprite attributes: w, h
#ca70#6070
; - ix: ptr to the row data of the sprite
#ca70#6070
; - iy: ptr to row pointers where to draw
#ca70#6070
; - a: x_offset (in bytes, applies to both source and target)
#ca70#6070
Lca70_draw_sprite_from_ix_to_iy:
#ca70#6070217
dd e5 
    push ix
#ca72#6072217
fd e5 
    push iy
#ca74#6074112
e5 
    push hl
#ca75#6075112
d5 
    push de
#ca76#6076112
c5 
    push bc
#ca77#6077112
f5 
    push af
#ca78#6078314
32 6e ca 
        ld (Lca6e_x_offset_tmp), a  ; store the x_offset
#ca7b#607b18
4e 
        ld c, (hl)
#ca7c#607c15
79 
        ld a, c
#ca7d#607d17
23 
        inc hl
#ca7e#607e18
46 
        ld b, (hl)
#ca7f#607f
Lca7f_row_loop:
#ca7f#607f112
c5 
        push bc
#ca80#6080422
ed 4b 6e ca 
            ld bc, (Lca6e_x_offset_tmp)  ; restore the x_offset
#ca84#6084321
fd 6e 00 
            ld l, (iy)
#ca87#6087321
fd 66 01 
            ld h, (iy + 1)  ; get target pointer
#ca8a#608a112
09 
            add hl, bc
#ca8b#608b15
eb 
            ex de, hl
#ca8c#608c212
fd 23 
            inc iy
#ca8e#608e212
fd 23 
            inc iy
#ca90#6090321
dd 6e 00 
            ld l, (ix)
#ca93#6093321
dd 66 01 
            ld h, (ix + 1)  ; get source pointer
#ca96#6096112
09 
            add hl, bc
#ca97#6097212
dd 23 
            inc ix
#ca99#6099212
dd 23 
            inc ix
#ca9b#609b15
4f 
            ld c, a
#ca9c#609c223/18
ed b0 
            ldir
#ca9e#609e111
c1 
        pop bc
#ca9f#609f214/9
10 de 
        djnz Lca7f_row_loop
#caa1#60a1111
f1 
    pop af
#caa2#60a2111
c1 
    pop bc
#caa3#60a3111
d1 
    pop de
#caa4#60a4111
e1 
    pop hl
#caa5#60a5216
fd e1 
    pop iy
#caa7#60a7216
dd e1 
    pop ix
#caa9#60a9111
c9 
    ret
#caaa#60aa
#caaa#60aa
#caaa#60aa
; --------------------------------
#caaa#60aa
; Checks is an object has crushed the player.
#caaa#60aa
Lcaaa_check_if_object_crushed_player:
#caaa#60aa217
dd e5 
    push ix
#caac#60ac112
e5 
    push hl
#caad#60ad112
d5 
    push de
#caae#60ae112
c5 
    push bc
#caaf#60af15
af 
        xor a
#cab0#60b0314
32 74 74 
        ld (L7474_check_if_object_crushed_player_flag), a
#cab3#60b3422
ed 4b 28 6b 
        ld bc, (L6b28_player_radius)
#cab7#60b717
0b 
        dec bc
#cab8#60b8422
dd 2a d1 6a 
        ld ix, (L6ad1_current_area_objects)
#cabc#60bc314
3a d0 6a 
        ld a, (L6ad0_current_area_n_objects)
#cabf#60bf15
b7 
        or a
#cac0#60c0318/11
c4 d5 ca 
        call nz, Lcad5_check_if_object_crushed_player_internal
#cac3#60c3422
dd 2a 63 74 
        ld ix, (L7463_global_area_objects)
#cac7#60c7314
3a 65 74 
        ld a, (L7465_global_area_n_objects)
#caca#60ca15
b7 
        or a
#cacb#60cb318/11
c4 d5 ca 
        call nz, Lcad5_check_if_object_crushed_player_internal
#cace#60ce15
af 
        xor a
#cacf#60cf
Lcacf:
#cacf#60cf111
c1 
    pop bc
#cad0#60d0111
d1 
    pop de
#cad1#60d1111
e1 
    pop hl
#cad2#60d2216
dd e1 
    pop ix
#cad4#60d4111
c9 
    ret
#cad5#60d5
#cad5#60d5
#cad5#60d5
; --------------------------------
#cad5#60d5
; Checks if an object from a given object list has crushed the player.
#cad5#60d5
; Input:
#cad5#60d5
; - ix: ptr to objects.
#cad5#60d5
; - a: number of objects to check.
#cad5#60d5
; - bc: player radius
#cad5#60d5
Lcad5_check_if_object_crushed_player_internal:
#cad5#60d5
Lcad5_check_if_object_crushed_player_internal_object_loop:
#cad5#60d5112
f5 
    push af
#cad6#60d6
        ; See if this object needs to be checked:
#cad6#60d6422
dd cb 00 66 
        bit 4, (ix + OBJECT_TYPE_AND_FLAGS)
#cada#60da311
ca 60 cb 
        jp z, Lcb60_next_object
#cadd#60dd
        ; Mark that we have already checked this object, only if the 4th bit
#cadd#60dd
        ; is set again to 1 by some game logic, the object will be checked again.
#cadd#60dd425
dd cb 00 a6 
        res 4, (ix + OBJECT_TYPE_AND_FLAGS)
#cae1#60e1422
ed 5b ad 6a 
        ld de, (L6aad_player_current_x)
#cae5#60e5321
dd 66 01 
        ld h, (ix + OBJECT_X)
#cae8#60e8318
cd 6d cb 
        call Lcb6d_hl_eq_h_times_64
#caeb#60eb15
b7 
        or a
#caec#60ec217
ed 42 
        sbc hl, bc  ; hl = (object x * 64 - bc)
#caee#60ee15
b7 
        or a
#caef#60ef217
ed 52 
        sbc hl, de  ; hl = (object x * 64) - (bc + player x)
#caf1#60f1311
f2 60 cb 
        jp p, Lcb60_next_object  ; no collision
#caf4#60f4
        ; collision in x not ruled out
#caf4#60f4321
dd 7e 01 
        ld a, (ix + OBJECT_X)
#caf7#60f7321
dd 86 04 
        add a, (ix + OBJECT_SIZE_X)
#cafa#60fa15
67 
        ld h, a
#cafb#60fb318
cd 6d cb 
        call Lcb6d_hl_eq_h_times_64
#cafe#60fe112
09 
        add hl, bc
#caff#60ff15
b7 
        or a
#cb00#6100217
ed 52 
        sbc hl, de
#cb02#6102311
fa 60 cb 
        jp m, Lcb60_next_object  ; no collision
#cb05#6105
        ; Collision in the x axis:
#cb05#6105422
ed 5b b1 6a 
        ld de, (L6ab1_player_current_z)
#cb09#6109321
dd 66 03 
        ld h, (ix + OBJECT_Z)
#cb0c#610c318
cd 6d cb 
        call Lcb6d_hl_eq_h_times_64
#cb0f#610f15
b7 
        or a
#cb10#6110217
ed 42 
        sbc hl, bc
#cb12#611215
b7 
        or a
#cb13#6113217
ed 52 
        sbc hl, de
#cb15#6115311
f2 60 cb 
        jp p, Lcb60_next_object
#cb18#6118
        ; collision in z not ruled out
#cb18#6118321
dd 7e 03 
        ld a, (ix + OBJECT_Z)
#cb1b#611b321
dd 86 06 
        add a, (ix + OBJECT_SIZE_Z)
#cb1e#611e15
67 
        ld h, a
#cb1f#611f318
cd 6d cb 
        call Lcb6d_hl_eq_h_times_64
#cb22#6122112
09 
        add hl, bc
#cb23#612315
b7 
        or a
#cb24#6124217
ed 52 
        sbc hl, de
#cb26#6126311
fa 60 cb 
        jp m, Lcb60_next_object
#cb29#6129
        ; Collision in the x and z axes:
#cb29#6129422
ed 5b af 6a 
        ld de, (L6aaf_player_current_y)
#cb2d#612d321
dd 66 02 
        ld h, (ix + OBJECT_Y)
#cb30#6130318
cd 6d cb 
        call Lcb6d_hl_eq_h_times_64
#cb33#613315
b7 
        or a
#cb34#6134217
ed 52 
        sbc hl, de
#cb36#6136311
f2 60 cb 
        jp p, Lcb60_next_object
#cb39#6139
        ; collision in y not ruled out
#cb39#6139314
3a b9 6a 
        ld a, (L6ab9_player_height)
#cb3c#613c15
3d 
        dec a
#cb3d#613d321
dd 86 02 
        add a, (ix + OBJECT_Y)
#cb40#6140321
dd 86 05 
        add a, (ix + OBJECT_SIZE_Y)
#cb43#614315
67 
        ld h, a
#cb44#6144318
cd 6d cb 
        call Lcb6d_hl_eq_h_times_64
#cb47#614715
b7 
        or a
#cb48#6148217
ed 52 
        sbc hl, de
#cb4a#614a311
fa 60 cb 
        jp m, Lcb60_next_object
#cb4d#614d
        ; Collision in the x, y and z axes:
#cb4d#614d
        ; Player insersects with a game object, trigger crushed game over!
#cb4d#614d28
3e 03 
        ld a, GAME_OVER_REASON_CRUSHED
#cb4f#614f314
32 79 74 
        ld (L7479_current_game_state), a
#cb52#6152311
21 00 00 
        ld hl, 0
#cb55#6155317
22 6c 74 
        ld (L746c_game_flags), hl
#cb58#6158318
cd 7b c8 
        call Lc87b_fade_out
#cb5b#615b111
e1 
        pop hl  ; pop af
#cb5c#615c111
e1 
    pop hl  ; cancel the "call" to this method
#cb5d#615d311
c3 cf ca 
    jp Lcacf
#cb60#6160
Lcb60_next_object:
#cb60#6160321
dd 5e 08 
        ld e, (ix + OBJECT_SIZE)
#cb63#616328
16 00 
        ld d, 0
#cb65#6165217
dd 19 
        add ix, de
#cb67#6167111
f1 
    pop af
#cb68#616815
3d 
    dec a
#cb69#6169311
c2 d5 ca 
    jp nz, Lcad5_check_if_object_crushed_player_internal_object_loop
#cb6c#616c111
c9 
    ret
#cb6d#616d
#cb6d#616d
#cb6d#616d
; --------------------------------
#cb6d#616d
; Note: This method is repeated! "La9de_hl_eq_h_times_64" does the same!
#cb6d#616d
; input:
#cb6d#616d
; - h
#cb6d#616d
; output:
#cb6d#616d
; - hl = h * 64
#cb6d#616d
Lcb6d_hl_eq_h_times_64:
#cb6d#616d28
2e 00 
    ld l, 0
#cb6f#616f210
cb 3c 
    srl h
#cb71#6171210
cb 1d 
    rr l
#cb73#6173210
cb 3c 
    srl h
#cb75#6175210
cb 1d 
    rr l
#cb77#6177111
c9 
    ret
#cb78#6178
#cb78#6178
#cb78#6178
; --------------------------------
#cb78#6178
; Effect for falling from a large height:
#cb78#6178
; - lose 5 strength
#cb78#6178
; - if strength reches 0, game over
#cb78#6178
; - It also plays 2 sfx (falling, and landing), and does a visual fade out effect for the fall
#cb78#6178
Lcb78_fall_from_height:
#cb78#6178112
f5 
    push af
#cb79#617915
af 
        xor a
#cb7a#617a314
32 b6 6a 
        ld (L6ab6_player_pitch_angle), a
#cb7d#617d28
3e 06 
        ld a, SFX_FALLING
#cb7f#617f314
32 7a 74 
        ld (L747a_requested_SFX), a
#cb82#618215
f3 
        di
#cb83#6183
        ; Lose 5 strength
#cb83#6183314
3a 0a 6b 
        ld a, (L6b0a_current_strength)
#cb86#618628
d6 05 
        sub 5
#cb88#6188311
f2 91 cb 
        jp p, Lcb91_sirvived_fall
#cb8b#618b
        ; Strength reached 0, we die because of the fall!
#cb8b#618b28
3e 04 
        ld a, GAME_OVER_REASON_FATAL_FALL
#cb8d#618d314
32 79 74 
        ld (L7479_current_game_state), a
#cb90#619015
af 
        xor a
#cb91#6191
Lcb91_sirvived_fall:
#cb91#6191314
32 0a 6b 
        ld (L6b0a_current_strength), a
#cb94#619415
fb 
        ei
#cb95#6195318
cd 7b c8 
        call Lc87b_fade_out
#cb98#619828
3e 01 
        ld a, 1
#cb9a#619a314
32 77 74 
        ld (L7477_render_buffer_effect), a  ; fade in effect
#cb9d#619d28
3e 05 
        ld a, SFX_THROW_ROCK_OR_LAND
#cb9f#619f314
32 7a 74 
        ld (L747a_requested_SFX), a
#cba2#61a2111
f1 
    pop af
#cba3#61a3111
c9 
    ret
#cba4#61a4
#cba4#61a4
#cba4#61a4
; --------------------------------
#cba4#61a4
; Checks if the player is not standing on any platform, and must fall.
#cba4#61a4
; If the height the player falls is too hight, cause damage. Otherwise,
#cba4#61a4
; just update player y.
#cba4#61a4
Lcba4_check_for_player_falling:
#cba4#61a4112
e5 
    push hl
#cba5#61a5112
d5 
    push de
#cba6#61a6112
f5 
    push af
#cba7#61a7
        ; We mark that this method has already been called:
#cba7#61a715
af 
        xor a
#cba8#61a8314
32 75 74 
        ld (L7475_call_Lcba4_check_for_player_falling_flag), a
#cbab#61ab317
2a ad 6a 
        ld hl, (L6aad_player_current_x)
#cbae#61ae317
22 56 74 
        ld (L7456_player_desired_x), hl
#cbb1#61b1317
2a b1 6a 
        ld hl, (L6ab1_player_current_z)
#cbb4#61b4317
22 5a 74 
        ld (L745a_player_desired_z), hl
#cbb7#61b7317
2a af 6a 
        ld hl, (L6aaf_player_current_y)
#cbba#61ba112
e5 
        push hl
#cbbb#61bb15
67 
            ld h, a
#cbbc#61bc15
6f 
            ld l, a
#cbbd#61bd317
22 58 74 
            ld (L7458_player_desired_y), hl  ; target going all the way down tot he floor
#cbc0#61c015
3c 
            inc a
#cbc1#61c1314
32 be 6a 
            ld (L6abe_use_eye_player_coordinate), a
#cbc4#61c4314
3a b9 6a 
            ld a, (L6ab9_player_height)
#cbc7#61c715
3d 
            dec a
#cbc8#61c815
5d 
            ld e, l
#cbc9#61c915
57 
            ld d, a
#cbca#61ca210
cb 3a 
            srl d
#cbcc#61cc210
cb 1b 
            rr e
#cbce#61ce210
cb 3a 
            srl d
#cbd0#61d0210
cb 1b 
            rr e  ; de = player height * 64
#cbd2#61d2112
d5 
            push de
#cbd3#61d3317
2a af 6a 
                ld hl, (L6aaf_player_current_y)
#cbd6#61d615
b7 
                or a
#cbd7#61d7217
ed 52 
                sbc hl, de  ; subtract player height * 64 (feet coordinate)
#cbd9#61d9317
22 af 6a 
                ld (L6aaf_player_current_y), hl
#cbdc#61dc
                ; Move player down until collision:
#cbdc#61dc318
cd d9 a5 
                call La5d9_move_player
#cbdf#61df15
af 
                xor a
#cbe0#61e0314
32 be 6a 
                ld (L6abe_use_eye_player_coordinate), a
#cbe3#61e3422
ed 5b af 6a 
                ld de, (L6aaf_player_current_y)
#cbe7#61e7217
ed 52 
                sbc hl, de
#cbe9#61e9112
29 
                add hl, hl
#cbea#61ea112
29 
                add hl, hl
#cbeb#61eb111
d1 
            pop de
#cbec#61ec15
bc 
            cp h
#cbed#61ed213/8
20 06 
            jr nz, Lcbf5_falling
#cbef#61ef
            ; Not falling
#cbef#61ef111
e1 
        pop hl
#cbf0#61f0317
22 af 6a 
        ld (L6aaf_player_current_y), hl
#cbf3#61f3213
18 20 
        jr Lcc15
#cbf5#61f5
Lcbf5_falling:
#cbf5#61f5
            ; Update game flags to trigger compass redraw, etc.
#cbf5#61f5314
3a 6c 74 
            ld a, (L746c_game_flags)
#cbf8#61f828
f6 14 
            or #14
#cbfa#61fa314
32 6c 74 
            ld (L746c_game_flags), a
#cbfd#61fd
            ; Check if we fell from very high, to cause damage:
#cbfd#61fd314
3a ba 6a 
            ld a, (L6aba_max_falling_height_without_damage)
#cc00#620015
bc 
            cp h
#cc01#6201111
e1 
        pop hl
#cc02#6202311
f2 08 cc 
        jp p, Lcc08_regular_fall
#cc05#6205
        ; Falling from high altitude, damage!
#cc05#6205318
cd 78 cb 
        call Lcb78_fall_from_height
#cc08#6208
Lcc08_regular_fall:
#cc08#6208317
2a af 6a 
        ld hl, (L6aaf_player_current_y)
#cc0b#620b15
7d 
        ld a, l
#cc0c#620c28
e6 c0 
        and #c0  ; clear the decimal part
#cc0e#620e28
f6 20 
        or #20  ; add "0.5"
#cc10#621015
6f 
        ld l, a
#cc11#6211112
19 
        add hl, de  ; add player height * 64 (we had subtracted it above)
#cc12#6212317
22 af 6a 
        ld (L6aaf_player_current_y), hl
#cc15#6215
Lcc15:
#cc15#6215111
f1 
    pop af
#cc16#6216111
d1 
    pop de
#cc17#6217111
e1 
    pop hl
#cc18#6218111
c9 
    ret
#cc19#6219
#cc19#6219
#cc19#6219
; --------------------------------
#cc19#6219
; Draws a "viewport sprite" to the game viewport:
#cc19#6219
; - Viewport sprites are special and have:
#cc19#6219
;   - a buffer to save the background they overwrite
#cc19#6219
;   - 8 versions of the sprite and "and mask", offset 0, 1, 2, ..., 7 pixels to the right
#cc19#6219
; - This method, saves the background in the buffer, and draws the sprite
#cc19#6219
; - The bit 7 of the sprite height is a flag indicating whether the sprite overwrites background,
#cc19#6219
;   or if it flips the bits in the background when drawing (xor).
#cc19#6219
; - Sprite is drawn starting from the bottom and moving up the screen.
#cc19#6219
; Input:
#cc19#6219
; - hl: pointer to sprite data
#cc19#6219
Lcc19_draw_viewport_sprite_with_offset:
#cc19#6219217
dd e5 
    push ix
#cc1b#621b217
fd e5 
    push iy
#cc1d#621d112
e5 
    push hl
#cc1e#621e112
d5 
    push de
#cc1f#621f112
c5 
    push bc
#cc20#6220112
f5 
    push af
#cc21#6221311
01 06 00 
        ld bc, 6
#cc24#6224311
11 c2 76 
        ld de, L76c2_buffer_sprite_x
#cc27#6227223/18
ed b0 
        ldir  ; Copy x, y, width, height, buffer ptr
#cc29#622915
54 
        ld d, h
#cc2a#622a15
5d 
        ld e, l
#cc2b#622b311
01 10 00 
        ld bc, 16
#cc2e#622e112
09 
        add hl, bc
#cc2f#622f15
eb 
        ex de, hl  ; hl = ptr to the masks ptrs, de = ptr to the frames ptrs
#cc30#623015
af 
        xor a
#cc31#6231314
32 c8 76 
        ld (L76c8_buffer_sprite_bytes_to_skip_at_start), a
#cc34#6234314
32 ca 76 
        ld (L76ca_bytes_to_skip_after_row), a
#cc37#6237416
dd 21 5c 72 
        ld ix, L725c_videomem_row_pointers
#cc3b#623b314
3a c3 76 
        ld a, (L76c3_buffer_sprite_y)
#cc3e#623e
          ; bc = 111 - y
#cc3e#623e28
d6 6f 
        sub 111
#cc40#6240210
ed 44 
        neg
#cc42#624215
4f 
        ld c, a
#cc43#6243210
cb 79 
        bit 7, c
#cc45#6245213/8
28 01 
        jr z, Lcc48_positive
#cc47#624715
05 
        dec b  ; when c is negative, make bc negative
#cc48#6248
Lcc48_positive:
#cc48#6248217
dd 09 
        add ix, bc
#cc4a#624a217
dd 09 
        add ix, bc  ; ix = videomem row pointer where to start drawing
#cc4c#624c314
3a c2 76 
        ld a, (L76c2_buffer_sprite_x)
#cc4f#624f15
3d 
        dec a
#cc50#625015
4f 
        ld c, a
#cc51#6251210
cb 39 
        srl c
#cc53#625328
fe c0 
        cp 192
#cc55#6255213/8
38 02 
        jr c, Lcc59
#cc57#6257210
cb f9 
        set 7, c
#cc59#6259
Lcc59:
#cc59#6259210
cb 29 
        sra c
#cc5b#625b210
cb 29 
        sra c  ; x = x coordinate / 8
#cc5d#625d314
3a c4 76 
        ld a, (L76c4_buffer_sprite_width)
#cc60#6260311
f2 7a cc 
        jp p, Lcc7a_positive_x_coordinate
#cc63#6263
        ; draw coordinate <= 0
#cc63#626315
81 
        add a, c  ; a = x + width
#cc64#6264311
ca 0b cd 
        jp z, Lcd0b_draw_complete
#cc67#6267311
fa 0b cd 
        jp m, Lcd0b_draw_complete  ; drawing outside of the rendering buffer
#cc6a#626a314
32 c4 76 
        ld (L76c4_buffer_sprite_width), a  ; amount of bytes to draw per row
#cc6d#626d15
79 
        ld a, c
#cc6e#626e210
ed 44 
        neg
#cc70#6270314
32 c8 76 
        ld (L76c8_buffer_sprite_bytes_to_skip_at_start), a  ; |x coordinate|
#cc73#6273314
32 ca 76 
        ld (L76ca_bytes_to_skip_after_row), a  ; |x coordinate|
#cc76#627628
0e 00 
        ld c, 0
#cc78#6278213
18 1a 
        jr Lcc94_prepare_drawing_code
#cc7a#627a
#cc7a#627a
Lcc7a_positive_x_coordinate:
#cc7a#627a15
47 
        ld b, a  ; b = width
#cc7b#627b15
79 
        ld a, c  ; a = x coordinate / 8
#cc7c#627c28
fe 18 
        cp SCREEN_WIDTH
#cc7e#627e311
d2 0b cd 
        jp nc, Lcd0b_draw_complete  ; drawing outside of the rendering buffer
#cc81#628115
80 
        add a, b
#cc82#628228
d6 18 
        sub SCREEN_WIDTH
#cc84#6284213/8
28 0e 
        jr z, Lcc94_prepare_drawing_code
#cc86#6286213/8
38 0c 
        jr c, Lcc94_prepare_drawing_code  ; drawing outside of the rendering buffer
#cc88#6288
        ; too wide!  set width to SCREEN_WIDTH - x
#cc88#628815
90 
        sub b
#cc89#6289210
ed 44 
        neg
#cc8b#628b314
32 c4 76 
        ld (L76c4_buffer_sprite_width), a
#cc8e#628e15
90 
        sub b  ; width - (SCREEN_WIDTH - x)
#cc8f#628f210
ed 44 
        neg
#cc91#6291314
32 ca 76 
        ld (L76ca_bytes_to_skip_after_row), a  ; width - (SCREEN_WIDTH - x)
#cc94#6294
#cc94#6294
Lcc94_prepare_drawing_code:
#cc94#6294
        ; Here:
#cc94#6294
        ; hl = hl = ptr to the masks ptrs
#cc94#6294
        ; de = ptr to the frames ptrs
#cc94#6294
        ; c = x coordinate to draw to
#cc94#6294314
3a c5 76 
        ld a, (L76c5_buffer_sprite_height)
#cc97#6297112
e5 
        push hl
#cc98#6298
            ; Check if we want to invert the background or not:
#cc98#6298311
21 18 05 
            ld hl, #0518  ; machine code for "jr Lccf5"
#cc9b#629b210
cb 7f 
            bit 7, a
#cc9d#629d213/8
28 05 
            jr z, Lcca4
#cc9f#629f28
e6 7f 
            and #7f  ; remove the background inversion flag
#cca1#62a1311
21 00 00 
            ld hl, 0  ; machine code for "nop; nop"
#cca4#62a4
Lcca4:
#cca4#62a4317
22 ee cc 
            ld (Lccee_selfmodifying), hl
#cca7#62a7111
e1 
        pop hl
#cca8#62a815
47 
        ld b, a
#cca9#62a9112
c5 
        push bc
#ccaa#62aa314
3a c2 76 
            ld a, (L76c2_buffer_sprite_x)
#ccad#62ad15
3d 
            dec a
#ccae#62ae28
e6 07 
            and #07
#ccb0#62b0213/8
28 08 
            jr z, Lccba_zero_pixel_offset
#ccb2#62b2
            ; Get the proper sprite and mask ptrs:
#ccb2#62b2
            ; There are 8 versions of each mask and sprite (offset 1 more pixel to the right each time).
#ccb2#62b215
87 
            add a, a
#ccb3#62b328
06 00 
            ld b, 0
#ccb5#62b515
4f 
            ld c, a
#ccb6#62b6112
09 
            add hl, bc  ; and mask
#ccb7#62b715
eb 
            ex de, hl
#ccb8#62b8112
09 
                add hl, bc  ; sprite data
#ccb9#62b915
eb 
            ex de, hl
#ccba#62ba
Lccba_zero_pixel_offset:
#ccba#62ba
            ; read the actual pointers to and mask and sprite data:
#ccba#62ba
            ; and mask:
#ccba#62ba18
7e 
            ld a, (hl)
#ccbb#62bb17
23 
            inc hl
#ccbc#62bc18
66 
            ld h, (hl)
#ccbd#62bd15
6f 
            ld l, a
#ccbe#62be
            ; sprite data:
#ccbe#62be18
1a 
            ld a, (de)
#ccbf#62bf17
13 
            inc de
#ccc0#62c015
4f 
            ld c, a
#ccc1#62c118
1a 
            ld a, (de)
#ccc2#62c215
57 
            ld d, a
#ccc3#62c315
59 
            ld e, c
#ccc4#62c4422
ed 4b c8 76 
            ld bc, (L76c8_buffer_sprite_bytes_to_skip_at_start)
#ccc8#62c8112
09 
            add hl, bc  ; and mask
#ccc9#62c915
eb 
            ex de, hl
#ccca#62ca112
09 
                add hl, bc  ; sprite data
#cccb#62cb15
eb 
            ex de, hl
#cccc#62cc111
c1 
        pop bc
#cccd#62cd422
fd 2a c6 76 
        ld iy, (L76c6_buffer_sprite_ptr)
#ccd1#62d1
Lccd1_drawing_loop_y:
#ccd1#62d1
        ; Here:
#ccd1#62d1
        ; b = height
#ccd1#62d1
        ; c = x coordinate
#ccd1#62d1
        ; iy = ptr to the buffer sprite ptr
#ccd1#62d1
        ; hl = ptr to and mask
#ccd1#62d1
        ; de = ptr to sprite data
#ccd1#62d1112
c5 
        push bc
#ccd2#62d2112
e5 
            push hl
#ccd3#62d3321
dd 66 01 
                ld h, (ix + 1)
#ccd6#62d6321
dd 6e 00 
                ld l, (ix)
#ccd9#62d9212
dd 2b 
                dec ix
#ccdb#62db212
dd 2b 
                dec ix
#ccdd#62dd28
06 00 
                ld b, 0
#ccdf#62df112
09 
                add hl, bc  ; add x coordinate
#cce0#62e015
4d 
                ld c, l
#cce1#62e115
44 
                ld b, h
#cce2#62e2111
e1 
            pop hl
#cce3#62e3314
3a c4 76 
            ld a, (L76c4_buffer_sprite_width)
#cce6#62e6
Lcce6_drawing_loop_x:
#cce6#62e6112
f5 
            push af
#cce7#62e718
0a 
                ld a, (bc)  ; read background byte
#cce8#62e8321
fd 77 00 
                ld (iy), a  ; save background to the buffer
#cceb#62eb18
a6 
                and (hl)  ; apply and mask
#ccec#62ec15
eb 
                ex de, hl
#cced#62ed18
b6 
                    or (hl)  ; add the sprite
#ccee#62ee
Lccee_selfmodifying:
#ccee#62ee213
18 05 
                    jr Lccf5  ; this jr can be replaced by "nop; nop" above, depending on a flag
#ccf0#62f0
                    ; invert the pixels in the background
#ccf0#62f018
1a 
                    ld a, (de)  ; and mask
#ccf1#62f115
2f 
                    cpl  ; invert the mask
#ccf2#62f2321
fd ae 00 
                    xor (iy)  ; invert background pixels
#ccf5#62f5
Lccf5:
#ccf5#62f515
eb 
                ex de, hl
#ccf6#62f618
02 
                ld (bc), a  ; write resulting byte
#ccf7#62f717
13 
                inc de
#ccf8#62f817
23 
                inc hl
#ccf9#62f917
03 
                inc bc
#ccfa#62fa212
fd 23 
                inc iy
#ccfc#62fc111
f1 
            pop af
#ccfd#62fd15
3d 
            dec a
#ccfe#62fe213/8
20 e6 
            jr nz, Lcce6_drawing_loop_x
#cd00#6300422
ed 4b ca 76 
            ld bc, (L76ca_bytes_to_skip_after_row)
#cd04#6304112
09 
            add hl, bc
#cd05#630515
eb 
            ex de, hl
#cd06#6306112
09 
            add hl, bc
#cd07#630715
eb 
            ex de, hl
#cd08#6308111
c1 
        pop bc
#cd09#6309214/9
10 c6 
        djnz Lccd1_drawing_loop_y
#cd0b#630b
Lcd0b_draw_complete:
#cd0b#630b111
f1 
    pop af
#cd0c#630c111
c1 
    pop bc
#cd0d#630d111
d1 
    pop de
#cd0e#630e111
e1 
    pop hl
#cd0f#630f216
fd e1 
    pop iy
#cd11#6311216
dd e1 
    pop ix
#cd13#6313111
c9 
    ret
#cd14#6314
#cd14#6314
#cd14#6314
; --------------------------------
#cd14#6314
; Draws a sprite within the game viewport (making sure we do not
#cd14#6314
; overflow the viewport).
#cd14#6314
; - This method is usually used to restore the background after calling 'Lcc19_draw_viewport_sprite_with_offset',
#cd14#6314
;   as the background is stored in a viewport sprite, as if it were a regular sprite.
#cd14#6314
; - The sprite is drawn flipped upside down.
#cd14#6314
; - The attributes pointer points to: (x, y, width, height, data ptr)
#cd14#6314
; Input:
#cd14#6314
; - hl: sprite attributes pointer
#cd14#6314
Lcd14_restore_view_port_background_after_drawing_sprite:
#cd14#6314217
dd e5 
    push ix
#cd16#6316112
e5 
    push hl
#cd17#6317112
d5 
    push de
#cd18#6318112
c5 
    push bc
#cd19#6319112
f5 
    push af
#cd1a#631a18
46 
        ld b, (hl)
#cd1b#631b416
dd 21 5c 72 
        ld ix, L725c_videomem_row_pointers
#cd1f#631f17
23 
        inc hl
#cd20#6320
        ; calculate bc = 111 - (input hl + 1)
#cd20#632018
7e 
        ld a, (hl)
#cd21#632128
d6 6f 
        sub 111
#cd23#6323210
ed 44 
        neg
#cd25#632515
4f 
        ld c, a
#cd26#632615
78 
        ld a, b
#cd27#632717
23 
        inc hl
#cd28#632828
06 00 
        ld b, 0
#cd2a#632a210
cb 79 
        bit 7, c
#cd2c#632c213/8
28 01 
        jr z, Lcd2f_positive
#cd2e#632e15
05 
        dec b
#cd2f#632f
Lcd2f_positive:
#cd2f#632f
        ; At this point:
#cd2f#632f
        ; a = (input hl): x coordinate
#cd2f#632f
        ; bc = 111 - (input hl + 1): y coordinate
#cd2f#632f
        ; ix = L725c_videomem_row_pointers
#cd2f#632f
        ; hl has incremented by 2 from input
#cd2f#632f217
dd 09 
        add ix, bc
#cd31#6331217
dd 09 
        add ix, bc
#cd33#633315
4f 
        ld c, a
#cd34#633415
0d 
        dec c
#cd35#633518
7e 
        ld a, (hl)  ; width
#cd36#633617
23 
        inc hl
#cd37#633718
46 
        ld b, (hl)  ; height
#cd38#633817
23 
        inc hl
#cd39#633918
5e 
        ld e, (hl)  ; pointer to the data to draw
#cd3a#633a17
23 
        inc hl
#cd3b#633b18
56 
        ld d, (hl)
#cd3c#633c15
eb 
        ex de, hl
#cd3d#633d112
f5 
        push af
#cd3e#633e15
78 
            ld a, b
#cd3f#633f28
e6 7f 
            and #7f  ; remove the "xor" bit flag from the sprite height.
#cd41#634115
47 
            ld b, a
#cd42#634215
79 
            ld a, c  ; x coordinate - 1
#cd43#6343210
cb 39 
            srl c  ; x coordinate / 2
#cd45#634528
fe c0 
            cp 192
#cd47#6347213/8
38 02 
            jr c, Lcd4b
#cd49#6349210
cb f9 
            set 7, c
#cd4b#634b
Lcd4b:
#cd4b#634b111
f1 
        pop af  ; a = width again
#cd4c#634c210
cb 29 
        sra c
#cd4e#634e210
cb 29 
        sra c  ; c = x coordinate / 8
#cd50#6350311
f2 5d cd 
        jp p, Lcd5d_positive_x_coordinate
#cd53#6353
        ; draw coordinate <= 0
#cd53#635315
81 
        add a, c  ; a = x + width
#cd54#6354213/8
28 2f 
        jr z, Lcd85_draw_complete
#cd56#6356311
fa 85 cd 
        jp m, Lcd85_draw_complete  ; drawing outside of the rendering buffer
#cd59#635928
0e 00 
        ld c, 0  ; x coordinate = 0
#cd5b#635b213
18 12 
        jr Lcd6f_start_to_draw
#cd5d#635d
Lcd5d_positive_x_coordinate:
#cd5d#635d15
57 
        ld d, a  ; d = width
#cd5e#635e15
79 
        ld a, c  ; a = x coordinate
#cd5f#635f28
fe 18 
        cp SCREEN_WIDTH
#cd61#6361213/8
30 22 
        jr nc, Lcd85_draw_complete  ; drawing outside of the rendering buffer
#cd63#636315
82 
        add a, d  ; a = x + width
#cd64#636428
d6 18 
        sub SCREEN_WIDTH
#cd66#6366213/8
28 06 
        jr z, Lcd6e_width_ok
#cd68#6368213/8
38 04 
        jr c, Lcd6e_width_ok
#cd6a#636a
        ; too wide!  set width to SCREEN_WIDTH - x
#cd6a#636a15
92 
        sub d
#cd6b#636b210
ed 44 
        neg
#cd6d#636d15
57 
        ld d, a
#cd6e#636e
Lcd6e_width_ok:
#cd6e#636e15
7a 
        ld a, d
#cd6f#636f
Lcd6f_start_to_draw:
#cd6f#636f
        ; Draw "b" rows of "c" bytes each from hl to the row pointers in (ix) (bottom up)
#cd6f#636f
        ; From each row only "a" bytes are copied.
#cd6f#636f112
c5 
        push bc
#cd70#6370321
dd 56 01 
            ld d, (ix + 1)
#cd73#6373321
dd 5e 00 
            ld e, (ix)
#cd76#6376212
dd 2b 
            dec ix
#cd78#6378212
dd 2b 
            dec ix
#cd7a#637a28
06 00 
            ld b, 0
#cd7c#637c15
eb 
            ex de, hl
#cd7d#637d112
09 
                add hl, bc
#cd7e#637e15
eb 
            ex de, hl
#cd7f#637f15
4f 
            ld c, a
#cd80#6380223/18
ed b0 
            ldir
#cd82#6382111
c1 
        pop bc
#cd83#6383214/9
10 ea 
        djnz Lcd6f_start_to_draw
#cd85#6385
Lcd85_draw_complete:
#cd85#6385111
f1 
    pop af
#cd86#6386111
c1 
    pop bc
#cd87#6387111
d1 
    pop de
#cd88#6388111
e1 
    pop hl
#cd89#6389216
dd e1 
    pop ix
#cd8b#638b111
c9 
    ret
#cd8c#638c
#cd8c#638c
#cd8c#638c
; --------------------------------
#cd8c#638c
; Draw pointer in the center of the viewport
#cd8c#638c
Lcd8c_draw_movement_center_pointer:
#cd8c#638c112
e5 
    push hl
#cd8d#638d112
d5 
    push de
#cd8e#638e112
c5 
    push bc
#cd8f#638f112
f5 
    push af
#cd90#6390
        ; position of the pointer:
#cd90#6390311
21 bf 61 
        ld hl, L5cbc_render_buffer + 53 * SCREEN_WIDTH + 11
#cd93#6393311
11 18 00 
        ld de, SCREEN_WIDTH
#cd96#639628
06 03 
        ld b, 3  ; top line of the pointer
#cd98#6398
Lcd98_loop:
#cd98#639828
3e 01 
        ld a, #01
#cd9a#639a18
ae 
        xor (hl)
#cd9b#639b18
77 
        ld (hl), a
#cd9c#639c112
19 
        add hl, de
#cd9d#639d214/9
10 f9 
        djnz Lcd98_loop
#cd9f#639f
#cd9f#639f28
3e 0e 
        ld a, #0e  ; right line
#cda1#63a118
ae 
        xor (hl)
#cda2#63a218
77 
        ld (hl), a
#cda3#63a317
23 
        inc hl
#cda4#63a428
3e e0 
        ld a, #e0  ; left line
#cda6#63a618
ae 
        xor (hl)
#cda7#63a718
77 
        ld (hl), a
#cda8#63a817
2b 
        dec hl
#cda9#63a928
06 03 
        ld b, 3  ; bottom line of the pointer
#cdab#63ab
Lcdab_loop:
#cdab#63ab112
19 
        add hl, de
#cdac#63ac28
3e 01 
        ld a, #01
#cdae#63ae18
ae 
        xor (hl)
#cdaf#63af18
77 
        ld (hl), a
#cdb0#63b0214/9
10 f9 
        djnz Lcdab_loop
#cdb2#63b2111
f1 
    pop af
#cdb3#63b3111
c1 
    pop bc
#cdb4#63b4111
d1 
    pop de
#cdb5#63b5111
e1 
    pop hl
#cdb6#63b6111
c9 
    ret
#cdb7#63b7
#cdb7#63b7
#cdb7#63b7
; --------------------------------
#cdb7#63b7
; Auxiliary data for the gate animation routine.
#cdb7#63b7
Lcdb7_gate_row_type:  ; Some rows of the gate require masking, others not, etc.
#cdb7#63b71
    db #00
#cdb8#63b8
Lcdb8_gate_rows_left_to_draw:
#cdb8#63b81
    db #00
#cdb9#63b9
Lcdb9_rows_left_of_the_same_type:
#cdb9#63b91
    db #00
#cdba#63ba
Lcdba_previous_gate_draw_y:
#cdba#63ba1
    db #00
#cdbb#63bb
Lcdbb_n_rows_to_clear_below:
#cdbb#63bb1
    db #00
#cdbc#63bc
Lcdbc_gate_and_mask:
#cdbc#63bc
Lcdbc_gate_and_mask_left:
#cdbc#63bc1
    db #00
#cdbd#63bd
Lcdbd_gate_and_mask_right:
#cdbd#63bd1
    db #00
#cdbe#63be
Lcdbe_gate_close_y_coordinates:
#cdbe#63be
    ; Terminates when finding an "#ff"
#cdbe#63be10
    db 1, 2, 4, 7, 11, 16, 22, 29, 37, 48
#cdc8#63c810
    db 58, 69, 81, 93, 107, 112, 107, 112, 111, 112
#cdd2#63d21
    db #ff
#cdd3#63d3
Lcdd3_gate_row_gfx_horizontal_bar:
#cdd3#63d33
    db #20, #00, #04
#cdd6#63d63
    db #2a, #8b, #b5
#cdd9#63d93
    db #ab, #f0, #e5
#cddc#63dc3
    db #a0, #00, #05
#cddf#63df
Lcddf_gate_row_gfx:  ; Part in between horizontal bars
#cddf#63df2
    db #00, #00
#cde1#63e12
    db #00, #00
#cde3#63e32
    db #80, #01
#cde5#63e52
    db #80, #01
#cde7#63e72
    db #00, #01
#cde9#63e92
    db #80, #01
#cdeb#63eb2
    db #00, #01
#cded#63ed2
    db #00, #01
#cdef#63ef2
    db #00, #00
#cdf1#63f12
    db #00, #01
#cdf3#63f32
    db #00, #01
#cdf5#63f52
    db #80, #00
#cdf7#63f72
    db #80, #00
#cdf9#63f92
    db #00, #00
#cdfb#63fb2
    db #80, #00
#cdfd#63fd2
    db #80, #00
#cdff#63ff2
    db #80, #00
#ce01#64012
    db #80, #01
#ce03#64032
    db #80, #01
#ce05#64052
    db #80, #01
#ce07#6407
Lce07_gate_last_row_gfx:
#ce07#64072
    db #00, #00
#ce09#6409
#ce09#6409
#ce09#6409
; --------------------------------
#ce09#6409
; Visualization of the gate opening or closing over the game screen.
#ce09#6409
; This assumes the 3d view of the game has already been rendered to the render buffer.
#ce09#6409
; Input:
#ce09#6409
; - carry flag: set -> open gate, reset -> close gate
#ce09#6409
Lce09_gate_open_close_effect:
#ce09#6409217
dd e5 
    push ix
#ce0b#640b217
fd e5 
    push iy
#ce0d#640d112
e5 
    push hl
#ce0e#640e112
d5 
    push de
#ce0f#640f112
c5 
    push bc
#ce10#6410112
f5 
    push af
#ce11#6411213/8
38 31 
        jr c, Lce44_open_gate
#ce13#6413
        ; Close gate:
#ce13#6413416
dd 21 be cd 
        ld ix, Lcdbe_gate_close_y_coordinates
#ce17#6417
Lce17_close_gate_loop:
#ce17#6417321
dd 7e 00 
        ld a, (ix)
#ce1a#641a28
fe ff 
        cp #ff  ; Sequence termination 
#ce1c#641c213/8
28 48 
        jr z, Lce66_done
#ce1e#641e15
4f 
        ld c, a
#ce1f#641f112
f5 
        push af
#ce20#642028
3e 02 
            ld a, 2
#ce22#6422314
32 a5 74 
            ld (L74a5_interrupt_timer), a
#ce25#6425318
cd 6f ce 
            call Lce6f_draw_gate
#ce28#6428111
f1 
        pop af
#ce29#642928
fe 70 
        cp SCREEN_HEIGHT_IN_PIXELS
#ce2b#642b28
3e 03 
        ld a, SFX_MENU_SELECT
#ce2d#642d318/11
cc ca c4 
        call z, Lc4ca_play_SFX  ; This is when the gate bounces at the bottom of the screen.
#ce30#6430
Lce30_pause_loop:
#ce30#6430314
3a a5 74 
        ld a, (L74a5_interrupt_timer)
#ce33#643315
b7 
        or a
#ce34#6434213/8
20 fa 
        jr nz, Lce30_pause_loop
#ce36#6436212
dd 23 
        inc ix
#ce38#6438321
dd 7e 00 
        ld a, (ix)
#ce3b#643b28
fe ff 
        cp #ff  ; Sequence termination
#ce3d#643d28
3e 09 
        ld a, SFX_GATE_CLOSE
#ce3f#643f318/11
cc ca c4 
        call z, Lc4ca_play_SFX
#ce42#6442213
18 d3 
        jr Lce17_close_gate_loop
#ce44#6444
#ce44#6444
Lce44_open_gate:
#ce44#644428
0e 70 
        ld c, SCREEN_HEIGHT_IN_PIXELS  ; start in the closed position
#ce46#6446318
cd 6f ce 
        call Lce6f_draw_gate
#ce49#644928
06 38 
        ld b, 56
#ce4b#644b28
0e 6e 
        ld c, 110
#ce4d#644d
Lce4d_open_gate_loop:
#ce4d#644d112
c5 
        push bc
#ce4e#644e28
3e 02 
            ld a, 2
#ce50#6450314
32 a5 74 
            ld (L74a5_interrupt_timer), a
#ce53#6453318
cd 6f ce 
            call Lce6f_draw_gate
#ce56#6456
Lce56_pause_loop:
#ce56#6456314
3a a5 74 
            ld a, (L74a5_interrupt_timer)
#ce59#645915
b7 
            or a
#ce5a#645a213/8
20 fa 
            jr nz, Lce56_pause_loop
#ce5c#645c111
c1 
        pop bc
#ce5d#645d15
0d 
        dec c  ; move the gate up 2 pixels each frame
#ce5e#645e15
0d 
        dec c
#ce5f#645f214/9
10 ec 
        djnz Lce4d_open_gate_loop
#ce61#646128
3e 07 
        ld a, SFX_GAME_START
#ce63#6463318
cd ca c4 
        call Lc4ca_play_SFX
#ce66#6466
Lce66_done:
#ce66#6466111
f1 
    pop af
#ce67#6467111
c1 
    pop bc
#ce68#6468111
d1 
    pop de
#ce69#6469111
e1 
    pop hl
#ce6a#646a216
fd e1 
    pop iy
#ce6c#646c216
dd e1 
    pop ix
#ce6e#646e111
c9 
    ret
#ce6f#646f
#ce6f#646f
#ce6f#646f
; --------------------------------
#ce6f#646f
; Renders the L5cbc_render_buffer to video memory, but drawing a game graphic on top.
#ce6f#646f
; The gate is drawn starting at coordinate "c" (bottom row of the gate).
#ce6f#646f
; Input:
#ce6f#646f
; - c: y coordinates of the gate.
#ce6f#646f
Lce6f_draw_gate:
#ce6f#646f217
dd e5 
    push ix
#ce71#647115
79 
        ld a, c
#ce72#6472314
32 b8 cd 
        ld (Lcdb8_gate_rows_left_to_draw), a
#ce75#647515
af 
        xor a
#ce76#647615
47 
        ld b, a
#ce77#6477314
32 bb cd 
        ld (Lcdbb_n_rows_to_clear_below), a  ; (Lcdbb_n_rows_to_clear_below) = 0
#ce7a#647a314
3a ba cd 
        ld a, (Lcdba_previous_gate_draw_y)  ; a = 0
#ce7d#647d
        ; If the gate is being moved up, we set (Lcdbb_n_rows_to_clear_below) to how many pixels
#ce7d#647d
        ; up it mved since last time (as we need to erase the bottom part of
#ce7d#647d
        ; the previous version of the gate):
#ce7d#647d15
91 
        sub c
#ce7e#647e213/8
38 03 
        jr c, Lce83
#ce80#6480314
32 bb cd 
        ld (Lcdbb_n_rows_to_clear_below), a
#ce83#6483
Lce83:
#ce83#648315
79 
        ld a, c
#ce84#6484314
32 ba cd 
        ld (Lcdba_previous_gate_draw_y), a
#ce87#6487311
11 fc 3f 
        ld de, #3ffc  ; and mask
#ce8a#648a416
dd 21 5c 72 
        ld ix, L725c_videomem_row_pointers
#ce8e#648e311
21 bc 5c 
        ld hl, L5cbc_render_buffer  ; Pointer to the pre-rendered background over which the gate will be drawn.
#ce91#649115
b7 
        or a
#ce92#6492311
ca e5 cf 
        jp z, Lcfe5_gate_draw_clear_bottom_rows  ; If no more pixels left to draw, go to clear bottom part.
#ce95#649528
fe 01 
        cp 1
#ce97#6497213/8
20 0e 
        jr nz, Lcea7_draw_non_last_gate_row
#ce99#6499
        ; Draw last row of the gate:
#ce99#6499314
32 b9 cd 
        ld (Lcdb9_rows_left_of_the_same_type), a
#ce9c#649c416
fd 21 07 ce 
        ld iy, Lce07_gate_last_row_gfx
#cea0#64a0311
11 fe 7f 
        ld de, #7ffe  ; and mask of last row
#cea3#64a328
3e 05 
        ld a, 5  ; Set row type to bottom row
#cea5#64a5213
18 71 
        jr Lcf18_gate_draw_row
#cea7#64a7
Lcea7_draw_non_last_gate_row:
#cea7#64a7
        ; Determine the gfx to draw in this row:
#cea7#64a728
fe 10 
        cp 16
#cea9#64a9213/8
30 16 
        jr nc, Lcec1_non_first_16_rows
#ceab#64ab
        ; One of the first 16 rows:
#ceab#64ab15
3d 
        dec a
#ceac#64ac314
32 b9 cd 
        ld (Lcdb9_rows_left_of_the_same_type), a
#ceaf#64af416
fd 21 df cd 
        ld iy, Lcddf_gate_row_gfx
#ceb3#64b328
d6 0e 
        sub 14
#ceb5#64b5213/8
28 61 
        jr z, Lcf18_gate_draw_row
#ceb7#64b7
        ; get the row gfx pointer:
#ceb7#64b7210
ed 44 
        neg
#ceb9#64b915
87 
        add a, a
#ceba#64ba15
4f 
        ld c, a
#cebb#64bb217
fd 09 
        add iy, bc
#cebd#64bd28
3e 04 
        ld a, 4
#cebf#64bf213
18 57 
        jr Lcf18_gate_draw_row
#cec1#64c1
Lcec1_non_first_16_rows:
#cec1#64c128
fe 14 
        cp 20
#cec3#64c3213/8
30 19 
        jr nc, Lcede_non_first_20_rows
#cec5#64c5
        ; It's a horizontal bar:
#cec5#64c528
d6 0f 
        sub 15
#cec7#64c7314
32 b9 cd 
        ld (Lcdb9_rows_left_of_the_same_type), a
#ceca#64ca416
fd 21 d3 cd 
        ld iy, Lcdd3_gate_row_gfx_horizontal_bar
#cece#64ce28
d6 04 
        sub 4
#ced0#64d0213/8
28 46 
        jr z, Lcf18_gate_draw_row
#ced2#64d2210
ed 44 
        neg
#ced4#64d415
4f 
        ld c, a
#ced5#64d515
87 
        add a, a
#ced6#64d615
81 
        add a, c
#ced7#64d715
4f 
        ld c, a
#ced8#64d8217
fd 09 
        add iy, bc
#ceda#64da28
3e 03 
        ld a, 3  ; solid row type (horizontal bar)
#cedc#64dc213
18 3a 
        jr Lcf18_gate_draw_row
#cede#64de
Lcede_non_first_20_rows:
#cede#64de
        ; The rest of this code, does the same as above, just identifying which part
#cede#64de
        ; of the gate we need to draw (horizontal bar, etc.), and get the correct pointer
#cede#64de
        ; in "iy", and row type in "a".
#cede#64de28
d6 13 
        sub 19
#cee0#64e0
Lcee0:
#cee0#64e028
fe 19 
        cp 25
#cee2#64e2213/8
38 04 
        jr c, Lcee8
#cee4#64e428
d6 18 
        sub 24
#cee6#64e6213
18 f8 
        jr Lcee0
#cee8#64e8
Lcee8:
#cee8#64e828
fe 15 
        cp 21
#ceea#64ea213/8
38 19 
        jr c, Lcf05
#ceec#64ec28
d6 14 
        sub 20
#ceee#64ee314
32 b9 cd 
        ld (Lcdb9_rows_left_of_the_same_type), a
#cef1#64f1416
fd 21 d3 cd 
        ld iy, Lcdd3_gate_row_gfx_horizontal_bar
#cef5#64f528
d6 04 
        sub 4
#cef7#64f7213/8
28 1f 
        jr z, Lcf18_gate_draw_row
#cef9#64f9210
ed 44 
        neg
#cefb#64fb15
4f 
        ld c, a
#cefc#64fc15
87 
        add a, a
#cefd#64fd15
81 
        add a, c
#cefe#64fe15
4f 
        ld c, a
#ceff#64ff217
fd 09 
        add iy, bc
#cf01#650128
3e 01 
        ld a, 1  ; solid row type (horizontal bar)
#cf03#6503213
18 13 
        jr Lcf18_gate_draw_row
#cf05#6505
Lcf05:
#cf05#6505314
32 b9 cd 
        ld (Lcdb9_rows_left_of_the_same_type), a
#cf08#6508416
fd 21 df cd 
        ld iy, Lcddf_gate_row_gfx
#cf0c#650c28
d6 14 
        sub 20
#cf0e#650e213/8
28 08 
        jr z, Lcf18_gate_draw_row
#cf10#6510210
ed 44 
        neg
#cf12#651215
87 
        add a, a
#cf13#651315
4f 
        ld c, a
#cf14#6514217
fd 09 
        add iy, bc
#cf16#651628
3e 02 
        ld a, 2
#cf18#6518
#cf18#6518
Lcf18_gate_draw_row:
#cf18#6518
        ; Draws a row of the gate of different types, depending on "a" (row type).
#cf18#6518
        ; "de" at this point contains the and-mask for left/right bytes.
#cf18#6518314
32 b7 cd 
        ld (Lcdb7_gate_row_type), a
#cf1b#651b422
ed 53 bc cd 
        ld (Lcdbc_gate_and_mask), de
#cf1f#651f
Lcf1f:
#cf1f#651f321
dd 5e 00 
        ld e, (ix)  ; Get ptr where to draw
#cf22#6522321
dd 56 01 
        ld d, (ix + 1)
#cf25#6525212
dd 23 
        inc ix  ; Next row
#cf27#6527212
dd 23 
        inc ix
#cf29#6529314
3a b7 cd 
        ld a, (Lcdb7_gate_row_type)
#cf2c#652c28
fe 01 
        cp 1
#cf2e#652e213/8
28 04 
        jr z, Lcf34_draw_solid_gate_row
#cf30#653028
fe 03 
        cp 3
#cf32#6532213/8
20 42 
        jr nz, Lcf76_draw_masking_gate_row
#cf34#6534
Lcf34_draw_solid_gate_row:
#cf34#6534311
01 18 00 
        ld bc, 24
#cf37#6537112
09 
        add hl, bc  ; advance "hl" (background ptr), since we are not using it in this row drawing iteration.
#cf38#6538112
e5 
        push hl
#cf39#6539
            ; Draw the gate row pattern 8 times to make a full gate row.
#cf39#6539
            ; Draw from "iy" to "de":
#cf39#653928
06 08 
            ld b, 8
#cf3b#653b
Lcf3b_draw_solid_gate_row_loop:
#cf3b#653b217
fd e5 
            push iy
#cf3d#653d111
e1 
            pop hl
#cf3e#653e28
0e 06 
            ld c, 6  ; Make sure ldi does not modify 'b'.
#cf40#6540218
ed a0 
            ldi
#cf42#6542218
ed a0 
            ldi
#cf44#6544218
ed a0 
            ldi
#cf46#6546214/9
10 f3 
            djnz Lcf3b_draw_solid_gate_row_loop
#cf48#6548111
e1 
        pop hl
#cf49#6549314
3a b9 cd 
        ld a, (Lcdb9_rows_left_of_the_same_type)
#cf4c#654c15
3d 
        dec a
#cf4d#654d213/8
20 1e 
        jr nz, Lcf6d
#cf4f#654f314
3a b7 cd 
        ld a, (Lcdb7_gate_row_type)
#cf52#655228
fe 01 
        cp 1
#cf54#6554213/8
20 06 
        jr nz, Lcf5c
#cf56#655628
3e 02 
        ld a, 2
#cf58#655828
0e 14 
        ld c, 20
#cf5a#655a213
18 04 
        jr Lcf60
#cf5c#655c
Lcf5c:
#cf5c#655c28
3e 04 
        ld a, 4
#cf5e#655e28
0e 0e 
        ld c, 14
#cf60#6560
Lcf60:
#cf60#6560314
32 b7 cd 
        ld (Lcdb7_gate_row_type), a
#cf63#656315
79 
        ld a, c
#cf64#6564314
32 b9 cd 
        ld (Lcdb9_rows_left_of_the_same_type), a
#cf67#6567416
fd 21 df cd 
        ld iy, Lcddf_gate_row_gfx
#cf6b#656b213
18 6c 
        jr Lcfd9_next_row
#cf6d#656d
Lcf6d:
#cf6d#656d314
32 b9 cd 
        ld (Lcdb9_rows_left_of_the_same_type), a
#cf70#657028
0e 03 
        ld c, 3
#cf72#6572217
fd 09 
        add iy, bc
#cf74#6574213
18 63 
        jr Lcfd9_next_row
#cf76#6576
#cf76#6576
Lcf76_draw_masking_gate_row:
#cf76#657628
06 08 
        ld b, 8  ; Gate is made out of 8 repeated horizontal blocks.
#cf78#6578
        ; Gate is read from (iy) [2 bytes], background from (hl), and we draw to (de):
#cf78#6578
Lcf78_draw_masking_gate_row_loop:
#cf78#6578
        ; Get the background left pixel, masked:
#cf78#6578314
3a bd cd 
        ld a, (Lcdbd_gate_and_mask_right)
#cf7b#657b18
a6 
        and (hl)
#cf7c#657c321
fd b6 00 
        or (iy)  ; add the gate byte
#cf7f#657f18
12 
        ld (de), a  ; draw it
#cf80#658017
23 
        inc hl
#cf81#658117
13 
        inc de
#cf82#6582
        ; Draw second byte as is (no need to mask, as it's in between gate bars):
#cf82#658228
0e 04 
        ld c, 4  ; make sure b is not modified
#cf84#6584218
ed a0 
        ldi
#cf86#6586
        ; Get the background right pixel, masked:
#cf86#6586314
3a bc cd 
        ld a, (Lcdbc_gate_and_mask_left)
#cf89#658918
a6 
        and (hl)
#cf8a#658a321
fd b6 01 
        or (iy + 1)
#cf8d#658d18
12 
        ld (de), a  ; add the gate byte
#cf8e#658e17
23 
        inc hl  ; draw it
#cf8f#658f17
13 
        inc de
#cf90#6590214/9
10 e6 
        djnz Lcf78_draw_masking_gate_row_loop
#cf92#6592
#cf92#6592314
3a b7 cd 
        ld a, (Lcdb7_gate_row_type)
#cf95#659528
fe 05 
        cp 5
#cf97#6597213/8
28 4c 
        jr z, Lcfe5_gate_draw_clear_bottom_rows
#cf99#6599314
3a b9 cd 
        ld a, (Lcdb9_rows_left_of_the_same_type)
#cf9c#659c15
3d 
        dec a
#cf9d#659d213/8
20 33 
        jr nz, Lcfd2
#cf9f#659f314
3a b7 cd 
        ld a, (Lcdb7_gate_row_type)
#cfa2#65a228
fe 04 
        cp 4
#cfa4#65a4213/8
20 12 
        jr nz, Lcfb8
#cfa6#65a6311
11 fe 7f 
        ld de, 32766  ; #7ffe
#cfa9#65a9422
ed 53 bc cd 
        ld (Lcdbc_gate_and_mask_left), de
#cfad#65ad28
3e 05 
        ld a, 5
#cfaf#65af314
32 b7 cd 
        ld (Lcdb7_gate_row_type), a
#cfb2#65b2416
fd 21 07 ce 
        ld iy, Lce07_gate_last_row_gfx
#cfb6#65b6213
18 21 
        jr Lcfd9_next_row
#cfb8#65b8
Lcfb8:
#cfb8#65b8314
3a b8 cd 
        ld a, (Lcdb8_gate_rows_left_to_draw)
#cfbb#65bb28
0e 03 
        ld c, 3
#cfbd#65bd28
fe 15 
        cp 21
#cfbf#65bf213/8
38 02 
        jr c, Lcfc3
#cfc1#65c128
0e 01 
        ld c, 1
#cfc3#65c3
Lcfc3:
#cfc3#65c328
3e 04 
        ld a, 4
#cfc5#65c5314
32 b9 cd 
        ld (Lcdb9_rows_left_of_the_same_type), a
#cfc8#65c815
79 
        ld a, c
#cfc9#65c9314
32 b7 cd 
        ld (Lcdb7_gate_row_type), a
#cfcc#65cc416
fd 21 d3 cd 
        ld iy, Lcdd3_gate_row_gfx_horizontal_bar
#cfd0#65d0213
18 07 
        jr Lcfd9_next_row
#cfd2#65d2
Lcfd2:
#cfd2#65d2314
32 b9 cd 
        ld (Lcdb9_rows_left_of_the_same_type), a
#cfd5#65d5212
fd 23 
        inc iy
#cfd7#65d7212
fd 23 
        inc iy
#cfd9#65d9
Lcfd9_next_row:
#cfd9#65d9314
3a b8 cd 
        ld a, (Lcdb8_gate_rows_left_to_draw)
#cfdc#65dc15
3d 
        dec a
#cfdd#65dd213/8
28 06 
        jr z, Lcfe5_gate_draw_clear_bottom_rows
#cfdf#65df314
32 b8 cd 
        ld (Lcdb8_gate_rows_left_to_draw), a
#cfe2#65e2311
c3 1f cf 
        jp Lcf1f
#cfe5#65e5
Lcfe5_gate_draw_clear_bottom_rows:
#cfe5#65e5
        ; Clear any rows below from any previous version of the gate that
#cfe5#65e5
        ; was drawn at a lower coordinate:
#cfe5#65e5314
3a bb cd 
        ld a, (Lcdbb_n_rows_to_clear_below)
#cfe8#65e815
b7 
        or a
#cfe9#65e9213/8
28 12 
        jr z, Lcffd_done
#cfeb#65eb
Lcfeb_clear_bottom_rows_loop:
#cfeb#65eb
        ; Copy one row directly from "hl" to screen:
#cfeb#65eb321
dd 5e 00 
        ld e, (ix)
#cfee#65ee321
dd 56 01 
        ld d, (ix + 1)
#cff1#65f1212
dd 23 
        inc ix
#cff3#65f3212
dd 23 
        inc ix
#cff5#65f5311
01 18 00 
        ld bc, 24
#cff8#65f8223/18
ed b0 
        ldir
#cffa#65fa15
3d 
        dec a
#cffb#65fb213/8
20 ee 
        jr nz, Lcfeb_clear_bottom_rows_loop
#cffd#65fd
Lcffd_done:
#cffd#65fd216
dd e1 
    pop ix
#cfff#65ff111
c9 
    ret
#d000#6600
#d000#6600
#d000#6600
; --------------------------------
#d000#6600
Ld000_character_draw_buffer_properties:
#d000#66003
    db 2, 8, #80  ; width (in bytes), height, and-mask of last byte
#d003#66032
    dw 16  ; 16 = 2 * 8 (size in bytes of each frame)
#d005#6605
Ld005_character_draw_buffer:
#d005#660516
    db #00, #00, #08, #00, #0c, #00, #fe, #00, #ff, #00, #fe, #00, #0c, #00, #08, #00
#d015#6615
#d015#6615
#d015#6615
; --------------------------------
#d015#6615
; Draws a string of text to screen.
#d015#6615
; Input:
#d015#6615
; - d: string length
#d015#6615
; - e: x offset
#d015#6615
; - hl: ptr to a text string (prefixed by 0 / 1):
#d015#6615
;       If prefix is 1, text is offset 5 pixels to the right.
#d015#6615
;       This is useful for centering text that has an odd length.
#d015#6615
; - ix: Pointer to the sequence of row pointers where to draw each row.
#d015#6615
Ld015_draw_string_without_erasing:
#d015#6615
    ; This is like "Ld01c_draw_string", but it uses drawing mode 3 in
#d015#6615
    ; the call to "Lc895_draw_sprite_to_ix_ptrs", which means that
#d015#6615
    ; we do not erase the background when drawing.
#d015#6615112
d5 
    push de
#d016#6616112
c5 
    push bc
#d017#661715
4a 
        ld c, d  ; c = string length
#d018#661828
16 80 
        ld d, 128  ; set drawing mode 3
#d01a#661a213
18 05 
        jr Ld021_draw_string_continue
#d01c#661c
Ld01c_draw_string:
#d01c#661c112
d5 
    push de
#d01d#661d112
c5 
    push bc
#d01e#661e15
4a 
        ld c, d  ; c = string length
#d01f#661f28
16 00 
        ld d, 0
#d021#6621
Ld021_draw_string_continue:
#d021#6621112
e5 
        push hl
#d022#6622112
f5 
        push af
#d023#662318
7e 
            ld a, (hl)
#d024#662417
23 
            inc hl
#d025#662515
b7 
            or a
#d026#6626213/8
28 26 
            jr z, Ld04e_no_indent
#d028#662815
0d 
            dec c  ; length-- (the first was just the length)
#d029#6629112
e5 
            push hl
#d02a#662a
                ; Clear the character draw buffer:
#d02a#662a311
21 05 d0 
                ld hl, Ld005_character_draw_buffer
#d02d#662d28
06 10 
                ld b, 16
#d02f#662f15
af 
                xor a
#d030#6630
Ld030_clear_loop:
#d030#663018
77 
                ld (hl), a
#d031#663117
23 
                inc hl
#d032#6632214/9
10 fc 
                djnz Ld030_clear_loop
#d034#6634
#d034#6634311
21 00 d0 
                ld hl, Ld000_character_draw_buffer_properties
#d037#6637318
cd 95 c8 
                call Lc895_draw_sprite_to_ix_ptrs
#d03a#663a15
79 
                ld a, c
#d03b#663b210
cb 27 
                sla a
#d03d#663d210
cb 27 
                sla a
#d03f#663f210
cb 27 
                sla a
#d041#664115
81 
                add a, c  ; a = length * 9  (each character is drawn 9 pixels to the right of the previous)
#d042#6642112
d5 
                push de
#d043#664315
83 
                    add a, e
#d044#664415
5f 
                    ld e, a  ; e = length * 9 + x_offset
#d045#6645318
cd 95 c8 
                    call Lc895_draw_sprite_to_ix_ptrs
#d048#6648111
d1 
                pop de
#d049#664928
3e 05 
                ld a, 5
#d04b#664b15
83 
                add a, e
#d04c#664c15
5f 
                ld e, a  ; x_offset += 5 (indent)
#d04d#664d111
e1 
            pop hl
#d04e#664e
Ld04e_no_indent:
#d04e#664e15
41 
            ld b, c  ; b = length
#d04f#664f
Ld04f_character_loop:
#d04f#664f112
c5 
            push bc
#d050#6650112
e5 
            push hl
#d051#6651112
d5 
                push de
#d052#665215
4a 
                    ld c, d  ; 0 or 128 (depending on whether Ld015 or Ld01c_draw_string was called)
#d053#665318
7e 
                    ld a, (hl)  ; get the next character to draw
#d054#665428
d6 20 
                    sub " "  ; get the index of the character
#d056#665615
6f 
                    ld l, a
#d057#665728
26 00 
                    ld h, 0
#d059#6659112
29 
                    add hl, hl
#d05a#665a112
29 
                    add hl, hl
#d05b#665b112
29 
                    add hl, hl
#d05c#665c311
11 47 7b 
                    ld de, L7b47_font
#d05f#665f112
19 
                    add hl, de  ; hl = L7b47_font + a * 8
#d060#6660
#d060#6660
                    ; Write the character in the character draw buffer:
#d060#6660311
11 05 d0 
                    ld de, Ld005_character_draw_buffer
#d063#666328
06 08 
                    ld b, 8
#d065#6665
Ld065_character_inner_draw_loop:
#d065#666518
7e 
                    ld a, (hl)
#d066#666618
12 
                    ld (de), a
#d067#666717
13 
                    inc de
#d068#666817
13 
                    inc de  ; We skip 2 bytes in the buffer, since the buffer is 16*8 pixels,
#d069#6669
                            ; but we are drawing an 8*8 character.
#d069#666917
23 
                    inc hl
#d06a#666a214/9
10 f9 
                    djnz Ld065_character_inner_draw_loop
#d06c#666c311
21 00 d0 
                    ld hl, Ld000_character_draw_buffer_properties
#d06f#666f111
d1 
                pop de
#d070#6670318
cd 95 c8 
                call Lc895_draw_sprite_to_ix_ptrs
#d073#667315
7b 
                ld a, e
#d074#667428
c6 09 
                add a, 9
#d076#667615
5f 
                ld e, a  ; x_offset += 9 (next character)
#d077#6677111
e1 
            pop hl
#d078#6678111
c1 
            pop bc
#d079#667917
23 
            inc hl
#d07a#667a
            ; next character
#d07a#667a214/9
10 d3 
            djnz Ld04f_character_loop
#d07c#667c111
f1 
        pop af
#d07d#667d111
e1 
        pop hl
#d07e#667e111
c1 
    pop bc
#d07f#667f111
d1 
    pop de
#d080#6680111
c9 
    ret
#d081#6681
#d081#6681
#d081#6681
; --------------------------------
#d081#66811
    db #c9  ; Unused? could be a left-over "ret".
#d082#6682
#d082#6682
#d082#6682
; --------------------------------
#d082#6682
Ld082_area_reference_start:
#d082#6682
Ld082_n_areas:
#d082#66821
    db 39  ; Number of areas
#d083#6683
Ld083_game_version:
#d083#66832
    dw #22fa  ; Game version ID
#d085#6685
Ld085_initial_area_id:
#d085#66851
    db #02
#d086#6686
Ld086_initial_player_object:  ; player start coordinates are taken from this object
#d086#66861
    db #01
#d087#6687
Ld087_starting_strength:
#d087#66871
    db #10
#d088#6688
Ld088_texture_patterns:  ; each texture has 4 bytes (to repeat vertically)
#d088#66884
    db #00, #00, #00, #00
#d08c#668c4
    db #ff, #ff, #ff, #ff
#d090#66904
    db #dd, #77, #dd, #77
#d094#66944
    db #aa, #55, #aa, #55
#d098#66984
    db #88, #22, #88, #22
#d09c#669c4
    db #55, #ff, #aa, #ff
#d0a0#66a04
    db #aa, #55, #55, #aa
#d0a4#66a44
    db #cc, #33, #cc, #33
#d0a8#66a84
    db #55, #55, #aa, #aa
#d0ac#66ac4
    db #ff, #55, #ff, #aa
#d0b0#66b04
    db #ff, #ff, #ff, #ff
#d0b4#66b44
    db #77, #dd, #77, #dd
#d0b8#66b84
    db #aa, #aa, #55, #55
#d0bc#66bc4
    db #33, #cc, #33, #cc
#d0c0#66c04
    db #22, #88, #22, #88
#d0c4#66c4
#d0c4#66c4
Ld0c4:  ; Unused?
#d0c4#66c42
    dw #01d5
#d0c6#66c6
Ld0c6_global_rules_offset:
#d0c6#66c62
    dw Ld11f_global_rules - Ld082_area_reference_start
#d0c8#66c8
#d0c8#66c8
    ; Game configuration parameters:
#d0c8#66c8
Ld0c8_speed_when_crawling:
#d0c8#66c81
    db #1e
#d0c9#66c9
Ld0c9_speed_when_walking:
#d0c9#66c91
    db #3c
#d0ca#66ca
Ld0ca_speed_when_running:
#d0ca#66ca1
    db #f0
#d0cb#66cb
Ld0cb_n_sprits_that_must_be_killed:
#d0cb#66cb1
    db #1a
#d0cc#66cc
Ld0cc_max_failling_height_in_room_units:
#d0cc#66cc1
    db #02
#d0cd#66cd
Ld0cd_max_climbable_height_in_room_units:
#d0cd#66cd1
    db #01
#d0ce#66ce
Ld0ce_yaw_rotation_speed:
#d0ce#66ce1
    db #02
#d0cf#66cf
Ld0cf_keyboard_hold_delays:
#d0cf#66cf2
    db #01, #01  ; Delay for the first key repeat if you hold the key, and delay for all repeats after that.
#d0d1#66d1
#d0d1#66d1
; - 39 16bit offsets (39 = (Ld082_n_areas)).
#d0d1#66d1
; - Each offset defines the start of a data blck with "Ld082_area_reference_start + offset".
#d0d1#66d1
Ld0d1_area_offsets:
#d0d1#66d12
    dw Ld169_area_1 - Ld082_area_reference_start
#d0d3#66d32
    dw Ld2be_area_ff - Ld082_area_reference_start
#d0d5#66d52
    dw Ld6c2_area_2 - Ld082_area_reference_start
#d0d7#66d72
    dw Ld8cf_area_3 - Ld082_area_reference_start
#d0d9#66d92
    dw Ld973_area_4 - Ld082_area_reference_start
#d0db#66db2
    dw Lda83_area_5 - Ld082_area_reference_start
#d0dd#66dd2
    dw Ldb5b_area_6 - Ld082_area_reference_start
#d0df#66df2
    dw Ldc74_area_7 - Ld082_area_reference_start
#d0e1#66e12
    dw Ldcd8_area_8 - Ld082_area_reference_start
#d0e3#66e32
    dw Ldddb_area_9 - Ld082_area_reference_start
#d0e5#66e52
    dw Lde47_area_10 - Ld082_area_reference_start
#d0e7#66e72
    dw Lde9f_area_11 - Ld082_area_reference_start
#d0e9#66e92
    dw Ldf1e_area_12 - Ld082_area_reference_start
#d0eb#66eb2
    dw Ldfad_area_13 - Ld082_area_reference_start
#d0ed#66ed2
    dw Le024_area_14 - Ld082_area_reference_start
#d0ef#66ef2
    dw Le090_area_15 - Ld082_area_reference_start
#d0f1#66f12
    dw Le1f3_area_22 - Ld082_area_reference_start
#d0f3#66f32
    dw Le48c_area_24 - Ld082_area_reference_start
#d0f5#66f52
    dw Le539_area_21 - Ld082_area_reference_start
#d0f7#66f72
    dw Le721_area_17 - Ld082_area_reference_start
#d0f9#66f92
    dw Le813_area_19 - Ld082_area_reference_start
#d0fb#66fb2
    dw Le86c_area_27 - Ld082_area_reference_start
#d0fd#66fd2
    dw Le8a3_area_28 - Ld082_area_reference_start
#d0ff#66ff2
    dw Le903_area_29 - Ld082_area_reference_start
#d101#67012
    dw Le953_area_49 - Ld082_area_reference_start
#d103#67032
    dw Leb18_area_30 - Ld082_area_reference_start
#d105#67052
    dw Leb75_area_31 - Ld082_area_reference_start
#d107#67072
    dw Lebca_area_32 - Ld082_area_reference_start
#d109#67092
    dw Lec68_area_33 - Ld082_area_reference_start
#d10b#670b2
    dw Lecd0_area_35 - Ld082_area_reference_start
#d10d#670d2
    dw Led69_area_37 - Ld082_area_reference_start
#d10f#670f2
    dw Leec2_area_36 - Ld082_area_reference_start
#d111#67112
    dw Lef4a_area_38 - Ld082_area_reference_start
#d113#67132
    dw Lf035_area_40 - Ld082_area_reference_start
#d115#67152
    dw Lf0ad_area_41 - Ld082_area_reference_start
#d117#67172
    dw Lf0f5_area_42 - Ld082_area_reference_start
#d119#67192
    dw Lf12c_area_43 - Ld082_area_reference_start
#d11b#671b2
    dw Lf203_area_44 - Ld082_area_reference_start
#d11d#671d2
    dw Lf2c4_area_46 - Ld082_area_reference_start
#d11f#671f
#d11f#671f
; The global rules are made out of a collection of "scripts":
#d11f#671f
; - The first byte is the number of "scripts".
#d11f#671f
; - Each script follows:
#d11f#671f
;   - First byte is the size of the script in bytes (not including the size)
#d11f#671f
;   - Then each script is made out of a collection of rules:
#d11f#671f
;     - The first byte of the rule is:
#d11f#671f
;       fftttttt:
#d11f#671f
;         - ff: determine which type of event will the rule match with:
#d11f#671f
;           - #00: movement
#d11f#671f
;           - #40: timer
#d11f#671f
;           - #80: stone throwing
#d11f#671f
;           - #c0: interact
#d11f#671f
;         - tttttt: rule type
#d11f#671f
;           - The size of each individual rule is determined by the type, and
#d11f#671f
;             the game determines it by checking the "L6b3c_rule_size_by_type" array.
#d11f#671f
;     - The rest of the bytes of the rule are the arguments of the rule.
#d11f#671f
;       - for example, rule type "1" had 3 bytes, encoding a 24 bit number that will
#d11f#671f
;         be added to the player score.
#d11f#671f
;     - Each "rule" is triggered if the current event that occurred (movement, interaction,
#d11f#671f
;       stone, timer) matches the flags. Some rules refer to objects, and the object the
#d11f#671f
;       player threw a rock to or interacted with is read from a global variable
#d11f#671f
;       from the game.
#d11f#671f
Ld11f_global_rules:
#d11f#671f1
    db 7  ; Number of scripts
#d120#6720
    ; Each script starts with the number of bytes remaining
#d120#67206
    db 5, #4e, #10, #01, #53, #02
#d126#672616
    db 15, #1e, #7f, #04, #88, #04, #89, #04, #8a, #2c, #05, #88, #05, #89, #05, #8a
#d136#67368
    db 7, #1e, #7e, #04, #8c, #2c, #05, #8c
#d13e#673e16
    db 15, #1e, #7d, #04, #90, #04, #91, #04, #92, #2c, #05, #90, #05, #91, #05, #92
#d14e#674e8
    db 7, #1e, #7c, #04, #94, #2c, #05, #94
#d156#675616
    db 15, #1e, #7b, #04, #96, #04, #97, #04, #98, #2c, #05, #96, #05, #97, #05, #98
#d166#67663
    db 2, #23, #00
#d169#6769
#d169#6769
    ; Each area block has the following structure:
#d169#6769
    ; The area starts with an 8 bit header:
#d169#6769
    ;   - area flags:
#d169#6769
    ;       - 4 least significant bits are the sky texture number.
#d169#6769
    ;       - most significant nibble are the floor texture number.
#d169#6769
    ;   - n objects
#d169#6769
    ;   - ID
#d169#6769
    ;   - offset to rule data (2 bytes)
#d169#6769
    ;   - scale
#d169#6769
    ;   - attribute color
#d169#6769
    ;   - area name
#d169#6769
    ; - There is a special area "Ld2be_area_ff" that I suspect has global objects, but I have not checked.
#d169#6769
    ; - Then there are as many objects as specified in the header.
#d169#6769
    ; - Each object has the following structure:
#d169#6769
    ;   - The byte 0 is the "type/state":
#d169#6769
    ;     - 4 least significant bits are the object type.
#d169#6769
    ;     - most significant nibble are the state/flags:
#d169#6769
    ;       - bit 5: destroyed
#d169#6769
    ;       - bit 6: invisible
#d169#6769
    ;     - types: (see OBJECT_TYPE_* definitions at the beginning of this gile)
#d169#6769
    ;   - bytes 1, 2, 3 are the x, y, z coordinates
#d169#6769
    ;   - bytes 4, 5, 6 are the width, height and length
#d169#6769
    ;   - byte 7: object ID
#d169#6769
    ;   - byte 8: contains the length of the object
#d169#6769
    ;   - bytes after that: additional data for the object:
#d169#6769
    ;     - For geometric shapes (ID >= 10):
#d169#6769
    ;       - first byte is their texture ID
#d169#6769
    ;       - after that is vertices (3 bytes per vertex: x, y, z)
#d169#6769
    ;     - For cubes (ID = 1), they have 3 bytes, containing the texture IDs for each of the 6 faces (2 per byte)
#d169#6769
    ;     - For rectangles (ID = 3), they have 1 byte, with the texture ID of the two sides of the rectangle.
#d169#6769
    ; - Some areas have a special object with ID "ff", that is not an object but contains a list of IDs of other objects.
#d169#6769
    ; - After all the objects, there is a "rules" area.
#d169#6769
Ld169_area_1:  ; WILDERNESS
#d169#6769
    ; Header:
#d169#67693
    db #81, 25, #01  ; flags, n objects, ID
#d16c#676c2
    dw #0154  ; offset to rules
#d16e#676e3
    db #01, #44, #00  ; scale, attribute, area name
#d171#6771
    ; Objects (25 of them for this area):
#d171#6771
    ; The first 9 bytes of an object are: type/state, x, y, z, dx, dy, dz, ID, size, the rest is extra info, specific fo each object.
#d171#677126
    db #03, #1a, #00, #1a, #4c, #00, #4c, #03, #1a, #10, #1c, #02, #12, #01, #2a, #1a, #22, #26, #1b, #32, #22, #10, #1b, #64, #13, #80  ; object 1
#d18b#678b12
    db #01, #50, #00, #50, #10, #16, #10, #05, #0c, #33, #00, #44  ; object 2
#d197#679712
    db #01, #20, #00, #50, #10, #16, #10, #07, #0c, #33, #00, #44  ; object 3
#d1a3#67a312
    db #01, #30, #00, #5a, #20, #12, #04, #0c, #0c, #00, #00, #50  ; object 4
#d1af#67af10
    db #03, #2b, #0f, #60, #01, #03, #00, #0d, #0a, #10  ; object 5
#d1b9#67b910
    db #03, #23, #04, #60, #01, #03, #00, #0e, #0a, #10  ; object 6
#d1c3#67c310
    db #03, #5c, #11, #60, #01, #03, #00, #0f, #0a, #10  ; object 7
#d1cd#67cd13
    db #03, #53, #04, #60, #01, #03, #00, #11, #0d, #10, #12, #13, #d8  ; object 8
#d1da#67da12
    db #c1, #3e, #00, #5e, #04, #01, #09, #10, #0c, #bb, #90, #60  ; object 9
#d1e6#67e612
    db #01, #3e, #01, #5e, #04, #08, #01, #13, #0c, #bb, #60, #d0  ; object 10
#d1f2#67f216
    db #ca, #3e, #01, #5e, #00, #07, #09, #15, #10, #22, #3e, #01, #67, #3e, #08, #5e  ; object 11
#d202#680216
    db #ca, #42, #01, #5e, #00, #07, #09, #16, #10, #22, #42, #01, #67, #42, #08, #5e  ; object 12
#d212#68129
    db #c0, #0e, #00, #7d, #00, #1c, #00, #1a, #09  ; object 13
#d21b#681b29
    db #03, #44, #07, #5e, #01, #01, #00, #1c, #1d, #60, #83, #16, #86, #11, #09, #86, #11, #0a, #86, #11, #0b, #83, #10, #83, #13, #83, #15, #9c, #08  ; object 14
#d238#68389
    db #c0, #3f, #01, #5e, #00, #00, #00, #12, #09  ; object 15
#d241#684128
    db #0d, #3e, #01, #5e, #04, #0b, #00, #02, #1c, #01, #3e, #08, #5e, #40, #0c, #5e, #42, #08, #5e, #42, #01, #5e, #3e, #01, #5e, #12, #11, #0c  ; object 16
#d25d#685d9
    db #c0, #25, #00, #62, #11, #1c, #00, #2a, #09  ; object 17
#d266#68669
    db #c0, #7c, #00, #01, #00, #24, #00, #1b, #09  ; object 18
#d26f#686f13
    db #c3, #06, #00, #6b, #01, #00, #01, #36, #0d, #11, #12, #21, #8b  ; object 19
#d27c#687c9
    db #c0, #3f, #0e, #68, #06, #1c, #00, #21, #09  ; object 20
#d285#688510
    db #03, #3d, #00, #66, #06, #00, #04, #23, #0a, #00  ; object 21
#d28f#688f9
    db #c0, #23, #04, #60, #00, #00, #00, #19, #09  ; object 22
#d298#689812
    db #01, #52, #03, #60, #03, #01, #02, #04, #0c, #dd, #aa, #99  ; object 23
#d2a4#68a49
    db #c0, #53, #04, #61, #00, #00, #00, #06, #09  ; object 24
#d2ad#68ad16
    db #03, #00, #00, #66, #7f, #00, #09, #01, #10, #00, #0c, #1f, #01, #60, #2f, #34  ; object 25
#d2bd#68bd
    ; ; Area rules: (0 rules in this area):
#d2bd#68bd1
    db 0
#d2be#68be
#d2be#68be
Ld2be_area_ff:
#d2be#68be
    ; Header:
#d2be#68be3
    db #00, 75, #ff  ; flags, n objects, ID
#d2c1#68c12
    dw #0403  ; offset to rules
#d2c3#68c33
    db #01, #00, #60  ; scale, attribute, area name
#d2c6#68c6
    ; Objects:
#d2c6#68c612
    db #01, #00, #00, #00, #7f, #02, #7f, #80, #0c, #00, #40, #00
#d2d2#68d212
    db #01, #02, #3d, #02, #7b, #02, #7b, #81, #0c, #00, #04, #00
#d2de#68de12
    db #01, #7d, #02, #00, #02, #3d, #7f, #83, #0c, #03, #00, #00
#d2ea#68ea12
    db #01, #02, #02, #7d, #7b, #3d, #02, #85, #0c, #00, #00, #02
#d2f6#68f621
    db #c0, #05, #02, #79, #00, #24, #00, #d6, #15, #e2, #17, #dc, #04, #d3, #03, #e3, #01, #c1, #98, #3a, #00
#d30b#690b19
    db #c0, #03, #02, #79, #00, #12, #00, #d7, #13, #89, #1c, #9c, #01, #a3, #01, #81, #c8, #af, #00
#d31e#691e19
    db #c0, #3e, #02, #7c, #00, #24, #00, #d8, #13, #dc, #0a, #e2, #11, #e3, #01, #c1, #c0, #d4, #01
#d331#693119
    db #c0, #79, #02, #79, #00, #36, #00, #d9, #13, #dc, #0d, #e2, #19, #e3, #01, #c1, #f0, #49, #02
#d344#694415
    db #c0, #79, #02, #79, #00, #24, #00, #da, #0f, #9c, #03, #81, #f8, #24, #01
#d353#69539
    db #c0, #79, #02, #3e, #00, #36, #00, #db, #09
#d35c#695c9
    db #c0, #79, #02, #06, #00, #00, #00, #dc, #09
#d365#69659
    db #c0, #79, #02, #06, #00, #36, #00, #dd, #09
#d36e#696e9
    db #c0, #3e, #02, #03, #00, #00, #00, #de, #09
#d377#69779
    db #c0, #06, #02, #06, #00, #12, #00, #df, #09
#d380#69809
    db #c0, #05, #02, #06, #00, #00, #00, #e0, #09
#d389#69899
    db #c0, #03, #02, #3e, #00, #12, #00, #e1, #09
#d392#699212
    db #41, #44, #02, #02, #02, #1c, #7b, #86, #0c, #03, #00, #00
#d39e#699e12
    db #41, #02, #1e, #02, #7b, #02, #7b, #8d, #0c, #00, #04, #00
#d3aa#69aa12
    db #01, #00, #02, #00, #02, #3b, #7f, #82, #0c, #30, #00, #00
#d3b6#69b612
    db #41, #02, #1f, #74, #72, #01, #09, #87, #0c, #00, #88, #05
#d3c2#69c212
    db #01, #02, #02, #00, #7b, #3d, #02, #84, #0c, #00, #00, #20
#d3ce#69ce12
    db #41, #02, #1a, #65, #2e, #06, #18, #c5, #0c, #55, #88, #77
#d3da#69da12
    db #41, #02, #14, #5d, #10, #06, #18, #ae, #0c, #ff, #66, #99
#d3e6#69e612
    db #41, #02, #0e, #55, #10, #06, #18, #af, #0c, #55, #88, #77
#d3f2#69f212
    db #41, #02, #08, #4d, #10, #06, #18, #c3, #0c, #ff, #aa, #dd
#d3fe#69fe12
    db #41, #02, #02, #45, #10, #06, #18, #c4, #0c, #55, #88, #77
#d40a#6a0a12
    db #41, #30, #02, #02, #02, #3b, #7b, #c6, #0c, #03, #00, #00
#d416#6a169
    db #c0, #0a, #02, #02, #00, #00, #00, #c7, #09
#d41f#6a1f9
    db #c0, #0a, #20, #7c, #00, #24, #00, #c8, #09
#d428#6a2812
    db #41, #02, #02, #40, #3e, #1c, #3d, #c9, #0c, #55, #88, #77
#d434#6a349
    db #c0, #2f, #02, #38, #00, #36, #00, #ca, #09
#d43d#6a3d14
    db #41, #02, #0c, #13, #01, #0a, #0a, #cb, #0e, #44, #ff, #55, #e2, #1f
#d44b#6a4b12
    db #43, #03, #13, #14, #00, #02, #02, #cc, #0c, #20, #f0, #cb
#d457#6a5712
    db #43, #03, #10, #14, #00, #02, #02, #cd, #0c, #20, #f0, #cb
#d463#6a6312
    db #43, #03, #0d, #14, #00, #02, #02, #d2, #0c, #20, #f0, #cb
#d46f#6a6f12
    db #43, #03, #10, #17, #00, #02, #02, #d3, #0c, #20, #f0, #cb
#d47b#6a7b12
    db #43, #03, #13, #1a, #00, #02, #02, #d4, #0c, #20, #f0, #cb
#d487#6a8712
    db #43, #03, #10, #1a, #00, #02, #02, #d5, #0c, #20, #f0, #cb
#d493#6a9312
    db #43, #03, #0d, #1a, #00, #02, #02, #e4, #0c, #20, #f0, #cb
#d49f#6a9f9
    db #c0, #41, #02, #60, #00, #12, #00, #e5, #09
#d4a8#6aa812
    db #41, #02, #16, #38, #7b, #02, #0e, #e6, #0c, #00, #04, #00
#d4b4#6ab412
    db #41, #02, #02, #46, #7b, #3b, #01, #e9, #0c, #00, #00, #02
#d4c0#6ac012
    db #41, #02, #02, #36, #7b, #3b, #02, #ea, #0c, #00, #00, #20
#d4cc#6acc9
    db #c0, #5e, #02, #7c, #00, #24, #00, #eb, #09
#d4d5#6ad59
    db #c0, #22, #02, #02, #00, #00, #00, #ec, #09
#d4de#6ade26
    db #47, #07, #28, #07, #18, #08, #10, #88, #1a, #d6, #d6, #90, #06, #04, #12, #0c, #90, #7f, #85, #88, #85, #89, #85, #8a, #b0, #d7
#d4f8#6af814
    db #41, #07, #30, #07, #18, #04, #10, #89, #0e, #dd, #00, #66, #b0, #88
#d506#6b0618
    db #46, #07, #34, #07, #18, #04, #10, #8a, #12, #d6, #d6, #90, #06, #06, #10, #0a, #b0, #88
#d518#6b1825
    db #4b, #3d, #0a, #40, #04, #00, #01, #8c, #19, #11, #3d, #0a, #41, #41, #0a, #41, #3f, #0a, #40, #90, #7e, #85, #8c, #b0, #d7
#d531#6b3122
    db #41, #43, #0f, #2f, #01, #0d, #07, #90, #16, #89, #11, #11, #90, #7d, #85, #90, #85, #91, #85, #92, #b0, #d7
#d547#6b4714
    db #41, #44, #14, #2f, #05, #01, #07, #91, #0e, #e0, #66, #11, #b0, #90
#d555#6b5514
    db #41, #48, #0f, #2f, #01, #05, #07, #92, #0e, #ee, #0b, #11, #b0, #90
#d563#6b6340
    db #46, #18, #07, #3f, #05, #02, #0a, #94, #28, #a5, #a2, #00, #00, #01, #05, #01, #e2, #17, #dc, #04, #d3, #03, #c5, #94, #c5, #7c, #e3, #01, #c9, #1c, #c1, #c8, #af, #00, #85, #94, #85, #7c, #b0, #d7
#d58b#6b8b26
    db #44, #31, #02, #3e, #02, #01, #02, #96, #1a, #fb, #eb, #11, #00, #01, #00, #01, #90, #7b, #85, #96, #85, #97, #85, #98, #b0, #d7
#d5a5#6ba518
    db #46, #2e, #02, #3e, #03, #01, #02, #97, #12, #05, #af, #00, #01, #01, #03, #01, #b0, #96
#d5b7#6bb718
    db #4a, #2a, #02, #3f, #04, #00, #00, #98, #12, #11, #2a, #02, #3f, #2e, #02, #3f, #b0, #96
#d5c9#6bc912
    db #41, #38, #02, #38, #10, #10, #10, #8b, #0c, #ff, #77, #55
#d5d5#6bd512
    db #41, #1d, #02, #1d, #08, #08, #08, #8e, #0c, #ff, #77, #55
#d5e1#6be112
    db #41, #5e, #30, #25, #1f, #02, #58, #8f, #0c, #dd, #ee, #77
#d5ed#6bed12
    db #41, #3f, #02, #02, #3e, #30, #1b, #93, #0c, #aa, #99, #ee
#d5f9#6bf912
    db #41, #6a, #02, #24, #11, #0a, #16, #95, #0c, #ee, #00, #99
#d605#6c0512
    db #41, #68, #0c, #22, #15, #01, #1a, #99, #0c, #11, #ff, #11
#d611#6c1116
    db #47, #3f, #0c, #38, #02, #04, #02, #9a, #10, #9d, #9d, #00, #01, #00, #01, #00
#d621#6c2120
    db #46, #3f, #10, #38, #02, #02, #02, #9b, #14, #6a, #6a, #00, #01, #01, #01, #01, #d3, #fe, #e2, #10
#d635#6c3512
    db #c1, #02, #02, #2d, #01, #17, #0b, #9c, #0c, #88, #55, #55
#d641#6c4112
    db #c1, #03, #0c, #2d, #08, #01, #0b, #9d, #0c, #e0, #bb, #55
#d64d#6c4d12
    db #c1, #0a, #02, #2d, #01, #0a, #0b, #9e, #0c, #ee, #00, #55
#d659#6c5916
    db #49, #02, #02, #13, #18, #0c, #10, #9f, #10, #e8, #e7, #80, #08, #00, #10, #0c
#d669#6c6916
    db #48, #02, #02, #23, #18, #0c, #30, #a0, #10, #87, #85, #e0, #07, #00, #11, #0c
#d679#6c7912
    db #41, #5e, #30, #02, #1f, #02, #7b, #a1, #0c, #77, #ff, #dd
#d685#6c8512
    db #41, #02, #30, #02, #1f, #02, #7b, #a2, #0c, #77, #ff, #dd
#d691#6c9112
    db #41, #02, #21, #02, #1f, #02, #7b, #a3, #0c, #77, #ff, #dd
#d69d#6c9d12
    db #41, #02, #12, #02, #1f, #02, #7b, #a4, #0c, #77, #ff, #dd
#d6a9#6ca912
    db #41, #17, #09, #2c, #18, #01, #28, #a5, #0c, #11, #ee, #11
#d6b5#6cb512
    db #41, #1d, #02, #30, #0d, #07, #20, #a6, #0c, #ff, #66, #cc
#d6c1#6cc1
    ; Area rules:
#d6c1#6cc11
    db #00
#d6c2#6cc2
#d6c2#6cc2
Ld6c2_area_2:  ; THE CRYPT
#d6c2#6cc2
    ; Header:
#d6c2#6cc23
    db #00, 24, #02  ; no floor/sky, 24 objects, room ID 2
#d6c5#6cc52
    dw #020c  ; offset to rules
#d6c7#6cc73
    db #13, #47, #01  ; scale, attribute, area name
#d6ca#6cca
    ; Objects:
#d6ca#6cca9
    db #c0, #80, #81, #82, #83, #84, #85, #ff, #09  ; object 1 (????)
#d6d3#6cd313
    db #c3, #7d, #02, #33, #00, #30, #18, #02, #0d, #11, #12, #03, #01  ; object 2 (????)
#d6e0#6ce016
    db #04, #27, #0c, #06, #50, #0e, #20, #03, #10, #1e, #0e, #80, #00, #0a, #0e, #17  ; object 3 (coffin body, part 1)
#d6f0#6cf016
    db #05, #0f, #0c, #06, #18, #0e, #20, #04, #10, #18, #08, #e0, #00, #08, #0e, #18  ; object 4 (coffin body, part 2)
#d700#6d0032
    db #04, #27, #1a, #06, #50, #02, #20, #05, #20, #8d, #0d, #90, #00, #0a, #01, #17, #e2, #24, #c4, #07, #c4, #08, #c5, #05, #c5, #06, #dc, #0b, #e3, #01, #c4, #7b  ; object 5 (coffin lid when closed, part 1)
#d720#6d2018
    db #05, #0f, #1a, #06, #18, #02, #20, #06, #12, #89, #09, #d0, #00, #08, #02, #18, #f0, #05  ; object 6 (coffin lid when closed, part 2)
#d732#6d3230
    db #c4, #2a, #1a, #06, #50, #20, #02, #07, #1e, #d5, #d8, #90, #08, #00, #18, #02, #e2, #25, #c4, #05, #c4, #06, #c5, #07, #c5, #08, #e3, #01, #dc, #08  ; object 7 (coffin lid when open, part 1)
#d750#6d5018
    db #c5, #12, #1a, #06, #18, #20, #02, #08, #12, #98, #95, #d0, #08, #00, #18, #02, #f0, #07  ; object 8 (coffin lid when open, part 2)
#d762#6d6212
    db #01, #28, #02, #5c, #30, #15, #18, #09, #0c, #88, #00, #77  ; object 9 (chest when closed)
#d76e#6d6e57
    db #06, #28, #17, #5c, #30, #07, #18, #0a, #39, #9e, #9e, #80, #00, #07, #30, #11, #e2, #24, #c5, #09, #c5, #0a, #c4, #0c, #c4, #0e, #c4, #0f, #c4, #10, #c4, #11, #c4, #12, #ce, #01, #00, #c4, #13, #c4, #14, #c4, #15, #c4, #16, #ed, #e3, #01, #dc, #0b, #ce, #11, #01, #c4, #1c, #cd, #11  ; object 10 (chest lid when closed)
#d7a7#6da742
    db #c8, #28, #17, #74, #30, #18, #09, #0c, #2a, #9e, #9e, #01, #00, #07, #30, #11, #e2, #25, #c5, #0c, #c5, #0e, #c5, #0f, #c5, #10, #c5, #11, #c5, #12, #c4, #09, #c4, #0a, #c5, #13, #c5, #1c, #e3, #01, #dc, #08  ; object 11 (chest lid when open)
#d7d1#6dd112
    db #c1, #28, #02, #5c, #02, #15, #18, #0e, #0c, #58, #a0, #77  ; object 12 (open chest wall side 1)
#d7dd#6ddd12
    db #c1, #56, #02, #5c, #02, #15, #18, #0f, #0c, #85, #a0, #77  ; object 13 (open chest wall side 2)
#d7e9#6de912
    db #c1, #2a, #02, #5c, #2c, #15, #02, #10, #0c, #00, #a0, #d7  ; object 14 (open chest wall, front)
#d7f5#6df512
    db #c1, #2a, #02, #72, #2c, #15, #02, #11, #0c, #00, #a0, #79  ; object 15 (open chest wall, back)
#d801#6e0112
    db #c1, #2a, #02, #5e, #2c, #01, #14, #12, #0c, #00, #10, #00  ; object 16 (open chest bottom)
#d80d#6e0d17
    db #c3, #3d, #03, #66, #0c, #00, #06, #13, #11, #b0, #d4, #20, #01, #c5, #13, #f0, #d8  ; object 17 (key)
#d81e#6e1e34
    db #01, #7c, #02, #33, #01, #30, #18, #17, #22, #55, #aa, #aa, #ce, #01, #00, #e2, #15, #db, #25, #e2, #2b, #db, #25, #e2, #13, #ec, #e2, #1a, #dc, #0b, #c5, #17, #c4, #02  ; object 18 (door blocking the exit)
#d840#6e409
    db #c0, #02, #02, #6d, #00, #1a, #00, #01, #09  ; object 19 (exit)
#d849#6e4965
    db #03, #02, #27, #6f, #00, #01, #01, #1b, #41, #33, #89, #10, #ae, #10, #09, #8c, #10, #8c, #1e, #94, #20, #01, #9a, #94, #20, #02, #9a, #94, #20, #03, #9a, #94, #20, #04, #9a, #94, #20, #05, #9a, #94, #20, #06, #9a, #94, #20, #07, #9a, #94, #20, #08, #9a, #94, #20, #09, #9a, #94, #20, #0a, #9a, #87, #16, #20, #87, #31, #13  ; object 20 (????)
#d88a#6e8a9
    db #c2, #00, #00, #00, #00, #00, #00, #7b, #09  ; object 21 (spirit)
#d893#6e9335
    db #c6, #51, #03, #68, #04, #03, #08, #1c, #23, #65, #62, #00, #00, #01, #04, #01, #e2, #17, #dc, #04, #d3, #03, #c5, #1c, #e3, #01, #ce, #12, #00, #c1, #98, #3a, #00, #cc, #12  ; object 22 (invisible piece of cheese in the chest)
#d8b6#6eb612
    db #01, #6b, #02, #12, #0a, #0a, #0a, #1d, #0c, #ff, #00, #55  ; object 23 (foot of coffin 1) 
#d8c2#6ec212
    db #01, #11, #02, #12, #0a, #0a, #0a, #1e, #0c, #ff, #00, #55  ; object 24 (foot of coffin 2)
#d8ce#6ece
    ; Area rules:
#d8ce#6ece1
    db #00
#d8cf#6ecf
#d8cf#6ecf
Ld8cf_area_3:  ; CRYPT CORRIDOR
#d8cf#6ecf
    ; I have only annotated the first few blocks above as an example (as it is a lot of work to do this by hand), all other blocks below are analogous.
#d8cf#6ecf8
    db #00, #0c, #03, #a3, #00, #08, #46, #02
#d8d7#6ed710
    db #c0, #80, #8d, #82, #86, #84, #85, #ff, #0b, #a5
#d8e1#6ee116
    db #a6, #03, #02, #02, #18, #00, #10, #08, #02, #0d, #11, #12, #02, #db, #c0, #02
#d8f1#6ef116
    db #02, #1c, #00, #12, #00, #01, #09, #03, #02, #02, #58, #00, #10, #08, #03, #0d
#d901#6f0116
    db #11, #12, #04, #db, #c0, #02, #02, #5c, #00, #12, #00, #04, #09, #03, #44, #02
#d911#6f1116
    db #58, #00, #10, #08, #05, #0d, #11, #12, #05, #e1, #c0, #43, #02, #5c, #00, #36
#d921#6f2116
    db #00, #06, #09, #03, #44, #02, #18, #00, #10, #08, #07, #0d, #11, #12, #06, #e1
#d931#6f3116
    db #c0, #43, #02, #1b, #00, #36, #00, #08, #09, #c3, #1f, #02, #7d, #08, #10, #00
#d941#6f4116
    db #09, #0d, #11, #12, #07, #de, #c0, #22, #02, #7c, #00, #24, #00, #0a, #09, #01
#d951#6f5116
    db #1f, #02, #7c, #08, #10, #01, #0e, #22, #11, #11, #55, #ce, #02, #00, #e2, #15
#d961#6f6116
    db #db, #25, #e2, #2f, #db, #25, #e2, #13, #ec, #e2, #1a, #dc, #0b, #c5, #0e, #c4
#d971#6f712
    db #09, #00
#d973#6f73
#d973#6f73
Ld973_area_4:  ; THE MOUSETRAP
#d973#6f738
    db #00, #11, #04, #0f, #01, #10, #47, #03
#d97b#6f7b6
    db #c0, #80, #81, #82, #83, #84
#d981#6f8116
    db #85, #ff, #0c, #a2, #a3, #a4, #03, #7d, #02, #38, #00, #20, #10, #02, #0d, #11
#d991#6f9116
    db #12, #03, #04, #01, #38, #02, #38, #01, #1c, #10, #01, #0c, #99, #11, #11, #01
#d9a1#6fa116
    db #44, #02, #38, #01, #0d, #10, #03, #0c, #99, #dd, #11, #01, #39, #0f, #38, #0c
#d9b1#6fb116
    db #01, #10, #04, #0c, #99, #af, #11, #01, #30, #14, #08, #20, #01, #20, #06, #0c
#d9c1#6fc116
    db #aa, #de, #aa, #01, #30, #02, #0c, #20, #12, #01, #07, #0c, #66, #00, #ff, #01
#d9d1#6fd116
    db #30, #02, #23, #20, #12, #01, #08, #0c, #66, #00, #55, #06, #36, #15, #12, #08
#d9e1#6fe116
    db #02, #0c, #0a, #30, #26, #2a, #00, #00, #01, #08, #01, #c5, #0a, #c4, #0b, #c4
#d9f1#6ff116
    db #0c, #c4, #05, #c4, #09, #c4, #0d, #c4, #0e, #c4, #0f, #c4, #10, #c5, #06, #c5
#da01#700116
    db #07, #c5, #08, #c5, #01, #c5, #03, #c5, #04, #f0, #d6, #c2, #00, #00, #00, #00
#da11#701116
    db #00, #00, #0b, #09, #c2, #00, #00, #00, #00, #00, #00, #0c, #09, #c1, #2e, #16
#da21#702116
    db #4c, #01, #1c, #10, #05, #16, #99, #11, #11, #85, #05, #85, #09, #85, #0d, #85
#da31#703116
    db #0b, #b0, #d7, #c1, #2f, #23, #4c, #0c, #01, #10, #09, #0e, #99, #af, #11, #b0
#da41#704116
    db #05, #c1, #3a, #16, #4c, #01, #0d, #10, #0d, #0e, #99, #d1, #11, #b0, #05, #c1
#da51#705116
    db #30, #2d, #12, #20, #01, #20, #0e, #16, #aa, #de, #aa, #85, #0e, #85, #0f, #85
#da61#706116
    db #10, #85, #0c, #b0, #d7, #c1, #30, #1b, #16, #20, #12, #01, #0f, #0e, #66, #00
#da71#707116
    db #ff, #b0, #0e, #c1, #30, #1b, #2d, #20, #12, #01, #10, #0e, #66, #00, #55, #b0
#da81#70812
    db #0e, #00
#da83#7083
#da83#7083
Lda83_area_5:  ; LAST TREASURE
#da83#70838
    db #00, #0c, #05, #d7, #00, #10, #47, #04
#da8b#708b6
    db #c0, #80, #81, #82, #83, #84
#da91#709116
    db #85, #ff, #0a, #93, #03, #02, #02, #38, #00, #20, #10, #02, #0d, #11, #12, #03
#daa1#70a116
    db #06, #03, #4e, #35, #02, #0c, #06, #00, #04, #11, #99, #d4, #20, #02, #c5, #04
#dab1#70b116
    db #f0, #d8, #c1, #0b, #02, #02, #12, #0e, #12, #01, #17, #66, #77, #55, #c5, #01
#dac1#70c116
    db #c7, #06, #0a, #e3, #01, #dc, #0e, #e2, #18, #01, #1c, #10, #02, #12, #0d, #12
#dad1#70d116
    db #03, #17, #aa, #99, #88, #c5, #03, #c7, #06, #0b, #e3, #01, #dc, #0e, #e2, #18
#dae1#70e116
    db #03, #0b, #02, #02, #12, #0e, #00, #0d, #0a, #55, #03, #1c, #10, #02, #12, #0d
#daf1#70f116
    db #00, #0e, #0a, #88, #01, #33, #02, #69, #28, #11, #10, #0f, #0c, #88, #11, #dd
#db01#710116
    db #06, #33, #13, #69, #28, #04, #10, #10, #24, #7e, #7e, #80, #00, #04, #28, #0c
#db11#711116
    db #ce, #06, #01, #e2, #24, #dc, #0b, #c5, #10, #c4, #11, #c4, #18, #c4, #1c, #e3
#db21#712116
    db #01, #ec, #e2, #13, #c8, #33, #13, #79, #28, #10, #04, #11, #10, #7e, #7e, #8f
#db31#713116
    db #00, #04, #28, #0c, #c3, #4c, #13, #6f, #0b, #00, #06, #18, #11, #22, #d4, #20
#db41#714116
    db #08, #c5, #18, #f0, #d8, #c6, #36, #13, #6d, #05, #02, #09, #1c, #14, #ba, #b6
#db51#715110
    db #00, #00, #01, #05, #01, #c5, #1c, #f0, #d6, #00
#db5b#715b
#db5b#715b
Ldb5b_area_6:  ; TANTALUS
#db5b#715b8
    db #00, #10, #06, #18, #01, #10, #47, #05
#db63#716314
    db #c0, #80, #81, #82, #83, #84, #85, #ff, #0a, #8f, #03, #02, #02, #38
#db71#717116
    db #00, #20, #10, #02, #0d, #11, #12, #03, #08, #04, #27, #0c, #06, #3c, #0e, #20
#db81#718116
    db #03, #10, #1e, #1e, #80, #00, #0a, #0e, #17, #05, #0f, #0c, #06, #18, #0e, #20
#db91#719116
    db #04, #10, #18, #08, #e0, #00, #08, #0e, #18, #04, #27, #1a, #06, #3c, #02, #20
#dba1#71a116
    db #05, #20, #8d, #0d, #90, #00, #0a, #01, #17, #e2, #24, #c4, #07, #c4, #08, #c5
#dbb1#71b116
    db #05, #c5, #06, #dc, #0b, #e3, #01, #c4, #7b, #05, #0f, #1a, #06, #18, #02, #20
#dbc1#71c116
    db #06, #12, #8d, #09, #d0, #00, #08, #02, #18, #f0, #05, #c4, #2a, #1a, #06, #3c
#dbd1#71d116
    db #20, #02, #07, #1e, #d5, #d8, #90, #08, #00, #18, #02, #e2, #25, #c5, #07, #c5
#dbe1#71e116
    db #08, #c4, #05, #c4, #06, #e3, #01, #dc, #08, #c5, #12, #1a, #06, #18, #20, #02
#dbf1#71f116
    db #08, #12, #98, #95, #d0, #08, #00, #18, #02, #f0, #07, #06, #62, #32, #6c, #08
#dc01#720116
    db #02, #0c, #09, #14, #ba, #b6, #00, #00, #01, #08, #01, #c5, #09, #f0, #d6, #01
#dc11#721116
    db #0b, #02, #6b, #12, #0e, #12, #0a, #17, #66, #77, #55, #c5, #0a, #c7, #05, #01
#dc21#722116
    db #e3, #01, #dc, #0e, #e2, #18, #c1, #1c, #10, #6b, #12, #0d, #12, #0b, #17, #aa
#dc31#723116
    db #99, #88, #c5, #0b, #c7, #05, #03, #e3, #01, #dc, #0e, #e2, #18, #03, #1c, #10
#dc41#724116
    db #7d, #12, #0d, #00, #0c, #0a, #88, #03, #0b, #02, #7d, #12, #0e, #00, #0d, #0a
#dc51#725116
    db #55, #01, #61, #02, #10, #02, #0a, #0d, #0f, #0c, #66, #00, #bb, #01, #0f, #02
#dc61#726116
    db #0e, #02, #0a, #10, #12, #0c, #66, #00, #bb, #c2, #00, #00, #00, #00, #00, #00
#dc71#72713
    db #7b, #09, #00
#dc74#7274
#dc74#7274
Ldc74_area_7:  ; BELENUS
#dc74#72748
    db #00, #06, #07, #63, #00, #10, #47, #06
#dc7c#727c5
    db #c0, #80, #81, #82, #83
#dc81#728116
    db #84, #85, #ff, #0c, #8b, #9f, #a0, #03, #38, #02, #02, #10, #20, #00, #02, #0d
#dc91#729116
    db #11, #12, #03, #0a, #03, #38, #02, #7d, #10, #20, #00, #03, #0d, #11, #12, #08
#dca1#72a116
    db #01, #03, #7d, #02, #38, #00, #20, #10, #05, #0d, #11, #12, #16, #01, #07, #3c
#dcb1#72b116
    db #12, #3c, #08, #08, #08, #04, #12, #d6, #d6, #00, #04, #04, #04, #04, #f0, #06
#dcc1#72c116
    db #06, #3c, #1a, #3c, #08, #02, #08, #06, #16, #6d, #6d, #a0, #02, #02, #06, #06
#dcd1#72d17
    db #c5, #04, #c5, #06, #f0, #d9, #00
#dcd8#72d8
#dcd8#72d8
Ldcd8_area_8:  ; POTHOLE
#dcd8#72d88
    db #00, #13, #08, #02, #01, #02, #46, #07
#dce0#72e01
    db #c0
#dce1#72e116
    db #80, #00, #00, #00, #00, #00, #ff, #09, #01, #09, #02, #0a, #0a, #3b, #01, #02
#dcf1#72f116
    db #0c, #00, #00, #20, #01, #07, #02, #01, #02, #3b, #17, #03, #0c, #30, #00, #00
#dd01#730116
    db #01, #13, #02, #01, #01, #3b, #17, #04, #0c, #03, #00, #00, #01, #00, #02, #18
#dd11#731116
    db #1a, #3d, #01, #05, #0c, #00, #00, #02, #c0, #0d, #02, #0b, #00, #00, #00, #01
#dd21#732116
    db #09, #01, #02, #3d, #01, #18, #02, #17, #06, #0c, #00, #04, #00, #03, #0d, #02
#dd31#733116
    db #0b, #02, #04, #00, #07, #0d, #11, #12, #07, #d8, #c3, #0f, #02, #18, #02, #04
#dd41#734116
    db #00, #08, #0d, #11, #12, #09, #c7, #c0, #0f, #02, #17, #00, #24, #00, #09, #09
#dd51#735116
    db #03, #0d, #1c, #18, #02, #04, #00, #0b, #0d, #11, #12, #20, #de, #03, #0c, #29
#dd61#736116
    db #18, #02, #04, #00, #0c, #0d, #11, #12, #2b, #de, #01, #0c, #1b, #17, #04, #01
#dd71#737116
    db #01, #0f, #0c, #bb, #ee, #dd, #01, #0b, #28, #17, #04, #01, #01, #10, #0c, #bb
#dd81#738116
    db #88, #dd, #c0, #0e, #0f, #17, #00, #24, #00, #12, #09, #c0, #0d, #1c, #17, #00
#dd91#739116
    db #24, #00, #13, #09, #c0, #0c, #29, #17, #00, #24, #00, #14, #09, #01, #0f, #02
#dda1#73a116
    db #17, #02, #04, #01, #16, #2b, #dd, #99, #55, #ef, #1d, #11, #e2, #1d, #db, #32
#ddb1#73b116
    db #e2, #27, #cc, #11, #ec, #e2, #1a, #dc, #0b, #c5, #16, #c4, #08, #c8, #09, #04
#ddc1#73c116
    db #c7, #09, #02, #e3, #01, #d1, #02, #1c, #03, #11, #1d, #18, #01, #02, #00, #18
#ddd1#73d110
    db #11, #ff, #d4, #20, #04, #c5, #18, #f0, #d8, #00
#dddb#73db
#dddb#73db
Ldddb_area_9:  ; THE STEPS
#dddb#73db8
    db #00, #05, #09, #6b, #00, #08, #07, #08
#dde3#73e314
    db #c0, #80, #81, #82, #af, #84, #85, #ff, #15, #ae, #c3, #c4, #c5, #c6
#ddf1#73f116
    db #cb, #cc, #cd, #d2, #d4, #d5, #e4, #03, #06, #02, #02, #08, #10, #00, #02, #0d
#de01#740116
    db #11, #12, #08, #09, #03, #06, #20, #7d, #08, #10, #00, #03, #0d, #11, #12, #0a
#de11#741116
    db #c7, #c3, #06, #02, #02, #08, #10, #00, #04, #20, #aa, #ef, #1d, #11, #e2, #1d
#de21#742116
    db #ec, #e2, #1a, #dc, #0b, #c5, #04, #c4, #02, #c8, #08, #16, #c7, #08, #08, #e3
#de31#743116
    db #01, #06, #2a, #02, #28, #04, #01, #08, #05, #14, #a5, #ab, #00, #00, #01, #04
#de41#74416
    db #01, #c5, #05, #f0, #d6, #00
#de47#7447
#de47#7447
Lde47_area_10:  ; THE STEPS
#de47#74478
    db #00, #05, #0a, #57, #00, #08, #07, #08
#de4f#744f2
    db #c0, #80
#de51#745116
    db #81, #82, #84, #85, #ae, #ff, #14, #af, #c3, #c4, #c5, #c6, #cb, #cc, #d2, #d3
#de61#746116
    db #d4, #e4, #03, #06, #02, #02, #08, #10, #00, #02, #0d, #11, #12, #09, #c8, #03
#de71#747116
    db #06, #20, #7d, #08, #10, #00, #03, #0d, #11, #12, #0b, #c7, #03, #30, #02, #34
#de81#748116
    db #00, #10, #08, #04, #0d, #11, #12, #1b, #e1, #06, #2a, #02, #28, #04, #01, #08
#de91#749114
    db #06, #14, #a5, #ab, #00, #00, #01, #04, #01, #c5, #06, #f0, #d6, #00
#de9f#749f
#de9f#749f
Lde9f_area_11:  ; THE STEPS
#de9f#749f8
    db #00, #06, #0b, #7e, #00, #08, #07, #08
#dea7#74a710
    db #c0, #80, #81, #82, #84, #85, #ae, #ff, #13, #af
#deb1#74b116
    db #c3, #c4, #c5, #c6, #cb, #cc, #d2, #d4, #e4, #03, #06, #02, #02, #08, #10, #00
#dec1#74c116
    db #02, #0d, #11, #12, #0a, #c8, #03, #06, #20, #7d, #08, #10, #00, #03, #0d, #11
#ded1#74d116
    db #12, #0c, #c7, #c3, #30, #02, #34, #00, #10, #08, #04, #0d, #11, #12, #1e, #e1
#dee1#74e116
    db #01, #2f, #02, #34, #01, #10, #08, #01, #28, #55, #11, #11, #ce, #05, #00, #e2
#def1#74f116
    db #15, #db, #25, #e2, #38, #db, #25, #e2, #13, #ec, #e2, #1a, #dc, #0b, #c5, #01
#df01#750116
    db #c4, #04, #c8, #1e, #03, #c7, #1e, #02, #06, #2a, #02, #28, #04, #01, #08, #08
#df11#751113
    db #14, #a5, #ab, #00, #00, #01, #04, #01, #c5, #08, #f0, #d6, #00
#df1e#751e
#df1e#751e
Ldf1e_area_12:  ; THE STEPS
#df1e#751e8
    db #00, #07, #0c, #8e, #00, #08, #07, #08
#df26#752611
    db #c0, #80, #81, #82, #84, #85, #ae, #ff, #12, #af, #c3
#df31#753116
    db #c4, #c5, #c6, #cb, #d2, #d3, #d4, #03, #06, #20, #7d, #08, #10, #00, #02, #0d
#df41#754116
    db #11, #12, #0d, #c7, #03, #06, #02, #02, #08, #10, #00, #03, #0d, #11, #12, #0b
#df51#755116
    db #c8, #c3, #30, #02, #34, #00, #10, #08, #04, #0d, #11, #12, #23, #e1, #03, #03
#df61#756116
    db #03, #5d, #06, #03, #00, #01, #11, #20, #d4, #20, #09, #c5, #01, #f0, #d8, #01
#df71#757116
    db #2f, #02, #34, #01, #10, #08, #08, #28, #ff, #11, #11, #ce, #04, #00, #e2, #15
#df81#758116
    db #db, #25, #e2, #43, #db, #25, #e2, #13, #ec, #e2, #1a, #dc, #0b, #c5, #08, #c4
#df91#759116
    db #04, #c8, #23, #01, #c7, #23, #02, #06, #2a, #02, #28, #04, #01, #08, #0c, #14
#dfa1#75a112
    db #a5, #ab, #00, #00, #01, #04, #01, #c5, #0c, #f0, #d6, #00
#dfad#75ad
#dfad#75ad
Ldfad_area_13:  ; THE STEPS
#dfad#75ad8
    db #00, #06, #0d, #76, #00, #08, #07, #08
#dfb5#75b512
    db #c0, #80, #81, #82, #84, #85, #ae, #ff, #11, #af, #c3, #c4
#dfc1#75c116
    db #c5, #c6, #cb, #cc, #e4, #03, #06, #02, #02, #08, #10, #00, #02, #0d, #11, #12
#dfd1#75d116
    db #0c, #c8, #03, #06, #20, #7d, #08, #10, #00, #03, #0d, #11, #12, #0e, #de, #c3
#dfe1#75e116
    db #30, #02, #34, #00, #10, #08, #04, #0d, #11, #12, #2c, #e1, #01, #2f, #02, #34
#dff1#75f116
    db #01, #10, #08, #01, #22, #ff, #11, #11, #ce, #03, #00, #e2, #15, #db, #25, #e2
#e001#760116
    db #4a, #db, #25, #e2, #13, #ec, #e2, #1a, #dc, #0b, #c5, #01, #c4, #04, #06, #2a
#e011#761116
    db #02, #28, #04, #01, #08, #08, #14, #a5, #ab, #00, #00, #01, #04, #01, #c5, #08
#e021#76213
    db #f0, #d6, #00
#e024#7624
#e024#7624
Le024_area_14:  ; LOOKOUT POST
#e024#76248
    db #00, #06, #0e, #6b, #00, #10, #46, #09
#e02c#762c5
    db #c0, #80, #81, #82, #83
#e031#763116
    db #84, #85, #ff, #0b, #9f, #a0, #03, #38, #02, #02, #10, #20, #00, #02, #0d, #11
#e041#764116
    db #12, #0d, #c8, #03, #34, #12, #7d, #0c, #22, #00, #03, #13, #11, #12, #01, #19
#e051#765116
    db #1a, #1b, #32, #12, #0e, #04, #c3, #7d, #02, #38, #00, #20, #10, #05, #0d, #11
#e061#766116
    db #12, #0f, #31, #c0, #3a, #02, #70, #00, #00, #00, #04, #09, #01, #7c, #02, #38
#e071#767116
    db #01, #20, #10, #01, #22, #ff, #11, #11, #ce, #07, #00, #e2, #15, #db, #25, #e2
#e081#768115
    db #33, #db, #25, #e2, #13, #ec, #e2, #1a, #dc, #0b, #c5, #01, #c4, #05, #00
#e090#7690
#e090#7690
Le090_area_15:  ; KERBEROS
#e090#76908
    db #00, #17, #0f, #62, #01, #10, #07, #0a
#e098#76989
    db #c0, #80, #81, #82, #83, #84, #85, #ff, #09
#e0a1#76a116
    db #03, #02, #02, #38, #00, #20, #10, #02, #0d, #11, #12, #0e, #db, #c3, #7d, #02
#e0b1#76b116
    db #38, #00, #20, #10, #01, #0d, #11, #12, #11, #d7, #05, #40, #12, #3c, #07, #04
#e0c1#76c116
    db #06, #03, #29, #da, #da, #18, #00, #02, #02, #04, #9f, #09, #9f, #0d, #89, #03
#e0d1#76d116
    db #ae, #03, #05, #85, #03, #85, #04, #85, #05, #84, #21, #85, #2f, #84, #01, #85
#e0e1#76e116
    db #32, #b0, #d7, #03, #47, #16, #40, #00, #04, #02, #04, #0a, #ff, #03, #47, #16
#e0f1#76f116
    db #3c, #00, #04, #02, #05, #0a, #ff, #05, #41, #12, #43, #06, #04, #06, #09, #1d
#e101#770116
    db #9a, #9a, #18, #00, #02, #02, #04, #89, #02, #ae, #02, #05, #85, #09, #85, #0a
#e111#771116
    db #85, #0b, #84, #22, #03, #47, #16, #47, #00, #04, #02, #0a, #0a, #55, #03, #47
#e121#772116
    db #16, #43, #00, #04, #02, #0b, #0a, #55, #05, #41, #12, #35, #06, #04, #06, #0d
#e131#773116
    db #1d, #9a, #9a, #18, #00, #02, #02, #04, #89, #04, #ae, #04, #05, #85, #0d, #85
#e141#774116
    db #0e, #85, #0f, #84, #1a, #03, #47, #16, #39, #00, #04, #02, #0e, #0a, #55, #03
#e151#775116
    db #47, #16, #35, #00, #04, #02, #0f, #0a, #55, #07, #49, #02, #37, #03, #09, #03
#e161#776116
    db #16, #10, #26, #26, #00, #00, #00, #01, #01, #07, #5b, #02, #37, #03, #09, #03
#e171#777116
    db #17, #10, #26, #26, #00, #02, #00, #03, #01, #07, #5b, #02, #44, #03, #09, #03
#e181#778116
    db #18, #10, #26, #26, #00, #02, #02, #03, #03, #07, #49, #02, #44, #03, #09, #03
#e191#779116
    db #19, #10, #26, #26, #00, #01, #02, #02, #03, #c7, #43, #0c, #35, #04, #06, #06
#e1a1#77a116
    db #1a, #10, #9a, #9a, #18, #01, #02, #03, #04, #c7, #42, #0c, #3c, #05, #06, #06
#e1b1#77b116
    db #21, #10, #da, #da, #18, #02, #02, #04, #04, #c7, #43, #0c, #43, #04, #06, #06
#e1c1#77c116
    db #22, #10, #9a, #9a, #18, #01, #02, #03, #04, #03, #7d, #02, #38, #00, #20, #10
#e1d1#77d116
    db #2f, #0a, #77, #c0, #0b, #02, #3e, #00, #12, #00, #31, #09, #02, #00, #00, #00
#e1e1#77e116
    db #00, #00, #00, #32, #09, #01, #47, #0b, #35, #18, #07, #14, #06, #0c, #88, #ee
#e1f1#77f12
    db #aa, #00
#e1f3#77f3
#e1f3#77f3
Le1f3_area_22:  ; LIFT SHAFT
#e1f3#77f38
    db #00, #2e, #16, #98, #02, #03, #45, #10
#e1fb#77fb6
    db #c0, #80, #81, #82, #83, #00
#e201#780116
    db #00, #ff, #09, #03, #02, #02, #10, #00, #06, #03, #02, #0d, #11, #12, #07, #db
#e211#781116
    db #03, #7d, #03, #10, #00, #06, #04, #04, #0d, #11, #12, #18, #01, #03, #7d, #10
#e221#782116
    db #10, #00, #06, #04, #05, #0d, #11, #12, #1d, #e5, #03, #7d, #1d, #10, #00, #06
#e231#783116
    db #04, #06, #0d, #11, #12, #21, #df, #03, #7d, #2a, #10, #00, #06, #04, #07, #0d
#e241#784116
    db #11, #12, #29, #e5, #01, #75, #02, #0e, #08, #09, #08, #08, #0c, #dd, #55, #88
#e251#785116
    db #c0, #7b, #02, #12, #00, #36, #00, #09, #09, #c0, #7c, #10, #12, #00, #36, #00
#e261#786116
    db #0a, #09, #c0, #7c, #1d, #12, #00, #36, #00, #0b, #09, #c0, #7c, #2b, #12, #00
#e271#787116
    db #36, #00, #0c, #09, #c0, #02, #02, #11, #00, #12, #00, #01, #09, #01, #02, #02
#e281#788116
    db #0a, #7b, #3b, #02, #0d, #0c, #00, #00, #20, #c1, #75, #0f, #0e, #08, #09, #08
#e291#789116
    db #0e, #0c, #dd, #55, #88, #c1, #75, #1c, #0e, #08, #09, #08, #0f, #0c, #dd, #55
#e2a1#78a116
    db #88, #c1, #75, #29, #0e, #08, #09, #08, #10, #0c, #dd, #55, #88, #c6, #76, #02
#e2b1#78b116
    db #1e, #06, #05, #08, #11, #10, #8e, #8e, #ff, #02, #02, #04, #06, #c6, #76, #0f
#e2c1#78c116
    db #1e, #06, #05, #08, #12, #10, #8e, #8e, #ff, #02, #02, #04, #06, #c6, #76, #1c
#e2d1#78d116
    db #1e, #06, #05, #08, #13, #10, #8e, #8e, #ff, #02, #02, #04, #06, #06, #76, #29
#e2e1#78e116
    db #1e, #06, #05, #08, #14, #10, #8e, #8e, #ff, #02, #02, #04, #06, #01, #77, #38
#e2f1#78f116
    db #12, #06, #01, #10, #16, #0c, #11, #88, #88, #0a, #79, #2e, #22, #00, #0b, #00
#e301#790116
    db #17, #10, #11, #79, #2e, #22, #79, #39, #22, #ca, #79, #32, #12, #00, #07, #00
#e311#791116
    db #19, #10, #11, #79, #32, #12, #79, #39, #12, #ca, #79, #21, #22, #00, #18, #00
#e321#792116
    db #1a, #10, #11, #79, #21, #22, #79, #39, #22, #ca, #79, #14, #22, #00, #25, #00
#e331#793116
    db #1b, #10, #11, #79, #14, #22, #79, #39, #22, #ca, #79, #07, #22, #00, #32, #00
#e341#794116
    db #1c, #10, #11, #79, #07, #22, #79, #39, #22, #ca, #79, #25, #12, #00, #14, #00
#e351#795116
    db #1d, #10, #11, #79, #25, #12, #79, #39, #12, #ca, #79, #18, #12, #00, #21, #00
#e361#796116
    db #1e, #10, #11, #79, #18, #12, #79, #39, #12, #0a, #79, #0b, #12, #00, #2e, #00
#e371#797116
    db #1f, #10, #11, #79, #0b, #12, #79, #39, #12, #c1, #0e, #0a, #17, #04, #04, #04
#e381#798116
    db #20, #0f, #99, #99, #99, #92, #31, #01, #07, #6f, #02, #20, #05, #02, #04, #21
#e391#799116
    db #10, #fe, #fe, #00, #01, #01, #04, #03, #06, #6f, #04, #20, #05, #02, #04, #23
#e3a1#79a116
    db #10, #fe, #fe, #90, #03, #02, #04, #03, #c7, #76, #02, #20, #05, #02, #04, #24
#e3b1#79b116
    db #10, #fe, #fe, #00, #01, #01, #04, #03, #c6, #76, #04, #20, #05, #02, #04, #26
#e3c1#79c116
    db #10, #fe, #fe, #90, #03, #02, #04, #03, #03, #6f, #02, #20, #00, #04, #04, #27
#e3d1#79d116
    db #24, #00, #2e, #1d, #17, #2f, #01, #03, #05, #21, #05, #23, #05, #27, #04, #24
#e3e1#79e116
    db #04, #26, #23, #01, #1c, #0e, #22, #18, #2d, #2c, #22, #1d, #c1, #74, #02, #24
#e3f1#79f116
    db #01, #01, #01, #28, #0c, #dd, #dd, #dd, #c1, #72, #02, #20, #01, #01, #01, #29
#e401#7a0116
    db #0c, #ff, #ff, #ff, #c1, #74, #02, #1d, #01, #01, #01, #2a, #0c, #ff, #ff, #ff
#e411#7a1116
    db #c1, #78, #02, #1d, #01, #01, #01, #2b, #0c, #ff, #ff, #ff, #01, #79, #20, #16
#e421#7a2116
    db #04, #02, #08, #2f, #0c, #55, #99, #aa, #03, #7a, #25, #28, #02, #04, #00, #31
#e431#7a3116
    db #11, #ee, #d4, #20, #07, #c5, #31, #f0, #d8, #c3, #78, #02, #1f, #02, #00, #04
#e441#7a4116
    db #34, #11, #ee, #d4, #20, #03, #c5, #34, #f0, #d8, #c3, #73, #02, #0c, #04, #06
#e451#7a5116
    db #00, #2e, #0d, #11, #12, #18, #0a, #c0, #74, #02, #0d, #00, #00, #00, #38, #09
#e461#7a6116
    db #03, #73, #02, #0c, #04, #06, #00, #39, #1e, #55, #e0, #18, #0e, #e2, #20, #ec
#e471#7a7116
    db #e2, #1a, #dc, #0b, #c5, #39, #c4, #2e, #c8, #18, #0b, #c7, #18, #09, #01, #02
#e481#7a8111
    db #02, #28, #7b, #3b, #04, #03, #0c, #00, #00, #22, #00
#e48c#7a8c
#e48c#7a8c
Le48c_area_24:  ; LIFT ENTRANCE 6
#e48c#7a8c8
    db #00, #0b, #18, #ac, #00, #08, #07, #12
#e494#7a9413
    db #c0, #80, #8d, #82, #83, #84, #85, #ff, #0c, #c9, #95, #99, #03
#e4a1#7aa116
    db #40, #02, #5a, #00, #10, #08, #02, #14, #11, #0b, #01, #00, #12, #31, #db, #2c
#e4b1#7ab116
    db #12, #16, #09, #c0, #40, #02, #5e, #00, #12, #00, #01, #09, #06, #73, #0d, #2b
#e4c1#7ac116
    db #05, #02, #0a, #05, #14, #b5, #b6, #00, #00, #01, #05, #01, #c5, #05, #f0, #d6
#e4d1#7ad116
    db #03, #1f, #1e, #1e, #06, #00, #06, #07, #0a, #11, #c0, #22, #0d, #20, #00, #0a
#e4e1#7ae116
    db #00, #08, #09, #c3, #1e, #02, #40, #08, #10, #00, #09, #0d, #11, #12, #16, #38
#e4f1#7af116
    db #c0, #21, #02, #3f, #00, #24, #00, #0a, #09, #01, #1e, #02, #3f, #08, #10, #01
#e501#7b0116
    db #0b, #21, #11, #11, #22, #de, #0e, #e2, #1c, #ec, #e2, #1a, #dc, #0b, #c5, #0b
#e511#7b1116
    db #c4, #09, #c8, #16, #39, #c7, #16, #2e, #e3, #01, #06, #24, #08, #3e, #02, #02
#e521#7b2116
    db #01, #0e, #14, #64, #60, #66, #01, #00, #01, #01, #85, #0e, #b0, #da, #02, #00
#e531#7b318
    db #00, #00, #00, #00, #00, #7d, #09, #00
#e539#7b39
#e539#7b39
Le539_area_21:  ; RAVINE
#e539#7b398
    db #00, #27, #15, #e7, #01, #01, #46, #0f
#e541#7b4116
    db #c0, #00, #00, #82, #00, #00, #00, #ff, #09, #01, #09, #02, #02, #02, #3b, #7b
#e551#7b5116
    db #02, #0c, #03, #00, #00, #03, #02, #34, #44, #00, #02, #01, #03, #0d, #11, #12
#e561#7b6116
    db #25, #0f, #c3, #02, #2e, #34, #00, #02, #01, #04, #0d, #11, #12, #25, #08, #03
#e571#7b7116
    db #02, #28, #04, #00, #02, #01, #05, #0d, #11, #12, #1f, #db, #03, #02, #22, #13
#e581#7b8116
    db #00, #02, #01, #06, #0d, #11, #12, #1b, #db, #01, #00, #00, #00, #09, #02, #7f
#e591#7b9116
    db #0b, #0c, #00, #10, #00, #03, #09, #22, #04, #00, #02, #01, #0c, #0d, #11, #12
#e5a1#7ba116
    db #1c, #d7, #01, #05, #21, #04, #01, #01, #10, #0d, #0c, #22, #44, #22, #01, #02
#e5b1#7bb116
    db #21, #13, #03, #01, #01, #0e, #0c, #22, #44, #22, #01, #06, #21, #04, #03, #01
#e5c1#7bc116
    db #01, #0f, #0c, #22, #44, #22, #01, #02, #27, #02, #02, #01, #24, #10, #0c, #22
#e5d1#7bd116
    db #44, #22, #03, #02, #28, #24, #00, #02, #01, #11, #0d, #11, #12, #1e, #db, #01
#e5e1#7be116
    db #02, #02, #48, #07, #3b, #02, #12, #0c, #00, #00, #05, #01, #02, #02, #00, #07
#e5f1#7bf116
    db #3d, #02, #13, #0c, #00, #00, #50, #01, #02, #3d, #02, #07, #02, #7b, #14, #0c
#e601#7c0116
    db #00, #0f, #00, #03, #09, #2e, #34, #00, #02, #01, #15, #0d, #11, #12, #28, #01
#e611#7c1116
    db #01, #02, #2d, #34, #07, #01, #01, #16, #0c, #22, #44, #22, #03, #09, #34, #44
#e621#7c2116
    db #00, #02, #01, #17, #0d, #11, #12, #2e, #e1, #01, #02, #2b, #41, #07, #09, #07
#e631#7c3116
    db #18, #0c, #55, #44, #ee, #c0, #08, #22, #04, #00, #36, #00, #1a, #09, #c0, #02
#e641#7c4116
    db #22, #13, #00, #12, #00, #1b, #09, #01, #07, #27, #02, #02, #01, #24, #1c, #0c
#e651#7c5116
    db #22, #44, #22, #03, #09, #28, #03, #00, #02, #01, #1d, #0d, #11, #12, #21, #d7
#e661#7c6116
    db #c0, #08, #28, #03, #00, #36, #00, #1e, #09, #c0, #02, #28, #04, #00, #12, #00
#e671#7c7116
    db #1f, #09, #c0, #02, #28, #24, #00, #12, #00, #20, #09, #c0, #08, #2e, #34, #00
#e681#7c8116
    db #36, #00, #21, #09, #c0, #02, #2e, #34, #00, #12, #00, #22, #09, #c0, #08, #34
#e691#7c9116
    db #44, #00, #36, #00, #23, #09, #c0, #02, #34, #44, #00, #12, #00, #24, #09, #03
#e6a1#7ca116
    db #02, #2e, #04, #00, #02, #01, #25, #0d, #11, #12, #2a, #db, #03, #09, #2e, #04
#e6b1#7cb116
    db #00, #02, #01, #26, #0d, #11, #12, #28, #08, #01, #02, #2d, #04, #07, #01, #01
#e6c1#7cc116
    db #27, #0c, #22, #44, #22, #c0, #08, #2e, #04, #00, #36, #00, #28, #09, #c0, #02
#e6d1#7cd116
    db #2e, #04, #00, #12, #00, #29, #09, #c1, #03, #28, #1c, #05, #01, #03, #2a, #0c
#e6e1#7ce116
    db #22, #99, #aa, #01, #07, #28, #1c, #01, #05, #03, #2b, #1e, #99, #22, #22, #dc
#e6f1#7cf116
    db #0e, #db, #19, #c5, #2b, #c4, #2a, #e3, #01, #dc, #08, #e2, #18, #c1, #f8, #24
#e701#7d0116
    db #01, #03, #02, #2e, #34, #00, #02, #01, #2c, #1e, #dd, #e0, #25, #14, #e2, #20
#e711#7d1116
    db #ec, #e2, #1a, #dc, #0b, #c5, #2c, #c4, #04, #c8, #25, #15, #c7, #25, #09, #00
#e721#7d21
#e721#7d21
Le721_area_17:  ; BELENUS KEY
#e721#7d218
    db #00, #0d, #11, #d0, #00, #05, #46, #0c
#e729#7d298
    db #c0, #80, #81, #82, #85, #00, #00, #ff
#e731#7d3116
    db #09, #01, #20, #02, #02, #02, #3b, #7b, #02, #0c, #03, #00, #00, #03, #02, #02
#e741#7d4116
    db #77, #00, #0a, #05, #03, #0d, #11, #12, #0f, #db, #01, #02, #02, #41, #1e, #3b
#e751#7d5116
    db #02, #04, #0c, #00, #00, #20, #c0, #1f, #02, #79, #00, #36, #00, #05, #09, #c3
#e761#7d6116
    db #20, #02, #77, #00, #0a, #05, #06, #0d, #11, #12, #13, #e1, #07, #02, #20, #43
#e771#7d7116
    db #0f, #1d, #3a, #01, #10, #00, #70, #00, #00, #00, #00, #3a, #07, #11, #20, #43
#e781#7d8116
    db #0f, #1d, #3a, #07, #10, #d0, #00, #00, #0f, #00, #0f, #3a, #cd, #09, #02, #7d
#e791#7d9116
    db #10, #2c, #00, #09, #1c, #11, #09, #1f, #7d, #11, #2e, #7d, #19, #1f, #7d, #19
#e7a1#7da116
    db #02, #7d, #09, #02, #7d, #12, #01, #12, #0b, #09, #1f, #7d, #10, #0f, #00, #0a
#e7b1#7db116
    db #13, #11, #09, #1f, #7d, #11, #2e, #7d, #19, #1f, #7d, #03, #09, #02, #7d, #10
#e7c1#7dc116
    db #1d, #00, #0b, #0a, #dd, #c0, #10, #02, #7c, #00, #24, #00, #0c, #09, #01, #1f
#e7d1#7dd116
    db #02, #77, #01, #0a, #05, #0d, #22, #ff, #11, #11, #ce, #14, #00, #e2, #15, #db
#e7e1#7de116
    db #25, #e2, #37, #db, #25, #e2, #13, #ec, #e2, #1a, #dc, #0b, #c5, #0d, #c4, #06
#e7f1#7df116
    db #01, #20, #0e, #01, #01, #0e, #02, #01, #0e, #03, #01, #0e, #04, #01, #0e, #05
#e801#7e0116
    db #01, #0e, #06, #01, #0e, #07, #01, #0e, #08, #01, #0e, #09, #01, #0e, #0a, #01
#e811#7e112
    db #0c, #14
#e813#7e13
#e813#7e13
Le813_area_19:  ; SPIRIT'S ABODE
#e813#7e138
    db #00, #08, #13, #58, #00, #10, #42, #0e
#e81b#7e1b6
    db #c0, #80, #81, #82, #83, #84
#e821#7e2116
    db #85, #ff, #09, #03, #02, #02, #38, #00, #20, #10, #01, #0d, #11, #12, #11, #05
#e831#7e3116
    db #03, #34, #12, #7d, #0c, #22, #00, #02, #0d, #11, #12, #01, #06, #02, #00, #00
#e841#7e4116
    db #00, #00, #00, #00, #7c, #09, #02, #00, #00, #00, #00, #00, #00, #7d, #09, #02
#e851#7e5116
    db #00, #00, #00, #00, #00, #00, #7e, #09, #02, #00, #00, #00, #00, #00, #00, #7f
#e861#7e6111
    db #09, #02, #00, #00, #00, #00, #00, #00, #7b, #09, #00
#e86c#7e6c
#e86c#7e6c
Le86c_area_27:  ; TUNNEL
#e86c#7e6c8
    db #00, #04, #1b, #36, #00, #08, #45, #13
#e874#7e7413
    db #c0, #80, #e6, #82, #83, #e9, #ea, #ff, #0b, #9a, #9b, #03, #02
#e881#7e8116
    db #02, #3b, #00, #10, #08, #03, #0d, #11, #12, #0a, #ca, #03, #7d, #02, #3b, #00
#e891#7e9116
    db #10, #08, #02, #0d, #11, #12, #15, #1b, #02, #00, #00, #00, #00, #00, #00, #7b
#e8a1#7ea12
    db #09, #00
#e8a3#7ea3
#e8a3#7ea3
Le8a3_area_28:  ; THE TUBE
#e8a3#7ea38
    db #00, #08, #1c, #5f, #00, #08, #47, #15
#e8ab#7eab6
    db #c0, #80, #8d, #82, #86, #84
#e8b1#7eb116
    db #85, #ff, #09, #03, #02, #02, #73, #00, #10, #08, #02, #0d, #11, #12, #15, #1a
#e8c1#7ec116
    db #03, #1f, #02, #02, #08, #10, #00, #04, #0d, #11, #12, #1d, #eb, #c0, #23, #02
#e8d1#7ed116
    db #02, #00, #00, #00, #03, #09, #02, #00, #00, #00, #00, #00, #00, #7c, #09, #01
#e8e1#7ee116
    db #02, #02, #39, #42, #08, #01, #01, #0c, #00, #dd, #ff, #01, #02, #02, #4e, #42
#e8f1#7ef116
    db #08, #01, #05, #0c, #00, #dd, #ff, #03, #02, #0a, #39, #40, #00, #16, #06, #0a
#e901#7f012
    db #d9, #00
#e903#7f03
#e903#7f03
Le903_area_29:  ; LIFT ENTRANCE 5
#e903#7f038
    db #00, #05, #1d, #4f, #00, #08, #07, #16
#e90b#7f0b6
    db #c0, #80, #82, #83, #84, #85
#e911#7f1116
    db #8d, #ff, #0d, #c9, #eb, #95, #99, #03, #5a, #02, #7d, #08, #10, #00, #02, #0d
#e921#7f2116
    db #11, #12, #1c, #03, #03, #40, #02, #5c, #00, #10, #08, #01, #14, #11, #0b, #01
#e931#7f3116
    db #01, #12, #31, #db, #2c, #12, #16, #0a, #03, #1f, #02, #1e, #06, #00, #06, #03
#e941#7f4116
    db #10, #11, #12, #18, #08, #1a, #22, #18, #02, #00, #00, #00, #00, #00, #00, #7d
#e951#7f512
    db #09, #00
#e953#7f53
#e953#7f53
Le953_area_49:  ; LIFT
#e953#7f538
    db #00, #13, #31, #c4, #01, #18, #47, #25
#e95b#7f5b6
    db #c0, #80, #81, #00, #83, #00
#e961#7f6116
    db #00, #ff, #09, #03, #7d, #02, #33, #00, #30, #18, #02, #68, #11, #12, #16, #e1
#e971#7f7116
    db #05, #08, #05, #0e, #05, #0f, #05, #10, #05, #11, #05, #12, #05, #13, #05, #14
#e981#7f8116
    db #05, #17, #05, #19, #05, #1a, #05, #1b, #05, #1c, #05, #1d, #05, #1e, #05, #1f
#e991#7f9116
    db #0b, #01, #00, #04, #14, #04, #17, #04, #1f, #04, #08, #12, #18, #e5, #2d, #0b
#e9a1#7fa116
    db #01, #01, #04, #13, #04, #1a, #04, #1e, #04, #0e, #12, #1d, #e5, #2d, #0b, #01
#e9b1#7fb116
    db #02, #04, #12, #04, #1b, #04, #1d, #04, #0f, #12, #21, #df, #2d, #0b, #01, #03
#e9c1#7fc116
    db #04, #11, #04, #1c, #04, #19, #04, #10, #12, #29, #e5, #01, #40, #02, #1e, #02
#e9d1#7fd116
    db #3b, #3e, #03, #0c, #30, #00, #00, #01, #42, #02, #1e, #3b, #3b, #02, #04, #0c
#e9e1#7fe116
    db #00, #00, #50, #01, #42, #02, #5c, #3b, #3b, #02, #05, #0c, #00, #00, #05, #01
#e9f1#7ff116
    db #74, #17, #20, #06, #12, #01, #06, #0c, #ee, #88, #77, #01, #76, #25, #21, #02
#ea01#800116
    db #02, #01, #07, #35, #22, #22, #11, #e0, #16, #24, #c8, #16, #24, #c8, #16, #26
#ea11#801116
    db #c7, #16, #29, #c7, #16, #2a, #c7, #16, #2b, #c7, #16, #34, #ed, #c5, #07, #c5
#ea21#802116
    db #0c, #c5, #0d, #c5, #0e, #c4, #0b, #c4, #08, #c4, #09, #c4, #0a, #d4, #01, #03
#ea31#803116
    db #01, #76, #21, #21, #02, #02, #01, #08, #1f, #22, #22, #11, #c5, #0b, #c5, #08
#ea41#804116
    db #c5, #0d, #c5, #0e, #c4, #07, #c4, #0c, #c4, #09, #c4, #0a, #d4, #01, #02, #01
#ea51#805116
    db #76, #1d, #21, #02, #02, #01, #09, #1f, #22, #22, #11, #c5, #0b, #c5, #0c, #c5
#ea61#806116
    db #09, #c5, #0e, #c4, #07, #c4, #08, #c4, #0d, #c4, #0a, #d4, #01, #01, #c1, #76
#ea71#807116
    db #19, #21, #02, #02, #01, #0a, #1f, #22, #22, #11, #c5, #0b, #c5, #0c, #c5, #0d
#ea81#808116
    db #c5, #0a, #c4, #07, #c4, #08, #c4, #09, #c4, #0e, #d4, #01, #00, #c1, #76, #25
#ea91#809116
    db #21, #02, #02, #01, #0b, #0e, #11, #11, #22, #f0, #07, #c1, #76, #21, #21, #02
#eaa1#80a116
    db #02, #01, #0c, #0e, #11, #11, #22, #f0, #08, #c1, #76, #1d, #21, #02, #02, #01
#eab1#80b116
    db #0d, #0e, #11, #11, #22, #f0, #09, #01, #76, #19, #21, #02, #02, #01, #0e, #0e
#eac1#80c116
    db #11, #11, #22, #f0, #0a, #c0, #66, #02, #3a, #06, #1e, #00, #01, #09, #c1, #6a
#ead1#80d116
    db #27, #23, #04, #03, #04, #13, #0f, #dd, #dd, #dd, #92, #16, #01, #01, #46, #1d
#eae1#80e116
    db #56, #10, #18, #06, #14, #0e, #ee, #88, #77, #e2, #16, #03, #48, #1f, #56, #0c
#eaf1#80f116
    db #14, #00, #15, #16, #aa, #e2, #16, #a2, #1e, #85, #15, #84, #0f, #81, #f8, #24
#eb01#810116
    db #01, #c3, #48, #1f, #56, #0c, #14, #00, #0f, #15, #11, #ce, #05, #00, #d4, #20
#eb11#81117
    db #05, #f0, #d8, #ec, #e2, #08, #00
#eb18#8118
#eb18#8118
Leb18_area_30:  ; TUNNEL
#eb18#81188
    db #00, #05, #1e, #5c, #00, #08, #45, #13
#eb20#81201
    db #c0
#eb21#812116
    db #80, #82, #83, #e6, #e9, #ea, #ff, #0b, #9a, #9b, #c3, #02, #02, #3b, #00, #10
#eb31#813116
    db #08, #02, #0d, #11, #12, #0b, #ca, #03, #7d, #02, #3b, #00, #10, #08, #01, #0d
#eb41#814116
    db #11, #12, #15, #20, #03, #02, #02, #3b, #00, #10, #08, #03, #26, #77, #ce, #05
#eb51#815116
    db #00, #e2, #15, #db, #25, #e2, #31, #db, #25, #e2, #13, #ec, #e2, #1a, #dc, #0b
#eb61#816116
    db #c5, #03, #c4, #02, #c8, #0b, #01, #c7, #0b, #04, #02, #00, #00, #00, #00, #00
#eb71#81714
    db #00, #7b, #09, #00
#eb75#8175
#eb75#8175
Leb75_area_31:  ; TUNNEL
#eb75#81758
    db #00, #05, #1f, #54, #00, #08, #45, #13
#eb7d#817d4
    db #c0, #80, #82, #83
#eb81#818116
    db #e6, #e9, #ea, #ff, #0b, #9a, #9b, #03, #7d, #02, #3b, #00, #10, #08, #02, #0d
#eb91#819116
    db #11, #12, #15, #1f, #c3, #02, #02, #3b, #00, #10, #08, #03, #0d, #11, #12, #20
#eba1#81a116
    db #db, #03, #02, #02, #3b, #00, #10, #08, #01, #1e, #ff, #e0, #20, #06, #e2, #1c
#ebb1#81b116
    db #ec, #dc, #0b, #c4, #03, #c8, #20, #01, #c7, #20, #02, #c5, #01, #e3, #01, #02
#ebc1#81c19
    db #00, #00, #00, #00, #00, #00, #7b, #09, #00
#ebca#81ca
#ebca#81ca
Lebca_area_32:  ; EPONA
#ebca#81ca8
    db #00, #08, #20, #9d, #00, #10, #07, #17
#ebd2#81d215
    db #c0, #80, #81, #82, #83, #84, #85, #ff, #0a, #8b, #c3, #7d, #02, #38, #00
#ebe1#81e116
    db #20, #10, #02, #0d, #11, #12, #1f, #e1, #03, #38, #02, #02, #10, #20, #00, #03
#ebf1#81f116
    db #0d, #11, #12, #08, #13, #01, #7c, #02, #38, #01, #20, #10, #01, #21, #22, #11
#ec01#820116
    db #11, #de, #06, #e2, #1c, #ec, #e2, #1a, #dc, #0b, #c5, #01, #c4, #02, #c8, #1f
#ec11#821116
    db #01, #c7, #1f, #03, #e3, #01, #06, #7b, #0f, #38, #01, #03, #04, #06, #14, #46
#ec21#822116
    db #46, #64, #00, #02, #01, #02, #85, #06, #b0, #da, #06, #73, #02, #6f, #05, #02
#ec31#823116
    db #09, #07, #14, #a5, #a2, #00, #00, #01, #05, #01, #c5, #07, #f0, #d6, #07, #3c
#ec41#824116
    db #12, #3c, #08, #08, #08, #09, #12, #9a, #9a, #00, #04, #04, #04, #04, #f0, #0a
#ec51#825116
    db #06, #3c, #1a, #3c, #08, #02, #08, #0a, #16, #a9, #a9, #70, #02, #02, #06, #06
#ec61#82617
    db #c5, #09, #c5, #0a, #f0, #d9, #00
#ec68#8268
#ec68#8268
Lec68_area_33:  ; LIFT ENTRANCE 4
#ec68#82688
    db #00, #06, #21, #67, #00, #08, #46, #19
#ec70#82701
    db #c0
#ec71#827116
    db #80, #8d, #82, #86, #84, #85, #ff, #0d, #ec, #8e, #a5, #a6, #03, #02, #02, #73
#ec81#828116
    db #00, #10, #08, #02, #0d, #11, #12, #15, #1e, #02, #00, #00, #00, #00, #00, #00
#ec91#829116
    db #7c, #09, #07, #1f, #0a, #1f, #04, #04, #04, #04, #12, #6d, #6d, #00, #02, #02
#eca1#82a116
    db #02, #02, #f0, #05, #06, #1f, #0e, #1f, #04, #01, #04, #05, #16, #d6, #d6, #70
#ecb1#82b116
    db #01, #01, #03, #03, #c5, #04, #c5, #05, #f0, #d9, #03, #02, #02, #04, #00, #10
#ecc1#82c115
    db #08, #01, #14, #11, #0b, #01, #02, #12, #31, #db, #2c, #12, #16, #0b, #00
#ecd0#82d0
#ecd0#82d0
Lecd0_area_35:  ; NANTOSUELTA
#ecd0#82d08
    db #00, #08, #23, #98, #00, #10, #07, #1a
#ecd8#82d89
    db #c0, #80, #81, #82, #83, #84, #85, #ff, #0b
#ece1#82e116
    db #8b, #a1, #c3, #02, #02, #38, #00, #20, #10, #02, #0d, #11, #12, #0c, #ca, #03
#ecf1#82f116
    db #7d, #02, #38, #00, #20, #10, #03, #0d, #11, #12, #25, #01, #03, #02, #02, #38
#ed01#830116
    db #00, #20, #10, #01, #26, #aa, #ce, #04, #00, #e2, #15, #db, #25, #e2, #31, #db
#ed11#831116
    db #25, #e2, #13, #ec, #e2, #1a, #dc, #0b, #c5, #01, #c4, #02, #c8, #0c, #08, #c7
#ed21#832116
    db #0c, #04, #02, #00, #00, #00, #00, #00, #00, #7f, #09, #06, #07, #02, #07, #05
#ed31#833116
    db #02, #09, #05, #14, #a5, #a2, #00, #00, #01, #05, #01, #c5, #05, #f0, #d6, #07
#ed41#834116
    db #3c, #12, #3c, #08, #08, #08, #07, #12, #8a, #8a, #00, #04, #04, #04, #04, #f0
#ed51#835116
    db #08, #06, #3c, #1a, #3c, #08, #02, #08, #08, #16, #a8, #a8, #d0, #02, #02, #06
#ed61#83618
    db #06, #c5, #07, #c5, #08, #f0, #d9, #00
#ed69#8369
#ed69#8369
Led69_area_37:  ; NO ROOM
#ed69#83698
    db #00, #16, #25, #58, #01, #08, #46, #1c
#ed71#837116
    db #c0, #80, #81, #82, #00, #84, #85, #ff, #09, #03, #02, #02, #1c, #00, #10, #08
#ed81#838116
    db #02, #0d, #11, #12, #23, #db, #c0, #02, #02, #20, #00, #12, #00, #01, #09, #01
#ed91#839116
    db #16, #02, #02, #02, #3b, #7b, #03, #0c, #03, #00, #00, #c3, #02, #02, #5c, #00
#eda1#83a116
    db #12, #08, #04, #0d, #11, #12, #24, #db, #c0, #02, #02, #60, #00, #12, #00, #05
#edb1#83b116
    db #09, #c0, #15, #02, #60, #00, #36, #00, #06, #09, #c3, #16, #02, #5c, #00, #12
#edc1#83c116
    db #08, #07, #0d, #11, #12, #26, #e1, #c0, #15, #02, #20, #00, #36, #00, #08, #09
#edd1#83d116
    db #c3, #16, #02, #1c, #00, #10, #08, #09, #0d, #11, #12, #15, #22, #03, #02, #1c
#ede1#83e116
    db #5c, #00, #10, #08, #0a, #0d, #11, #12, #2c, #db, #03, #16, #1c, #5c, #00, #10
#edf1#83f116
    db #08, #0b, #0d, #11, #12, #15, #24, #01, #02, #1b, #5c, #04, #01, #08, #0c, #0c
#ee01#840116
    db #44, #55, #dd, #01, #12, #1b, #5c, #04, #01, #08, #0d, #0c, #44, #55, #dd, #c0
#ee11#841116
    db #02, #1c, #60, #00, #12, #00, #0e, #09, #c0, #15, #1c, #60, #00, #36, #00, #0f
#ee21#842116
    db #09, #01, #02, #02, #5b, #01, #12, #0a, #10, #18, #dd, #55, #55, #e2, #1a, #dc
#ee31#843116
    db #0b, #c5, #10, #c4, #11, #c4, #04, #e3, #01, #c1, #02, #02, #5b, #0a, #12, #01
#ee41#844116
    db #11, #18, #55, #55, #dd, #e2, #1b, #dc, #0b, #c5, #11, #c5, #04, #c4, #10, #e3
#ee51#845116
    db #01, #01, #15, #02, #5b, #01, #12, #0a, #12, #24, #88, #55, #55, #ce, #09, #00
#ee61#846116
    db #e2, #15, #db, #19, #e2, #46, #db, #19, #e2, #13, #ec, #e2, #1a, #dc, #0b, #c5
#ee71#847116
    db #12, #c4, #07, #c4, #13, #c1, #0c, #02, #5b, #0a, #12, #01, #13, #18, #55, #55
#ee81#848116
    db #88, #e2, #1b, #dc, #0b, #c5, #13, #c5, #07, #c4, #12, #e3, #01, #06, #14, #0a
#ee91#849116
    db #1c, #01, #02, #02, #14, #14, #69, #ad, #99, #00, #01, #01, #01, #85, #14, #b0
#eea1#84a116
    db #da, #01, #15, #02, #1c, #01, #10, #08, #15, #1f, #22, #11, #11, #de, #14, #e2
#eeb1#84b116
    db #1c, #ec, #e2, #1a, #dc, #0b, #c5, #15, #c4, #09, #c8, #15, #2c, #c7, #15, #04
#eec1#84c11
    db #00
#eec2#84c2
#eec2#84c2
Leec2_area_36:  ; STALACTITES
#eec2#84c28
    db #00, #07, #24, #87, #00, #10, #07, #1b
#eeca#84ca7
    db #c0, #80, #81, #82, #83, #84, #85
#eed1#84d116
    db #ff, #0d, #9c, #9d, #9e, #a1, #03, #7d, #02, #38, #00, #20, #10, #02, #0d, #11
#eee1#84e116
    db #12, #25, #05, #02, #00, #00, #00, #00, #00, #00, #7f, #09, #01, #3a, #30, #3d
#eef1#84f116
    db #0c, #0d, #0c, #03, #24, #dd, #aa, #ff, #e2, #18, #e0, #2c, #0a, #db, #19, #e2
#ef01#850116
    db #08, #ec, #dc, #0e, #c5, #03, #c4, #05, #c8, #2c, #08, #c7, #2c, #01, #e3, #01
#ef11#851116
    db #01, #3a, #23, #49, #0c, #1a, #0c, #04, #24, #99, #66, #55, #e2, #18, #e0, #2c
#ef21#852116
    db #0a, #db, #19, #e2, #08, #ec, #dc, #0e, #c5, #04, #c4, #06, #c8, #2c, #09, #c7
#ef31#853116
    db #2c, #05, #e3, #01, #c3, #3a, #3d, #3d, #0c, #00, #0c, #05, #0a, #aa, #c3, #3a
#ef41#85419
    db #3d, #49, #0c, #00, #0c, #06, #0a, #66, #00
#ef4a#854a
#ef4a#854a
Lef4a_area_38:  ; THE TRAPEZE
#ef4a#854a8
    db #00, #11, #26, #ea, #00, #10, #07, #1d
#ef52#855215
    db #c0, #80, #81, #82, #83, #84, #85, #ff, #0c, #9c, #9d, #9e, #03, #02, #02
#ef61#856116
    db #3a, #00, #20, #10, #02, #0d, #11, #12, #25, #06, #02, #00, #00, #00, #00, #00
#ef71#857116
    db #00, #7d, #09, #01, #02, #02, #38, #45, #1c, #01, #01, #0c, #55, #ee, #77, #01
#ef81#858116
    db #46, #02, #39, #01, #16, #44, #03, #0c, #55, #88, #00, #01, #3a, #02, #6d, #0c
#ef91#859116
    db #06, #10, #04, #0c, #05, #77, #ee, #01, #47, #26, #38, #2e, #01, #02, #08, #0c
#efa1#85a116
    db #11, #99, #88, #01, #75, #32, #33, #08, #01, #0b, #09, #0c, #55, #88, #77, #0a
#efb1#85b116
    db #48, #27, #39, #00, #16, #00, #0a, #10, #11, #48, #27, #39, #48, #3d, #39, #0a
#efc1#85c116
    db #74, #27, #39, #00, #16, #00, #0b, #10, #11, #74, #27, #39, #74, #3d, #39, #01
#efd1#85d116
    db #41, #27, #3d, #0c, #02, #02, #0c, #0c, #11, #99, #88, #0a, #42, #29, #3e, #00
#efe1#85e116
    db #14, #00, #0d, #10, #11, #42, #29, #3e, #42, #3d, #3e, #0a, #4c, #29, #3e, #00
#eff1#85f116
    db #14, #00, #0e, #10, #11, #4c, #29, #3e, #4c, #3d, #3e, #01, #75, #33, #33, #01
#f001#860116
    db #03, #0b, #0f, #0c, #ff, #99, #55, #01, #76, #33, #33, #07, #03, #01, #10, #0c
#f011#861116
    db #00, #99, #55, #01, #76, #33, #3d, #07, #03, #01, #11, #0c, #00, #99, #55, #06
#f021#862116
    db #78, #33, #34, #05, #02, #09, #13, #14, #25, #c2, #00, #00, #01, #05, #01, #c5
#f031#86314
    db #13, #f0, #d6, #00
#f035#8635
#f035#8635
Lf035_area_40:  ; TUNNEL
#f035#86358
    db #00, #0a, #28, #77, #00, #04, #45, #13
#f03d#863d4
    db #c0, #80, #84, #85
#f041#864116
    db #00, #00, #00, #ff, #09, #03, #3d, #02, #02, #04, #08, #00, #02, #0d, #11, #12
#f051#865116
    db #29, #01, #01, #43, #02, #02, #02, #0b, #7b, #03, #0c, #03, #00, #00, #01, #39
#f061#866116
    db #02, #02, #02, #0b, #7b, #04, #0c, #30, #00, #00, #01, #3b, #0d, #02, #08, #02
#f071#867116
    db #7b, #05, #0c, #00, #04, #00, #03, #3b, #02, #77, #00, #08, #04, #06, #0d, #11
#f081#868116
    db #12, #15, #21, #c0, #3c, #02, #79, #00, #12, #00, #01, #09, #03, #3b, #02, #1e
#f091#869116
    db #00, #08, #04, #07, #0d, #11, #12, #15, #28, #c0, #3c, #02, #1f, #00, #12, #00
#f0a1#86a112
    db #08, #09, #02, #00, #00, #00, #00, #00, #00, #7e, #09, #00
#f0ad#86ad
#f0ad#86ad
Lf0ad_area_41:  ; LIFT ENTRANCE 3
#f0ad#86ad8
    db #00, #05, #29, #47, #00, #08, #46, #1f
#f0b5#86b512
    db #c0, #80, #82, #83, #84, #85, #8d, #ff, #0c, #c9, #95, #99
#f0c1#86c116
    db #03, #42, #02, #7d, #08, #10, #00, #02, #0d, #11, #12, #28, #de, #c0, #46, #02
#f0d1#86d116
    db #7c, #00, #24, #00, #01, #09, #03, #40, #02, #5a, #00, #10, #08, #03, #14, #11
#f0e1#86e116
    db #0b, #01, #03, #12, #31, #db, #2c, #12, #16, #0c, #02, #00, #00, #00, #00, #00
#f0f1#86f14
    db #00, #7d, #09, #00
#f0f5#86f5
#f0f5#86f5
Lf0f5_area_42:  ; TUNNEL
#f0f5#86f58
    db #00, #04, #2a, #36, #00, #08, #45, #13
#f0fd#86fd4
    db #c0, #80, #82, #83
#f101#870116
    db #e6, #e9, #ea, #ff, #0b, #9a, #9b, #03, #7d, #02, #3b, #00, #10, #08, #02, #0d
#f111#871116
    db #11, #12, #15, #29, #03, #02, #02, #3b, #00, #10, #08, #03, #0d, #11, #12, #2b
#f121#872111
    db #db, #02, #00, #00, #00, #00, #00, #00, #7b, #09, #00
#f12c#872c
#f12c#872c
Lf12c_area_43:  ; THE SWITCH
#f12c#872c8
    db #00, #0b, #2b, #c7, #00, #10, #07, #20
#f134#873413
    db #c0, #80, #81, #82, #83, #84, #85, #ff, #0e, #9f, #a0, #a1, #a3
#f141#874116
    db #a4, #03, #7d, #02, #38, #00, #20, #10, #02, #0d, #11, #12, #2a, #e1, #c3, #38
#f151#875116
    db #02, #02, #10, #20, #00, #03, #0d, #11, #12, #08, #14, #01, #3d, #16, #7a, #06
#f161#876116
    db #0e, #03, #01, #0c, #11, #11, #55, #03, #3f, #1a, #7a, #02, #06, #00, #04, #0a
#f171#877116
    db #11, #07, #3f, #1c, #76, #02, #04, #04, #05, #20, #4a, #4a, #00, #00, #04, #02
#f181#878116
    db #04, #db, #08, #dc, #0e, #c5, #05, #c5, #06, #c4, #07, #c4, #08, #c4, #03, #e3
#f191#879116
    db #01, #06, #3f, #20, #76, #02, #02, #04, #06, #12, #46, #4a, #00, #00, #02, #02
#f1a1#87a116
    db #02, #f0, #05, #c6, #3f, #1a, #76, #02, #04, #04, #07, #12, #4a, #4a, #00, #00
#f1b1#87b116
    db #04, #02, #04, #f0, #08, #c7, #3f, #18, #76, #02, #02, #04, #08, #20, #46, #4a
#f1c1#87c116
    db #00, #00, #02, #02, #02, #db, #08, #dc, #0e, #c5, #07, #c5, #08, #c4, #05, #c4
#f1d1#87d116
    db #06, #c5, #03, #e3, #01, #02, #00, #00, #00, #00, #00, #00, #7f, #09, #06, #73
#f1e1#87e116
    db #02, #6f, #05, #02, #09, #09, #14, #a5, #a2, #00, #00, #01, #05, #01, #c5, #09
#f1f1#87f116
    db #f0, #d6, #01, #0e, #5e, #03, #5c, #0e, #45, #03, #45, #07, #45, #08, #44, #05
#f201#88012
    db #44, #06
#f203#8803
#f203#8803
Lf203_area_44:  ; THE PILLAR
#f203#88038
    db #00, #0e, #2c, #c0, #00, #10, #07, #21
#f20b#880b6
    db #c0, #80, #81, #82, #83, #84
#f211#881116
    db #85, #ff, #0a, #8f, #03, #02, #02, #38, #00, #20, #10, #02, #0d, #11, #12, #0d
#f221#882116
    db #ca, #03, #7d, #02, #38, #00, #20, #10, #03, #0d, #11, #12, #25, #0e, #c1, #3a
#f231#883116
    db #02, #3d, #0c, #0d, #0c, #01, #0c, #dd, #aa, #ff, #c1, #3a, #02, #49, #0c, #1a
#f241#884116
    db #0c, #05, #0c, #99, #66, #55, #01, #3a, #02, #55, #0c, #2e, #0c, #06, #0c, #dd
#f251#885116
    db #aa, #ff, #03, #3a, #02, #3d, #0c, #00, #0c, #08, #0a, #aa, #03, #3a, #02, #49
#f261#886116
    db #0c, #00, #0c, #09, #0a, #66, #01, #3c, #02, #3f, #08, #04, #14, #0a, #14, #22
#f271#887116
    db #ee, #55, #dc, #0e, #c5, #0a, #c4, #0b, #e3, #01, #c1, #48, #02, #3f, #08, #04
#f281#888116
    db #14, #0b, #0c, #22, #ee, #55, #03, #3b, #30, #5b, #04, #00, #04, #07, #0e, #20
#f291#889116
    db #c5, #07, #f0, #d9, #02, #00, #00, #00, #00, #00, #00, #7f, #09, #06, #07, #02
#f2a1#88a116
    db #07, #05, #02, #09, #0c, #14, #a5, #a2, #00, #00, #01, #05, #01, #c5, #0c, #f0
#f2b1#88b116
    db #d6, #03, #60, #32, #52, #03, #00, #06, #0d, #11, #b0, #d4, #20, #0a, #c5, #0d
#f2c1#88c13
    db #f0, #d8, #00
#f2c4#88c4
#f2c4#88c4
Lf2c4_area_46:  ; THE RAT TRAP
#f2c4#88c48
    db #00, #0d, #2e, #b7, #00, #10, #07, #23
#f2cc#88cc9
    db #c0, #80, #81, #82, #83, #84, #85, #ff, #09
#f2d5#88d513
    db #03, #02, #02, #38, #00, #20, #10, #02, #0d, #11, #12, #15, #23
#f2e2#88e236
    db #03, #7b, #11, #3d, #00, #0c, #06, #01, #24, #22, #d4, #20, #06, #c5, #01, #dc, #0a, #e2, #11, #c1, #c0, #d4, #01, #da, #db, #10, #c5, #07, #c5, #0e, #c4, #0b, #e3, #01, #dc, #0e
#f306#890612
    db #01, #7b, #0d, #3a, #02, #13, #0c, #06, #0c, #ff, #66, #bb
#f312#89129
    db #02, #00, #00, #00, #00, #00, #00, #7f, #09
#f31b#891b12
    db #01, #63, #26, #02, #01, #17, #7b, #07, #0c, #99, #88, #77
#f327#892712
    db #01, #02, #02, #6b, #7b, #24, #01, #08, #0c, #00, #88, #ee
#f333#893312
    db #01, #02, #02, #14, #7b, #24, #01, #09, #0c, #00, #88, #ee
#f33f#893f12
    db #01, #02, #26, #14, #0a, #01, #58, #0a, #0c, #77, #88, #99
#f34b#894b12
    db #c1, #63, #09, #15, #01, #17, #56, #0b, #0c, #99, #88, #77
#f357#895710
    db #03, #63, #09, #6b, #01, #1d, #00, #0c, #0a, #11
#f361#896110
    db #03, #63, #09, #15, #01, #1d, #00, #0d, #0a, #11
#f36b#896b16
    db #0a, #63, #20, #40, #1a, #06, #00, #0e, #10, #11, #7d, #20, #40, #63, #26, #40
#f37b#897b1
    db #00
#f37c#897c
#f37c#897c
#f37c#897c
; --------------------------------
#f37c#897c
; RAM Variables:
#f37c#897c
#f37c#897c
Lfdfd_interrupt_jp: equ #fdfd  ; 1 byte
#f37c#897c
Lfdfe_interrupt_pointer: equ #fdfe  ; 2 bytes
#f37c#897c
Lfe00_interrupt_vector_table: equ #fe00  ; 257 bytes