1#include "ap_snes.h" 2#include "ap_macro.h" 3#include "ap_math.h" 4#include "ap_map.h" 5#include "ap_plan.h" 6 7uint64_t ap_frame = 0; 8struct ap_ram ap_ram; 9struct ap_snes9x * ap_emu = NULL; 10bool ap_manual_mode = false; 11 12char ap_info_string[INFO_STRING_SIZE]; 13bool ap_debug; 14struct ap_sprite ap_sprites[16]; 15bool ap_sprites_changed; 16struct ap_pushblock ap_pushblocks[16]; 17 18const char * const ap_tile_attr_names[] = { 19#define X(d) [CONCAT(TILE_ATTR_, d)] = STRINGIFY(d), 20TILE_ATTR_LIST 21#undef X 22}; 23 24const char * ap_tile_attr_name(uint8_t idx) { 25 uint16_t attr = ap_tile_attrs[idx]; 26 static char sbuf[1024]; 27 char * buf = sbuf; 28#define X(d) if (attr & CONCAT(TILE_ATTR_, d)) { \ 29 if (buf != sbuf) { *buf++ = '|'; } \ 30 buf += sprintf(buf, STRINGIFY(d)); \ 31 } 32TILE_ATTR_LIST 33#undef X 34 return sbuf; 35} 36 37const char * const ap_sprite_attr_names[] = { 38#define X(d) [CONCAT(SPRITE_ATTR_, d)] = STRINGIFY(d), 39SPRITE_ATTR_LIST 40#undef X 41}; 42 43const char * ap_sprite_attr_name(uint16_t attr) { 44 static char sbuf[1024]; 45 char * buf = sbuf; 46#define X(d) if (attr & CONCAT(SPRITE_ATTR_, d)) { \ 47 if (buf != sbuf) { *buf++ = '|'; } \ 48 buf += sprintf(buf, STRINGIFY(d)); \ 49 } 50SPRITE_ATTR_LIST 51#undef X 52 return sbuf; 53} 54 55 56void 57ap_init(struct ap_snes9x * _emu) 58{ 59 ap_emu = _emu; 60 61#define X(name, type, offset) ap_ram.name = (type *) ap_emu->base(offset); 62AP_RAM_LIST 63#undef X 64 65 printf("----- initialized ------ \n"); 66 ap_emu->load("home"); 67 //ap_emu->load("well"); 68 //ap_emu->load("castle"); 69 //ap_emu->load("estpal"); 70 //ap_emu->load("epsta"); 71 //ap_emu->load("prearmos"); 72 //ap_emu->load("cave_front"); 73 //ap_emu->load("cave"); 74 //ap_emu->load("hc_stairs"); 75 //ap_emu->load("rock"); 76 //ap_emu->load("stair_test"); 77 //ap_emu->load("near_hole"); 78 //ap_emu->load("mmcave"); 79 //ap_emu->load("basement"); 80 //ap_emu->load("dam_puzzle"); 81 //ap_emu->load("blinds_house"); 82 //ap_emu->load("atchest"); 83 //ap_emu->load("pyramid"); 84 ap_emu->load("hpegs"); 85 86 ap_plan_init(); 87} 88 89void 90ap_ram_print() 91{ 92 LOG("All RAM:"); 93 size_t i = 0; 94#define X(name, type, offset) \ 95 printf("%24s: %#-10x", STRINGIFY(name), *ap_ram.name); \ 96 if (i++ % 6 == 5) { printf("\n"); } 97AP_RAM_LIST 98#undef X 99} 100 101uint16_t 102ap_sprite_attrs_for_type(uint8_t type, uint16_t subtype, uint16_t dungeon_room) 103{ 104 uint16_t attrs = ap_sprite_attrs[type]; 105 if (attrs & SPRITE_ATTR_SUBT) { 106 for (size_t i = 0; i < ARRAYLEN(ap_sprite_subtypes); i++) { 107 const struct ap_sprite_subtype *st= &ap_sprite_subtypes[i]; 108 if (st->only_dungeon_room != 0 && dungeon_room != st->only_dungeon_room) { 109 continue; 110 } 111 if (st->type == type && st->subtype == subtype) { 112 return st->attrs; 113 } 114 } 115 return attrs & ~SPRITE_ATTR_SUBT; 116 } 117 return attrs; 118} 119 120void 121ap_sprites_update() { 122 ap_sprites_changed = false; 123 124 for (size_t i = 0; i < 16; i++) { 125 struct ap_sprite * sprite = &ap_sprites[i]; 126 if (ap_ram.sprite_type[i] != sprite->type) { 127 ap_sprites_changed = true; 128 } 129 } 130 if (ap_sprites_changed) { 131 //LOGB("Sprites changed"); 132 } 133 134 memset(ap_sprites, 0, sizeof ap_sprites); 135 for (size_t i = 0; i < 16; i++) { 136 struct ap_sprite * sprite = &ap_sprites[i]; 137 if (ap_ram.sprite_type[i] == 0) 138 continue; 139 140 sprite->type = ap_ram.sprite_type[i]; 141 sprite->state = ap_ram.sprite_state[i]; 142 sprite->subtype = ap_ram.sprite_subtype1[i] | (ap_ram.sprite_subtype2[i] << 8); 143 sprite->interaction = ap_ram.sprite_interaction[i]; 144 sprite->hp = ap_ram.sprite_hp[i]; 145 sprite->drop = ap_ram.sprite_drop[i] == 0x03 ? 0 : ap_ram.sprite_drop[i]; 146 147 sprite->attrs = ap_sprite_attrs_for_type(sprite->type, sprite->subtype, *ap_ram.dungeon_room); 148 bool spawned = ap_ram.sprite_spawned[i]; 149 150 switch (sprite->type) { 151 /* 152 case 0x41: // Guard-like sprites 153 case 0x42: 154 case 0x43: 155 case 0x44: 156 case 0x45: 157 case 0x46: 158 case 0x47: 159 case 0x48: 160 case 0x49: 161 case 0x4a: 162 case 0x4b: 163 case 0x6a: 164 case 0x18: // Moldorm 165 case 0xa7: // Stalfos 166 case 0x83: // Green Igor 167 case 0x84: // Red Igor 168 case 0x4e: // Curly thing 169 case 0x4f: // Curly thing 170 sprite->active = false; 171 if ((sprite->interaction & 0x1F) && sprite->hp > 0) { 172 sprite->active = true; 173 } 174 break; 175 case 0x53: // Armos Knights 176 sprite->active = sprite->hp > 0; // && spawned; 177 break; 178 */ 179 default: 180 if (sprite->attrs & SPRITE_ATTR_TALK) { 181 sprite->active = true; 182 } else { 183 sprite->active = sprite->state != 0; 184 } 185 break; 186 } 187 188 sprite->hitbox_tl = XY(ap_ram.sprite_x_lo[i], ap_ram.sprite_y_lo[i]); 189 sprite->hitbox_tl.x += ap_ram.sprite_x_hi[i] << 8u; 190 sprite->hitbox_tl.y += ap_ram.sprite_y_hi[i] << 8u; 191 192 if (*ap_ram.in_building) { 193 sprite->hitbox_tl.x = ((sprite->hitbox_tl.x & ~0x1FF) << 2) | (sprite->hitbox_tl.x & 0x1FF); 194 sprite->hitbox_tl.x += 0x4000; 195 if (!ap_ram.sprite_lower_level[i] && ap_ram.sprite_type[i] != 0x50) { 196 sprite->hitbox_tl.x += 0x200; 197 } 198 } 199 200 uint8_t h = ap_ram.sprite_hitbox_idx[i] & 0x1Fu; 201 sprite->tl = sprite->hitbox_tl; 202 sprite->tl.x += ap_ram.hitbox_x_lo[h]; 203 sprite->tl.x += ap_ram.hitbox_x_hi[h] << 8u; 204 sprite->tl.y += ap_ram.hitbox_y_lo[h]; 205 sprite->tl.y += ap_ram.hitbox_y_hi[h] << 8u; 206 207 sprite->br = sprite->tl; 208 sprite->br.x += ap_ram.hitbox_width[h]; 209 sprite->br.y += ap_ram.hitbox_height[h]; 210 211 if (sprite->attrs & SPRITE_ATTR_BLKF) { 212 assert(!(sprite->attrs & SPRITE_ATTR_BLKS)); 213 sprite->hitbox_tl = sprite->tl; 214 sprite->hitbox_br = sprite->br; 215 } else if (sprite->attrs & SPRITE_ATTR_BLKS) { 216 sprite->hitbox_br = XYOP1(sprite->hitbox_tl, +15); 217 } else { 218 sprite->hitbox_tl = XY(0, 0); 219 sprite->hitbox_br = XY(0, 0); 220 } 221 if (sprite->type == 0x40) { 222 // Hyrule Castle Barrier to Agahnim's Tower 223 sprite->hitbox_br.y += 16; 224 } 225 } 226 227 // The blocks don't seem to update in real-time so not sure if this 228 // memory region is actually useful 229 memset(ap_pushblocks, 0, sizeof(ap_pushblocks)); 230 size_t n_blocks = 0; 231 if (*ap_ram.in_building) { 232 struct xy raw_room_tl; 233 raw_room_tl = XYOP1(ap_link_xy(), & (uint16_t) ~0x1FF); 234 for (size_t i = 0; i < (0x18C / 4); i++) { 235 uint16_t room_id = ap_ram.block_data[i] & 0xFFFF; 236 if (room_id != *ap_ram.dungeon_room) { 237 continue; 238 } 239 uint16_t tile_addr = ap_ram.block_data[i] >> 16; 240 struct xy xy = XY((tile_addr & 0x7E) << 2, (tile_addr & 0x1F80) >> 4); 241 //LOG("Raw block %#x: %#x %#x", tile_addr, xy.x, xy.y); 242 xy = XYOP2(raw_room_tl, +, xy); 243 //struct xy xy = ap_map16_to_xy(raw_room_tl, tile_addr & 0x1FFF); 244 if (tile_addr & 0x2000) { 245 xy = XYFLIPBG(xy); // XXX test this 246 } 247 ap_pushblocks[n_blocks++].tl = xy; 248 assert(n_blocks < ARRAYLEN(ap_pushblocks)); 249 //LOGB("> Block at %#x " PRIXYV, tile_addr, PRIXYVF(xy)); 250 } 251 } 252} 253 254void 255ap_sprites_print() 256{ 257 struct xy link = ap_link_xy(); 258 for (uint8_t i = 0; i < 16; i++) { 259 if (ap_sprites[i].type == 0) 260 continue; 261 LOG("Sprite %-2u: %c attrs=%s type=%#-4x subtype=%#-6x state=%#-4x inter=%#-4x hp=%-2d drop=%#-4x " PRIBBV " dist=%d", 262 i, "qA"[!!ap_sprites[i].active], ap_sprite_attr_name(ap_sprites[i].attrs), 263 ap_sprites[i].type, ap_sprites[i].subtype, ap_sprites[i].state, 264 ap_sprites[i].interaction, ap_sprites[i].hp, ap_sprites[i].drop, 265 PRIBBVF(ap_sprites[i]), XYL1BOXDIST(link, ap_sprites[i].tl, ap_sprites[i].br)); 266 } 267 //LOG("Overlord %#x timer: %#x", ap_ram.overlord_types[7], ap_ram.overlord_timers[7]); 268 269 // This only works inside 270 // The blocks don't seem to update in real-time so not sure if this 271 // memory region is actually useful 272 for (size_t i = 0; i < ARRAYLEN(ap_pushblocks); i++) { 273 if (XYEQ(ap_pushblocks[i].tl, XY(0, 0))) { 274 continue; 275 } 276 LOG("Pushblock: " PRIXYV, PRIXYVF(ap_pushblocks[i].tl)); 277 } 278} 279 280const char * ap_door_attr_name(uint16_t idx) { 281 uint16_t attr = ap_door_attrs[idx]; 282 static char sbuf[1024]; 283 char *buf = sbuf; 284 if (!attr) { 285 sprintf(buf, "unknown:%#x", idx); 286 return sbuf; 287 } 288 289#define X(d) if (attr & CONCAT(DOOR_ATTR_, d)) { \ 290 if (buf != sbuf) { *buf++ = '|'; } \ 291 buf += sprintf(buf, STRINGIFY(d)); \ 292 } 293DOOR_ATTR_LIST 294#undef X 295 return sbuf; 296} 297 298const char * const ap_inventory_names[] = { 299#define X(i, n) [i] = STRINGIFY(n), 300INVENTORY_LIST 301#undef X 302}; 303 304struct ap_ancillia ap_ancillia[N_ANCILLIA]; 305 306void 307ap_ancillia_update() { 308 for (size_t i = 0; i < N_ANCILLIA; i++) { 309 struct ap_ancillia * ancillia = &ap_ancillia[i]; 310 ancillia->type = ap_ram.ancillia_type[i]; 311 ancillia->attrs = ap_ancillia_attrs[ancillia->type]; 312 ancillia->bf0 = ap_ram.ancillia_bf0[i]; 313 314 ancillia->tl = XY(ap_ram.ancillia_x_lo[i], ap_ram.ancillia_y_lo[i]); 315 ancillia->tl.x += ap_ram.ancillia_x_hi[i] << 8u; 316 ancillia->tl.y += ap_ram.ancillia_y_hi[i] << 8u; 317 if (*ap_ram.in_building) { 318 ancillia->tl.x = ((ancillia->tl.x & ~0x1FF) << 2) | (ancillia->tl.x & 0x1FF); 319 ancillia->tl.x += 0x4000; 320 if (!ap_ram.ancillia_lower_level[i]) { 321 ancillia->tl.x += 0x200; 322 } 323 } 324 ancillia->br = XYOP1(ancillia->tl, +15); 325 326 ancillia->subpixel = XY(ap_ram.ancillia_x_sub[i], ap_ram.ancillia_y_sub[i]); 327 ancillia->velocity = XY(ap_ram.ancillia_x_vel[i], ap_ram.ancillia_y_vel[i]); 328 } 329} 330 331void 332ap_ancillia_print() { 333 const struct xy link = ap_link_xy(); 334 bool printed_any = false; 335 for (size_t i = 0; i < N_ANCILLIA; i++) { 336 const struct ap_ancillia * ancillia = &ap_ancillia[i]; 337 if (ancillia->type == 0) { 338 continue; 339 } 340 LOG("Ancillia %zu: type=%#x bf0=%#x " PRIXYV " dist=%d", 341 i, ancillia->type, ancillia->bf0, 342 PRIXYVF(ancillia->tl), XYL1DIST(link, ancillia->tl)); 343 printed_any = true; 344 } 345 if (!printed_any) { 346 LOG("No Ancillia"); 347 } 348} 349 350const char * 351ap_quadrant_print(uint8_t quadmask) { 352 static char sbuf[8]; 353 char *buf = sbuf; 354 if (quadmask & QUAD_A) *buf++ = 'A'; 355 if (quadmask & QUAD_B) *buf++ = 'B'; 356 if (quadmask & QUAD_C) *buf++ = 'C'; 357 if (quadmask & QUAD_D) *buf++ = 'D'; 358 *buf++ = '\0'; 359 return sbuf; 360} 361 362const char * ap_room_tag_print(const struct ap_room_tag * tag) { 363 if (tag == NULL) { 364 return ""; 365 } 366 367 const char *action = "(unknown)"; 368 switch(tag->action) { 369#define X(n) case CONCAT(ROOM_ACTION_, n): action = STRINGIFY(n); break; 370ROOM_ACTION_LIST 371#undef X 372 } 373 374 const char *result = "(unknown)"; 375 switch(tag->result) { 376#define X(n) case CONCAT(ROOM_RESULT_, n): result = STRINGIFY(n); break; 377ROOM_RESULT_LIST 378#undef X 379 } 380 381 static char sbuf[256]; 382 snprintf(sbuf, sizeof(sbuf), "%s:%s:%s", 383 ap_quadrant_print(tag->quadmask), action, result); 384 return sbuf; 385}