// Block properties, some cutscene graphics #include "sm_rtl.h" #include "ida_types.h" #include "variables.h" #include "funcs.h" #define fnkPlmHeaderDefPtrs 0x949139 #define off_9492D9 ((uint16*)RomFixedPtr(0x9492d9)) #define off_9492E9 ((uint16*)RomFixedPtr(0x9492e9)) #define kPlmHeaderDefPtrs ((uint16*)RomFixedPtr(0x949139)) #define off_94936B ((uint16*)RomFixedPtr(0x94936b)) #define kBlockShotBombedReactionShootablePlm ((uint16 *)RomPtr_94(0x9ea6)) int32 *cur_coll_amt32; typedef struct CollInfo { int32 ci_r18_r20; uint16 ci_r24; uint16 ci_r26; uint16 ci_r28; uint16 ci_r30; uint16 ci_r32; uint16 ci_r38; uint16 ci_r40; } CollInfo; typedef struct PostGrappleCollInfo { uint16 pgci_r26; uint16 pgci_r28; uint16 pgci_r32; } PostGrappleCollInfo; typedef uint8 Func_CollInfo_U8(CollInfo *ci); typedef uint16 Func_PostGrappleCollInfo_U16(PostGrappleCollInfo *pgci); static uint16 GrappleInstr_Goto(uint16 j); static uint16 Samus_GetXposSpan(void); static uint16 Samus_GetYposSpan(void); static uint16 BlockFunc_9C73(uint16 k); static void BlockFunc_A06A(uint16 k); static void BlockFunc_A0F4(uint16 a, uint16 r22, uint16 r24, uint16 r26, uint16 r28); static void BlockFunc_A11A(uint16 a, uint16 r24, uint16 r26, uint16 r28); static void CalculateBlockAt(uint16 r26, uint16 r28, uint16 r30, uint16 r32); static void BlockBombedReact(CollInfo *ci, uint16 v0); static void BlockColl_BombExplosion(CollInfo *ci, uint16 k); static uint8 BlockShotReactHoriz_Slope_Square(CollInfo *ci, uint16 a, uint16 k); static uint8 BlockShotReactVert_Slope_Square(CollInfo *ci, uint16 a, uint16 k); static uint8 BlockShotReactHoriz_Slope_NonSquare(CollInfo *ci); static uint8 BlockShotReactVert_Slope_NonSquare(CollInfo *ci); static uint8 BlockReact_AA64_SpikeAir(CollInfo *ci); static uint8 BlockReact_AA64_SpikeBlock(CollInfo *ci); static void DrawGrappleOams(uint16 x_r20, uint16 y_r24, uint16 chr_r38); static void DrawGrappleOams3(void); static uint16 PostGrappleColl_Vert_Solid(PostGrappleCollInfo *pgci); static uint16 PostGrappleColl_Horiz_Solid(PostGrappleCollInfo *pgci); static const uint8 kAlignPos_Tab1[512] = { 16, 16, 16, 16, 16, 16, 16, 16, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 16, 16, 16, 16, 16, 16, 16, 16, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 15, 14, 13, 12, 11, 10, 9, 9, 10, 11, 12, 13, 14, 15, 16, 16, 14, 12, 10, 8, 6, 4, 2, 2, 4, 6, 8, 10, 12, 14, 16, 16, 16, 16, 16, 16, 16, 16, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 12, 12, 12, 8, 8, 8, 8, 4, 4, 4, 4, 0, 0, 0, 0, 14, 14, 12, 12, 10, 10, 8, 8, 6, 6, 4, 4, 2, 2, 0, 0, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 16, 16, 16, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 16, 16, 16, 16, 16, 16, 16, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 16, 16, 16, 16, 16, 16, 16, 16, 16, 14, 12, 10, 8, 6, 4, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 4, 6, 8, 10, 12, 14, 16, 16, 16, 15, 15, 15, 14, 14, 14, 13, 13, 13, 12, 12, 12, 11, 11, 11, 10, 10, 10, 9, 9, 9, 8, 8, 8, 7, 7, 7, 6, 6, 6, 5, 5, 5, 4, 4, 4, 3, 3, 3, 2, 2, 2, 1, 1, 1, 20, 20, 20, 20, 20, 20, 20, 20, 16, 14, 12, 10, 8, 6, 4, 2, 16, 14, 12, 10, 8, 6, 4, 2, 0, 0, 0, 0, 0, 0, 0, 0, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 15, 12, 9, 6, 3, 20, 20, 20, 20, 20, 20, 14, 11, 8, 5, 2, 0, 0, 0, 0, 0, 16, 13, 10, 7, 4, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; static const uint8 kAlignYPos_Tab0[512] = { 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 16, 16, 16, 16, 16, 16, 16, 16, 0, 0, 0, 0, 0, 0, 0, 0, 16, 16, 16, 16, 16, 16, 16, 16, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 15, 14, 13, 12, 11, 10, 9, 9, 10, 11, 12, 13, 14, 15, 16, 16, 14, 12, 10, 8, 6, 4, 2, 2, 4, 6, 8, 10, 12, 14, 16, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 12, 12, 12, 8, 8, 8, 8, 4, 4, 4, 4, 0, 0, 0, 0, 14, 14, 12, 12, 10, 10, 8, 8, 6, 6, 4, 4, 2, 2, 0, 0, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 16, 16, 16, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 16, 16, 16, 16, 16, 16, 16, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 16, 16, 15, 15, 14, 14, 13, 13, 12, 12, 11, 11, 10, 10, 9, 9, 8, 8, 7, 7, 6, 6, 5, 5, 4, 4, 3, 3, 2, 2, 1, 1, 16, 16, 16, 15, 15, 15, 14, 14, 14, 13, 13, 13, 12, 12, 12, 11, 11, 11, 10, 10, 10, 9, 9, 9, 8, 8, 8, 7, 7, 7, 6, 6, 6, 5, 5, 5, 4, 4, 4, 3, 3, 3, 2, 2, 2, 1, 1, 1, 20, 20, 20, 20, 20, 20, 20, 20, 16, 14, 12, 10, 8, 6, 4, 2, 16, 14, 12, 10, 8, 6, 4, 2, 0, 0, 0, 0, 0, 0, 0, 0, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 15, 12, 9, 6, 3, 20, 20, 20, 20, 20, 20, 14, 11, 8, 5, 2, 0, 0, 0, 0, 0, 16, 13, 10, 7, 4, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; ////////////////////////////////////////////////////////////// // BANK 94 ////////////////////////////////////////////////////////////// static const uint8 kTab948E54[20] = { 0, 0, 0x80, 0x80, 0, 0x80, 0, 0x80, 0, 0, 0, 0x80, 0, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, }; static const uint16 kBlockColl_Horiz_Slope_NonSquare_Tab[64] = { 0, 0x100, 0, 0x100, 0, 0x100, 0, 0x100, 0, 0x100, 0, 0x100, 0, 0x100, 0, 0x100, 0, 0x100, 0, 0x100, 0, 0x100, 0, 0x100, 0, 0x100, 0, 0x100, 0x1000, 0xb0, 0x1000, 0xb0, 0, 0x100, 0, 0x100, 0x1000, 0xc0, 0, 0x100, 0x1000, 0xc0, 0x1000, 0xc0, 0x800, 0xd8, 0x800, 0xd8, 0x600, 0xf0, 0x600, 0xf0, 0x600, 0xf0, 0x4000, 0x80, 0x4000, 0x80, 0x6000, 0x50, 0x6000, 0x50, 0x6000, 0x50, }; static uint16 PostGrappleColl_Horiz_Slope_NonSquare(PostGrappleCollInfo *pgci, uint16 k) { // 0x948000 if (!(samus_collision_direction & 1)) { if ((samus_x_pos >> 4) != SnesModulus(cur_block_index, room_width_in_blocks)) return -1; if ((BTS[k] & 0x40) == 0) return PostGrappleColl_Horiz_Solid(pgci); uint16 v3 = samus_y_pos ^ (BTS[k] & 0x80 ? 0xF : 0); uint16 v4 = 16 * (BTS[k] & 0x1F) + (v3 & 0xF); int16 result = (kAlignPos_Tab1[v4] & 0x1F) - (pgci->pgci_r32 & 0xF) - 1; return (result >= 0) ? result : -1; } else { if ((samus_x_pos >> 4) != SnesModulus(cur_block_index, room_width_in_blocks)) return -1; if (BTS[k] & 0x40) return PostGrappleColl_Horiz_Solid(pgci); uint16 v6 = samus_y_pos ^ (BTS[k] & 0x80 ? 0xF : 0); uint16 v7 = 16 * (BTS[k] & 0x1F) + (v6 & 0xF); int16 result = (kAlignPos_Tab1[v7] & 0x1F) - (pgci->pgci_r32 & 0xF) - 1; return (result <= 0) ? ~result : -1; } } static uint16 PostGrappleColl_Vert_Slope_NonSquare(PostGrappleCollInfo *pgci, uint16 k) { // 0x9480E0 if (!(samus_collision_direction & 1)) { uint16 mod = SnesModulus(cur_block_index, room_width_in_blocks); if ((samus_x_pos >> 4) != mod) return -1; uint16 temp_collision_DD4 = pgci->pgci_r32 & 0xF; if (!(BTS[k] & 0x80)) return PostGrappleColl_Vert_Solid(pgci); uint16 v4 = samus_x_pos ^ ((BTS[k] & 0x40) != 0 ? 0xf : 0); uint16 v5 = 16 * (BTS[k] & 0x1F) + (v4 & 0xF); uint16 result = (kAlignYPos_Tab0[v5] & 0x1F) - temp_collision_DD4 - 1; return ((int16)result >= 0) ? result : -1; } uint16 mod = SnesModulus(cur_block_index, room_width_in_blocks); if ((samus_x_pos >> 4) != mod) return -1; uint16 temp_collision_DD4 = pgci->pgci_r32 & 0xF; if (BTS[k] & 0x80) return PostGrappleColl_Vert_Solid(pgci); uint16 v8 = samus_x_pos ^ ((BTS[k] & 0x40) != 0 ? 0xf : 0); uint16 v9 = 16 * (BTS[k] & 0x1F) + (v8 & 0xF); uint16 v10 = (kAlignYPos_Tab0[v9] & 0x1F) - temp_collision_DD4 - 1; return ((int16)v10 <= 0) ? ~v10 : -1; } static uint16 PostGrappleColl_Horiz_Slope_Square(PostGrappleCollInfo *pgci, uint16 k) { // 0x9481B8 uint16 temp_collision_DD4 = 4 * (BTS[k] & 0x1F); uint16 temp_collision_DD6 = BTS[k] >> 6; uint16 v1 = temp_collision_DD4 + (temp_collision_DD6 ^ ((pgci->pgci_r32 & 8) >> 3)); if (!pgci->pgci_r26) { if (((samus_y_radius + samus_y_pos - 1) & 8) == 0) { if (!kTab948E54[v1]) return -1; goto LABEL_10; } goto LABEL_7; } if (pgci->pgci_r26 != pgci->pgci_r28 || ((samus_y_pos - samus_y_radius) & 8) == 0) { LABEL_7: if (kTab948E54[v1]) goto LABEL_10; } if (!kTab948E54[v1 ^ 2]) return -1; LABEL_10: if (samus_collision_direction & 1) return pgci->pgci_r32 & 7; else return pgci->pgci_r32 & 7 ^ 7; } static uint16 PostGrappleColl_Vertical_Slope_Square(PostGrappleCollInfo *pgci, uint16 k) { // 0x948230 uint16 temp_collision_DD4 = 4 * (BTS[k] & 0x1F); uint16 temp_collision_DD6 = BTS[k] >> 6; uint16 v1 = temp_collision_DD4 + (temp_collision_DD6 ^ ((pgci->pgci_r32 & 8) >> 2)); if (!pgci->pgci_r26) { if (((samus_x_radius + samus_x_pos - 1) & 8) == 0) { if (!kTab948E54[v1]) return -1; goto LABEL_10; } goto LABEL_7; } if (pgci->pgci_r26 != pgci->pgci_r28 || ((samus_x_pos - samus_x_radius) & 8) == 0) { LABEL_7: if (kTab948E54[v1]) goto LABEL_10; } if (!kTab948E54[v1 ^ 1]) return -1; LABEL_10: if (samus_collision_direction & 1) return pgci->pgci_r32 & 7; else return pgci->pgci_r32 & 7 ^ 7; } static uint16 ClearCarry_0(PostGrappleCollInfo *pgci) { // 0x9482A7 return -1; } static uint16 PostGrappleColl_Horiz_Slope(PostGrappleCollInfo *pgci) { // 0x9482A9 if ((BTS[cur_block_index] & 0x1F) < 5) return PostGrappleColl_Horiz_Slope_Square(pgci, cur_block_index); else return PostGrappleColl_Horiz_Slope_NonSquare(pgci, cur_block_index); } static uint16 PostGrappleColl_Horiz_Solid(PostGrappleCollInfo *pgci) { // 0x9482BE return pgci->pgci_r32 & 0xF; } static uint16 PostGrappleColl_Vert_Slope(PostGrappleCollInfo *pgci) { // 0x9482C5 if ((BTS[cur_block_index] & 0x1F) < 5) return PostGrappleColl_Vertical_Slope_Square(pgci, cur_block_index); else return PostGrappleColl_Vert_Slope_NonSquare(pgci, cur_block_index); } static uint16 PostGrappleColl_Vert_Solid(PostGrappleCollInfo *pgci) { // 0x9482DA return pgci->pgci_r32 & 0xF; } static Func_PostGrappleCollInfo_U16 *const kPostGrappleColl_Horiz[16] = { // 0x948321 ClearCarry_0, PostGrappleColl_Horiz_Slope, ClearCarry_0, ClearCarry_0, ClearCarry_0, ClearCarry_0, ClearCarry_0, ClearCarry_0, PostGrappleColl_Horiz_Solid, PostGrappleColl_Horiz_Solid, PostGrappleColl_Horiz_Solid, PostGrappleColl_Horiz_Solid, PostGrappleColl_Horiz_Solid, PostGrappleColl_Horiz_Solid, PostGrappleColl_Horiz_Solid, PostGrappleColl_Horiz_Solid, }; static Func_PostGrappleCollInfo_U16 *const kPostGrappleColl_Vert[16] = { ClearCarry_0, PostGrappleColl_Vert_Slope, ClearCarry_0, ClearCarry_0, ClearCarry_0, ClearCarry_0, ClearCarry_0, ClearCarry_0, PostGrappleColl_Vert_Solid, PostGrappleColl_Vert_Solid, PostGrappleColl_Vert_Solid, PostGrappleColl_Vert_Solid, PostGrappleColl_Vert_Solid, PostGrappleColl_Vert_Solid, PostGrappleColl_Vert_Solid, PostGrappleColl_Vert_Solid, }; static uint16 PostGrappleColl_Horiz(PostGrappleCollInfo *pgci, uint16 k) { cur_block_index = k >> 1; return kPostGrappleColl_Horiz[(level_data[k >> 1] & 0xF000) >> 12](pgci); } static uint16 PostGrappleColl_Vert(PostGrappleCollInfo *pgci, uint16 k) { // 0x948338 cur_block_index = k >> 1; return kPostGrappleColl_Vert[(level_data[k >> 1] & 0xF000) >> 12](pgci); } static void PostGrappleCollisionDetect_Right(void) { // 0x94834F int16 v0; int16 v2; samus_collision_direction = 1; distance_to_eject_samus_left = 0; uint16 r28 = Samus_GetYposSpan(); uint16 prod = Mult8x8((uint16)(samus_y_pos - samus_y_radius) >> 4, room_width_in_blocks); // r22 = samus_x_subpos; uint16 r24 = samus_x_pos; uint16 R32 = samus_x_radius + samus_x_pos - 1; v0 = R32 >> 4; cur_block_index = prod + v0; uint16 v1 = 2 * cur_block_index; PostGrappleCollInfo pgci = { .pgci_r26 = r28, .pgci_r28 = r28, .pgci_r32 = R32 }; do { v2 = PostGrappleColl_Horiz(&pgci, v1); if (v2 >= 0) { uint16 v3 = v2 + 1; if (v3 >= distance_to_eject_samus_left) distance_to_eject_samus_left = v3; } v1 += room_width_in_blocks * 2; --pgci.pgci_r26; } while ((pgci.pgci_r26 & 0x8000) == 0); } static void PostGrappleCollisionDetect_Left(void) { // 0x9483B1 int16 v0; int16 v2; samus_collision_direction = 0; distance_to_eject_samus_right = 0; uint16 r28 = Samus_GetYposSpan(); uint16 prod = Mult8x8((uint16)(samus_y_pos - samus_y_radius) >> 4, room_width_in_blocks); //r22 = samus_x_subpos; uint16 r24 = samus_x_pos; uint16 R32 = samus_x_pos - samus_x_radius; v0 = (uint16)(samus_x_pos - samus_x_radius) >> 4; cur_block_index = prod + v0; uint16 v1 = 2 * cur_block_index; PostGrappleCollInfo pgci = { .pgci_r26 = r28, .pgci_r28 = r28, .pgci_r32 = R32 }; do { v2 = PostGrappleColl_Horiz(&pgci, v1); if (v2 >= 0) { uint16 v3 = v2 + 1; if (v3 >= distance_to_eject_samus_right) distance_to_eject_samus_right = v3; } v1 += room_width_in_blocks * 2; --pgci.pgci_r26; } while ((pgci.pgci_r26 & 0x8000) == 0); } static void PostGrappleCollisionDetect_Down(void) { // 0x94840F int16 v0; int16 v2; samus_collision_direction = 3; distance_to_eject_samus_up = 0; uint16 r28 = Samus_GetXposSpan(); //r22 = samus_y_subpos; uint16 r24 = samus_y_pos; uint16 R32 = samus_y_radius + samus_y_pos - 1; uint16 prod = Mult8x8(R32 >> 4, room_width_in_blocks); v0 = (uint16)(samus_x_pos - samus_x_radius) >> 4; cur_block_index = prod + v0; uint16 v1 = 2 * cur_block_index; PostGrappleCollInfo pgci = { .pgci_r26 = r28, .pgci_r28 = r28, .pgci_r32 = R32 }; do { v2 = PostGrappleColl_Vert(&pgci, v1); if (v2 >= 0) { uint16 v3 = v2 + 1; if (v3 >= distance_to_eject_samus_up) distance_to_eject_samus_up = v3; } v1 += 2; --pgci.pgci_r26; } while ((pgci.pgci_r26 & 0x8000) == 0); } static void PostGrappleCollisionDetect_Up(void) { // 0x94846A int16 v0; int16 v2; samus_collision_direction = 2; distance_to_eject_samus_down = 0; uint16 r28 = Samus_GetXposSpan(); //r22 = samus_y_subpos; uint16 r24 = samus_y_pos; uint16 R32 = samus_y_pos - samus_y_radius; uint16 prod = Mult8x8((uint16)(samus_y_pos - samus_y_radius) >> 4, room_width_in_blocks); v0 = (uint16)(samus_x_pos - samus_x_radius) >> 4; cur_block_index = prod + v0; uint16 v1 = 2 * cur_block_index; PostGrappleCollInfo pgci = { .pgci_r26 = r28, .pgci_r28 = r28, .pgci_r32 = R32 }; do { v2 = PostGrappleColl_Vert(&pgci, v1); if (v2 >= 0) { uint16 v3 = v2 + 1; if (v3 >= distance_to_eject_samus_down) distance_to_eject_samus_down = v3; } v1 += 2; --pgci.pgci_r26; } while ((pgci.pgci_r26 & 0x8000) == 0); } void PostGrappleCollisionDetect_X(void) { // 0x9484C4 PostGrappleCollisionDetect_Right(); PostGrappleCollisionDetect_Left(); } void PostGrappleCollisionDetect_Y(void) { // 0x9484CD PostGrappleCollisionDetect_Down(); PostGrappleCollisionDetect_Up(); } static uint8 BlockColl_Horiz_Slope_NonSquare(CollInfo *ci) { // 0x9484D6 if ((current_slope_bts & 0x80) != 0 || __PAIR32__(samus_y_speed, samus_y_subspeed)) return 0; uint16 v1 = 4 * (current_slope_bts & 0x1F); uint16 v2 = ci->ci_r18_r20 >> 8; if (ci->ci_r18_r20 >= 0) { ci->ci_r18_r20 = Multiply16x16(v2, kBlockColl_Horiz_Slope_NonSquare_Tab[(v1 >> 1) + 1]); } else { ci->ci_r18_r20 = -(int32)Multiply16x16(-v2, kBlockColl_Horiz_Slope_NonSquare_Tab[(v1 >> 1) + 1]); } return 0; } static uint8 BlockColl_Vert_Slope_NonSquare(CollInfo *ci, uint16 k) { // 0x9486FE if (samus_collision_direction & 1) { if ((samus_x_pos >> 4) != SnesModulus(cur_block_index, room_width_in_blocks)) return 0; if (BTS[k] & 0x80) return 0; uint16 v10 = (BTS[k] & 0x40) != 0 ? samus_x_pos ^ 0xF : samus_x_pos; uint16 v11 = 16 * (BTS[k] & 0x1F) + (v10 & 0xF); int16 v12 = (kAlignYPos_Tab0[v11] & 0x1F) - ((samus_y_radius + ci->ci_r24 - 1) & 0xF) - 1; if (v12 <= 0) { int16 v13 = (ci->ci_r18_r20 >> 16) + v12; if (v13 < 0) v13 = 0; ci->ci_r18_r20 = v13 << 16; return 1; } else { return 0; } } else { if ((samus_x_pos >> 4) != SnesModulus(cur_block_index, room_width_in_blocks)) return 0; if (!(BTS[k] & 0x80)) return 0; uint16 v4 = (BTS[k] & 0x40) != 0 ? (samus_x_pos ^ 0xF) : (samus_x_pos); uint16 v5 = 16 * (BTS[k] & 0x1F) + (v4 & 0xF); int16 v6 = (kAlignYPos_Tab0[v5] & 0x1F) - ((ci->ci_r24 - samus_y_radius) & 0xF ^ 0xF) - 1; if (v6 <= 0) { int16 v7 = (ci->ci_r18_r20 >> 16) + v6; if (v7 < 0) v7 = 0; ci->ci_r18_r20 = v7 << 16; return 1; } else { return 0; } } } void Samus_AlignYPosSlope(void) { // 0x9487F4 if ((enable_horiz_slope_coll & 2) == 0) return; uint16 r26 = samus_x_pos; uint16 R28 = samus_y_radius + samus_y_pos - 1; CalculateBlockAt(r26, R28, 0, 0); if ((level_data[cur_block_index] & 0xF000) == 4096 && (BTS[cur_block_index] & 0x1F) >= 5) { uint16 temp_collision_DD4 = (samus_y_radius + samus_y_pos - 1) & 0xF; uint16 temp_collision_DD6 = 16 * (BTS[cur_block_index] & 0x1F); uint8 v0 = BTS[cur_block_index]; if (!(v0 & 0x80)) { uint16 v1 = (v0 & 0x40) != 0 ? samus_x_pos ^ 0xF : samus_x_pos; uint16 v2 = (kAlignYPos_Tab0[temp_collision_DD6 + (v1 & 0xF)] & 0x1F) - temp_collision_DD4 - 1; if ((int16)v2 < 0) { samus_y_pos += v2; samus_pos_adjusted_by_slope_flag = 1; } } } r26 = samus_x_pos; R28 = samus_y_pos - samus_y_radius; CalculateBlockAt(r26, R28, 0, 0); if ((level_data[cur_block_index] & 0xF000) == 4096 && (BTS[cur_block_index] & 0x1F) >= 5) { uint16 temp_collision_DD4 = (samus_y_pos - samus_y_radius) & 0xF ^ 0xF; uint16 temp_collision_DD6 = 16 * (BTS[cur_block_index] & 0x1F); uint8 v3 = BTS[cur_block_index]; if (v3 & 0x80) { uint16 v4 = (v3 & 0x40) != 0 ? samus_x_pos ^ 0xF : samus_x_pos; uint16 v6 = (kAlignYPos_Tab0[temp_collision_DD6 + (v4 & 0xF)] & 0x1F) - temp_collision_DD4 - 1; if ((int16)v6 <= 0) { samus_y_pos -= v6; samus_pos_adjusted_by_slope_flag = 1; } } } } static uint8 BlockColl_Horiz_Slope_Square(CollInfo *ci, uint16 a, uint16 k) { // 0x948D2B uint16 temp_collision_DD4 = 4 * a; uint16 temp_collision_DD6 = BTS[k] >> 6; uint16 v2 = 4 * a + (temp_collision_DD6 ^ ((ci->ci_r32 & 8) >> 3)); if (!ci->ci_r26) { if (((samus_y_radius + samus_y_pos - 1) & 8) == 0) { if (!kTab948E54[v2]) return 0; goto LABEL_10; } goto LABEL_7; } if (ci->ci_r26 != ci->ci_r28 || ((samus_y_pos - samus_y_radius) & 8) == 0) { LABEL_7: if (kTab948E54[v2]) goto LABEL_10; } if (!kTab948E54[v2 ^ 2]) return 0; LABEL_10: if (ci->ci_r18_r20 < 0) { int16 v5 = samus_x_radius + (ci->ci_r32 | 7) + 1 - samus_x_pos; if (v5 >= 0) v5 = 0; ci->ci_r18_r20 = v5 << 16; samus_x_subpos = 0; } else { // todo: carry int16 v4 = (__PAIR32__((ci->ci_r32 & 0xFFF8) - samus_x_radius, ci->ci_r32 & 0xFFF8) - __PAIR32__(samus_x_pos, samus_x_radius)) >> 16; if (v4 < 0) v4 = 0; ci->ci_r18_r20 = v4 << 16; samus_x_subpos = -1; } return 1; } static uint8 BlockColl_Vert_Slope_Square(CollInfo *ci, uint16 a, uint16 k) { // 0x948DBD uint16 temp_collision_DD4 = 4 * a; uint16 temp_collision_DD6 = BTS[k] >> 6; uint16 v2 = 4 * a + (temp_collision_DD6 ^ ((ci->ci_r32 & 8) >> 2)); if (!ci->ci_r26) { if (((samus_x_radius + samus_x_pos - 1) & 8) == 0) { if (!kTab948E54[v2]) return 0; goto LABEL_10; } goto LABEL_7; } if (ci->ci_r26 != ci->ci_r28 || ((samus_x_pos - samus_x_radius) & 8) == 0) { LABEL_7: if (kTab948E54[v2]) goto LABEL_10; } if (!kTab948E54[v2 ^ 1]) return 0; LABEL_10: if (ci->ci_r18_r20 < 0) { int16 v5 = samus_y_radius + (ci->ci_r32 | 7) + 1 - samus_y_pos; if (v5 >= 0) v5 = 0; ci->ci_r18_r20 = v5 << 16; samus_y_subpos = 0; return 1; } else { // todo: fix carry int16 v4 = (__PAIR32__((ci->ci_r32 & 0xFFF8) - samus_y_radius, ci->ci_r32 & 0xFFF8) - __PAIR32__(samus_y_pos, samus_y_radius)) >> 16; if (v4 < 0) v4 = 0; ci->ci_r18_r20 = v4 << 16; samus_y_subpos = -1; samus_pos_adjusted_by_slope_flag = 1; return 1; } } static uint8 ClearCarry_1(CollInfo *ci) { // 0x948E7D return 0; } static uint8 ClearCarry_2(CollInfo *ci) { // 0x948E7F return 0; } static uint8 ClearCarry_3(CollInfo *ci) { // 0x948E81 return 0; } static void BlockColl_SpikeBlock_BTS0(void) { // 0x948E83 if ((area_index != 3 || CheckBossBitForCurArea(1) & 1) && !samus_invincibility_timer) { samus_invincibility_timer = 60; samus_knockback_timer = 10; samus_periodic_damage += 60; knockback_x_dir = ((samus_pose_x_dir ^ 0xC) & 8) != 0; } } static void BlockColl_SpikeBlock_BTS1(void) { // 0x948ECF if (!samus_invincibility_timer) { samus_invincibility_timer = 60; samus_knockback_timer = 10; samus_periodic_damage += 16; knockback_x_dir = ((samus_pose_x_dir ^ 0xC) & 8) != 0; } } static void BlockColl_SpikeBlock_BTS3(void) { // 0x948F0A if (!samus_invincibility_timer) { samus_invincibility_timer = 60; samus_knockback_timer = 10; samus_periodic_damage += 16; knockback_x_dir = ((samus_pose_x_dir ^ 0xC) & 8) != 0; } } static uint8 SetCarry(CollInfo *ci) { return 1; } static uint8 ClearCarry_4(CollInfo *ci) { // 0x948F47 return 0; } static uint8 BlockColl_Horiz_SolidShootGrappleBlock(CollInfo *ci) { // 0x948F49 if (ci->ci_r18_r20 < 0) { int16 v2 = samus_x_radius + (ci->ci_r32 | 0xF) + 1 - samus_x_pos; if (v2 >= 0) v2 = 0; ci->ci_r18_r20 = v2 << 16; samus_x_subpos = 0; return 1; } else { int16 v0 = (ci->ci_r32 & 0xFFF0) - samus_x_radius - samus_x_pos; if (v0 < 0) v0 = 0; ci->ci_r18_r20 = v0 << 16; samus_x_subpos = -1; return 1; } } static uint8 BlockColl_Vert_SolidShootGrappleBlock(CollInfo *ci) { // 0x948F82 if (ci->ci_r18_r20 < 0) { int16 v2 = samus_y_radius + (ci->ci_r32 | 0xF) + 1 - samus_y_pos; if (v2 >= 0) v2 = 0; ci->ci_r18_r20 = v2 << 16; samus_y_subpos = 0; return 1; } else { int16 v0 = (ci->ci_r32 & 0xFFF0) - samus_y_radius - samus_y_pos; if (v0 < 0) v0 = 0; ci->ci_r18_r20 = v0 << 16; samus_y_subpos = -1; return 1; } } static uint8 BlockColl_Horiz_Slope(CollInfo *ci) { // 0x948FBB uint16 v0 = BTS[cur_block_index] & 0x1F; if (v0 < 5) return BlockColl_Horiz_Slope_Square(ci, v0, cur_block_index); current_slope_bts = BTS[cur_block_index]; return BlockColl_Horiz_Slope_NonSquare(ci); } static uint8 BlockColl_Vert_Slope(CollInfo *ci) { // 0x948FDA uint16 v0 = BTS[cur_block_index] & 0x1F; if (v0 < 5) return BlockColl_Vert_Slope_Square(ci, v0, cur_block_index); current_slope_bts = BTS[cur_block_index]; return BlockColl_Vert_Slope_NonSquare(ci, cur_block_index); } static uint8 ClearCarry_5(CollInfo *ci) { // 0x949018 return 0; } static uint8 BlockColl_Vert_SpikeAir(CollInfo *ci) { // 0x94901A return 0; } static void SetCarry_Spikeblk(void) { } static Func_V *const kBlockColl_SpikeBlock[16] = { // 0x94904B BlockColl_SpikeBlock_BTS0, BlockColl_SpikeBlock_BTS1, SetCarry_Spikeblk, BlockColl_SpikeBlock_BTS3, SetCarry_Spikeblk, SetCarry_Spikeblk, SetCarry_Spikeblk, SetCarry_Spikeblk, SetCarry_Spikeblk, SetCarry_Spikeblk, SetCarry_Spikeblk, SetCarry_Spikeblk, SetCarry_Spikeblk, SetCarry_Spikeblk, SetCarry_Spikeblk, SetCarry_Spikeblk, }; static uint8 BlockColl_Horiz_SpikeBlock(CollInfo *ci) { kBlockColl_SpikeBlock[BTS[cur_block_index]](); return BlockColl_Horiz_SolidShootGrappleBlock(ci); } static uint8 BlockColl_Vert_SpikeBlock(CollInfo *ci) { // 0x94905D kBlockColl_SpikeBlock[BTS[cur_block_index]](); return BlockColl_Vert_SolidShootGrappleBlock(ci); } static uint8 BlockColl_Horiz_SpecialAir(CollInfo *ci) { // 0x94906F uint8 v0 = BTS[cur_block_index]; if ((v0 & 0x80) != 0) { const uint16 *v2 = (const uint16 *)RomPtr_94(off_9492D9[area_index]); return SpawnPLM(v2[v0 & 0x7f]) & 1; } else { SpawnPLM(kPlmHeaderDefPtrs[v0]); return 0; } } static uint8 BlockColl_Vert_SpecialAir(CollInfo *ci) { // 0x94909D uint8 v0 = BTS[cur_block_index]; if ((v0 & 0x80) != 0) { const uint16 *v2 = (const uint16 *)RomPtr_94(off_9492D9[area_index]); return SpawnPLM(v2[v0 & 0x7f]) & 1; } else { SpawnPLM(kPlmHeaderDefPtrs[v0]); return 0; } } static uint8 BlockColl_Horiz_SpecialBlock(CollInfo *ci) { // 0x9490CB uint8 v0 = BTS[cur_block_index]; if ((v0 & 0x80) != 0) { const uint16 *v2 = (const uint16 *)RomPtr_94(off_9492E9[area_index]); uint8 v4 = SpawnPLM(v2[v0 & 0x7f]) & 1; if (v4) return BlockColl_Horiz_SolidShootGrappleBlock(ci); return v4; } else { uint8 v1 = SpawnPLM(kPlmHeaderDefPtrs[v0]) & 1; if (v1) return BlockColl_Horiz_SolidShootGrappleBlock(ci); return v1; } } static uint8 BlockColl_Vert_SpecialBlock(CollInfo *ci) { // 0x949102 uint8 v0 = BTS[cur_block_index]; if ((v0 & 0x80) != 0) { const uint16 *v3 = (const uint16 *)RomPtr_94(off_9492E9[area_index]); uint8 v4 = SpawnPLM(v3[v0 & 0x7F]) & 1; if (v4) return BlockColl_Vert_SolidShootGrappleBlock(ci); return v4; } else { uint8 v1 = SpawnPLM(kPlmHeaderDefPtrs[v0]) & 1; if (v1) return BlockColl_Vert_SolidShootGrappleBlock(ci); return v1; } } static uint8 BlockColl_Horiz_BombableAir(CollInfo *ci) { // 0x9492F9 uint8 v0 = BTS[cur_block_index]; if ((v0 & 0x80) == 0) SpawnPLM(off_94936B[v0]); return 0; } static uint8 BlockColl_Vert_BombableAir(CollInfo *ci) { // 0x949313 uint8 v0 = BTS[cur_block_index]; if ((v0 & 0x80) == 0) SpawnPLM(off_94936B[v0]); return 0; } static uint8 BlockColl_Horiz_BombBlock(CollInfo *ci) { // 0x94932D uint8 v0 = BTS[cur_block_index]; if ((v0 & 0x80) != 0) return BlockColl_Horiz_SolidShootGrappleBlock(ci); uint8 v1 = SpawnPLM(off_94936B[v0]) & 1; if (v1) return BlockColl_Horiz_SolidShootGrappleBlock(ci); else return v1; } static uint8 BlockColl_Vert_BombBlock(CollInfo *ci) { // 0x94934C uint8 v0 = BTS[cur_block_index]; if ((v0 & 0x80) != 0) return BlockColl_Vert_SolidShootGrappleBlock(ci); uint8 v1 = SpawnPLM(off_94936B[v0]) & 1; if (v1) return BlockColl_Vert_SolidShootGrappleBlock(ci); else return v1; } uint8 BlockColl_Horiz_Door(CollInfo *ci) { // 0x94938B door_transition_function = FUNC16(DoorTransitionFunction_HandleElevator); door_bts = BTS[cur_block_index]; uint16 v0 = *(uint16 *)RomPtr_8F(door_list_pointer + 2 * (door_bts & 0x7F)); if ((get_DoorDef(v0)->room_definition_ptr & 0x8000) == 0) { if (samus_pose < kGameState_9_HitDoorBlock) elevator_flags = 1; return BlockColl_Horiz_SolidShootGrappleBlock(ci); } else { door_def_ptr = v0; game_state = kGameState_9_HitDoorBlock; return 0; } } uint8 BlockColl_Vert_Door(CollInfo *ci) { // 0x9493CE door_transition_function = FUNC16(DoorTransitionFunction_HandleElevator); door_bts = BTS[cur_block_index]; uint16 v0 = *(uint16 *)RomPtr_8F(door_list_pointer + 2 * (door_bts & 0x7F)); if ((get_DoorDef(v0)->room_definition_ptr & 0x8000) == 0) { if (samus_pose < kPose_09_MoveR_NoAim) elevator_flags = 1; return BlockColl_Vert_SolidShootGrappleBlock(ci); } else { door_def_ptr = v0; game_state = kPose_09_MoveR_NoAim; return 0; } } static uint8 BlockReact_HorizExt(CollInfo *ci) { // 0x949411 if (BTS[cur_block_index]) { cur_block_index += (int8)BTS[cur_block_index]; return 0xff; // special } return 0; } static uint8 BlockReact_VertExt(CollInfo *ci) { // 0x949447 if (BTS[cur_block_index]) { cur_block_index += (int8)BTS[cur_block_index] * room_width_in_blocks; return 0xff; // special } return 0; } static uint16 Samus_GetYposSpan(void) { // 0x949495 uint16 r26 = (samus_y_pos - samus_y_radius) & 0xFFF0; r26 = (uint16)(samus_y_radius + samus_y_pos - 1 - r26) >> 4; return r26; } static uint16 Samus_GetXposSpan(void) { // 0x9494B5 uint16 r26 = (samus_x_pos - samus_x_radius) & 0xFFF0; r26 = (uint16)(samus_x_radius + samus_x_pos - 1 - r26) >> 4; return r26; } static Func_CollInfo_U8 *const kBlockColl_Horiz_CheckColl[16] = { // 0x949515 ClearCarry_4, BlockColl_Horiz_Slope, ClearCarry_5, BlockColl_Horiz_SpecialAir, ClearCarry_4, BlockReact_HorizExt, ClearCarry_4, BlockColl_Horiz_BombableAir, BlockColl_Horiz_SolidShootGrappleBlock, BlockColl_Horiz_Door, BlockColl_Horiz_SpikeBlock, BlockColl_Horiz_SpecialBlock, BlockColl_Horiz_SolidShootGrappleBlock, BlockReact_VertExt, BlockColl_Horiz_SolidShootGrappleBlock, BlockColl_Horiz_BombBlock, }; static Func_CollInfo_U8 *const kBlockColl_Vert_CheckColl[16] = { ClearCarry_4, BlockColl_Vert_Slope, BlockColl_Vert_SpikeAir, BlockColl_Vert_SpecialAir, ClearCarry_4, BlockReact_HorizExt, ClearCarry_4, BlockColl_Vert_BombableAir, BlockColl_Vert_SolidShootGrappleBlock, BlockColl_Vert_Door, BlockColl_Vert_SpikeBlock, BlockColl_Vert_SpecialBlock, BlockColl_Vert_SolidShootGrappleBlock, BlockReact_VertExt, BlockColl_Vert_SolidShootGrappleBlock, BlockColl_Vert_BombBlock, }; static uint8 BlockColl_Horiz_CheckColl(CollInfo *ci, uint16 k) { uint8 rv; cur_block_index = k >> 1; cur_coll_amt32 = &ci->ci_r18_r20; // kludge needed for SpawnPLM do { rv = kBlockColl_Horiz_CheckColl[(level_data[cur_block_index] & 0xF000) >> 12](ci); } while (rv & 0x80); cur_coll_amt32 = NULL; return rv; } static uint8 BlockColl_Vert_CheckColl(CollInfo *ci, uint16 k) { // 0x94952C uint8 rv; cur_block_index = k >> 1; cur_coll_amt32 = &ci->ci_r18_r20; do { rv = kBlockColl_Vert_CheckColl[(level_data[cur_block_index] & 0xF000) >> 12](ci); } while (rv & 0x80); cur_coll_amt32 = NULL; return rv; } static Pair_Bool_Amt BlockColl_Handle_Horiz(int32 amt) { // 0x949543 uint16 r28 = Samus_GetYposSpan(); uint16 prod = Mult8x8((uint16)(samus_y_pos - samus_y_radius) >> 4, room_width_in_blocks); uint16 v1; //r22 = r20 + samus_x_subpos; uint16 v0 = (amt + __PAIR32__(samus_x_pos, samus_x_subpos)) >> 16; uint16 r24 = v0; if (amt >= 0) v1 = samus_x_radius + v0 - 1; else v1 = v0 - samus_x_radius; uint16 v2 = 2 * (prod + (v1 >> 4)); CollInfo ci = { .ci_r18_r20 = amt, .ci_r24 = r24, .ci_r26 = r28, .ci_r28 = r28, .ci_r32 = v1 }; while (!(BlockColl_Horiz_CheckColl(&ci, v2) & 1)) { v2 += room_width_in_blocks * 2; if ((--ci.ci_r26 & 0x8000) != 0) return (Pair_Bool_Amt) {false, ci.ci_r18_r20}; } return (Pair_Bool_Amt) { true, ci.ci_r18_r20 }; } static Pair_Bool_Amt BlockColl_Handle_Vert_LeftToRight(int32 amt) { // 0x94959E uint16 r28 = Samus_GetXposSpan(); //r22 = r20 + samus_y_subpos; uint16 v0 = (amt + __PAIR32__(samus_y_pos, samus_y_subpos)) >> 16, v1; uint16 r24 = v0; if (amt >= 0) v1 = samus_y_radius + v0 - 1; else v1 = v0 - samus_y_radius; uint16 prod = Mult8x8(v1 >> 4, room_width_in_blocks); uint16 v2 = (uint16)(samus_x_pos - samus_x_radius) >> 4; cur_block_index = prod + v2; CollInfo ci = { .ci_r18_r20 = amt, .ci_r24 = r24, .ci_r26 = r28, .ci_r28 = r28, .ci_r32 = v1 }; for (int i = 2 * cur_block_index; !(BlockColl_Vert_CheckColl(&ci, i) & 1); i += 2) { if ((--ci.ci_r26 & 0x8000) != 0) return (Pair_Bool_Amt) { false, ci.ci_r18_r20 }; } return (Pair_Bool_Amt) { true, ci.ci_r18_r20 }; } static Pair_Bool_Amt BlockColl_Handle_Vert_RightToLeft(int32 amt) { // 0x9495F5 uint16 r28 = Samus_GetXposSpan(); uint16 r26 = 0; //r22 = r20 + samus_y_subpos; uint16 v0 = (amt + __PAIR32__(samus_y_pos, samus_y_subpos)) >> 16, v1; uint16 r24 = v0; if (amt >= 0) v1 = samus_y_radius + v0 - 1; else v1 = v0 - samus_y_radius; uint16 prod = Mult8x8(v1 >> 4, room_width_in_blocks); uint16 v2 = (uint16)(samus_x_radius + samus_x_pos - 1) >> 4; cur_block_index = prod + v2; CollInfo ci = { .ci_r18_r20 = amt, .ci_r24 = r24, .ci_r26 = r26, .ci_r28 = r28, .ci_r32 = v1 }; for (int i = 2 * cur_block_index; !(BlockColl_Vert_CheckColl(&ci, i) & 1); i -= 2) { if (ci.ci_r28 < ++ci.ci_r26) return (Pair_Bool_Amt) { false, ci.ci_r18_r20 }; } return (Pair_Bool_Amt) { true, ci.ci_r18_r20 }; } // Returns the new value of amt and not the carry flag, // it can be inferred from samus_collision_flag int32 WallJumpBlockCollDetect(int32 amt) { // 0x94967F samus_collision_direction |= 0xF; flag_samus_in_quicksand = 0; Pair_Bool_Amt pair = BlockColl_Handle_Horiz(amt); samus_collision_flag = pair.flag; return pair.amt >= 0 ? pair.amt : -pair.amt; } // Returns the new value of amt and not the carry flag, // it can be inferred from samus_collision_flag static int32 CollDetectDueToPoseChange_SingleBlock(int32 amt) { // 0x9496E3 samus_collision_direction |= 0xF; flag_samus_in_quicksand = 0; Pair_Bool_Amt pair = !(nmi_frame_counter_word & 1) ? BlockColl_Handle_Vert_LeftToRight(amt) : BlockColl_Handle_Vert_RightToLeft(amt); samus_collision_flag = pair.flag; return pair.amt >= 0 ? pair.amt : -pair.amt; } // Returns the new value of amt and not the carry flag, // it can be inferred from samus_collision_flag int32 Samus_CollDetectChangedPose(int32 amt) { // 0x9496AB if ((abs16(amt >> 16) & 0xFFF8) == 0) return CollDetectDueToPoseChange_SingleBlock(amt); int32 amt_backup = amt; amt = CollDetectDueToPoseChange_SingleBlock(INT16_SHL16((amt >> 16) & 0xFFF0 | 8)); if (samus_collision_flag) return amt; return CollDetectDueToPoseChange_SingleBlock(amt_backup); } int32 Samus_MoveRight_NoSolidColl(int32 amt) { // 0x94971E Pair_Bool_Amt pair; samus_collision_flag = (amt != 0 && (flag_samus_in_quicksand = 0, pair = BlockColl_Handle_Horiz(amt), amt = pair.amt, pair.flag)); AddToHiLo(&samus_x_pos, &samus_x_subpos, amt); return amt; } int32 Samus_MoveDown_NoSolidColl(int32 amt) { // 0x949763 if (amt) { samus_pos_adjusted_by_slope_flag = 0; flag_samus_in_quicksand = 0; Pair_Bool_Amt pair = (nmi_frame_counter_word & 1) == 0 ? BlockColl_Handle_Vert_LeftToRight(amt) : BlockColl_Handle_Vert_RightToLeft(amt); amt = pair.amt; if (pair.flag) { samus_collision_flag = 1; AddToHiLo(&samus_y_pos, &samus_y_subpos, amt); return amt; } } samus_collision_flag = (flag_samus_in_quicksand != 0); AddToHiLo(&samus_y_pos, &samus_y_subpos, amt); return amt; } static uint8 BlockInsideReact_Slope(CollInfo *ci) { // 0x9497BF return 0; } static uint8 BlockInsideReact_ShootableAir(CollInfo *ci) { // 0x9497D0 samus_x_speed_table_pointer = addr_kSamusSpeedTable_Normal_X__plus__12; return 0; } static void ClearCarry_8(void) { // 0x9497D8 } static void nullsub_165(void) { // 0x9497D7 } static void BlockInsideReact_SpikeAir_BTS2(void) { // 0x949866 if (!samus_contact_damage_index && !samus_invincibility_timer) { samus_invincibility_timer = 60; samus_knockback_timer = 10; samus_periodic_damage += 16; knockback_x_dir = ((*(uint16 *)&samus_pose_x_dir ^ 0xC) & 8) != 0; } samus_x_speed_table_pointer = addr_kSamusSpeedTable_Normal_X__plus__12; } static Func_V *const kBlockInsideReact_SpikeAir[16] = { // 0x9498CC ClearCarry_8, ClearCarry_8, BlockInsideReact_SpikeAir_BTS2, nullsub_165, nullsub_165, nullsub_165, nullsub_165, nullsub_165, nullsub_165, nullsub_165, nullsub_165, nullsub_165, nullsub_165, nullsub_165, nullsub_165, nullsub_165, }; static uint8 BlockInsideReact_SpikeAir(CollInfo *ci) { kBlockInsideReact_SpikeAir[BTS[cur_block_index]](); return 0; } static uint8 BlockInsideReact_Special_(CollInfo *ci) { // 0x9498DC samus_x_speed_table_pointer = addr_kSamusSpeedTable_Normal_X__plus__12; return 0; } static void BlockInsideReact_SpecialAir_Default(void) { // 0x9498E3 samus_x_speed_table_pointer = addr_kSamusSpeedTable_Normal_X__plus__12; } static void BlockInsideReact_SpecialAir_8(void) { // 0x9498EA if ((area_index != 3 || CheckBossBitForCurArea(1) & 1) && !samus_y_speed) { extra_samus_x_subdisplacement = 0; extra_samus_x_displacement = 2; } samus_x_speed_table_pointer = addr_kSamusSpeedTable_Normal_X__plus__12; } static void BlockInsideReact_SpecialAir_9(void) { // 0x949910 if ((area_index != 3 || CheckBossBitForCurArea(1) & 1) && !samus_y_speed) { extra_samus_x_subdisplacement = 0; extra_samus_x_displacement = -2; } samus_x_speed_table_pointer = addr_kSamusSpeedTable_Normal_X__plus__12; } static void BlockInsideReact_SpecialAir_10(void) { // 0x949936 extra_samus_x_subdisplacement = 0; extra_samus_x_displacement = 2; samus_x_speed_table_pointer = addr_kSamusSpeedTable_Normal_X__plus__12; } static void BlockInsideReact_SpecialAir_11(void) { // 0x949946 extra_samus_x_subdisplacement = 0; extra_samus_x_displacement = -2; samus_x_speed_table_pointer = addr_kSamusSpeedTable_Normal_X__plus__12; } static void BlockInsideReact_SpecialAir_70(void) { // 0x949956 if (inside_block_reaction_samus_point == 1) SpawnPLM(addr_kPlmHeader_B6FF); } static const uint16 g_off_949B06[8] = { // 0x949B16 0x9a06, 0x9a26, 0x9a46, 0x9a66, 0x9a86, 0x9aa6, 0x9ac6, 0x9ae6, }; static Func_V *const off_949966[80] = { BlockInsideReact_SpecialAir_Default, BlockInsideReact_SpecialAir_Default, BlockInsideReact_SpecialAir_Default, BlockInsideReact_SpecialAir_Default, BlockInsideReact_SpecialAir_Default, BlockInsideReact_SpecialAir_Default, BlockInsideReact_SpecialAir_Default, BlockInsideReact_SpecialAir_Default, BlockInsideReact_SpecialAir_8, BlockInsideReact_SpecialAir_9, BlockInsideReact_SpecialAir_10, BlockInsideReact_SpecialAir_11, BlockInsideReact_SpecialAir_Default, BlockInsideReact_SpecialAir_Default, BlockInsideReact_SpecialAir_Default, BlockInsideReact_SpecialAir_Default, BlockInsideReact_SpecialAir_Default, BlockInsideReact_SpecialAir_Default, BlockInsideReact_SpecialAir_Default, BlockInsideReact_SpecialAir_Default, BlockInsideReact_SpecialAir_Default, BlockInsideReact_SpecialAir_Default, BlockInsideReact_SpecialAir_Default, BlockInsideReact_SpecialAir_Default, BlockInsideReact_SpecialAir_Default, BlockInsideReact_SpecialAir_Default, BlockInsideReact_SpecialAir_Default, BlockInsideReact_SpecialAir_Default, BlockInsideReact_SpecialAir_Default, BlockInsideReact_SpecialAir_Default, BlockInsideReact_SpecialAir_Default, BlockInsideReact_SpecialAir_Default, BlockInsideReact_SpecialAir_Default, BlockInsideReact_SpecialAir_Default, BlockInsideReact_SpecialAir_Default, BlockInsideReact_SpecialAir_Default, BlockInsideReact_SpecialAir_Default, BlockInsideReact_SpecialAir_Default, BlockInsideReact_SpecialAir_Default, BlockInsideReact_SpecialAir_Default, BlockInsideReact_SpecialAir_Default, BlockInsideReact_SpecialAir_Default, BlockInsideReact_SpecialAir_Default, BlockInsideReact_SpecialAir_Default, BlockInsideReact_SpecialAir_Default, BlockInsideReact_SpecialAir_Default, BlockInsideReact_SpecialAir_Default, BlockInsideReact_SpecialAir_Default, BlockInsideReact_SpecialAir_Default, BlockInsideReact_SpecialAir_Default, BlockInsideReact_SpecialAir_Default, BlockInsideReact_SpecialAir_Default, BlockInsideReact_SpecialAir_Default, BlockInsideReact_SpecialAir_Default, BlockInsideReact_SpecialAir_Default, BlockInsideReact_SpecialAir_Default, BlockInsideReact_SpecialAir_Default, BlockInsideReact_SpecialAir_Default, BlockInsideReact_SpecialAir_Default, BlockInsideReact_SpecialAir_Default, BlockInsideReact_SpecialAir_Default, BlockInsideReact_SpecialAir_Default, BlockInsideReact_SpecialAir_Default, BlockInsideReact_SpecialAir_Default, BlockInsideReact_SpecialAir_Default, BlockInsideReact_SpecialAir_Default, BlockInsideReact_SpecialAir_Default, BlockInsideReact_SpecialAir_Default, BlockInsideReact_SpecialAir_Default, BlockInsideReact_SpecialAir_Default, BlockInsideReact_SpecialAir_70, BlockInsideReact_SpecialAir_Default, BlockInsideReact_SpecialAir_Default, BlockInsideReact_SpecialAir_Default, BlockInsideReact_SpecialAir_Default, BlockInsideReact_SpecialAir_Default, BlockInsideReact_SpecialAir_Default, BlockInsideReact_SpecialAir_Default, BlockInsideReact_SpecialAir_Default, BlockInsideReact_SpecialAir_Default, }; static uint8 BlockInsideReact_SpecialAir(CollInfo *ci) { uint8 v0 = BTS[cur_block_index]; if (v0 & 0x80) { const uint8 *v3 = RomPtr_94(g_off_949B06[area_index]); SpawnPLM(*(uint16 *)&v3[2 * (v0 & 0x7F)]); } else { off_949966[v0](); } return 0; } void BlockInsideDetection(void) { // 0x949B60 static Func_CollInfo_U8 *const kSamus_BlockInsideDetection[16] = { BlockInsideReact_ShootableAir, BlockInsideReact_Slope, BlockInsideReact_SpikeAir, BlockInsideReact_SpecialAir, BlockInsideReact_ShootableAir, BlockReact_HorizExt, BlockInsideReact_ShootableAir, BlockInsideReact_ShootableAir, BlockInsideReact_Special_, BlockInsideReact_Special_, BlockInsideReact_Special_, BlockInsideReact_Special_, BlockInsideReact_Special_, BlockReact_VertExt, BlockInsideReact_Special_, BlockInsideReact_Special_, }; *(uint16 *)&samus_x_decel_mult = 0; extra_samus_x_subdisplacement = 0; extra_samus_x_displacement = 0; extra_samus_y_subdisplacement = 0; extra_samus_y_displacement = 0; inside_block_reaction_samus_point = 0; uint16 r26 = samus_x_pos; uint16 samus_bottom_boundary_position = samus_y_radius + samus_y_pos - 1; uint16 r28 = samus_y_radius + samus_y_pos - 1; CalculateBlockAt(r26, r28, 0, 0); CollInfo ci = { .ci_r24 = 0, .ci_r26 = r26, .ci_r28 = r28 }; uint8 rv; do { rv = kSamus_BlockInsideDetection[(HIBYTE(level_data[cur_block_index]) & 0xF0) >> 4](&ci); } while (rv & 0x80); inside_block_reaction_samus_point = 1; if (((samus_bottom_boundary_position ^ samus_y_pos) & 0xFFF0) != 0) { r26 = samus_x_pos; r28 = samus_y_pos; CalculateBlockAt(r26, r28, 0, 0); CollInfo ci = { .ci_r24 = 0, .ci_r26 = r26, .ci_r28 = r28 }; do { rv = kSamus_BlockInsideDetection[(HIBYTE(level_data[cur_block_index]) & 0xF0) >> 4](&ci); } while (rv & 0x80); } inside_block_reaction_samus_point = 2; if (((samus_bottom_boundary_position ^ (uint16)(samus_y_pos - samus_y_radius)) & 0xFFF0) != 0 && ((samus_y_pos ^ (samus_bottom_boundary_position ^ (uint16)(samus_y_pos - samus_y_radius)) & 0xFFF0) & 0xFFF0) != 0) { r26 = samus_x_pos; r28 = samus_y_pos - samus_y_radius; CalculateBlockAt(r26, r28, 0, 0); CollInfo ci = { .ci_r24 = 0, .ci_r26 = r26, .ci_r28 = r28 }; do { rv = kSamus_BlockInsideDetection[(HIBYTE(level_data[cur_block_index]) & 0xF0) >> 4](&ci); } while (rv & 0x80); } } void CalculateBlockAt(uint16 r26, uint16 r28, uint16 r30, uint16 r32) { // 0x949C1D int16 v0; int16 v1; uint16 temp_collision_DD4; v0 = r30 + r26; if ((int16)(r30 + r26) >= 0 && sign16(v0 - 4096) && (temp_collision_DD4 = (uint16)(v0 & 0xFFF0) >> 4, v1 = r32 + r28, (int16)(r32 + r28) >= 0) && sign16(v1 - 4096)) { uint16 RegWord = (uint16)(v1 & 0xFFF0) >> 4; RegWord = Mult8x8(RegWord, room_width_in_blocks); cur_block_index = temp_collision_DD4 + RegWord; } else { cur_block_index = -1; } } static const uint8 kBlockFunc_9C73_Tab0[36] = { // 0x949C73 3, 20, 0, 10, 40, 1, 5, 30, 0, 10, 40, 1, 20, 80, 0, 20, 80, 1, 20, 80, 0, 20, 80, 1, 30, 100, 0, 30, 100, 1, 30, 100, 0, 30, 100, 1, }; static const int8 kBlockFunc_9C73_Tab1[18] = { 0, 0, 10, 0, 50, 0, 50, 3, 0, -1, 10, 2, 0, -1, 0, -1, 0, -1, }; uint16 BlockFunc_9C73(uint16 v0) { int v1 = v0 >> 1; if ((projectile_type[v1] & 0xF00) != 0) { return kBlockFunc_9C73_Tab1[2 * (HIBYTE(projectile_type[v1]) & 0xF) + 1]; } else { int r18 = projectile_type[v1] & 0xF; return kBlockFunc_9C73_Tab0[3 * r18 + 2]; } } void BombOrPowerBomb_Func1(uint16 v0) { // 0x949CAC int16 v2; int16 v3; uint16 temp_collision_DD2 = BlockFunc_9C73(v0); int v1 = v0 >> 1; v2 = projectile_x_pos[v1]; if (v2 >= 0) { uint16 r26 = projectile_x_pos[v1]; if ((int16)(HIBYTE(v2) - room_width_in_scrolls) < 0) { v3 = projectile_y_pos[v1]; if (v3 >= 0) { uint16 R28 = projectile_y_pos[v1]; if ((int16)(HIBYTE(v3) - room_height_in_scrolls) < 0) { cur_block_index = 0; CalculateBlockAt(r26, R28, 0, 0); CollInfo ci = { .ci_r24 = 0, .ci_r26 = r26, .ci_r28 = R28 }; if (temp_collision_DD2 == 2) BlockColl_BombExplosion(&ci, v0); else BlockFunc_A06A(v0); } } } } } static uint16 BlockColl_GetBlockIndexAbove(uint16 k) { // 0x949D34 return k - room_width_in_blocks - room_width_in_blocks; } static uint16 BlockColl_GetBlockIndexRight(uint16 k) { // 0x949D3E return room_width_in_blocks * 2 + k + 1 + 1; } static uint16 BlockColl_GetBlockIndexLeft(uint16 k) { // 0x949D49 return k - 4; } static uint16 BlockColl_GetBlockIndexBelow(uint16 k) { // 0x949D4E return room_width_in_blocks * 2 + k + 1 + 1; } static void BlockColl_BombExplosion(CollInfo *ci, uint16 k) { // 0x949CF4 int16 v2; int v1 = k >> 1; if (!projectile_variables[v1]) { v2 = projectile_type[v1]; if ((v2 & 1) == 0) { projectile_type[v1] = v2 | 1; if (cur_block_index != 0xFFFF) { uint16 v3 = 2 * cur_block_index; BlockBombedReact(ci, 2 * cur_block_index); uint16 idx = BlockColl_GetBlockIndexAbove(v3); BlockBombedReact(ci, idx); uint16 idx2 = BlockColl_GetBlockIndexRight(idx); BlockBombedReact(ci, idx2); idx = BlockColl_GetBlockIndexLeft(idx2); BlockBombedReact(ci, idx); idx = BlockColl_GetBlockIndexBelow(idx); BlockBombedReact(ci, idx); } } } } static uint8 ClearCarry_9(CollInfo *ci) { // 0x949D59 return 0; } static uint8 SetCarry_0(CollInfo *ci) { // 0x949D5B return 1; } static uint8 sub_949D5D(CollInfo *ci) { // 0x949D5D if ((BTS[cur_block_index] & 0x1F) < 5) return 1; else return BlockShotReactVert_Slope_NonSquare(ci); } static uint8 BlockBombedReact_Special(CollInfo *ci) { // 0x949D71 uint8 v0 = BTS[cur_block_index]; if ((v0 & 0x80) != 0) { uint16 *kBlockBombedReact_Region_Plm = (uint16 *)RomPtr_94(0x9e44); const uint16 *v2 = (uint16*)RomPtr_94(kBlockBombedReact_Region_Plm[area_index]); SpawnPLM(v2[v0 & 0x7F]); } else { uint16 *kBlockBombedReact_Special_Plm = (uint16 *)RomPtr_94(0x9dA4); SpawnPLM(kBlockBombedReact_Special_Plm[v0]); } return 1; } static uint8 BlockReact_ShootableAir(CollInfo *ci) { // 0x949E55 uint8 v0 = BTS[cur_block_index]; if ((v0 & 0x80) == 0) { uint16 t = kBlockShotBombedReactionShootablePlm[v0]; if (t == 0xb974) ci->ci_r38 = 0, ci->ci_r40 = 0xffff; SpawnPLM(t); } return 0; } static uint8 BlockReact_Shootable(CollInfo *ci) { // 0x949E73 uint8 v0 = BTS[cur_block_index]; if ((v0 & 0x80) != 0) { uint16 *kBlockShotBombGrappleReaction_ShootableBlock_RegionPlm = (uint16 *)RomPtr_94(0x9FC6); uint16 *v2 = (uint16*)RomPtr_94(kBlockShotBombGrappleReaction_ShootableBlock_RegionPlm[area_index]); SpawnPLM(v2[v0 & 0x7f]); } else { uint16 t = kBlockShotBombedReactionShootablePlm[v0]; if (t == 0xb974) ci->ci_r38 = 0, ci->ci_r40 = 0xffff; SpawnPLM(t); } return 1; } static uint8 BlockReact_BombableAir(CollInfo *ci) { // 0x949FD6 uint16 *kBlockShotBombGrappleReact_BombableBlockPlm = (uint16 *)RomPtr_94(0xA012); uint8 v0 = BTS[cur_block_index]; if ((v0 & 0x80) == 0) SpawnPLM(kBlockShotBombGrappleReact_BombableBlockPlm[v0]); return 0; } static uint8 BlockReact_BombableBlock(CollInfo *ci) { // 0x949FF4 uint16 *kBlockShotBombGrappleReact_BombableBlockPlm = (uint16 *)RomPtr_94(0xA012); uint8 v0 = BTS[cur_block_index]; if ((v0 & 0x80) == 0) SpawnPLM(kBlockShotBombGrappleReact_BombableBlockPlm[v0]); return 1; } static Func_CollInfo_U8 *const kBlockBombedReact[16] = { // 0x94A052 ClearCarry_9, ClearCarry_9, ClearCarry_9, ClearCarry_9, BlockReact_ShootableAir, BlockReact_HorizExt, ClearCarry_9, BlockReact_BombableAir, SetCarry_0, SetCarry_0, SetCarry_0, BlockBombedReact_Special, BlockReact_Shootable, BlockReact_VertExt, SetCarry_0, BlockReact_BombableBlock, }; static void BlockBombedReact(CollInfo *ci, uint16 v0) { cur_block_index = v0 >> 1; while (kBlockBombedReact[(level_data[cur_block_index] & 0xF000) >> 12](ci) & 0x80) {} } void BlockFunc_A06A(uint16 k) { // 0x94A06A int16 v2; int16 v3; int v1 = k >> 1; v2 = projectile_variables[v1]; if (v2) { if (v2 < 0) projectile_variables[v1] = 0; } else { uint16 r18 = HIBYTE(power_bomb_explosion_radius); uint16 r20 = (uint16)(3 * HIBYTE(power_bomb_explosion_radius)) >> 2; v3 = power_bomb_explosion_x_pos - HIBYTE(power_bomb_explosion_radius); if (v3 < 0) v3 = 0; uint16 r22 = (uint16)v3 >> 4; uint16 v4 = (uint16)(r18 + power_bomb_explosion_x_pos) >> 4; if (v4 >= room_width_in_blocks) v4 = room_width_in_blocks - 1; uint16 r24 = v4; uint16 v5 = power_bomb_explosion_y_pos - r20; if ((int16)v5 < 0) v5 = 0; uint16 r26 = v5 >> 4; uint16 v6 = (uint16)(r20 + power_bomb_explosion_y_pos) >> 4; if (v6 >= room_height_in_blocks) v6 = room_height_in_blocks - 1; uint16 R28 = v6; uint16 a = r26 | (r22 << 8); BlockFunc_A0F4(a, r22, r24, r26, R28); BlockFunc_A11A(a, r24, r26, R28); BlockFunc_A0F4(R28 | (r22 << 8), r22, r24, r26, R28); BlockFunc_A11A(r26 | (r24 << 8), r24, r26, R28); } } static void BlockFunc_A0F4(uint16 a, uint16 r22, uint16 r24, uint16 r26, uint16 r28) { // 0x94A0F4 uint16 RegWord = Mult8x8(a, room_width_in_blocks); uint16 v3 = 2 * (RegWord + HIBYTE(a)); int16 v4 = r24 - r22; CollInfo ci = { .ci_r24 = r24, .ci_r26 = r26, .ci_r28 = r28 }; do { BlockBombedReact(&ci, v3); v3 += 2; } while (--v4 >= 0); } static void BlockFunc_A11A(uint16 a, uint16 r24, uint16 r26, uint16 r28) { // 0x94A11A uint16 RegWord = Mult8x8(a, room_width_in_blocks); uint16 v3 = 2 * (RegWord + HIBYTE(a)); int16 v4 = r28 - r26; CollInfo ci = { .ci_r24 = r24, .ci_r26 = r26, .ci_r28 = r28 }; do { BlockBombedReact(&ci, v3); v3 += room_width_in_blocks * 2; } while (--v4 >= 0); } static uint8 BlockShotReactHoriz_Slope(CollInfo *ci) { // 0x94A147 if ((BTS[cur_block_index] & 0x1F) < 5) return BlockShotReactVert_Slope_Square(ci, BTS[cur_block_index] & 0x1F, cur_block_index); else return BlockShotReactVert_Slope_NonSquare(ci); } static uint8 SetCarry_1(void) { // 0x94A15C return 1; } static uint8 BlockShotReactVert_Slope(CollInfo *ci) { // 0x94A15E if ((BTS[cur_block_index] & 0x1F) < 5) return BlockShotReactHoriz_Slope_Square(ci, BTS[cur_block_index] & 0x1F, cur_block_index); else return BlockShotReactHoriz_Slope_NonSquare(ci); } static uint8 SetCarry_2(void) { // 0x94A173 return 1; } static uint8 BlockShotReactHoriz(CollInfo *ci, uint16 k) { // 0x94A1B5 static Func_CollInfo_U8 *const kBlockShotReactHoriz[16] = { ClearCarry_9, BlockShotReactHoriz_Slope, ClearCarry_9, ClearCarry_9, BlockReact_ShootableAir, BlockReact_HorizExt, ClearCarry_9, BlockReact_BombableAir, SetCarry_0, SetCarry_0, SetCarry_0, SetCarry_0, BlockReact_Shootable, BlockReact_VertExt, SetCarry_0, BlockReact_BombableBlock, }; uint8 v1; if (k >= room_size_in_blocks) return 1; cur_block_index = k >> 1; do { v1 = kBlockShotReactHoriz[(level_data[cur_block_index] & 0xF000) >> 12](ci); } while (v1 & 0x80); if (v1) ci->ci_r40--; return v1; } static uint8 BlockShotReactVert(CollInfo *ci, uint16 k) { // 0x94A1D6 static Func_CollInfo_U8 *const kBlockShotReactVert[16] = { ClearCarry_9, BlockShotReactVert_Slope, ClearCarry_9, ClearCarry_9, BlockReact_ShootableAir, BlockReact_HorizExt, ClearCarry_9, BlockReact_BombableAir, SetCarry_0, SetCarry_0, SetCarry_0, SetCarry_0, BlockReact_Shootable, BlockReact_VertExt, SetCarry_0, BlockReact_BombableBlock, }; uint8 v1; if (k >= room_size_in_blocks) return 1; cur_block_index = k >> 1; do { v1 = kBlockShotReactVert[(level_data[cur_block_index] & 0xF000) >> 12](ci); } while (v1 & 0x80); if (v1) --ci->ci_r40; return v1; } static uint16 BlockGetSomePos1(uint16 k) { // 0x94A1F7 int v1 = k >> 1; uint16 r38 = (projectile_y_pos[v1] - projectile_y_radius[v1]) & 0xFFF0; return (uint16)(projectile_y_radius[v1] + projectile_y_pos[v1] - 1 - r38) >> 4; } static uint16 BlockGetSomePos2(uint16 k) { // 0x94A219 int v1 = k >> 1; uint16 r38 = (projectile_x_pos[v1] - projectile_x_radius[v1]) & 0xFFF0; return (uint16)(projectile_x_radius[v1] + projectile_x_pos[v1] - 1 - r38) >> 4; } uint8 BlockCollNoWaveBeamHoriz(uint16 k) { // 0x94A23B uint16 v7; int v1 = k >> 1; int32 amt = INT16_SHL8(projectile_bomb_x_speed[v1]); uint16 some_pos = BlockGetSomePos1(k); uint16 prod = Mult8x8((uint16)(projectile_y_pos[v1] - projectile_y_radius[v1]) >> 4, room_width_in_blocks); AddToHiLo(&projectile_x_pos[v1], &projectile_bomb_x_subpos[v1], amt); //r22 = projectile_bomb_x_subpos[v1]; uint16 r24 = projectile_x_pos[v1]; if (amt < 0) v7 = projectile_x_pos[v1] - projectile_x_radius[v1]; else v7 = projectile_x_radius[v1] + projectile_x_pos[v1] - 1; uint16 R28 = v7; uint16 v8 = 2 * (prod + (v7 >> 4)); if (!sign16(some_pos - 16) || (int16)(HIBYTE(R28) - room_width_in_scrolls) >= 0) return 0; CollInfo ci = { .ci_r18_r20 = amt, .ci_r24 = r24, .ci_r26 = some_pos, .ci_r28 = R28, .ci_r30 = 0, .ci_r38 = some_pos, .ci_r40 = some_pos }; do { BlockShotReactHoriz(&ci, v8); v8 += room_width_in_blocks * 2; } while ((--ci.ci_r38 & 0x8000) == 0); if ((ci.ci_r40 & 0x8000) == 0) return 0; KillProjectile(k); return 1; } uint8 BlockCollNoWaveBeamVert(uint16 k) { // 0x94A2CA uint16 v7; int v1 = k >> 1; int32 amt = INT16_SHL8(projectile_bomb_y_speed[v1]); uint16 some_pos = BlockGetSomePos2(k); AddToHiLo(&projectile_y_pos[v1], &projectile_bomb_y_subpos[v1], amt); //r22 = projectile_bomb_y_subpos[v1]; uint16 r24 = projectile_y_pos[v1]; if (amt < 0) v7 = projectile_y_pos[v1] - projectile_y_radius[v1]; else v7 = projectile_y_radius[v1] + projectile_y_pos[v1] - 1; uint16 R28 = v7; uint16 v8 = (uint16)(projectile_x_pos[v1] - projectile_x_radius[v1]) >> 4; uint16 v9 = 2 * (Mult8x8(v7 >> 4, room_width_in_blocks) + v8); if (!sign16(some_pos - 16) || (int16)(HIBYTE(R28) - room_height_in_scrolls) >= 0) return 0; CollInfo ci = { .ci_r18_r20 = amt, .ci_r24 = r24, .ci_r26 = some_pos, .ci_r28 = R28, .ci_r30 = 0, .ci_r38 = some_pos, .ci_r40 = some_pos }; do { BlockShotReactVert(&ci, v9); v9 += 2; } while ((--ci.ci_r38 & 0x8000) == 0); if ((ci.ci_r40 & 0x8000) == 0) return 0; KillProjectile(k); return 1; } uint8 BlockCollWaveBeamHoriz(uint16 k) { // 0x94A352 uint16 v7; int v1 = k >> 1; int32 amt = INT16_SHL8(projectile_bomb_x_speed[v1]); uint16 some_pos = BlockGetSomePos1(k); uint16 prod = Mult8x8((uint16)(projectile_y_pos[v1] - projectile_y_radius[v1]) >> 4, room_width_in_blocks); AddToHiLo(&projectile_x_pos[v1], &projectile_bomb_x_subpos[v1], amt); //r22 = projectile_bomb_x_subpos[v1]; uint16 r24 = projectile_x_pos[v1]; if (amt < 0) v7 = projectile_x_pos[v1] - projectile_x_radius[v1]; else v7 = projectile_x_radius[v1] + projectile_x_pos[v1] - 1; uint16 R28 = v7; uint16 v8 = 2 * (prod + (v7 >> 4)); if (!sign16(some_pos - 16)) return 0; CollInfo ci = { .ci_r18_r20 = amt, .ci_r24 = r24, .ci_r26 = some_pos, .ci_r28 = R28, .ci_r30 = 0, .ci_r38 = some_pos, .ci_r40 = some_pos }; uint8 v9 = HIBYTE(projectile_y_pos[v1]); if (!sign8(v9) && (int16)(v9 - room_height_in_scrolls) < 0 && (int16)(HIBYTE(R28) - room_width_in_scrolls) < 0) { do { BlockShotReactHoriz(&ci, v8); v8 += room_width_in_blocks * 2; } while ((--ci.ci_r38 & 0x8000) == 0); } return 0; } uint8 BlockCollWaveBeamVert(uint16 k) { // 0x94A3E4 uint16 v7; int v1 = k >> 1; int32 amt = INT16_SHL8(projectile_bomb_y_speed[v1]); uint16 some_pos = BlockGetSomePos2(k); AddToHiLo(&projectile_y_pos[v1], &projectile_bomb_y_subpos[v1], amt); //r22 = projectile_bomb_y_subpos[v1]; uint16 r24 = projectile_y_pos[v1]; if (amt < 0) v7 = projectile_y_pos[v1] - projectile_y_radius[v1]; else v7 = projectile_y_radius[v1] + projectile_y_pos[v1] - 1; uint16 R28 = v7; uint16 prod = Mult8x8(v7 >> 4, room_width_in_blocks); uint16 v8 = (uint16)(projectile_x_pos[v1] - projectile_x_radius[v1]) >> 4; uint16 v9 = 2 * (prod + v8); if (!sign16(some_pos - 16)) return 0; uint8 v10 = HIBYTE(projectile_x_pos[v1]); CollInfo ci = { .ci_r18_r20 = amt, .ci_r24 = r24, .ci_r26 = some_pos, .ci_r28 = R28, .ci_r30 = 0, .ci_r38 = some_pos, .ci_r40 = some_pos }; if (!sign8(v10) && (int16)(v10 - room_width_in_scrolls) < 0 && (int16)(HIBYTE(R28) - room_height_in_scrolls) < 0) { do { BlockShotReactVert(&ci, v9); v9 += 2; } while ((--ci.ci_r38 & 0x8000) == 0); } return 0; } uint8 BlockCollMissileHoriz(uint16 k) { // 0x94A46F int v1 = k >> 1; int32 amt = INT16_SHL8(projectile_bomb_x_speed[v1]); uint16 prod = Mult8x8(projectile_y_pos[v1] >> 4, room_width_in_blocks); AddToHiLo(&projectile_x_pos[v1], &projectile_bomb_x_subpos[v1], amt); uint16 v3 = projectile_bomb_x_subpos[v1]; //r22 = projectile_bomb_x_subpos[v1]; uint16 r24 = projectile_x_pos[v1]; uint16 r28 = r24; uint16 v7 = 2 * (prod + (projectile_x_pos[v1] >> 4)); CollInfo ci = { .ci_r18_r20 = amt, .ci_r24 = r24, .ci_r26 = 0, .ci_r28 = r28, .ci_r30 = 1, .ci_r38 = 0 }; if ((int16)(HIBYTE(r24) - room_width_in_scrolls) >= 0 || !BlockShotReactHoriz(&ci, v7)) return 0; KillProjectile(k); return 1; } uint8 BlockCollMissileVert(uint16 k) { // 0x94A4D9 int v1 = k >> 1; int32 amt = INT16_SHL8(projectile_bomb_y_speed[v1]); AddToHiLo(&projectile_y_pos[v1], &projectile_bomb_y_subpos[v1], amt); //2r22 = projectile_bomb_y_subpos[v1]; uint16 r24 = projectile_y_pos[v1]; uint16 r28 = r24; uint16 prod = Mult8x8(projectile_y_pos[v1] >> 4, room_width_in_blocks); uint16 v7 = projectile_x_pos[v1] >> 4; uint16 v8 = 2 * (prod + v7); CollInfo ci = { .ci_r18_r20 = amt, .ci_r24 = r24, .ci_r26 = 0, .ci_r28 = r28, .ci_r30 = 1, .ci_r38 = 0 }; if ((int16)(HIBYTE(r24) - room_height_in_scrolls) >= 0 || !BlockShotReactVert(&ci, v8)) return 0; KillProjectile(k); return 1; } static uint8 BlockShotReact_Slope_NonSquare(CollInfo *ci, uint16 j, uint16 k) { // 0x94A58F uint16 v2 = (projectile_x_pos[j >> 1] & 0xf) ^ ((BTS[k] & 0x40) != 0 ? 0xf : 0); uint16 v4 = (projectile_y_pos[j >> 1] & 0xf) ^ ((BTS[k] & 0x80) != 0 ? 0xf : 0); uint16 v5 = kAlignYPos_Tab0[16 * (BTS[k] & 0x1F) + (v2 & 0xF)] & 0x1F; if ((int16)(v5 - v4) <= 0) { ci->ci_r38 = 0; ci->ci_r40 = 0; return 1; } else { return 0; } } static uint8 BlockShotReactVert_Slope_NonSquare(CollInfo *ci) { // 0x94A543 uint16 v0 = cur_block_index; uint16 v1 = projectile_index; uint16 div = SnesDivide(cur_block_index, room_width_in_blocks); if ((projectile_y_pos[v1 >> 1] >> 4) == div) return BlockShotReact_Slope_NonSquare(ci, v1, v0); else return 0; } static uint8 BlockShotReactHoriz_Slope_NonSquare(CollInfo *ci) { // 0x94A569 uint16 v0 = cur_block_index; uint16 v1 = projectile_index; uint16 mod = SnesModulus(cur_block_index, room_width_in_blocks); if ((projectile_x_pos[v1 >> 1] >> 4) == mod) return BlockShotReact_Slope_NonSquare(ci, v1, v0); else return 0; } uint8 BlockCollSpreadBomb(uint16 k) { // 0x94A621 static Func_CollInfo_U8 *const kBlockCollSpreadBomb[16] = { ClearCarry_9, sub_949D5D, ClearCarry_9, ClearCarry_9, SetCarry_0, BlockReact_HorizExt, ClearCarry_9, ClearCarry_9, SetCarry_0, SetCarry_0, SetCarry_0, SetCarry_0, SetCarry_0, BlockReact_VertExt, SetCarry_0, SetCarry_0, }; int v1 = k >> 1; uint16 r26 = projectile_x_pos[v1]; uint16 r28 = projectile_y_pos[v1]; cur_block_index = 0; CalculateBlockAt(r26, r28, 0, 0); CollInfo ci = { .ci_r24 = 0, .ci_r26 = r26, .ci_r28 = r28, .ci_r30 = 0, .ci_r32 = 0 }; if (!projectile_variables[v1]) { BlockColl_BombExplosion(&ci, k); return 0; } if (cur_block_index == 0xFFFF) return 1; uint8 rv; do { rv = kBlockCollSpreadBomb[(level_data[cur_block_index] & 0xF000) >> 12](&ci); } while (rv & 0x80); return rv; } static uint8 BlockShotReactVert_Slope_Square(CollInfo *ci, uint16 a, uint16 k) { // 0x94A66A uint16 temp_collision_DD4 = 4 * a; uint16 temp_collision_DD6 = BTS[k] >> 6; uint16 v2 = 4 * a + (temp_collision_DD6 ^ ((ci->ci_r28 & 8) >> 3)); int v3 = projectile_index >> 1; if (!ci->ci_r30) { if (!ci->ci_r26) { if (((projectile_y_pos[v3] - projectile_y_radius[v3]) & 8) != 0 || !kTab948E54[v2]) { uint16 v4 = v2 ^ 2; if (((LOBYTE(projectile_y_radius[v3]) + LOBYTE(projectile_y_pos[v3]) - 1) & 8) == 0 || !kTab948E54[v4]) { return 0; } } return 1; } if (ci->ci_r38) { if (ci->ci_r38 == ci->ci_r26 && ((projectile_y_pos[v3] - projectile_y_radius[v3]) & 8) != 0) { return kTab948E54[v2 ^ 2] != 0; } } else if (((LOBYTE(projectile_y_radius[v3]) + LOBYTE(projectile_y_pos[v3]) - 1) & 8) == 0) { return kTab948E54[v2] != 0; } if (kTab948E54[v2] != 0) return 1; return kTab948E54[v2 ^ 2] != 0; } if ((projectile_y_pos[v3] & 8) != 0) v2 ^= 2; return kTab948E54[v2] != 0; } static uint8 BlockShotReactHoriz_Slope_Square(CollInfo *ci, uint16 a, uint16 k) { // 0x94A71A uint16 temp_collision_DD4 = 4 * a; uint16 temp_collision_DD6 = BTS[k] >> 6; uint16 v2 = 4 * a + (temp_collision_DD6 ^ ((ci->ci_r28 & 8) >> 2)); if (!ci->ci_r30) { if (!ci->ci_r26) { int v3 = projectile_index >> 1; if (((projectile_x_pos[v3] - projectile_x_radius[v3]) & 8) != 0 || kTab948E54[v2] == 0) { uint16 v4 = v2 ^ 1; if (((LOBYTE(projectile_x_radius[v3]) + LOBYTE(projectile_x_pos[v3]) - 1) & 8) == 0 || kTab948E54[v4] == 0) { return 0; } } return 1; } if (ci->ci_r38) { if (ci->ci_r38 == ci->ci_r26 && ((projectile_x_pos[projectile_index >> 1] - projectile_x_radius[projectile_index >> 1]) & 8) != 0) { return kTab948E54[v2 ^ 1] != 0; } } else if (((LOBYTE(projectile_x_radius[projectile_index >> 1]) + LOBYTE(projectile_x_pos[projectile_index >> 1]) - 1) & 8) == 0) { return kTab948E54[v2] != 0; } if (kTab948E54[v2] != 0) return 1; return kTab948E54[v2 ^ 1] != 0; } if ((projectile_x_pos[projectile_index >> 1] & 8) != 0) v2 ^= 1; return kTab948E54[v2] != 0; } static uint8 ClearCarryZero(CollInfo *ci) { // 0x94A7C9 return 0; } static uint8 SetCarryClearOvf(CollInfo *ci) { // 0x94A7CD return 1; } static uint8 BlockReactGrapple_GrappleBlock(CollInfo *ci) { // 0x94A7D1 static const uint16 kBlockReactGrapple_GrappleBlockPlm[4] = { 0xd0d8, 0xd0dc, 0xd0e0, 0xd0d8, }; grapple_beam_flags &= ~0x8000; if (BTS[cur_block_index] & 0x80) return 0; else return SpawnPLM(kBlockReactGrapple_GrappleBlockPlm[BTS[cur_block_index]]); } static uint8 BlockReactGrapple_SpikeBlock(CollInfo *ci) { // 0x94A7FD static const uint16 kBlockReactGrapple_SpikeBlockPlm[16] = { 0xd0e4, 0xd0e4, 0xd0e4, 0xd0e8, 0xd0e4, 0xd0e4, 0xd0e4, 0xd0e4, 0xd0e4, 0xd0e4, 0xd0e4, 0xd0e4, 0xd0e4, 0xd0e4, 0xd0e4, 0xd0e4, }; if (BTS[cur_block_index] & 0x80) return 0; else return SpawnPLM(kBlockReactGrapple_SpikeBlockPlm[BTS[cur_block_index]]); } uint8 BlockCollGrappleBeam(void) { // 0x94A85B int32 grapple_vel_x = (int16)grapple_beam_extension_x_velocity << 6; int32 grapple_vel_y = (int16)grapple_beam_extension_y_velocity << 6; uint8 result = 0; for(int i = 0; i < 4; i++) { AddToHiLo(&grapple_beam_end_x_offset, &grapple_beam_end_x_suboffset, grapple_vel_x); AddToHiLo(&grapple_beam_end_y_offset, &grapple_beam_end_y_suboffset, grapple_vel_y); SetHiLo(&grapple_beam_end_x_pos, &grapple_beam_end_x_subpos, __PAIR32__(grapple_beam_end_x_offset, grapple_beam_end_x_suboffset) + __PAIR32__(samus_x_pos, samus_x_subpos) + (grapple_beam_origin_x_offset << 16)); SetHiLo(&grapple_beam_end_y_pos, &grapple_beam_end_y_subpos, __PAIR32__(grapple_beam_end_y_offset, grapple_beam_end_y_suboffset) + __PAIR32__(samus_y_pos, samus_y_subpos) + (grapple_beam_origin_y_offset << 16)); result = BlockReactGrapple(); if ((result & 0x40) != 0 && (result & 1) != 0) { grapple_beam_end_x_pos = grapple_beam_end_x_pos & 0xFFF0 | 8; grapple_beam_end_y_pos = grapple_beam_end_y_pos & 0xFFF0 | 8; return result; } } return result; } uint8 BlockReactGrapple(void) { // 0x94A91F int16 v0; static Func_CollInfo_U8 *const kBlockReactGrapple[16] = { ClearCarryZero, SetCarryClearOvf, ClearCarryZero, ClearCarryZero, BlockReact_ShootableAir, BlockReact_HorizExt, ClearCarryZero, BlockReact_BombableAir, SetCarryClearOvf, SetCarryClearOvf, BlockReactGrapple_SpikeBlock, SetCarryClearOvf, BlockReact_Shootable, BlockReact_VertExt, BlockReactGrapple_GrappleBlock, BlockReact_BombableBlock, }; uint16 prod = Mult8x8(grapple_beam_end_y_pos >> 4, room_width_in_blocks); v0 = grapple_beam_end_x_pos >> 4; cur_block_index = prod + v0; CollInfo ci = { 0 }; uint8 rv; do { rv = kBlockReactGrapple[(level_data[cur_block_index] & 0xF000) >> 12](&ci); } while (rv & 0x80); return rv; } const int16 kSinCosTable8bit_Sext[320] = { // 0x94A957 -256, -255, -255, -255, -254, -254, -253, -252, -251, -249, -248, -246, -244, -243, -241, -238, -236, -234, -231, -228, -225, -222, -219, -216, -212, -209, -205, -201, -197, -193, -189, -185, -181, -176, -171, -167, -162, -157, -152, -147, -142, -136, -131, -126, -120, -115, -109, -103, -97, -92, -86, -80, -74, -68, -62, -56, -49, -43, -37, -31, -25, -18, -12, -6, 0, 6, 12, 18, 25, 31, 37, 43, 49, 56, 62, 68, 74, 80, 86, 92, 97, 103, 109, 115, 120, 126, 131, 136, 142, 147, 152, 157, 162, 167, 171, 176, 181, 185, 189, 193, 197, 201, 205, 209, 212, 216, 219, 222, 225, 228, 231, 234, 236, 238, 241, 243, 244, 246, 248, 249, 251, 252, 253, 254, 254, 255, 255, 255, 256, 255, 255, 255, 254, 254, 253, 252, 251, 249, 248, 246, 244, 243, 241, 238, 236, 234, 231, 228, 225, 222, 219, 216, 212, 209, 205, 201, 197, 193, 189, 185, 181, 176, 171, 167, 162, 157, 152, 147, 142, 136, 131, 126, 120, 115, 109, 103, 97, 92, 86, 80, 74, 68, 62, 56, 49, 43, 37, 31, 25, 18, 12, 6, 0, -6, -12, -18, -25, -31, -37, -43, -49, -56, -62, -68, -74, -80, -86, -92, -97, -103, -109, -115, -120, -126, -131, -136, -142, -147, -152, -157, -162, -167, -171, -176, -181, -185, -189, -193, -197, -201, -205, -209, -212, -216, -219, -222, -225, -228, -231, -234, -236, -238, -241, -243, -244, -246, -248, -249, -251, -252, -253, -254, -254, -255, -255, -255, -256, -255, -255, -255, -254, -254, -253, -252, -251, -249, -248, -246, -244, -243, -241, -238, -236, -234, -231, -228, -225, -222, -219, -216, -212, -209, -205, -201, -197, -193, -189, -185, -181, -176, -171, -167, -162, -157, -152, -147, -142, -136, -131, -126, -120, -115, -109, -103, -97, -92, -86, -80, -74, -68, -62, -56, -49, -43, -37, -31, -25, -18, -12, -6, }; static void BlockFunc_A957(uint16 tmpD82, uint16 tmpD84) { int16 v5; int16 v7; uint16 v0 = tmpD82, v2, v3; if ((grapple_beam_flags & 0x8000) == 0) { int v1 = tmpD82 >> 1; if ((kSinCosTable8bit_Sext[v1 + 64] & 0x8000) != 0) v2 = grapple_beam_end_x_pos & 0xFFF0 | 7; else v2 = grapple_beam_end_x_pos & 0xFFF0 | 8; grapple_beam_end_x_pos = v2; if ((kSinCosTable8bit_Sext[v1] & 0x8000) != 0) v3 = grapple_beam_end_y_pos & 0xFFF0 | 7; else v3 = grapple_beam_end_y_pos & 0xFFF0 | 8; grapple_beam_end_y_pos = v3; } int v4 = v0 >> 1; v5 = kSinCosTable8bit_Sext[v4 + 64]; uint16 v6, v8; if (v5 < 0) { if (v5 == -256) { v6 = grapple_beam_end_x_pos - tmpD84; } else { uint16 prod = Mult8x8(tmpD84, -(int8)v5); v6 = grapple_beam_end_x_pos - (prod >> 8); } } else if (v5 == 256) { v6 = tmpD84 + grapple_beam_end_x_pos; } else { uint16 prod = Mult8x8(tmpD84, kSinCosTable8bit_Sext[v4 + 64]); v6 = grapple_beam_end_x_pos + (prod >> 8); } grapple_beam_grapple_start_x = v6; grapple_beam_grapple_start_block_x = (uint8)(v6 >> 4); v7 = kSinCosTable8bit_Sext[v4]; if (v7 < 0) { if (v7 == -256) { v8 = grapple_beam_end_y_pos - tmpD84; } else { uint16 prod = Mult8x8(tmpD84, -v7); v8 = grapple_beam_end_y_pos - (prod >> 8); } } else if (v7 == 256) { v8 = tmpD84 + grapple_beam_end_y_pos; } else { uint16 prod = Mult8x8(tmpD84, kSinCosTable8bit_Sext[v4]); v8 = grapple_beam_end_y_pos + (prod >> 8); } grapple_beam_grapple_start_y = v8; grapple_beam_grapple_start_block_y = (uint8)(v8 >> 4); } static uint8 ClearCarry_10(CollInfo *ci) { // 0x94AA9A return 0; } static uint8 SetCarry_3(CollInfo *ci) { // 0x94AA9C return 1; } static uint8 BlockReact_AA64(void) { // 0x94AA64 static Func_CollInfo_U8 *const kBlockReactLut_AB90[16] = { ClearCarry_10, SetCarry_3, BlockReact_AA64_SpikeAir, ClearCarry_10, ClearCarry_10, BlockReact_HorizExt, ClearCarry_10, ClearCarry_10, SetCarry_3, SetCarry_3, BlockReact_AA64_SpikeBlock, SetCarry_3, SetCarry_3, BlockReact_VertExt, SetCarry_3, SetCarry_3, }; uint16 v0 = grapple_beam_grapple_start_block_x; uint16 RegWord = Mult8x8(grapple_beam_grapple_start_block_y, room_width_in_blocks); cur_block_index = RegWord + v0; CollInfo ci = { 0 }; uint8 rv; do { rv = kBlockReactLut_AB90[(level_data[cur_block_index] & 0xF000) >> 12](&ci); } while (rv & 0x80); return rv; } static const uint16 g_word_94AAD7[16] = { // 0x94AA9E 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; static const uint16 g_word_94AAF7[16] = { 0, 0, 0x10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; static uint8 BlockReact_AA64_SpikeAir(CollInfo *ci) { int16 v0; int16 v2; if (!samus_invincibility_timer) { v0 = *(uint16 *)&BTS[cur_block_index]; if (v0 >= 0) { int v1 = v0; if (g_word_94AAF7[v1] | g_word_94AAD7[v1]) { v2 = (g_word_94AAD7[v1] + __PAIR32__(samus_periodic_damage, samus_periodic_subdamage)) >> 16; samus_periodic_subdamage += g_word_94AAD7[v1]; samus_periodic_damage = g_word_94AAF7[v1] + v2; samus_invincibility_timer = 60; samus_knockback_timer = 10; } } } return 0; } static const uint16 g_word_94AB50[16] = { // 0x94AB17 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; static const uint16 g_word_94AB70[16] = { 60, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; static uint8 BlockReact_AA64_SpikeBlock(CollInfo *ci) { int16 v0; int16 v2; if (!samus_invincibility_timer) { v0 = *(uint16 *)&BTS[cur_block_index]; if (v0 >= 0) { int v1 = v0; if (g_word_94AB70[v1] | g_word_94AB50[v1]) { v2 = (g_word_94AB50[v1] + __PAIR32__(samus_periodic_damage, samus_periodic_subdamage)) >> 16; samus_periodic_subdamage += g_word_94AB50[v1]; samus_periodic_damage = g_word_94AB70[v1] + v2; samus_invincibility_timer = 60; samus_knockback_timer = 10; } } } return 1; } static Func_CollInfo_U8 *const kBlockReactLut_AB90[16] = { // 0x94ABB0 ClearCarry_10, SetCarry_3, BlockReact_AA64_SpikeAir, ClearCarry_10, ClearCarry_10, BlockReact_HorizExt, ClearCarry_10, ClearCarry_10, SetCarry_3, SetCarry_3, BlockReact_AA64_SpikeBlock, SetCarry_3, SetCarry_3, BlockReact_VertExt, SetCarry_3, SetCarry_3, }; static uint8 BlockFunc_ABB0(void) { uint8 rv; uint16 v0 = grapple_beam_grapple_start_block_x; uint16 RegWord = Mult8x8(grapple_beam_grapple_start_block_y, room_width_in_blocks); cur_block_index = RegWord + v0; CollInfo ci = { 0 }; do { rv = kBlockReactLut_AB90[(level_data[cur_block_index] & 0xF000) >> 12](&ci); } while (rv & 0x80); return rv; } static uint8 BlockFunc_ABE6(uint16 tmpD82) { // 0x94ABE6 uint8 v0; g_word_7E0D98 = 6; uint16 grapple_beam_tmpD84 = grapple_beam_length + 8; while (1) { BlockFunc_A957(tmpD82, grapple_beam_tmpD84); v0 = BlockFunc_ABB0() & 1; if (v0) break; grapple_beam_tmpD84 += 8; if (!--g_word_7E0D98) return 0; } return v0; } void BlockFunc_AC11(void) { // 0x94AC11 uint16 grapple_beam_tmpD82 = 2 * grapple_beam_end_angle_hi; uint16 grapple_beam_tmpD84 = grapple_beam_length; BlockFunc_A957(grapple_beam_tmpD82, grapple_beam_tmpD84); x_pos_of_start_of_grapple_beam = grapple_beam_grapple_start_x; y_pos_of_start_of_grapple_beam = grapple_beam_grapple_start_y; } uint8 BlockFunc_AC31(void) { // 0x94AC31 if (!grapple_beam_length_delta) return 0; uint16 end = grapple_beam_length_delta + grapple_beam_length; if ((grapple_beam_length_delta & 0x8000) != 0) { if (end < 8) { grapple_beam_length_delta = 0; end = 8; } int increment = 8; uint16 grapple_beam_tmpD82 = 2 * grapple_beam_end_angle_hi; for (uint16 v1 = grapple_beam_length; v1 != end; v1--) { uint16 grapple_beam_tmpD84 = increment + v1 - 1; BlockFunc_A957(grapple_beam_tmpD82, grapple_beam_tmpD84); if (BlockReact_AA64()) { grapple_beam_length = v1; return 1; } } grapple_beam_length = end; return 0; } else { if (end >= 63) { grapple_beam_length_delta = 0; end = 63; } int increment = 56; uint16 grapple_beam_tmpD82 = 2 * grapple_beam_end_angle_hi; for (uint16 v1 = grapple_beam_length; v1 != end; v1++) { uint16 grapple_beam_tmpD84 = increment + v1 + 1; BlockFunc_A957(grapple_beam_tmpD82, grapple_beam_tmpD84); if (BlockReact_AA64()) { grapple_beam_length = v1; return 1; } } grapple_beam_length = end; return 0; } } uint8 HandleMovementAndCollForSamusGrapple(void) { // 0x94ACFE uint16 prod16; int16 v4; int16 v7; uint16 v3, v6; uint16 grapple_beam_tmpD86, grapple_beam_tmpD88; uint16 tmpD9C; uint16 v0 = 256; if ((grapple_beam_flags & 1) != 0) v0 = 160; uint16 v1 = grapple_beam_unkD2E + grapple_beam_unkD26; if ((int16)(grapple_beam_unkD2E + grapple_beam_unkD26) >= 0) { prod16 = Multiply16x16(v1, v0) >> 8; if (!prod16) return 0; tmpD9C = prod16; grapple_beam_tmpD88 = 2 * ((uint16)(grapple_beam_end_angle16 + prod16) >> 8); uint16 v2; v2 = 2 * grapple_beam_end_angle_hi; if (v2 != grapple_beam_tmpD88) { while (1) { grapple_beam_tmpD86 = v2; uint16 grapple_beam_tmpD82 = (v2 + 2) & 0x1FF; if (BlockFunc_ABE6(grapple_beam_tmpD82) & 1) break; v2 = (grapple_beam_tmpD86 + 2) & 0x1FF; if (v2 == grapple_beam_tmpD88) goto LABEL_12; } LOBYTE(v4) = 0; HIBYTE(v4) = grapple_beam_tmpD86 >> 1; grapple_beam_end_angle16 = v4 | 0x80; grapple_beam_end_angles_mirror = v4 | 0x80; if (g_word_7E0D98 != 6 && g_word_7E0D98 != 5 || grapple_beam_length != 8) goto LABEL_39; LABEL_23: grapple_beam_unkD36 |= 0x8000; grapple_beam_unkD26 = 0; grapple_beam_unkD2E = 0; return 1; } LABEL_12: grapple_beam_end_angle16 += tmpD9C; grapple_beam_end_angles_mirror = grapple_beam_end_angle16; grapple_beam_unkD36 &= ~0x8000; if ((--grapple_beam_unkD30 & 0x8000) != 0) grapple_beam_unkD30 = 0; if ((grapple_beam_unkD2E & 0x8000) == 0) { v3 = grapple_beam_unkD2E - 6; if ((int16)(grapple_beam_unkD2E - 6) >= 0) { LABEL_19: grapple_beam_unkD2E = v3; return 0; } } else { v3 = grapple_beam_unkD2E + 6; if ((int16)(grapple_beam_unkD2E + 6) < 0) goto LABEL_19; } v3 = 0; goto LABEL_19; } prod16 = Multiply16x16(-v1, v0) >> 8; if (!prod16) return 0; tmpD9C = -prod16; grapple_beam_tmpD88 = 2 * ((uint16)(grapple_beam_end_angle16 - prod16) >> 8); uint16 v5; v5 = 2 * grapple_beam_end_angle_hi; if (v5 == grapple_beam_tmpD88) { LABEL_28: grapple_beam_end_angle16 += tmpD9C; grapple_beam_end_angles_mirror = grapple_beam_end_angle16; grapple_beam_unkD36 &= ~0x8000; if ((--grapple_beam_unkD30 & 0x8000) != 0) grapple_beam_unkD30 = 0; if ((grapple_beam_unkD2E & 0x8000) == 0) { v6 = grapple_beam_unkD2E - 6; if ((int16)(grapple_beam_unkD2E - 6) >= 0) { LABEL_35: grapple_beam_unkD2E = v6; return 0; } } else { v6 = grapple_beam_unkD2E + 6; if ((int16)(grapple_beam_unkD2E + 6) < 0) goto LABEL_35; } v6 = 0; goto LABEL_35; } while (1) { grapple_beam_tmpD86 = v5; uint16 grapple_beam_tmpD82 = (v5 - 2) & 0x1FF; if (BlockFunc_ABE6(grapple_beam_tmpD82) & 1) break; v5 = (grapple_beam_tmpD86 - 2) & 0x1FF; if (v5 == grapple_beam_tmpD88) goto LABEL_28; } LOBYTE(v7) = 0; HIBYTE(v7) = grapple_beam_tmpD86 >> 1; grapple_beam_end_angle16 = v7 | 0x80; grapple_beam_end_angles_mirror = v7 | 0x80; if ((g_word_7E0D98 == 6 || g_word_7E0D98 == 5) && grapple_beam_length == 8) goto LABEL_23; LABEL_39: grapple_beam_unkD30 = 16; grapple_beam_unkD26 = -((int16)grapple_beam_unkD26 >> 1); grapple_beam_unkD2E = -((int16)grapple_beam_unkD2E >> 1); return 1; } uint8 BlockFunc_AEE3(void) { // 0x94AEE3 if (((grapple_beam_unkD26 ^ grapple_beam_end_angle16) & 0x8000) != 0) { grapple_beam_unkD38 = 0; return 1; } else { if (++grapple_beam_unkD38 == 32) grapple_beam_function = FUNC16(GrappleBeam_Func2); grapple_beam_unkD26 = 0; grapple_beam_unkD2E = 0; return 1; } } void GrappleFunc_AF87(void) { // 0x94AF87 for (int i = 30; i >= 0; i -= 8) { int v1 = i >> 1; grapple_segment_anim_instr_ptrs[v1] = addr_word_94B197; grapple_segment_anim_instr_timers[v1 + 15] = addr_word_94B193; grapple_segment_anim_instr_timers[v1 + 14] = addr_word_94B18F; grapple_segment_anim_instr_timers[v1 + 13] = addr_word_94B18B; grapple_segment_anim_instr_timers[v1] = 1; *(uint16 *)((uint8 *)&grapple_point_anim_ptr + i) = 1; *(uint16 *)((uint8 *)&grapple_point_anim_timer + i) = 1; *(uint16 *)((uint8 *)&grapple_beam_unkD3C + i) = 1; } } uint16 GrappleInstr_Goto(uint16 j) { // 0x94B0F4 return *(uint16 *)RomPtr_94(j); } uint16 CallGrappleInstr(uint32 ea, uint16 j) { switch (ea) { case fnGrappleInstr_Goto: return GrappleInstr_Goto(j); // 0x94b0f4 default: return Unreachable(); } } void HandleGrappleBeamGfx(void) { // 0x94AFBA int v1 = CalculateAngleFromXY(grapple_beam_end_x_pos - x_pos_of_start_of_grapple_beam_prevframe, grapple_beam_end_y_pos - y_pos_of_start_of_grapple_beam_prevframe); uint32 r28_r26 = (int16)kSinCosTable8bit_Sext[v1 + 64] << 11; uint32 r32_r30 = (int16)kSinCosTable8bit_Sext[v1] << 11; uint16 chr = (grapple_beam_end_angle_hi & 0x80) >> 1; chr |= 2 * ((grapple_beam_end_angle_hi ^ chr) & 0x40 ^ 0x40); chr <<= 8; uint32 r20_r18 = (x_pos_of_start_of_grapple_beam_prevframe - layer1_x_pos - 4) << 16; uint32 r24_r22 = (y_pos_of_start_of_grapple_beam_prevframe - layer1_y_pos - 4) << 16; if ((grapple_beam_length & 0x8000) != 0) return; int n = ((grapple_beam_length / 8) & 0xF) - 1; int q = 15; do { int i; if (grapple_segment_anim_instr_timers[q]-- == 1) { const uint16 *v9; for (i = grapple_segment_anim_instr_ptrs[q]; ; ) { v9 = (const uint16 *)RomPtr_94(i); if ((*v9 & 0x8000) == 0) break; i = CallGrappleInstr(*v9 | 0x940000, i + 2); } grapple_segment_anim_instr_timers[q] = *v9; grapple_segment_anim_instr_ptrs[q] = i + 4; } if (((r24_r22 | r20_r18) & 0xFF000000) != 0) break; uint16 v12 = *(uint16 *)RomPtr_94(grapple_segment_anim_instr_ptrs[q] - 2); DrawGrappleOams(r20_r18 >> 16, r24_r22 >> 16, chr | v12); r20_r18 += r28_r26; r24_r22 += r32_r30; } while (q--, --n >= 0); if (samus_pose == kPose_B2_FaceR_Grapple_Air || samus_pose == kPose_B3_FaceL_Grapple_Air) { DrawGrappleOams3(); } else { if (((grapple_beam_end_y_pos - layer1_y_pos) & 0xFF00) == 0) DrawGrappleOams3(); } } static void DrawGrappleOams(uint16 x_r20, uint16 y_r24, uint16 chr_r38) { // 0x94B0AA uint16 v1 = oam_next_ptr; OamEnt *v2 = gOamEnt(oam_next_ptr); v2->xcoord = x_r20; v2->ycoord = y_r24; *(uint16 *)&v2->charnum = chr_r38; oam_next_ptr = v1 + 4; } static void DrawGrappleOams3(void) { // 0x94B14B uint16 idx = oam_next_ptr; OamEnt *v2 = gOamEnt(idx); uint16 x = grapple_beam_end_x_pos - layer1_x_pos - 4; v2->xcoord = x; v2->ycoord = grapple_beam_end_y_pos - layer1_y_pos - 4; *(uint16 *)&v2->charnum = 14880; oam_ext[idx >> 5] |= (((x & 0x100) >> 8)) << (2 * ((idx >> 2) & 7)); oam_next_ptr = idx + 4; }