If you are still using the old URL (datacrystal.romhacking.net), please update your bookmarks! The old URL may stop working soon.
The current URL is datacrystal.tcrf.net.
The current URL is datacrystal.tcrf.net.
Castlevania II: Belmont's Revenge/ROM map
Jump to navigation
Jump to search
The following article is a ROM map for Castlevania II: Belmont's Revenge.
Format for PRG-ROM is Bank:RAM address.
(r:symbol) marks the start of a callable subroutine. (RSTxy:symbol) marks a callable subroutine which can be called with the special quick-access RST commands. (t:symbol) marks the start of a data table.
X:7FFF all swappable banks store list their bank number as the last byte of the bank. 0:0000 (RST00:jumptable_entity_state) jumptable (indirect jump by entry in table following call to RST00 according to current entity's state variable) 0:0003 (r:jumptable) jumptable by A. 0:0008 (RST08:ld_from_table) hl <- (hl + 2a) 0:000C (r:ld_hl_hl) hl <- (hl) 0:0010 (RST10:entity_set_image) sets entity's image (see "Images" section below) 0:0018 (RST18:entity_set_timer) sets entity property $08 to A. This seems to be the entity's timer, such as how long until fire despawns or belmont's hitstun. 0:0020 (RST20:entity_get_x) e <- $17, a <- x position of entity. 0:0028 (RST28:add_hl_a) hl += a, then a <- l. 0:0030 (RST30:entity_inc_state) increments the state variable (D:01) of the current entity. 0:0038 (RST38:entity_get_y) get Y position of current entity. 0:01D9 (r:longcall_2_438D) stores current bank (read from $7FFF) on stack, calls routine 2:438D, then returns to caller bank. 0:0D23 (r:entity_set_state_and_substate) entity state <- b, substate (attacking) <- c 0:0D2A (r:belmont_apply_velocity) adds belmont's velocity to belmont's x position 0:2868 (r:load_substage_word_from_table) hl <- ((hl + stage) + substage*2) 0:286D (r:load_substage_byte_from_table) a <- ((hl + stage) + substage) 0:2873 (r:load_stage_data) hl <- (hl + stage); a <- substage. 0:2881 (r:add_bc_a) bc += a, then a <- c. 0:2886 (r_add_de_a) de += a, then a <- e 0:2986 (r:memcpy) directly copies bc bytes from hl to de. After this, hl and de point to the end of their respective buffers. Before calling, if de=hl+1, smears bc copies of [hl]. This can be a handy way to zero out a large buffer. 0:297B (r:leftshift_bc_4) leftshifts bc by 4. 0:2986 (r:lda_00) a <- $00 0:2989 (r:lda_06) a <- $06 0:298C (r:lda_7F) a <- $7F 0:298F (r:lda_06) a <- $80 0:2AC7 (r:wait_for_blank) Seems to wait to the end of the current blanking period (if applicable) and then to the start of the next. 0:2ca4 change this 2-byte word from 41c0 to 4280 to free up some extra space behind Belmont's head for sprite-hacking. Specifically, this means the map screen blank tile will be loaded from somewhere else. (You'll want to do the same at 0:2ce4 for the map screen as well.) 0:2E24 (r:transfer_buffers_to_vram) Transfers multiple buffers to vram. Before calling, ($ca81) should be set to the transfer scheme (see 0:2E57, below), and hl should point to a zero-terminated meta-buffer containing structs as follows: - 2 bytes (Big-Endian): destination vram address divided by 0x10 - 1 byte: destination length in units of 0x10 (source length depends on this and $ca81 scheme) - 1 byte: source bank - 2 bytes (Little-Endian) source address 0:2E57 (r:transfer_buffer_to_vram) transfers bc from buffer:hl into vram:de, using one of four schemes as selected by ($ca81): - 0: copy bytes from hl 1:1 (e.g. 0, 1, 2, 3, 4, 5...) - 1: duplicate every byte in hl (e.g. 0, 0, 1, 1, 2, 2, ...) - 2: even bytes from hl, odd bytes 0 (e.g. 0, 0, 1, 0, 2, 0, ...) - 3: odd bytes from hl, even bytes 0 (e.g 0, 0, 0, 1, 0, 2, ...) 0:35A9 (r:mbc_bankswap_1) loads swappable bank 1. 0:35AA (r:mbc_bankswap) loads swappable bank from cpu register a. 0:35AF (r:mbc_bankswap_2) loads swappable bank 2. 0:35B5 (r:mbc_bankswap_6) loads swappable bank 6. 0:35BB (r:mbc_bankswap_7) loads swappable bank 7. 0:35C1 (r:mbc_bankswap_3) loads swappable bank 3. 0:36B5 (r:get_tilechunk_address_from_de_plus_4ea2) hl <- 4x4 tile-chunk address (points to bank 2), indexed from [de+$(4ea2)] in bank 6 0:38E0 (r:entity_set_animation) Set animation (prop 0C,0B,0A) to (bc):0:(bc+1) (bc):0:(bc+1) 0:3DAC (r:entity_set_x_velocity_0) Entity x velocity <- 00. 0:3DAF (r:entity_set_x_velocity) Entity x velocity <- cb. 0:3DB4 (r:entity_set_y_velocity_0) Entity y velocity <- 00. 0:3DB7 (r:entity_set_y_velocity) Entity y velocity <- cb. 0:3DBA (r:write_word) (hl) <- cb 0:3DBE (r:entity_get_x_velocity) cb <- Entity x velocity. 0:3DC5 (r:entity_get_y_velocity) cb <- Entity x velocity. 0:3DC8 (r:read_word) cb <- (hl) 2:43ae (r:get_pointer_to_tiledata) de <- a*20 + (tiledata_ptr / ca92:ca93). 2:4407 (r:transfer_4x4_tiles_to_vram) input: bc points to top-left of 4x4 vram tiles, hl points to length-16 array. Also copies the tiles to to bc+$3C00 (i.e. $D000-$D800) 3:5242 (t:stage_table_unkA) (index via load_substage_data): ?? 3:58AC (t:stage_table_unkB) (index via load_substage_data): ?? 3:5D25 (t:stage_table_lantern) (index via load_substage_data): lantern data 3:6C49 (r:screen_coords_arithmetic) bc <- a plus bc in screen-radix. "screen-radix" here means that b represents screen dimensions ($A0 or $80 depending on vertical or horizontal), and c ranges between 0 and the screen dimension. Before calling, store screen dimension ($80 or $A0) in $(CBC3). 3:6D6B (r:inc_CBC4) increments $(CBC4) 6:421D (r:entity_update) Belmont frame update routine. Called from 0:05FA. 6:4235-4241 Belmont update jumptable 6:427F Belmont state 0 (standing) routine 6:4289 Belmont state 2 (crouching) routine 6:42E9 Belmont state 1 (walking) routine 6:4293 Belmont state 3 (jumping) routine 6:42A1 Belmont state 4 (??) routine 6:44A6 Belmont state 5 (??) routine 6:44D2 Belmont state 6 (??) routine 6:4510 Belmont state 7 (??) routine 6:461B (r:input_A_pressed) A gets zero or 10 depending on if the A button was pressed this frame. Status flags set 6:4621 (r:input_up_down_held) A and status flags 6:4627 (r:input_left_right_held) A and status flags 6:462D (r:input_B_pressed) A and status flags 6:4633 (r:input_B_held) A and status flags 6:4639 (r:input_down_held) A and status flags 6:464B (r:input_up_held) A and status flags 6:4651 (r:input_any_held) A and status flags 6:4801 (r:belmont_set_walk) Read left/right input and set Belmont to be walking left or right accordingly. 6:4817 (r:entity_move_face_right) Entity moves and faces right at velocity 0x90 6:4817 (r:entity_move_face_left) Entity moves and faces left at velocity -0x90
Bank swap routines:
- All are in bank 0, and all write to $2180 to change the bank. For some reason, bank 5 is always swapped inline rather than by function call.
Images
- Entities' images are stored in property 0A. Editing this value will change the entity's image -- for example, the axe might appear as a torch, at least until the axe's animation restores the image to the next frame of axe animation. Below is a partially-complete table of images (Please contribute!).
0: Torch (frame 0) 1: Torch (frame 1) 2: Coin (frame 0) 3: Coin (frame 1) 4: Score Orb 5: Small heart 6: Large Heart 7: Wall meat 08: fire (frame 0) 09: fire (frame 1) 0A: 1-up 0B: holy water (icon) 0C: holy water (projectile) 0D-10: Axe/Cross (frames 0-3) 11-23: Belmont poses 24-29: whip
and so on.
Entity indices (stored in RAM addresses XY00, XY >= $C6) -- range from 0-7F.
00: (no entity) 01: Lantern/Item: Axe/Cross 02: Lantern/Item: Holy Water 03: Lantern/Item: Coin 04: Lantern/Item: Whip Upgrade Orb 05: Lantern/Item: Small Heart 06: Big Heart 07: (debris) 08: (debris with big heart?) 09: Rat? 0A: ? 0B: breakable block? 0C: Punaguchi 0D: Punaguchi 0E: Rat? 0F: ? (explodes when struck) 10-13: ? 14: vertically moving flame? 15-16: ? 17-1B: ? (palette cycles, and turns to flame when struck.) 1C: ? (ascends) 1D: ? (gravity) 1E: ? (descends) 1F: bat? 20: bat? 21: ? (sessile enemy) 22: Lantern/Item: orb that crashes the game 23-24: ? 25: eyeball spawner (right) 26: eyeball spawner (left) 27-29: ? 2A: (immediately explodes) 2B: ? (deals contact damage, but cannot be destroyed) 2C: ? (like 2B but larger and does more damage) 2D: ? (like 2D) 2E-2F: ? 30: ? (sessile enemy) 31: ? (like 2B) 32: ? 33: ? (descending enemy) 34: raven 35: whip upgrade orb 36: ? 37-3A: ? 3B: ? (sessile enemy, explodes) 3C: eyeball spawner (above) 3D-3E: ? 3F: ? (sessile enemy) 40: ? 41: jumping dagger-thrower 42-44: ? (like 2B) 45: Lantern/Item: boss start (Darkside) 46: ? 47: ? (enemy, drops and dies) 48-49: ? 4A: moving platform, contact damage? 4B-4D: ? 4E: background flame 50: moving platform, covers screen? 51: ? (sticks to top of screen) 52: ? 53: Lantern/Item: boss start (Angel mummy) 54: ? 55: ? (projectile?) 56: ? (moves across screen, leaving trail.) 57: like 56, but in reverse. 58-5A: ? 5B: Night Stalker 5C: ? (contact damage) 5D: ? 60: Lantern/Item: boss start? 61: ? 62: ? (palette cycles, deals damage) 64: ? (like 5C) 65-68: ? 69: Lantern/Item: boss start (Bone Serpent) 6A: Bone Serpent (part) 6B: ? (moves to constant position at top of screen) 6C: Bone Serpent (part) 6D: Bone Serpent (part) 6E: moves to side of screen 6F: Bone Serpent (part) 70: ? (strange glitching tiles) 71: ? 72: Lantern/Item: boss start (Soleil) 73: Lantern/Item: boss start 74: ? (circular movement) 75-78: ? 79-7E: (crashes game) 7F: ?