]> git.localhorst.tv Git - alttp.git/blob - resources/js/helpers/alttp-ram.js
adlib chat
[alttp.git] / resources / js / helpers / alttp-ram.js
1 export const RAM_ADDR = {
2         PRIZE_MAP: 0x1209B,
3         FREE_ITEM_MENU: 0x180045,
4         CRYSTAL_MAP: 0x180050,
5         GT_CRYSTALS: 0x18019A,
6         GANON_TYPE: 0x1801A8,
7         SEED_TYPE: 0x180210,
8         INIT_SRAM: 0x183000,
9 };
10
11 export const SRAM_ADDR = {
12         ROOM_DATA_START: 0x000,
13         ROOM_DATA_END: 0x250,
14         OW_DATA_START: 0x280,
15         PYRAMID_SCREEN: 0x2DB,
16         OW_DATA_END: 0x300,
17         INV_START: 0x340,
18         INV_END: 0x4EF,
19 };
20
21 export const WRAM_ADDR = {
22         GAME_MODE: 0x10,
23         CURRENT_DUNGEON: 0x10E,
24         SAVE_DATA: 0xF000,
25 };
26
27 export const INV_ADDR = {
28         BOW: 0x00,
29         BOOM: 0x01,
30         HOOK: 0x02,
31         BOMB: 0x03,
32         POWDER: 0x04,
33         FROD: 0x05,
34         IROD: 0x06,
35         BOMBOS: 0x07,
36         ETHER: 0x08,
37         QUAKE: 0x09,
38         LAMP: 0x0A,
39         HAMMER: 0x0B,
40         FLUTE: 0x0C,
41         BUGNET: 0x0D,
42         BOOK: 0x0E,
43         BOTTLE: 0x0F,
44         SOMARIA: 0x10,
45         BYRNA: 0x11,
46         CAPE: 0x12,
47         MIRROR: 0x13,
48         GLOVE: 0x14,
49         BOOTS: 0x15,
50         FLIPPERS: 0x16,
51         MOONPEARL: 0x17,
52         SWORD: 0x19,
53         SHIELD: 0x1A,
54         ARMOR: 0x1B,
55         BOTTLE_1: 0x1C,
56         BOTTLE_2: 0x1D,
57         BOTTLE_3: 0x1E,
58         BOTTLE_4: 0x1F,
59         WALLET: 0x20,
60         RUPEES: 0x22,
61         COMPASS: 0x24,
62         BIG_KEY: 0x26,
63         MAP: 0x28,
64         HEART_PIECE: 0x2B,
65         HEALTH: 0x2C,
66         MAGIC: 0x2E,
67         KEYS: 0x2F,
68         PENDANTS: 0x34,
69         ARROWS: 0x37,
70         ABILITIES: 0x39,
71         CRYSTALS: 0x3A,
72         MAGIC_USE: 0x3B,
73         SMALL_KEY_START: 0x3C,
74         SMALL_KEY_END: 0x4C,
75         RANDO_BOOM: 0x4C,
76         RANDO_POWDER: 0x4C,
77         RANDO_FLUTE: 0x4C,
78         RANDO_BOW: 0x4E,
79         RANDO_CHECKS_START: 0x180,
80         RANDO_CHECKS_END: 0x18F,
81         RANDO_KEY_START: 0x1A0,
82         RANDO_KEY_END: 0x1AF,
83 };
84
85 export const DUNGEON_IDS = {
86         SEWERS: 0,
87         HC: 1,
88         EP: 2,
89         DP: 3,
90         CT: 4,
91         SP: 5,
92         PD: 6,
93         MM: 7,
94         SW: 8,
95         IP: 9,
96         TH: 10,
97         TT: 11,
98         TR: 12,
99         GT: 13,
100 };
101
102 export const DUNGEON_MASKS = {
103         SEWERS: 0x0080,
104         HC: 0x0040,
105         EP: 0x0020,
106         DP: 0x0010,
107         CT: 0x0008,
108         SP: 0x0004,
109         PD: 0x0002,
110         MM: 0x0001,
111         SW: 0x8000,
112         IP: 0x4000,
113         TH: 0x2000,
114         TT: 0x1000,
115         TR: 0x0800,
116         GT: 0x0400,
117 };
118
119 export const ABILITY_MASKS = {
120         SWIM: 0x02,
121         DASH: 0x04,
122         PULL: 0x08,
123         TALK: 0x20,
124         READ: 0x40,
125 };
126
127 export const IN_GAME_MODES = [
128         0x05, // loading game
129         0x06, // entering dungeon
130         0x07, // dungeon
131         0x08, // entering overworld
132         0x09, // overworld
133         0x0A, // entering special overworld
134         0x0B, // special overworld
135         0x0E, // text/menu/map
136         0x0F, // closing spot
137         0x10, // opening spot
138         0x11, // falling
139         0x12, // dying
140         0x13, // fanfare
141         0x15, // mirror
142         0x16, // refill
143         0x17, // S&Q
144         0x18, // aga 2 cutscene
145         0x19, // triforce room
146         0x1B, // spawn select
147 ];
148
149 export const getShort = (data, offset) => (data[offset] * 256) + data[offset + 1];
150
151 export const buildPrizeMap = (prizes, crystals) => {
152         const map = {};
153         Object.entries(DUNGEON_IDS).forEach(([, id]) => {
154                 const isCrystal = !!(crystals && crystals[id]);
155                 const mask = (prizes && prizes[id]) || 0;
156                 map[id] = { isCrystal, mask };
157         });
158         return map;
159 };
160
161 export const isBossDefeated = (data, room) => {
162         return !!(data && (data[(2 * room) + 1] & 0x08));
163 };
164
165 export const isChestOpen = (data, room, chest) => {
166         if (chest < 4) {
167                 return !!(data && (data[2 * room] & Math.pow(2, chest + 4)));
168         } else {
169                 return !!(data && (data[(2 * room) + 1] & Math.pow(2, chest - 4)));
170         }
171 };
172
173 export const hasVisitedQuadrant = (data, room, quadrant) => {
174         return !!(data && (data[2 * room] & Math.pow(2, quadrant - 1)));
175 };
176
177 export const GT_BASEMENT_CHECKS = [
178         'iceM',
179         'iceL',
180         'iceR',
181         'dmUL',
182         'dmUR',
183         'dmBL',
184         'dmBR',
185         'randoUL',
186         'randoUR',
187         'randoBL',
188         'randoBR',
189         'fireSnake',
190         'mapChest',
191         'hopeL',
192         'hopeR',
193         'bobsChest',
194         'torchSeen',
195         'tileRoom',
196         'compassUL',
197         'compassUR',
198         'compassBL',
199         'compassBR',
200 ];
201
202 export const GT_BASEMENT_ALL = [
203         'iceM',
204         'iceL',
205         'iceR',
206         'dmUL',
207         'dmUR',
208         'dmBL',
209         'dmBR',
210         'randoUL',
211         'randoUR',
212         'randoBL',
213         'randoBR',
214         'fireSnake',
215         'mapChest',
216         'hopeL',
217         'hopeR',
218         'bobsChest',
219         'torch',
220         'torchSeen',
221         'tileRoom',
222         'compassUL',
223         'compassUR',
224         'compassBL',
225         'compassBR',
226 ];
227
228 export const getGTBasementState = (data) => ({
229         iceM: isChestOpen(data, 0x1C, 0),
230         iceL: isChestOpen(data, 0x1C, 1),
231         iceR: isChestOpen(data, 0x1C, 2),
232         dmUL: isChestOpen(data, 0x7B, 0),
233         dmUR: isChestOpen(data, 0x7B, 1),
234         dmBL: isChestOpen(data, 0x7B, 2),
235         dmBR: isChestOpen(data, 0x7B, 3),
236         randoUL: isChestOpen(data, 0x7C, 0),
237         randoUR: isChestOpen(data, 0x7C, 1),
238         randoBL: isChestOpen(data, 0x7C, 2),
239         randoBR: isChestOpen(data, 0x7C, 3),
240         fireSnake: isChestOpen(data, 0x7D, 0),
241         mapChest: isChestOpen(data, 0x8B, 0),
242         hopeL: isChestOpen(data, 0x8C, 1),
243         hopeR: isChestOpen(data, 0x8C, 2),
244         bobsChest: isChestOpen(data, 0x8C, 3),
245         torchSeen: hasVisitedQuadrant(data, 0x8C, 4),
246         torch: isChestOpen(data, 0x8C, 6),
247         tileRoom: isChestOpen(data, 0x8D, 0),
248         compassUL: isChestOpen(data, 0x9D, 0),
249         compassUR: isChestOpen(data, 0x9D, 1),
250         compassBL: isChestOpen(data, 0x9D, 2),
251         compassBR: isChestOpen(data, 0x9D, 3),
252 });
253
254 export const countGTBasementState = (state) =>
255         GT_BASEMENT_CHECKS.reduce((acc, cur) => state[cur] ? acc + 1 : acc, 0);
256
257 export const compareGTBasementState = (prev, cur) => {
258         for (let i = 0; i < GT_BASEMENT_ALL.length; ++i) {
259                 if (prev[GT_BASEMENT_ALL[i]] !== cur[GT_BASEMENT_ALL[i]]) {
260                         return GT_BASEMENT_ALL[i];
261                 }
262         }
263         return '';
264 };