ref: 18c351f101ddcd572360dc21be029ba3e62d45d0
dir: /tile_detect.c/
#include "tile_detect.h"
#include "zelda_rtl.h"
#include "ancilla.h"
#include "variables.h"
#include "overworld.h"
static const uint8 kDetectTiles_tab0[] = { 8, 24, 0, 15 };
static const uint8 kDetectTiles_tab1[] = { 0, 0, 8, 8 };
static const uint8 kDetectTiles_tab2[] = { 8, 8, 16, 16 };
static const uint8 kDetectTiles_tab3[] = { 15, 15, 23, 23 };
static const int8 kDetectTiles_tab4[] = { 7, 24, -1, 16 };
static const uint8 kDetectTiles_tab5[] = { 0, 0, 8, 8 };
static const uint8 kDetectTiles_tab6[] = { 15, 15, 23, 23 };
uint8 Overworld_GetTileAttributeAtLocation(uint16 x, uint16 y) { // 80882e
uint16 t;
t = ((y - overworld_offset_base_y) & overworld_offset_mask_y) * 8;
t |= ((x - overworld_offset_base_x) & overworld_offset_mask_x);
t = overworld_tileattr[t >> 1] * 4;
t |= (y & 8) >> 2;
t |= (x & 1);
t = GetMap16toMap8Table()[t];
uint8 rv = GetMap8toTileAttr()[t & 0x1ff];
if (rv >= 0x10 && rv < 0x1C) {
rv |= (t >> 14) & 1;
}
return rv;
}
void TileDetect_Movement_Y(uint16 direction) { // 87cdcb
assert(direction < 4);
TileDetect_ResetState();
tiledetect_pit_tile = 0;
tiledetect_which_y_pos[0] = (link_y_coord + kDetectTiles_tab0[direction]);
uint16 y = tiledetect_which_y_pos[0] & tilemap_location_calc_mask;
uint16 x0 = ((link_x_coord + kDetectTiles_tab1[direction]) & tilemap_location_calc_mask) >> 3;
uint16 x1 = ((link_x_coord + kDetectTiles_tab2[direction]) & tilemap_location_calc_mask) >> 3;
uint16 x2 = ((link_x_coord + kDetectTiles_tab3[direction]) & tilemap_location_calc_mask) >> 3;
scratch_1 = x2;
TileDetection_Execute(x0, y, 1);
TileDetection_Execute(x1, y, 2);
TileDetection_Execute(x2, y, 4);
}
void TileDetect_Movement_X(uint16 direction) { // 87ce2a
assert(direction < 4);
TileDetect_ResetState();
tiledetect_pit_tile = 0;
uint16 x = ((link_x_coord + kDetectTiles_tab0[direction]) & tilemap_location_calc_mask) >> 3;
uint16 y0 = ((link_y_coord + kDetectTiles_tab1[direction]) & tilemap_location_calc_mask);
tiledetect_which_y_pos[0] = link_y_coord + kDetectTiles_tab2[direction];
uint16 y1 = tiledetect_which_y_pos[0] & tilemap_location_calc_mask;
tiledetect_which_y_pos[1] = link_y_coord + kDetectTiles_tab3[direction];
uint16 y2 = tiledetect_which_y_pos[1] & tilemap_location_calc_mask;
TileDetection_Execute(x, y0, 1);
TileDetection_Execute(x, y1, 2);
TileDetection_Execute(x, y2, 4);
}
void TileDetect_Movement_VerticalSlopes(uint16_t direction) { // 87ce85
assert(direction < 4);
TileDetect_ResetState();
tiledetect_pit_tile = 0;
uint16 y = (link_y_coord + kDetectTiles_tab4[direction]) & tilemap_location_calc_mask;
uint16 x0 = ((link_x_coord + kDetectTiles_tab5[direction]) & tilemap_location_calc_mask) >> 3;
uint16 x1 = ((link_x_coord + kDetectTiles_tab6[direction]) & tilemap_location_calc_mask) >> 3;
TileDetection_Execute(x0, y, 1);
TileDetection_Execute(x1, y, 2);
}
void TileDetect_Movement_HorizontalSlopes(uint16_t direction) { // 87cec9
assert(direction < 4);
TileDetect_ResetState();
tiledetect_pit_tile = 0;
uint16 x = ((link_x_coord + kDetectTiles_tab4[direction]) & tilemap_location_calc_mask) >> 3;
uint16 y0 = ((link_y_coord + kDetectTiles_tab5[direction]) & tilemap_location_calc_mask);
uint16 y1 = ((link_y_coord + kDetectTiles_tab6[direction]) & tilemap_location_calc_mask);
TileDetection_Execute(x, y0, 1);
TileDetection_Execute(x, y1, 2);
}
void Player_TileDetectNearby() { // 87cf12
TileDetect_ResetState();
tiledetect_pit_tile = 0;
uint16 x0 = ((link_x_coord + kDetectTiles_tab1[0]) & tilemap_location_calc_mask) >> 3;
uint16 x1 = ((link_x_coord + kDetectTiles_tab3[0]) & tilemap_location_calc_mask) >> 3;
uint16 y0 = ((link_y_coord + kDetectTiles_tab1[2]) & tilemap_location_calc_mask);
uint16 y1 = ((link_y_coord + kDetectTiles_tab3[2]) & tilemap_location_calc_mask);
scratch_1 = y0;
TileDetection_Execute(x0, y0, 8);
TileDetection_Execute(x0, y1, 2);
TileDetection_Execute(x1, y0, 4);
TileDetection_Execute(x1, y1, 1);
}
void Hookshot_CheckTileCollision(int k) { // 87d576
uint8 bak0 = BYTE(dungeon_room_index);
uint8 bak1 = link_is_on_lower_level;
if (ancilla_arr1[k]) {
if (!BYTE(kind_of_in_room_staircase))
BYTE(dungeon_room_index) += 0x10;
link_is_on_lower_level ^= 1;
}
uint16 x = Ancilla_GetX(k), y = Ancilla_GetY(k);
int dir = ancilla_dir[k];
tiledetect_pit_tile = 0;
TileDetect_ResetState();
if (dung_hdr_collision == 2) {
link_is_on_lower_level = 1;
Hookshot_CheckSingleLayerTileCollision(x + BG1HOFS_copy2 - BG2HOFS_copy2, y + BG1VOFS_copy2 - BG2VOFS_copy2, dir);
link_is_on_lower_level = 0;
}
Hookshot_CheckSingleLayerTileCollision(x, y, dir);
link_is_on_lower_level = bak1;
BYTE(dungeon_room_index) = bak0;
}
void Hookshot_CheckSingleLayerTileCollision(uint16 x, uint16 y, int dir) { // 87d607
static const uint8 kHookShot_CheckColl_X[8] = { 0, 15, 0, 15, 0, 0, 8, 8 };
static const uint8 kHookShot_CheckColl_Y[8] = { 0, 0, 7, 7, 0, 15, 0, 15 };
uint16 y0 = (y + kHookShot_CheckColl_Y[dir * 2 + 0]) & tilemap_location_calc_mask;
uint16 y1 = (y + kHookShot_CheckColl_Y[dir * 2 + 1]) & tilemap_location_calc_mask;
uint16 x0 = ((x + kHookShot_CheckColl_X[dir * 2 + 0]) & tilemap_location_calc_mask) >> 3;
uint16 x1 = ((x + kHookShot_CheckColl_X[dir * 2 + 1]) & tilemap_location_calc_mask) >> 3;
TileDetection_Execute(x0, y0, 1);
TileDetection_Execute(x1, y1, 2);
}
void HandleNudgingInADoor(int8 speed) { // 87d667
uint8 y;
if (link_last_direction_moved_towards & 2) {
y = (uint8)link_y_coord < 0x80 ? 1 : 0;
} else {
y = (uint8)link_x_coord < 0x80 ? 3 : 2;
}
tiledetect_pit_tile = 0;
TileDetect_ResetState();
static const int8 kDetectTiles_7_Y[] = { 8, 23, 16, 16 };
static const int8 kDetectTiles_7_X[] = { 8, 8, 0, 15 };
uint16 x0 = ((link_x_coord + kDetectTiles_7_X[y]) & tilemap_location_calc_mask) >> 3;
uint16 y0 = ((link_y_coord + kDetectTiles_7_Y[y]) & tilemap_location_calc_mask);
TileDetection_Execute(x0, y0, 1);
if (((R14 | detection_of_ledge_tiles_horiz_uphoriz) & 3) == 0) {
if (((tiledetect_vertical_ledge | detection_of_unknown_tile_types) & 0x33) == 0)
return;
}
if (link_last_direction_moved_towards & 2)
link_y_coord -= speed;
else
link_x_coord -= speed;
}
void TileCheckForMirrorBonk() { // 87d6f4
tiledetect_pit_tile = 0;
TileDetect_ResetState();
uint16 x0 = ((link_x_coord + 2) & tilemap_location_calc_mask) >> 3;
uint16 x1 = ((link_x_coord + 13) & tilemap_location_calc_mask) >> 3;
uint16 y0 = ((link_y_coord + 10) & tilemap_location_calc_mask);
uint16 y1 = ((link_y_coord + 21) & tilemap_location_calc_mask);
scratch_1 = y0;
TileDetection_Execute(x0, y0, 8);
TileDetection_Execute(x0, y1, 2);
TileDetection_Execute(x1, y0, 4);
TileDetection_Execute(x1, y1, 1);
}
// Used when holding sword in doorway
void TileDetect_SwordSwingDeepInDoor(uint8 dw) { // 87d73e
tiledetect_pit_tile = 0;
TileDetect_ResetState();
static const int8 kDoorwayDetectX[] = { 8, 8, -1, 16 };
static const int8 kDoorwayDetectY[] = { -1, 24, 16, 16 };
int o = (dw - 1) * 2;
uint16 x0 = ((link_x_coord + kDoorwayDetectX[o + 0]) & tilemap_location_calc_mask) >> 3;
uint16 x1 = ((link_x_coord + kDoorwayDetectX[o + 1]) & tilemap_location_calc_mask) >> 3;
uint16 y0 = ((link_y_coord + kDoorwayDetectY[o + 0]) & tilemap_location_calc_mask);
uint16 y1 = ((link_y_coord + kDoorwayDetectY[o + 1]) & tilemap_location_calc_mask);
TileDetection_Execute(x0, y0, 1);
TileDetection_Execute(x1, y1, 2);
}
void TileDetect_ResetState() { // 87d798
R12 = 0;
R14 = 0;
tiledetect_diagonal_tile = 0;
tiledetect_stair_tile = 0;
tiledetect_pit_tile = 0;
tiledetect_inroom_staircase = 0;
tiledetect_var2 = 0;
tiledetect_var1 = 0;
tiledetect_moving_floor_tiles = 0;
tiledetect_deepwater = 0;
tiledetect_normal_tiles = 0;
tiledetect_icy_floor = 0;
tiledetect_water_staircase = 0;
tiledetect_thick_grass = 0;
tiledetect_shallow_water = 0;
tiledetect_destruction_aftermath = 0;
tiledetect_read_something = 0;
tiledetect_vertical_ledge = 0;
detection_of_ledge_tiles_horiz_uphoriz = 0;
tiledetect_ledges_down_leftright = 0;
detection_of_unknown_tile_types = 0;
tiledetect_chest = 0;
tiledetect_key_lock_gravestones = 0;
bitfield_spike_cactus_tiles = 0;
tiledetect_spike_floor_and_tile_triggers = 0;
bitmask_for_dashable_tiles = 0;
tiledetect_misc_tiles = 0;
tiledetect_var4 = 0;
}
void TileDetection_Execute(uint16 x, uint16 y, uint16 bits) { // 87d9d8
uint8 tile;
uint16 offs = 0;
if (player_is_indoors) {
force_move_any_direction = force_move_any_direction & 0xff;
offs = (y & ~7) * 8 + (x & 63) + (link_is_on_lower_level ? 0x1000 : 0);
tile = dung_bg2_attr_table[offs];
if (cheatWalkThroughWalls)
tile = 0;
link_tile_below = tile;
} else {
tile = Overworld_GetTileAttributeAtLocation(x, y);
}
TileDetect_ExecuteInner(tile, offs, bits, player_is_indoors);
}
void TileDetect_ExecuteInner(uint8 tile, uint16 offs, uint16 bits, bool is_indoors) { // 87dc2e
static const uint8 word_87DC55[] = { 4, 0, 6, 2 };
if (cheatWalkThroughWalls)
tile = 0;
switch (tile) {
case 0x00: case 0x05: case 0x06: case 0x07: case 0x14: case 0x15: case 0x16: case 0x17: case 0x21: case 0x23: case 0x24: case 0x25: case 0x38: case 0x39: case 0x3a: case 0x3b: case 0x3c: case 0x41: case 0x45: case 0x47: case 0x49: case 0x5e: case 0x5f: case 0x61: case 0x62: case 0x64: case 0x65: case 0x66: case 0xa6: case 0xa7: case 0xbe: case 0xbf: case 0xd0: case 0xd1: case 0xd2: case 0xd3: case 0xd4: case 0xd5: case 0xd6: case 0xd7: case 0xd8: case 0xd9: case 0xda: case 0xdb: case 0xdc: case 0xdd: case 0xde: case 0xdf: case 0xe0: case 0xe1: case 0xe2: case 0xe3: case 0xe4: case 0xe5: case 0xe6: case 0xe7: case 0xe8: case 0xe9: case 0xea: case 0xeb: case 0xec: case 0xed: case 0xee: case 0xef: // TileBehavior_NothingOW
if (!is_indoors)
tiledetect_normal_tiles |= bits;
break;
case 0x01: case 0x02: case 0x03: // TileBehavior_StandardCollision
case 0x26: case 0x43:
R14 |= bits;
break;
case 0x6c: case 0x6d: case 0x6e: case 0x6f:
if (is_indoors)
R14 |= bits;
else
tiledetect_normal_tiles |= bits;
break;
case 0x04:
if (is_indoors) {
R14 |= bits;
} else {
tiledetect_thick_grass |= bits;
}
break;
case 0x0b:
if (is_indoors) {
R14 |= bits;
} else {
index_of_interacting_tile = tile;
tiledetect_deepwater |= bits << 4;
}
break;
case 0x08: // TileBehavior_DeepWater
tiledetect_deepwater |= bits;
break;
case 0x09: // TileBehavior_ShallowWater
tiledetect_shallow_water |= bits;
break;
case 0x0a: // TileBehavior_ShortWaterLadder
tiledetect_normal_tiles |= bits;
break;
case 0x0c: // TileBehavior_OverlayMask_0C
tiledetect_moving_floor_tiles |= bits;
break;
case 0x0d: // TileBehavior_SpikeFloor
if (!flag_block_link_menu && !(dung_savegame_state_bits & 0x8000))
tiledetect_spike_floor_and_tile_triggers |= bits << 4;
break;
case 0x0e: // TileBehavior_GanonIce
tiledetect_icy_floor |= bits;
break;
case 0x0f: // TileBehavior_PalaceIce
tiledetect_icy_floor |= bits << 4;
break;
case 0x10: case 0x11: case 0x12: case 0x13: // TileBehavior_Slope
R12 |= bits;
tiledetect_diag_state = word_87DC55[tile & 3];
break;
case 0x18: case 0x19: case 0x1a: case 0x1b: // TileBehavior_SlopeOuter
tiledetect_diagonal_tile |= bits;
R12 |= bits;
tiledetect_diag_state = word_87DC55[tile & 3];
break;
case 0x1c: // TileBehavior_OverlayMask_1C
tiledetect_water_staircase |= bits;
break;
case 0x1d: // TileBehavior_NorthSingleLayerStairs
index_of_interacting_tile = tile;
tiledetect_inroom_staircase |= bits;
tiledetect_stair_tile |= bits;
break;
case 0x1e: case 0x1f: // TileBehavior_NorthSwapLayerStairs
index_of_interacting_tile = tile;
tiledetect_inroom_staircase |= bits;
tiledetect_stair_tile |= bits;
break;
case 0x20: case 0xb0: case 0xb1: case 0xb2: case 0xb3: case 0xb4: case 0xb5: case 0xb6: case 0xb7: case 0xb8: case 0xb9: case 0xba: case 0xbb: case 0xbc: case 0xbd: // TileBehavior_Pit
if (!player_on_somaria_platform)
tiledetect_pit_tile |= bits;
break;
case 0x22: case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: case 0x35: case 0x36: case 0x37: // TileHandlerIndoor_22
tiledetect_stair_tile |= bits;
break;
case 0x27: // TileBehavior_Hookshottables
R14 |= bits;
tiledetect_misc_tiles |= bits;
break;
case 0x28: // TileBehavior_Ledge_North
index_of_interacting_tile = tile;
tiledetect_vertical_ledge |= bits;
break;
case 0x29: // TileBehavior_Ledge_South
index_of_interacting_tile = tile;
tiledetect_vertical_ledge |= bits << 4;
break;
case 0x2a: case 0x2b: // TileBehavior_Ledge_EastWest
index_of_interacting_tile = tile;
detection_of_ledge_tiles_horiz_uphoriz |= bits;
break;
case 0x2c: case 0x2e: // TileBehavior_Ledge_NorthDiagonal
index_of_interacting_tile = tile;
detection_of_ledge_tiles_horiz_uphoriz |= bits << 4;
break;
case 0x2d: case 0x2f: // TileBehavior_Ledge_SouthDiagonal
index_of_interacting_tile = tile;
tiledetect_ledges_down_leftright |= bits;
break;
case 0x3d: case 0x3e: case 0x3f: // TileHandlerIndoor_3E
index_of_interacting_tile = tile;
tiledetect_inroom_staircase |= bits << 4;
tiledetect_stair_tile |= bits;
break;
case 0x40: // TileBehavior_ThickGrass
tiledetect_thick_grass |= bits;
break;
case 0x44: // TileBehavior_Spike
if (!flag_block_link_menu && !(dung_savegame_state_bits & 0x8000))
bitfield_spike_cactus_tiles |= bits;
else
R14 |= bits;
break;
case 0x46: // TileBehavior_HylianPlaque
tiledetect_spike_floor_and_tile_triggers |= bits;
R14 |= bits;
break;
case 0x48: case 0x4a: // TileBehavior_DiggableGround
tiledetect_destruction_aftermath |= bits;
tiledetect_normal_tiles |= bits;
break;
case 0x4b: // TileBehavior_Warp
tiledetect_thick_grass |= bits << 4;
break;
case 0x50: case 0x51: case 0x52: case 0x53: case 0x54: case 0x55: case 0x56: { // TileBehavior_Liftable
static const uint8 kTile50data[] = { 0x54, 0x52, 0x50, 0x51, 0x53, 0x55, 0x56 };
for (int i = 6; i >= 0; i--) {
if (kTile50data[i] == tile) {
if (tile == 0x50 || tile == 0x51)
bitmask_for_dashable_tiles |= bits << 4;
tiledetect_read_something |= bits;
interacting_with_liftable_tile_x2 = i * 2;
R14 |= bits;
tiledetect_misc_tiles |= bits;
break;
}
}
break;
}
case 0x57: // TileBehavior_BonkRocks
R14 |= bits;
bitmask_for_dashable_tiles |= bits << 4;
break;
case 0x58: case 0x59: case 0x5a: case 0x5b: case 0x5c: case 0x5d: // TileBehavior_Chest
tiledetect_misc_tiles |= bits;
index_of_interacting_tile = tile;
if (dung_chest_locations[tile - 0x58] >= 0x8000) {
R14 |= bits;
tiledetect_key_lock_gravestones |= bits << 4;
if (bits & 2)
tiledetect_tile_type = tile;
} else {
tiledetect_chest |= bits; // small key lock
R14 |= bits;
}
break;
case 0x60: // TileBehavior_RupeeTile
if (is_indoors) {
if (dung_bg2_attr_table[offs + 64] == 0x60) {
tiledetect_misc_tiles |= bits << 8;
} else {
tiledetect_misc_tiles |= bits << 12;
}
} else {
tiledetect_normal_tiles |= bits;
}
break;
case 0x63: // TileBehavior_MinigameChest
tiledetect_misc_tiles |= bits;
index_of_interacting_tile = tile;
tiledetect_chest |= bits; // small key lock
R14 |= bits;
break;
case 0x67: // TileBehavior_CrystalPeg_Up
R14 |= bits;
tiledetect_misc_tiles |= bits;
bitfield_spike_cactus_tiles |= bits << 4;
break;
case 0x68: // TileBehavior_Conveyor_Upwards
tiledetect_var4 |= bits;
break;
case 0x69: // TileBehavior_Conveyor_Downwards
tiledetect_var4 |= bits << 4;
break;
case 0x6a: // TileBehavior_Conveyor_Leftwards
tiledetect_var4 |= bits << 8;
break;
case 0x6b: // TileBehavior_Conveyor_Rightwards
tiledetect_var4 |= bits << 12;
break;
case 0x70: case 0x71: case 0x72: case 0x73: case 0x74: case 0x75: case 0x76: case 0x77: case 0x78: case 0x79: case 0x7a: case 0x7b: case 0x7c: case 0x7d: case 0x7e: case 0x7f: // TileBehavior_ManipulablyReplaced
if (bits & 2)
tiledetect_var2 |= 1 << (tile & 0xf);
R14 |= bits;
tiledetect_misc_tiles |= bits;
break;
case 0x80: case 0x81: case 0x84: case 0x85: case 0x86: case 0x87: case 0x88: case 0x89: case 0x8a: case 0x8b: case 0x8c: case 0x8d: // TileHandlerIndoor_80
R14 |= bits << 4;
tiledetect_var1 = 2 * (tile & 1);
break;
case 0x82: case 0x83: // TileHandlerIndoor_82
R14 |= (bits << 4) | (bits << 8);
tiledetect_var1 = 2 * (tile & 1);
break;
case 0x8e: case 0x8f: // TileBehavior_Entrance
R14 |= bits << 4;
bitmask_for_dashable_tiles |= bits;
tiledetect_var1 = 0;
break;
case 0x90: case 0x91: case 0x92: case 0x93: case 0x94: case 0x95: case 0x96: case 0x97: // TileBehavior_LayerToggleShutterDoor
room_transitioning_flags = 1;
R14 |= (bits << 4) | (bits << 8);
tiledetect_var1 = 2 * (tile & 1);
break;
case 0x98: case 0x99: case 0x9a: case 0x9b: case 0x9c: case 0x9d: case 0x9e: case 0x9f: case 0xa8: case 0xa9: case 0xaa: case 0xab: case 0xac: case 0xad: case 0xae: case 0xaf: // TileBehavior_LayerAndDungeonToggleShutterDoor
room_transitioning_flags = 3;
R14 |= (bits << 4) | (bits << 8);
tiledetect_var1 = 2 * (tile & 1);
break;
case 0xa0: case 0xa1: case 0xa4: case 0xa5: // TileBehavior_DungeonToggleManualDoor
room_transitioning_flags = 2;
R14 |= bits << 4;
tiledetect_var1 = 2 * (tile & 1);
break;
case 0xa2: case 0xa3: // TileBehavior_DungeonToggleShutterDoor
room_transitioning_flags = 2;
R14 |= (bits << 4) | (bits << 8);
tiledetect_var1 = 2 * (tile & 1);
break;
case 0xc0: case 0xc1: case 0xc2: case 0xc3: case 0xc4: case 0xc5: case 0xc6: case 0xc7: case 0xc8: case 0xc9: case 0xca: case 0xcb: case 0xcc: case 0xcd: case 0xce: case 0xcf: // TileBehavior_LightableTorch
R14 |= bits;
tiledetect_misc_tiles |= bits;
break;
case 0xf0: case 0xf1: case 0xf2: case 0xf3: case 0xf4: case 0xf5: case 0xf6: case 0xf7: case 0xf8: case 0xf9: case 0xfa: case 0xfb: case 0xfc: case 0xfd: case 0xfe: case 0xff: // TileBehavior_FlaggableDoor
R14 |= bits;
tiledetect_misc_tiles |= bits << 4;
break;
case 0x42: // TileBehavior_GraveStone
if (!is_indoors) {
tiledetect_key_lock_gravestones |= bits;
R14 |= bits;
}
break;
case 0x4c: case 0x4d: // TileBehavior_UnusedCornerType
if (!is_indoors) {
index_of_interacting_tile = tile;
detection_of_unknown_tile_types |= bits;
}
break;
case 0x4e: case 0x4f: // TileBehavior_EasternRuinsCorner
if (!is_indoors) {
index_of_interacting_tile = tile;
detection_of_unknown_tile_types |= bits << 4;
}
break;
default:
assert(0);
}
}