ap_snes.c385 lines · 11.6 KB · raw
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}