ap_req.c128 lines · 3.6 KB · raw
1#include "ap_req.h"
2#include "bm.h"
3
4const char * const ap_requirement_names[] = {
5#define X(i, n) [CONCAT(REQUIREMENT_, n)] = STRINGIFY(n),
6REQUIREMENT_LIST
7#undef X
8    NULL,
9};
10
11static struct ap_reqmask current_reqmask = {0};
12
13static void reqmask_set(struct ap_reqmask * mask, enum ap_requirement req) {
14    assert(req < _REQUIREMENT_MAX);
15    BM_SET(mask->bits, req);
16}
17
18static bool reqmask_match(const struct ap_reqmask * src) {
19    if (BM_ISEMPTY(src->bits)) return false;
20    return BM_ISMATCH(src->bits, current_reqmask.bits);
21}
22
23static void reqmask_print(const struct ap_reqmask * mask, char **buf_p) {
24    char * buf = *buf_p;
25    if (BM_ISEMPTY(mask->bits)) {
26        buf += sprintf(buf, "None");
27    } else {
28        bool first = true;
29        for (int i = 0; i < _REQUIREMENT_MAX; i++) {
30            if (BM_ISSET(mask->bits, i)) {
31                if (first) {
32                    first = false;
33                } else {
34                    *buf++ = '&';
35                }
36                buf += sprintf(buf, "%s", ap_requirement_names[i]);
37            }
38        }
39    }
40    *buf_p = buf;
41}
42
43void ap_req_update() {
44    memset(&current_reqmask, 0, sizeof(current_reqmask));
45#define X(i, n) \
46    if (i != 0 && ap_ram.inventory_base[i] != 0) { \
47        reqmask_set(&current_reqmask, CONCAT(REQUIREMENT_, n)); \
48    }
49    REQUIREMENT_LIST
50#undef X
51    if (*ap_ram.inventory_sword > 1) {
52        reqmask_set(&current_reqmask, REQUIREMENT_MASTER_SWORD);
53    }
54    if (*ap_ram.dungeon_current_keys> 0) {
55        // XXX how to handle this across dungeons
56        reqmask_set(&current_reqmask, REQUIREMENT_KEY);
57    }
58    if (*ap_ram.sram_pendants & 0x01) {
59        reqmask_set(&current_reqmask, REQUIREMENT_GREEN_PENDANT);
60    }
61    if ((*ap_ram.sram_pendants & 0x07) == 0x07) {
62        reqmask_set(&current_reqmask, REQUIREMENT_ALL_PENDANTS);
63    }
64    if ((*ap_ram.sram_crystals & 0x05) == 0x05) {
65        reqmask_set(&current_reqmask, REQUIREMENT_FIVESIX_CRYSTALS);
66    }
67    if ((*ap_ram.sram_crystals & 0x7F) == 0x7F) {
68        reqmask_set(&current_reqmask, REQUIREMENT_ALL_CRYSTALS);
69    }
70    if (*ap_ram.inventory_gloves >= 1) {
71        reqmask_set(&current_reqmask, REQUIREMENT_GLOVES_1);
72    }
73    if (*ap_ram.inventory_gloves >= 2) {
74        reqmask_set(&current_reqmask, REQUIREMENT_GLOVES_2);
75    }
76}
77
78void ap_req_init(struct ap_req * req) {
79    memset(req, 0x00, sizeof(*req));
80}
81
82void ap_req_require(struct ap_req * req, size_t slot, uint16_t requirement) {
83    assert(slot < AP_REQ_SLOTS);
84    assert(requirement < (uint16_t) _REQUIREMENT_MAX);
85    reqmask_set(&req->alternative_requirements[slot], requirement);
86}
87
88bool ap_req_is_satisfied(const struct ap_req * req) {
89    bool all_zero = true;
90    for (size_t i = 0; i < AP_REQ_SLOTS; i++) {
91        if (reqmask_match(&req->alternative_requirements[i])) {
92            return true;
93        }
94        if (!BM_ISEMPTY(req->alternative_requirements[i].bits)) {
95            all_zero = false;
96        }
97    }
98    return all_zero;
99}
100
101const char * ap_req_print(const struct ap_req * req) {
102    static char sbuf[4096];
103    char *buf = sbuf;
104    if (req == NULL) {
105        reqmask_print(&current_reqmask, &buf);
106        return sbuf;
107    }
108
109    *buf++ = '[';
110    bool first = true;
111    for (size_t i = 0; i < AP_REQ_SLOTS; i++) {
112        if (BM_ISEMPTY(req->alternative_requirements[i].bits)) {
113            continue;
114        }
115        if (first) {
116            first = false;
117        } else {
118            buf += sprintf(buf, " | ");
119        }
120        reqmask_print(&req->alternative_requirements[i], &buf);
121    }
122    if (first) {
123        buf += sprintf(buf, "Any");
124    }
125    *buf++ = ']';
126    *buf++ = '\0';
127    return sbuf;
128}