]> git.localhorst.tv Git - alttp.git/blob - resources/js/helpers/tracker.js
fix missing gt bosses on merge
[alttp.git] / resources / js / helpers / tracker.js
1 import {
2         DUNGEON_IDS,
3         DUNGEON_MASKS,
4         INV_ADDR,
5         SRAM_ADDR,
6         getShort,
7         isBossDefeated,
8         isChestOpen,
9 } from './alttp-ram';
10 import Logic from './logic';
11
12 export const BOOLEAN_STATES = [
13         'blue-boomerang',
14         'bomb',
15         'bombos',
16         'bow',
17         'bowless-silvers',
18         'book',
19         'boots',
20         'bugnet',
21         'byrna',
22         'cape',
23         'duck',
24         'ether',
25         'fire-rod',
26         'flippers',
27         'flute',
28         'half-magic',
29         'hammer',
30         'hookshot',
31         'ice-rod',
32         'lamp',
33         'mirror',
34         'moonpearl',
35         'mushroom',
36         'powder',
37         'quake',
38         'quarter-magic',
39         'red-boomerang',
40         'shovel',
41         'silvers',
42         'somaria',
43 ];
44
45 export const INTEGER_STATES = [
46         'bottle',
47         'heart-piece',
48         'lift',
49         'mail',
50         'shield',
51         'sword',
52 ];
53
54 export const INITIAL = {
55         mail: 1,
56 };
57
58 export const BOSSES = [
59         'armos',
60         'lanmolas',
61         'moldorm',
62         'helma',
63         'arrghus',
64         'mothula',
65         'blind',
66         'kholdstare',
67         'vitreous',
68         'trinexx',
69 ];
70
71 export const CONFIG = {
72         bossShuffle: false,
73         glitches: 'none',
74         showMap: 'situational',
75         showCompass: 'situational',
76         showSmall: 'always',
77         showBig: 'always',
78         wildMap: false,
79         wildCompass: false,
80         wildSmall: false,
81         wildBig: false,
82         worldState: 'open',
83 };
84
85 export const DUNGEONS = [
86         {
87                 id: 'hc',
88                 map: true,
89                 compass: false,
90                 sk: 1,
91                 bk: true,
92                 dropBk: true,
93                 items: 6,
94                 boss: null,
95                 bosses: [],
96                 bossRoom: 0x80,
97                 prize: false,
98                 offset: DUNGEON_IDS.HC,
99                 mask: DUNGEON_MASKS.HC,
100                 checks: [
101                         'dark-cross',
102                         'hc-map-chest',
103                         'hc-boom',
104                         'hc-cell',
105                         'sanc',
106                         'sewers-left',
107                         'sewers-mid',
108                         'sewers-right',
109                 ],
110         },
111         {
112                 id: 'ct',
113                 map: false,
114                 compass: false,
115                 sk: 2,
116                 bk: false,
117                 items: 0,
118                 boss: 'aga',
119                 bosses: ['aga'],
120                 bossRoom: 0x20,
121                 prize: false,
122                 offset: DUNGEON_IDS.CT,
123                 mask: DUNGEON_MASKS.CT,
124                 checks: [
125                         'ct-1',
126                         'ct-2',
127                 ],
128         },
129         {
130                 id: 'gt',
131                 map: true,
132                 compass: true,
133                 sk: 4,
134                 bk: true,
135                 items: 20,
136                 boss: 'aga',
137                 bosses: ['aga'],
138                 bossRoom: 0x0D,
139                 prize: false,
140                 offset: DUNGEON_IDS.GT,
141                 mask: DUNGEON_MASKS.GT,
142                 checks: [
143                         'gt-hope-left',
144                         'gt-hope-right',
145                         'gt-tile-room',
146                         'gt-compass-tl',
147                         'gt-compass-tr',
148                         'gt-compass-bl',
149                         'gt-compass-br',
150                         'gt-torch',
151                         'gt-dm-tl',
152                         'gt-dm-tr',
153                         'gt-dm-bl',
154                         'gt-dm-br',
155                         'gt-map-chest',
156                         'gt-firesnake',
157                         'gt-rando-tl',
158                         'gt-rando-tr',
159                         'gt-rando-bl',
160                         'gt-rando-br',
161                         'gt-bobs-chest',
162                         'gt-ice-left',
163                         'gt-ice-mid',
164                         'gt-ice-right',
165                         'gt-big-chest',
166                         'gt-helma-left',
167                         'gt-helma-right',
168                         'gt-pre-moldorm',
169                         'gt-post-moldorm',
170                 ],
171         },
172         {
173                 id: 'ep',
174                 map: true,
175                 compass: true,
176                 sk: 0,
177                 bk: true,
178                 items: 3,
179                 boss: 'armos',
180                 bosses: ['armos'],
181                 bossRoom: 0xC8,
182                 prize: true,
183                 isPendant: true,
184                 prizeMask: 0x04,
185                 offset: DUNGEON_IDS.EP,
186                 mask: DUNGEON_MASKS.EP,
187                 checks: [
188                         'ep-cannonball',
189                         'ep-map-chest',
190                         'ep-compass-chest',
191                         'ep-big-chest',
192                         'ep-big-key-chest',
193                         'ep-boss-defeated',
194                 ],
195         },
196         {
197                 id: 'dp',
198                 map: true,
199                 compass: true,
200                 sk: 1,
201                 bk: true,
202                 items: 2,
203                 boss: 'lanmolas',
204                 bosses: ['lanmolas'],
205                 bossRoom: 0x33,
206                 prize: true,
207                 isPendant: true,
208                 prizeMask: 0x02,
209                 offset: DUNGEON_IDS.DP,
210                 mask: DUNGEON_MASKS.DP,
211                 checks: [
212                         'dp-torch',
213                         'dp-map-chest',
214                         'dp-big-chest',
215                         'dp-compass-chest',
216                         'dp-big-key-chest',
217                         'dp-boss-defeated',
218                 ],
219         },
220         {
221                 id: 'th',
222                 map: true,
223                 compass: true,
224                 sk: 1,
225                 bk: true,
226                 items: 2,
227                 boss: 'moldorm',
228                 bosses: ['moldorm'],
229                 bossRoom: 0x07,
230                 prize: true,
231                 isPendant: true,
232                 prizeMask: 0x01,
233                 offset: DUNGEON_IDS.TH,
234                 mask: DUNGEON_MASKS.TH,
235                 checks: [
236                         'th-basement-cage',
237                         'th-map-chest',
238                         'th-big-key-chest',
239                         'th-compass-chest',
240                         'th-big-chest',
241                         'th-boss-defeated',
242                 ],
243         },
244         {
245                 id: 'pd',
246                 map: true,
247                 compass: true,
248                 sk: 6,
249                 bk: true,
250                 items: 5,
251                 boss: 'helma',
252                 bosses: ['helma'],
253                 bossRoom: 0x5A,
254                 prize: true,
255                 prizeMask: 0x02,
256                 offset: DUNGEON_IDS.PD,
257                 mask: DUNGEON_MASKS.PD,
258                 checks: [
259                         'pd-shooter-room',
260                         'pd-stalfos-basement',
261                         'pd-big-key-chest',
262                         'pd-arena-bridge',
263                         'pd-arena-ledge',
264                         'pd-map-chest',
265                         'pd-compass-chest',
266                         'pd-basement-left',
267                         'pd-basement-right',
268                         'pd-harmless-hellway',
269                         'pd-maze-top',
270                         'pd-maze-bottom',
271                         'pd-big-chest',
272                         'pd-boss-defeated',
273                 ],
274         },
275         {
276                 id: 'sp',
277                 map: true,
278                 compass: true,
279                 sk: 1,
280                 bk: true,
281                 items: 6,
282                 boss: 'arrghus',
283                 bosses: ['arrghus'],
284                 bossRoom: 0x06,
285                 prize: true,
286                 prizeMask: 0x10,
287                 offset: DUNGEON_IDS.SP,
288                 mask: DUNGEON_MASKS.SP,
289                 checks: [
290                         'sp-lobby',
291                         'sp-map-chest',
292                         'sp-big-chest',
293                         'sp-compass-chest',
294                         'sp-west-chest',
295                         'sp-big-key-chest',
296                         'sp-flooded-left',
297                         'sp-flooded-right',
298                         'sp-waterfall',
299                         'sp-boss-defeated',
300                 ],
301         },
302         {
303                 id: 'sw',
304                 map: true,
305                 compass: true,
306                 sk: 3,
307                 bk: true,
308                 items: 2,
309                 boss: 'mothula',
310                 bosses: ['mothula'],
311                 bossRoom: 0x29,
312                 prize: true,
313                 prizeMask: 0x40,
314                 offset: DUNGEON_IDS.SW,
315                 mask: DUNGEON_MASKS.SW,
316                 checks: [
317                         'sw-big-chest',
318                         'sw-map-chest',
319                         'sw-pot-prison',
320                         'sw-compass-chest',
321                         'sw-pinball-room',
322                         'sw-big-key-chest',
323                         'sw-bridge-chest',
324                         'sw-boss-defeated',
325                 ],
326         },
327         {
328                 id: 'tt',
329                 map: true,
330                 compass: true,
331                 sk: 1,
332                 bk: true,
333                 items: 4,
334                 boss: 'blind',
335                 bosses: ['blind'],
336                 bossRoom: 0xAC,
337                 prize: true,
338                 prizeMask: 0x20,
339                 offset: DUNGEON_IDS.TT,
340                 mask: DUNGEON_MASKS.TT,
341                 checks: [
342                         'tt-map-chest',
343                         'tt-ambush-chest',
344                         'tt-compass-chest',
345                         'tt-big-key-chest',
346                         'tt-attic',
347                         'tt-cell',
348                         'tt-big-chest',
349                         'tt-boss-defeated',
350                 ],
351         },
352         {
353                 id: 'ip',
354                 map: true,
355                 compass: true,
356                 sk: 2,
357                 bk: true,
358                 items: 3,
359                 boss: 'kholdstare',
360                 bosses: ['kholdstare'],
361                 bossRoom: 0xDE,
362                 prize: true,
363                 prizeMask: 0x04,
364                 offset: DUNGEON_IDS.IP,
365                 mask: DUNGEON_MASKS.IP,
366                 checks: [
367                         'ip-compass-chest',
368                         'ip-big-key-chest',
369                         'ip-map-chest',
370                         'ip-spike-chest',
371                         'ip-freezor-chest',
372                         'ip-big-chest',
373                         'ip-ice-t',
374                         'ip-boss-defeated',
375                 ],
376         },
377         {
378                 id: 'mm',
379                 map: true,
380                 compass: true,
381                 sk: 3,
382                 bk: true,
383                 items: 2,
384                 boss: 'vitreous',
385                 bosses: ['vitreous'],
386                 bossRoom: 0x90,
387                 prize: true,
388                 prizeMask: 0x01,
389                 offset: DUNGEON_IDS.MM,
390                 mask: DUNGEON_MASKS.MM,
391                 checks: [
392                         'mm-bridge-chest',
393                         'mm-spike-chest',
394                         'mm-lobby-chest',
395                         'mm-compass-chest',
396                         'mm-big-key-chest',
397                         'mm-big-chest',
398                         'mm-map-chest',
399                         'mm-boss-defeated',
400                 ],
401         },
402         {
403                 id: 'tr',
404                 map: true,
405                 compass: true,
406                 sk: 4,
407                 bk: true,
408                 items: 5,
409                 boss: 'trinexx',
410                 bosses: ['trinexx'],
411                 bossRoom: 0xA4,
412                 prize: true,
413                 prizeMask: 0x08,
414                 offset: DUNGEON_IDS.TR,
415                 mask: DUNGEON_MASKS.TR,
416                 checks: [
417                         'tr-roller-left',
418                         'tr-roller-right',
419                         'tr-compass-chest',
420                         'tr-chomps',
421                         'tr-big-key-chest',
422                         'tr-big-chest',
423                         'tr-crysta-roller',
424                         'tr-laser-bridge-top',
425                         'tr-laser-bridge-left',
426                         'tr-laser-bridge-right',
427                         'tr-laser-bridge-bottom',
428                         'tr-boss-defeated',
429                 ],
430         },
431 ];
432
433 export const OVERWORLD_LOCATIONS = [
434         {
435                 id: 'blacksmith',
436                 address: 0x411,
437                 mask: 0x04,
438         },
439         {
440                 id: 'bombos-tablet',
441                 address: 0x411,
442                 mask: 0x02,
443         },
444         {
445                 id: 'bottle-vendor',
446                 address: 0x3C9,
447                 mask: 0x02,
448         },
449         {
450                 id: 'bumper-cave',
451                 address: 0x2CA,
452                 mask: 0x40,
453         },
454         {
455                 id: 'catfish',
456                 address: 0x410,
457                 mask: 0x20,
458         },
459         {
460                 id: 'desert-ledge',
461                 address: 0x2B0,
462                 mask: 0x40,
463         },
464         {
465                 id: 'digging-game',
466                 address: 0x2E8,
467                 mask: 0x40,
468         },
469         {
470                 id: 'ether-tablet',
471                 address: 0x411,
472                 mask: 0x01,
473         },
474         {
475                 id: 'floating-island',
476                 address: 0x285,
477                 mask: 0x40,
478         },
479         {
480                 id: 'flute-spot',
481                 address: 0x2AA,
482                 mask: 0x40,
483         },
484         {
485                 id: 'hobo',
486                 address: 0x3C9,
487                 mask: 0x01,
488         },
489         {
490                 id: 'lake-hylia-island',
491                 address: 0x2B5,
492                 mask: 0x40,
493         },
494         {
495                 id: 'library',
496                 address: 0x410,
497                 mask: 0x80,
498         },
499         {
500                 id: 'magic-bat',
501                 address: 0x411,
502                 mask: 0x80,
503         },
504         {
505                 id: 'mushroom-spot',
506                 address: 0x411,
507                 mask: 0x10,
508         },
509         {
510                 id: 'old-man',
511                 address: 0x410,
512                 mask: 0x01,
513         },
514         {
515                 id: 'pedestal',
516                 address: 0x300,
517                 mask: 0x40,
518         },
519         {
520                 id: 'potion-shop',
521                 address: 0x411,
522                 mask: 0x20,
523         },
524         {
525                 id: 'purple-chest',
526                 address: 0x3C9,
527                 mask: 0x10,
528         },
529         {
530                 id: 'pyramid',
531                 address: 0x2DB,
532                 mask: 0x40,
533         },
534         {
535                 id: 'race-game',
536                 address: 0x2A8,
537                 mask: 0x40,
538         },
539         {
540                 id: 'saha',
541                 address: 0x410,
542                 mask: 0x10,
543         },
544         {
545                 id: 'sick-kid',
546                 address: 0x410,
547                 mask: 0x04,
548         },
549         {
550                 id: 'spec-rock',
551                 address: 0x283,
552                 mask: 0x40,
553         },
554         {
555                 id: 'stumpy',
556                 address: 0x410,
557                 mask: 0x08,
558         },
559         {
560                 id: 'sunken-treasure',
561                 address: 0x2BB,
562                 mask: 0x40,
563         },
564         {
565                 id: 'uncle',
566                 address: 0x3C6,
567                 mask: 0x01,
568         },
569         {
570                 id: 'zora',
571                 address: 0x410,
572                 mask: 0x02,
573         },
574         {
575                 id: 'zora-ledge',
576                 address: 0x301,
577                 mask: 0x40,
578         },
579 ];
580
581 export const UNDERWORLD_LOCATIONS = [
582         {
583                 id: 'aginah',
584                 room: 0x10A,
585                 chest: 0,
586         },
587         {
588                 id: 'blinds-hut-top',
589                 room: 0x11D,
590                 chest: 0,
591         },
592         {
593                 id: 'blinds-hut-left',
594                 room: 0x11D,
595                 chest: 1,
596         },
597         {
598                 id: 'blinds-hut-right',
599                 room: 0x11D,
600                 chest: 2,
601         },
602         {
603                 id: 'blinds-hut-far-left',
604                 room: 0x11D,
605                 chest: 3,
606         },
607         {
608                 id: 'blinds-hut-far-right',
609                 room: 0x11D,
610                 chest: 4,
611         },
612         {
613                 id: 'bonk-rocks',
614                 room: 0x124,
615                 chest: 0,
616         },
617         {
618                 id: 'brewery',
619                 room: 0x106,
620                 chest: 0,
621         },
622         {
623                 id: 'c-house',
624                 room: 0x11C,
625                 chest: 0,
626         },
627         {
628                 id: 'cave-45',
629                 room: 0x11B,
630                 chest: 6,
631         },
632         {
633                 id: 'checkerboard',
634                 room: 0x126,
635                 chest: 5,
636         },
637         {
638                 id: 'chest-game',
639                 room: 0x106,
640                 chest: 6,
641         },
642         {
643                 id: 'chicken-house',
644                 room: 0x108,
645                 chest: 0,
646         },
647         {
648                 id: 'ct-1',
649                 area: 'ct',
650                 room: 0xE0,
651                 chest: 0,
652         },
653         {
654                 id: 'ct-2',
655                 area: 'ct',
656                 room: 0xD0,
657                 chest: 0,
658         },
659         {
660                 id: 'dark-cross',
661                 area: 'hc',
662                 room: 0x32,
663                 chest: 0,
664         },
665         {
666                 id: 'dp-big-chest',
667                 area: 'dp',
668                 room: 0x73,
669                 chest: 0,
670         },
671         {
672                 id: 'dp-big-key-chest',
673                 area: 'dp',
674                 room: 0x75,
675                 chest: 0,
676         },
677         {
678                 id: 'dp-compass-chest',
679                 area: 'dp',
680                 room: 0x85,
681                 chest: 0,
682         },
683         {
684                 id: 'dp-map-chest',
685                 area: 'dp',
686                 room: 0x74,
687                 chest: 0,
688         },
689         {
690                 id: 'dp-torch',
691                 area: 'dp',
692                 room: 0x73,
693                 chest: 6,
694         },
695         {
696                 id: 'ep-big-chest',
697                 area: 'ep',
698                 room: 0xA9,
699                 chest: 0,
700         },
701         {
702                 id: 'ep-big-key-chest',
703                 area: 'ep',
704                 room: 0xB8,
705                 chest: 0,
706         },
707         {
708                 id: 'ep-cannonball',
709                 area: 'ep',
710                 room: 0xB9,
711                 chest: 0,
712         },
713         {
714                 id: 'ep-compass-chest',
715                 area: 'ep',
716                 room: 0xA8,
717                 chest: 0,
718         },
719         {
720                 id: 'ep-map-chest',
721                 area: 'ep',
722                 room: 0xAA,
723                 chest: 0,
724         },
725         {
726                 id: 'flooded-chest',
727                 room: 0x10B,
728                 chest: 0,
729         },
730         {
731                 id: 'graveyard-ledge',
732                 room: 0x11B,
733                 chest: 5,
734         },
735         {
736                 id: 'gt-hope-left',
737                 area: 'gt',
738                 room: 0x8C,
739                 chest: 1,
740         },
741         {
742                 id: 'gt-hope-right',
743                 area: 'gt',
744                 room: 0x8C,
745                 chest: 2,
746         },
747         {
748                 id: 'gt-tile-room',
749                 area: 'gt',
750                 room: 0x8D,
751                 chest: 0,
752         },
753         {
754                 id: 'gt-compass-tl',
755                 area: 'gt',
756                 room: 0x9D,
757                 chest: 0,
758         },
759         {
760                 id: 'gt-compass-tr',
761                 area: 'gt',
762                 room: 0x9D,
763                 chest: 1,
764         },
765         {
766                 id: 'gt-compass-bl',
767                 area: 'gt',
768                 room: 0x9D,
769                 chest: 2,
770         },
771         {
772                 id: 'gt-compass-br',
773                 area: 'gt',
774                 room: 0x9D,
775                 chest: 3,
776         },
777         {
778                 id: 'gt-torch',
779                 area: 'gt',
780                 room: 0x8C,
781                 chest: 6,
782         },
783         {
784                 id: 'gt-dm-tl',
785                 area: 'gt',
786                 room: 0x7B,
787                 chest: 0,
788         },
789         {
790                 id: 'gt-dm-tr',
791                 area: 'gt',
792                 room: 0x7B,
793                 chest: 1,
794         },
795         {
796                 id: 'gt-dm-bl',
797                 area: 'gt',
798                 room: 0x7B,
799                 chest: 2,
800         },
801         {
802                 id: 'gt-dm-br',
803                 area: 'gt',
804                 room: 0x7B,
805                 chest: 3,
806         },
807         {
808                 id: 'gt-map-chest',
809                 area: 'gt',
810                 room: 0x8B,
811                 chest: 0,
812         },
813         {
814                 id: 'gt-firesnake',
815                 area: 'gt',
816                 room: 0x7D,
817                 chest: 0,
818         },
819         {
820                 id: 'gt-rando-tl',
821                 area: 'gt',
822                 room: 0x7C,
823                 chest: 0,
824         },
825         {
826                 id: 'gt-rando-tr',
827                 area: 'gt',
828                 room: 0x7C,
829                 chest: 1,
830         },
831         {
832                 id: 'gt-rando-bl',
833                 area: 'gt',
834                 room: 0x7C,
835                 chest: 2,
836         },
837         {
838                 id: 'gt-rando-br',
839                 area: 'gt',
840                 room: 0x7C,
841                 chest: 3,
842         },
843         {
844                 id: 'gt-bobs-chest',
845                 area: 'gt',
846                 room: 0x8C,
847                 chest: 3,
848         },
849         {
850                 id: 'gt-ice-left',
851                 area: 'gt',
852                 room: 0x1C,
853                 chest: 1,
854         },
855         {
856                 id: 'gt-ice-mid',
857                 area: 'gt',
858                 room: 0x1C,
859                 chest: 0,
860         },
861         {
862                 id: 'gt-ice-right',
863                 area: 'gt',
864                 room: 0x1C,
865                 chest: 2,
866         },
867         {
868                 id: 'gt-big-chest',
869                 area: 'gt',
870                 room: 0x8C,
871                 chest: 0,
872         },
873         {
874                 id: 'gt-helma-left',
875                 area: 'gt',
876                 room: 0x3D,
877                 chest: 0,
878         },
879         {
880                 id: 'gt-helma-right',
881                 area: 'gt',
882                 room: 0x3D,
883                 chest: 1,
884         },
885         {
886                 id: 'gt-pre-moldorm',
887                 area: 'gt',
888                 room: 0x3D,
889                 chest: 2,
890         },
891         {
892                 id: 'gt-post-moldorm',
893                 area: 'gt',
894                 room: 0x4D,
895                 chest: 0,
896         },
897         {
898                 id: 'hammer-pegs',
899                 room: 0x127,
900                 chest: 6,
901         },
902         {
903                 id: 'hc-boom',
904                 area: 'hc',
905                 room: 0x71,
906                 chest: 0,
907         },
908         {
909                 id: 'hc-cell',
910                 area: 'hc',
911                 room: 0x80,
912                 chest: 0,
913         },
914         {
915                 id: 'hc-map-chest',
916                 area: 'hc',
917                 room: 0x72,
918                 chest: 0,
919         },
920         {
921                 id: 'hookshot-cave-br',
922                 room: 0x3C,
923                 chest: 3,
924         },
925         {
926                 id: 'hookshot-cave-tr',
927                 room: 0x3C,
928                 chest: 0,
929         },
930         {
931                 id: 'hookshot-cave-tl',
932                 room: 0x3C,
933                 chest: 1,
934         },
935         {
936                 id: 'hookshot-cave-bl',
937                 room: 0x3C,
938                 chest: 2,
939         },
940         {
941                 id: 'hype-cave-top',
942                 room: 0x11E,
943                 chest: 0,
944         },
945         {
946                 id: 'hype-cave-left',
947                 room: 0x11E,
948                 chest: 1,
949         },
950         {
951                 id: 'hype-cave-right',
952                 room: 0x11E,
953                 chest: 2,
954         },
955         {
956                 id: 'hype-cave-bottom',
957                 room: 0x11E,
958                 chest: 3,
959         },
960         {
961                 id: 'hype-cave-npc',
962                 room: 0x11E,
963                 chest: 6,
964         },
965         {
966                 id: 'ice-rod-cave',
967                 room: 0x120,
968                 chest: 0,
969         },
970         {
971                 id: 'ip-compass-chest',
972                 area: 'ip',
973                 room: 0x2E,
974                 chest: 0,
975         },
976         {
977                 id: 'ip-big-key-chest',
978                 area: 'ip',
979                 room: 0x1F,
980                 chest: 0,
981         },
982         {
983                 id: 'ip-map-chest',
984                 area: 'ip',
985                 room: 0x3F,
986                 chest: 0,
987         },
988         {
989                 id: 'ip-spike-chest',
990                 area: 'ip',
991                 room: 0x5F,
992                 chest: 0,
993         },
994         {
995                 id: 'ip-freezor-chest',
996                 area: 'ip',
997                 room: 0x7E,
998                 chest: 0,
999         },
1000         {
1001                 id: 'ip-big-chest',
1002                 area: 'ip',
1003                 room: 0x9E,
1004                 chest: 0,
1005         },
1006         {
1007                 id: 'ip-ice-t',
1008                 area: 'ip',
1009                 room: 0xAE,
1010                 chest: 0,
1011         },
1012         {
1013                 id: 'kak-well-top',
1014                 room: 0x2F,
1015                 chest: 0,
1016         },
1017         {
1018                 id: 'kak-well-left',
1019                 room: 0x2F,
1020                 chest: 1,
1021         },
1022         {
1023                 id: 'kak-well-mid',
1024                 room: 0x2F,
1025                 chest: 2,
1026         },
1027         {
1028                 id: 'kak-well-right',
1029                 room: 0x2F,
1030                 chest: 3,
1031         },
1032         {
1033                 id: 'kak-well-bottom',
1034                 room: 0x2F,
1035                 chest: 4,
1036         },
1037         {
1038                 id: 'kings-tomb',
1039                 room: 0x113,
1040                 chest: 0,
1041         },
1042         {
1043                 id: 'links-house',
1044                 room: 0x104,
1045                 chest: 0,
1046         },
1047         {
1048                 id: 'lost-woods-hideout',
1049                 room: 0xE1,
1050                 chest: 5,
1051         },
1052         {
1053                 id: 'lumberjack',
1054                 room: 0xE2,
1055                 chest: 5,
1056         },
1057         {
1058                 id: 'mimic-cave',
1059                 room: 0x10C,
1060                 chest: 0,
1061         },
1062         {
1063                 id: 'mini-moldorm-far-left',
1064                 room: 0x123,
1065                 chest: 0,
1066         },
1067         {
1068                 id: 'mini-moldorm-left',
1069                 room: 0x123,
1070                 chest: 1,
1071         },
1072         {
1073                 id: 'mini-moldorm-right',
1074                 room: 0x123,
1075                 chest: 2,
1076         },
1077         {
1078                 id: 'mini-moldorm-far-right',
1079                 room: 0x123,
1080                 chest: 3,
1081         },
1082         {
1083                 id: 'mini-moldorm-npc',
1084                 room: 0x123,
1085                 chest: 6,
1086         },
1087         {
1088                 id: 'mm-bridge-chest',
1089                 room: 0xA2,
1090                 chest: 0,
1091         },
1092         {
1093                 id: 'mm-spike-chest',
1094                 room: 0xB3,
1095                 chest: 0,
1096         },
1097         {
1098                 id: 'mm-lobby-chest',
1099                 room: 0xC2,
1100                 chest: 0,
1101         },
1102         {
1103                 id: 'mm-compass-chest',
1104                 room: 0xC1,
1105                 chest: 0,
1106         },
1107         {
1108                 id: 'mm-big-key-chest',
1109                 room: 0xD1,
1110                 chest: 0,
1111         },
1112         {
1113                 id: 'mm-big-chest',
1114                 room: 0xC3,
1115                 chest: 0,
1116         },
1117         {
1118                 id: 'mm-map-chest',
1119                 room: 0xC3,
1120                 chest: 1,
1121         },
1122         {
1123                 id: 'mire-shed-left',
1124                 room: 0x10D,
1125                 chest: 0,
1126         },
1127         {
1128                 id: 'mire-shed-right',
1129                 room: 0x10D,
1130                 chest: 1,
1131         },
1132         {
1133                 id: 'paradox-lower-far-left',
1134                 room: 0xEF,
1135                 chest: 0,
1136         },
1137         {
1138                 id: 'paradox-lower-left',
1139                 room: 0xEF,
1140                 chest: 1,
1141         },
1142         {
1143                 id: 'paradox-lower-right',
1144                 room: 0xEF,
1145                 chest: 2,
1146         },
1147         {
1148                 id: 'paradox-lower-far-right',
1149                 room: 0xEF,
1150                 chest: 3,
1151         },
1152         {
1153                 id: 'paradox-lower-mid',
1154                 room: 0xEF,
1155                 chest: 4,
1156         },
1157         {
1158                 id: 'paradox-upper-left',
1159                 room: 0xFF,
1160                 chest: 0,
1161         },
1162         {
1163                 id: 'paradox-upper-right',
1164                 room: 0xFF,
1165                 chest: 1,
1166         },
1167         {
1168                 id: 'pd-shooter-room',
1169                 room: 0x09,
1170                 chest: 0,
1171         },
1172         {
1173                 id: 'pd-stalfos-basement',
1174                 room: 0x0A,
1175                 chest: 0,
1176         },
1177         {
1178                 id: 'pd-big-key-chest',
1179                 room: 0x3A,
1180                 chest: 0,
1181         },
1182         {
1183                 id: 'pd-arena-bridge',
1184                 room: 0x2A,
1185                 chest: 1,
1186         },
1187         {
1188                 id: 'pd-arena-ledge',
1189                 room: 0x2A,
1190                 chest: 0,
1191         },
1192         {
1193                 id: 'pd-map-chest',
1194                 room: 0x2B,
1195                 chest: 0,
1196         },
1197         {
1198                 id: 'pd-big-chest',
1199                 room: 0x1A,
1200                 chest: 0,
1201         },
1202         {
1203                 id: 'pd-compass-chest',
1204                 room: 0x1A,
1205                 chest: 1,
1206         },
1207         {
1208                 id: 'pd-harmless-hellway',
1209                 room: 0x1A,
1210                 chest: 2,
1211         },
1212         {
1213                 id: 'pd-maze-top',
1214                 room: 0x19,
1215                 chest: 0,
1216         },
1217         {
1218                 id: 'pd-maze-bottom',
1219                 room: 0x19,
1220                 chest: 1,
1221         },
1222         {
1223                 id: 'pd-basement-left',
1224                 room: 0x6A,
1225                 chest: 0,
1226         },
1227         {
1228                 id: 'pd-basement-right',
1229                 room: 0x6A,
1230                 chest: 1,
1231         },
1232         {
1233                 id: 'pyramid-fairy-left',
1234                 room: 0x116,
1235                 chest: 0,
1236         },
1237         {
1238                 id: 'pyramid-fairy-right',
1239                 room: 0x116,
1240                 chest: 1,
1241         },
1242         {
1243                 id: 'saha-left',
1244                 room: 0x105,
1245                 chest: 0,
1246         },
1247         {
1248                 id: 'saha-mid',
1249                 room: 0x105,
1250                 chest: 1,
1251         },
1252         {
1253                 id: 'saha-right',
1254                 room: 0x105,
1255                 chest: 2,
1256         },
1257         {
1258                 id: 'sanc',
1259                 area: 'hc',
1260                 room: 0x12,
1261                 chest: 0,
1262         },
1263         {
1264                 id: 'secret-passage',
1265                 room: 0x55,
1266                 chest: 0,
1267         },
1268         {
1269                 id: 'sewers-left',
1270                 area: 'hc',
1271                 room: 0x11,
1272                 chest: 0,
1273         },
1274         {
1275                 id: 'sewers-mid',
1276                 area: 'hc',
1277                 room: 0x11,
1278                 chest: 1,
1279         },
1280         {
1281                 id: 'sewers-right',
1282                 area: 'hc',
1283                 room: 0x11,
1284                 chest: 2,
1285         },
1286         {
1287                 id: 'sp-lobby',
1288                 area: 'sp',
1289                 room: 0x28,
1290                 chest: 0,
1291         },
1292         {
1293                 id: 'sp-map-chest',
1294                 area: 'sp',
1295                 room: 0x37,
1296                 chest: 0,
1297         },
1298         {
1299                 id: 'sp-big-chest',
1300                 area: 'sp',
1301                 room: 0x36,
1302                 chest: 0,
1303         },
1304         {
1305                 id: 'sp-compass-chest',
1306                 area: 'sp',
1307                 room: 0x46,
1308                 chest: 0,
1309         },
1310         {
1311                 id: 'sp-west-chest',
1312                 area: 'sp',
1313                 room: 0x34,
1314                 chest: 0,
1315         },
1316         {
1317                 id: 'sp-big-key-chest',
1318                 area: 'sp',
1319                 room: 0x35,
1320                 chest: 0,
1321         },
1322         {
1323                 id: 'sp-flooded-left',
1324                 area: 'sp',
1325                 room: 0x76,
1326                 chest: 0,
1327         },
1328         {
1329                 id: 'sp-flooded-right',
1330                 area: 'sp',
1331                 room: 0x76,
1332                 chest: 1,
1333         },
1334         {
1335                 id: 'sp-waterfall',
1336                 area: 'sp',
1337                 room: 0x66,
1338                 chest: 0,
1339         },
1340         {
1341                 id: 'spec-rock-cave',
1342                 room: 0xEA,
1343                 chest: 6,
1344         },
1345         {
1346                 id: 'spike-cave',
1347                 room: 0x117,
1348                 chest: 0,
1349         },
1350         {
1351                 id: 'spiral-cave',
1352                 room: 0xFE,
1353                 chest: 0,
1354         },
1355         {
1356                 id: 'super-bunny-top',
1357                 room: 0xF8,
1358                 chest: 0,
1359         },
1360         {
1361                 id: 'super-bunny-bottom',
1362                 room: 0xF8,
1363                 chest: 0,
1364         },
1365         {
1366                 id: 'sw-big-chest',
1367                 area: 'sw',
1368                 room: 0x58,
1369                 chest: 0,
1370         },
1371         {
1372                 id: 'sw-map-chest',
1373                 area: 'sw',
1374                 room: 0x58,
1375                 chest: 1,
1376         },
1377         {
1378                 id: 'sw-compass-chest',
1379                 area: 'sw',
1380                 room: 0x67,
1381                 chest: 0,
1382         },
1383         {
1384                 id: 'sw-big-key-chest',
1385                 area: 'sw',
1386                 room: 0x57,
1387                 chest: 0,
1388         },
1389         {
1390                 id: 'sw-pot-prison',
1391                 area: 'sw',
1392                 room: 0x57,
1393                 chest: 1,
1394         },
1395         {
1396                 id: 'sw-pinball-room',
1397                 area: 'sw',
1398                 room: 0x68,
1399                 chest: 0,
1400         },
1401         {
1402                 id: 'sw-bridge-chest',
1403                 area: 'sw',
1404                 room: 0x59,
1405                 chest: 0,
1406         },
1407         {
1408                 id: 'tavern',
1409                 room: 0x103,
1410                 chest: 0,
1411         },
1412         {
1413                 id: 'th-basement-cage',
1414                 area: 'th',
1415                 room: 0x87,
1416                 chest: 6,
1417         },
1418         {
1419                 id: 'th-big-key-chest',
1420                 area: 'th',
1421                 room: 0x87,
1422                 chest: 0,
1423         },
1424         {
1425                 id: 'th-map-chest',
1426                 area: 'th',
1427                 room: 0x77,
1428                 chest: 0,
1429         },
1430         {
1431                 id: 'th-big-chest',
1432                 area: 'th',
1433                 room: 0x27,
1434                 chest: 0,
1435         },
1436         {
1437                 id: 'th-compass-chest',
1438                 area: 'th',
1439                 room: 0x27,
1440                 chest: 1,
1441         },
1442         {
1443                 id: 'tr-roller-left',
1444                 area: 'tr',
1445                 room: 0xB7,
1446                 chest: 0,
1447         },
1448         {
1449                 id: 'tr-roller-right',
1450                 area: 'tr',
1451                 room: 0xB7,
1452                 chest: 1,
1453         },
1454         {
1455                 id: 'tr-compass-chest',
1456                 area: 'tr',
1457                 room: 0xD6,
1458                 chest: 0,
1459         },
1460         {
1461                 id: 'tr-chomps',
1462                 area: 'tr',
1463                 room: 0xB6,
1464                 chest: 0,
1465         },
1466         {
1467                 id: 'tr-big-key-chest',
1468                 area: 'tr',
1469                 room: 0x14,
1470                 chest: 0,
1471         },
1472         {
1473                 id: 'tr-big-chest',
1474                 area: 'tr',
1475                 room: 0x24,
1476                 chest: 0,
1477         },
1478         {
1479                 id: 'tr-crysta-roller',
1480                 area: 'tr',
1481                 room: 0x04,
1482                 chest: 0,
1483         },
1484         {
1485                 id: 'tr-laser-bridge-top',
1486                 area: 'tr',
1487                 room: 0xD5,
1488                 chest: 0,
1489         },
1490         {
1491                 id: 'tr-laser-bridge-left',
1492                 area: 'tr',
1493                 room: 0xD5,
1494                 chest: 1,
1495         },
1496         {
1497                 id: 'tr-laser-bridge-right',
1498                 area: 'tr',
1499                 room: 0xD5,
1500                 chest: 2,
1501         },
1502         {
1503                 id: 'tr-laser-bridge-bottom',
1504                 area: 'tr',
1505                 room: 0xD5,
1506                 chest: 3,
1507         },
1508         {
1509                 id: 'tt-map-chest',
1510                 area: 'tt',
1511                 room: 0xDB,
1512                 chest: 0,
1513         },
1514         {
1515                 id: 'tt-big-key-chest',
1516                 area: 'tt',
1517                 room: 0xDB,
1518                 chest: 1,
1519         },
1520         {
1521                 id: 'tt-ambush-chest',
1522                 area: 'tt',
1523                 room: 0xCB,
1524                 chest: 0,
1525         },
1526         {
1527                 id: 'tt-compass-chest',
1528                 area: 'tt',
1529                 room: 0xDC,
1530                 chest: 0,
1531         },
1532         {
1533                 id: 'tt-attic',
1534                 area: 'tt',
1535                 room: 0x65,
1536                 chest: 0,
1537         },
1538         {
1539                 id: 'tt-cell',
1540                 area: 'tt',
1541                 room: 0x45,
1542                 chest: 0,
1543         },
1544         {
1545                 id: 'tt-big-chest',
1546                 area: 'tt',
1547                 room: 0x44,
1548                 chest: 0,
1549         },
1550         {
1551                 id: 'waterfall-fairy-left',
1552                 room: 0x114,
1553                 chest: 0,
1554         },
1555         {
1556                 id: 'waterfall-fairy-right',
1557                 room: 0x114,
1558                 chest: 1,
1559         },
1560 ];
1561
1562 export const applyLogic = (config, dungeons, state) => {
1563         const logic = Logic[config.worldState];
1564         const map = {};
1565         for (const name in logic) {
1566                 map[name] = logic[name](config, dungeons, state);
1567         }
1568         return map;
1569 };
1570
1571 export const shouldShowDungeonItem = (config, which) => {
1572         const show = config[`show${which}`] || 'always';
1573         const wild = config[`wild${which}`] || false;
1574         switch (show) {
1575                 default:
1576                 case 'always':
1577                         return true;
1578                 case 'situational':
1579                         return wild;
1580                 case 'never':
1581                         return false;
1582         }
1583 };
1584
1585 export const toggleBoolean = name => state => ({
1586         ...state,
1587         [name]: !state[name],
1588 });
1589
1590 export const increment = (name, max, skipZero) => state => {
1591         let newValue = ((state[name] || 0) + 1) % (max + 1);
1592         if (skipZero && !newValue) {
1593                 newValue = 1;
1594         }
1595         return {
1596                 ...state,
1597                 [name]: newValue,
1598         };
1599 };
1600
1601 export const decrement = (name, max, skipZero) => state => {
1602         let newValue = ((state[name] || 0) + max) % (max + 1);
1603         if (skipZero && !newValue) {
1604                 newValue = max;
1605         }
1606         return {
1607                 ...state,
1608                 [name]: newValue,
1609         };
1610 };
1611
1612 export const highestActive = (state, names) => {
1613         for (let i = names.length; i >= 0; --i) {
1614                 if (state[names[i]]) {
1615                         return names[i];
1616                 }
1617         }
1618         return null;
1619 };
1620
1621 export const clearAll = names => state => {
1622         const changes = names.reduce((acc, cur) => ({ ...acc, [cur]: true }), {});
1623         return { ...state, ...changes };
1624 };
1625
1626 export const unclearAll = names => state => {
1627         const changes = names.reduce((acc, cur) => ({ ...acc, [cur]: false }), {});
1628         return { ...state, ...changes };
1629 };
1630
1631 export const countClearedLocations = (state, locations) =>
1632         locations.reduce((acc, cur) => state[cur] ? acc + 1 : acc, 0);
1633
1634 export const hasClearedLocations = (state, locations) =>
1635         countClearedLocations(state, locations) === locations.length;
1636
1637 export const getLocationStatus = (name, logic, state) => {
1638         if (state[name]) return 'cleared';
1639         if (logic[name]) return logic[name];
1640         return logic.fallback;
1641 };
1642
1643 export const getCombinedStatus = statuses => {
1644         if (statuses.filter(s => s === 'cleared').length === statuses.length) {
1645                 return 'cleared';
1646         }
1647         if (statuses.filter(s => ['available', 'cleared'].includes(s)).length === statuses.length) {
1648                 return 'available';
1649         }
1650         if (statuses.filter(s => ['unavailable', 'cleared'].includes(s)).length === statuses.length) {
1651                 return 'unavailable';
1652         }
1653         return 'partial';
1654 };
1655
1656 export const aggregateLocationStatus = (names, logic, state) => {
1657         const statuses = names.map(name => getLocationStatus(name, logic, state));
1658         return getCombinedStatus(statuses);
1659 };
1660
1661 export const countRemainingLocations = (state, locations) =>
1662         locations.reduce((acc, cur) => state[cur] ? acc : acc + 1, 0);
1663
1664 export const getGanonCrystals = (state) => state['ganon-crystals'];
1665
1666 export const getGTCrystals = (state) => state['gt-crystals'];
1667
1668 export const getGTBoss = (state, which) => state[`gt-${which}-boss`];
1669
1670 export const hasDungeonBoss = (state, dungeon) =>
1671         !dungeon.boss || !!state[`${dungeon.id}-boss-defeated`];
1672
1673 export const getDungeonBoss = (state, dungeon) =>
1674         state[`${dungeon.id}-boss`] || dungeon.boss || null;
1675
1676 export const hasDungeonPrize = (state, dungeon) =>
1677         !dungeon.prize || !!state[`${dungeon.id}-prize-acquired`];
1678
1679 export const getDungeonPrize = (state, dungeon) => state[`${dungeon.id}-prize`] || null;
1680
1681 export const getDungeonClearedItems = (state, dungeon) => state[`${dungeon.id}-checks`] || 0;
1682
1683 export const getDungeonRemainingItems = (state, dungeon) =>
1684         Math.max(0, dungeon.items - getDungeonClearedItems(state, dungeon));
1685
1686 export const getDungeonAcquiredSKs = (state, dungeon) => state[`${dungeon.id}-small-key`] || 0;
1687
1688 export const isDungeonCleared = (state, dungeon) => {
1689         const hasItems = !getDungeonRemainingItems(state, dungeon);
1690         const hasBoss = hasDungeonBoss(state, dungeon);
1691         const hasPrize = hasDungeonPrize(state, dungeon);
1692         return hasItems && hasBoss && hasPrize;
1693 };
1694
1695 export const aggregateDungeonStatus = (dungeon, logic, state) => {
1696         if (isDungeonCleared(state, dungeon)) {
1697                 return 'cleared';
1698         }
1699         if (logic[dungeon.id] === 'unavailable') {
1700                 return 'unavailable';
1701         }
1702         const checks = [...dungeon.checks];
1703         if (['ct', 'gt'].includes(dungeon.id)) {
1704                 checks.push(`${dungeon.id}-boss-killable`);
1705         }
1706         const statuses = checks.map(name => getLocationStatus(name, logic, state));
1707         return getCombinedStatus(statuses);
1708 };
1709
1710 export const toggleBossDefeated = dungeon => toggleBoolean(`${dungeon.id}-boss-defeated`);
1711
1712 export const setBossDefeated = (dungeon, defeated) =>
1713         state => ({ ...state, [`${dungeon.id}-boss-defeated`]: !!defeated });
1714
1715 export const togglePrizeAcquired = dungeon => toggleBoolean(`${dungeon.id}-prize-acquired`);
1716
1717 export const setPrizeAcquired = (dungeon, acquired) =>
1718         state => ({ ...state, [`${dungeon.id}-prize-acquired`]: !!acquired });
1719
1720 export const addDungeonCheck = dungeon => increment(`${dungeon.id}-checks`, dungeon.items);
1721
1722 export const removeDungeonCheck = dungeon => decrement(`${dungeon.id}-checks`, dungeon.items);
1723
1724 export const resetDungeonChecks = dungeon => state => ({ ...state, [`${dungeon.id}-checks`]: 0 });
1725
1726 export const completeDungeonChecks = dungeon =>
1727         state => ({ ...state, [`${dungeon.id}-checks`]: dungeon.items });
1728
1729 export const makeEmptyState = () => {
1730         const state = {};
1731         BOOLEAN_STATES.forEach(p => {
1732                 state[p] = INITIAL[p] || false;
1733         });
1734         INTEGER_STATES.forEach(p => {
1735                 state[p] = INITIAL[p] || 0;
1736         });
1737         DUNGEONS.forEach(dungeon => {
1738                 state[`${dungeon.id}-map`] = false;
1739                 state[`${dungeon.id}-compass`] = false;
1740                 state[`${dungeon.id}-small-key`] = 0;
1741                 state[`${dungeon.id}-big-key`] = false;
1742                 state[`${dungeon.id}-checks`] = 0;
1743                 if (dungeon.boss) {
1744                         state[`${dungeon.id}-boss`] = dungeon.boss;
1745                         state[`${dungeon.id}-boss-defeated`] = false;
1746                 }
1747                 if (dungeon.prize) {
1748                         state[`${dungeon.id}-prize`] = 'crystal';
1749                         state[`${dungeon.id}-prize-acquired`] = false;
1750                 }
1751                 if (dungeon.id === 'gt') {
1752                         state['gt-bot-boss'] = 'armos';
1753                         state['gt-mid-boss'] = 'lanmolas';
1754                         state['gt-top-boss'] = 'moldorm';
1755                 }
1756         });
1757         OVERWORLD_LOCATIONS.forEach(location => {
1758                 state[location.id] = false;
1759         });
1760         UNDERWORLD_LOCATIONS.forEach(location => {
1761                 state[location.id] = false;
1762         });
1763         state['mm-medallion'] = null;
1764         state['tr-medallion'] = null;
1765         state['gt-crystals'] = 7;
1766         state['ganon-crystals'] = 7;
1767         return state;
1768 };
1769
1770 const collectInventory = (state, data, prizeMap) => {
1771         state.bow = !!(data[INV_ADDR.RANDO_BOW] & 0x80);
1772         state.silvers = (data[INV_ADDR.RANDO_BOW] & 0xC0) == 0xC0;
1773         state['bowless-silvers'] = (data[INV_ADDR.RANDO_BOW] & 0xC0) == 0x40;
1774         state['blue-boomerang'] = !!(data[INV_ADDR.RANDO_BOOM] & 0x40);
1775         state['red-boomerang'] = !!(data[INV_ADDR.RANDO_BOOM] & 0x80);
1776         state.hookshot = !!data[INV_ADDR.HOOK];
1777         state.bomb = data[INV_ADDR.BOMB];
1778         state.mushroom = !!(data[INV_ADDR.RANDO_POWDER] & 0x20);
1779         state.powder = !!(data[INV_ADDR.RANDO_POWDER] & 0x10);
1780         state['fire-rod'] = !!data[INV_ADDR.FROD];
1781         state['ice-rod'] = !!data[INV_ADDR.IROD];
1782         state.bombos = !!data[INV_ADDR.BOMBOS];
1783         state.ether = !!data[INV_ADDR.ETHER];
1784         state.quake = !!data[INV_ADDR.QUAKE];
1785         state.lamp = !!data[INV_ADDR.LAMP];
1786         state.hammer = !!data[INV_ADDR.HAMMER];
1787         state.shovel = !!(data[INV_ADDR.RANDO_FLUTE] & 0x04);
1788         state.flute = !!(data[INV_ADDR.RANDO_FLUTE] & 0x03);
1789         state.duck = !!(data[INV_ADDR.RANDO_FLUTE] & 0x01);
1790         state.bugnet = !!data[INV_ADDR.BUGNET];
1791         state.book = !!data[INV_ADDR.BOOK];
1792         state.bottle = 0;
1793         if (data[INV_ADDR.BOTTLE_1]) {
1794                 ++state.bottle;
1795         }
1796         if (data[INV_ADDR.BOTTLE_2]) {
1797                 ++state.bottle;
1798         }
1799         if (data[INV_ADDR.BOTTLE_3]) {
1800                 ++state.bottle;
1801         }
1802         if (data[INV_ADDR.BOTTLE_4]) {
1803                 ++state.bottle;
1804         }
1805         state.somaria = !!data[INV_ADDR.SOMARIA];
1806         state.byrna = !!data[INV_ADDR.BYRNA];
1807         state.cape = !!data[INV_ADDR.CAPE];
1808         state.mirror = !!data[INV_ADDR.MIRROR];
1809         state.lift = data[INV_ADDR.GLOVE];
1810         state.boots = !!data[INV_ADDR.BOOTS];
1811         state.flippers = !!data[INV_ADDR.FLIPPERS];
1812         state.moonpearl = !!data[INV_ADDR.MOONPEARL];
1813         state.sword = data[INV_ADDR.SWORD];
1814         state.shield = data[INV_ADDR.SHIELD];
1815         state.mail = data[INV_ADDR.ARMOR] + 1;
1816         state['heart-piece'] = data[INV_ADDR.HEART_PIECE];
1817         state['half-magic'] = data[INV_ADDR.MAGIC_USE] > 0;
1818         state['quarter-magic'] = data[INV_ADDR.MAGIC_USE] > 1;
1819         const map = getShort(data, INV_ADDR.MAP);
1820         const compass = getShort(data, INV_ADDR.COMPASS);
1821         const bigKey = getShort(data, INV_ADDR.BIG_KEY);
1822         DUNGEONS.forEach(dungeon => {
1823                 state[`${dungeon.id}-map`] = !!(map & dungeon.mask);
1824                 state[`${dungeon.id}-compass`] = !!(compass & dungeon.mask);
1825                 state[`${dungeon.id}-small-key`] = data[INV_ADDR.RANDO_KEY_START + dungeon.offset];
1826                 state[`${dungeon.id}-big-key`] = !!(bigKey & dungeon.mask);
1827                 if (dungeon.prize) {
1828                         const isCrystal = prizeMap[dungeon.offset].isCrystal;
1829                         const prizeFlags = data[isCrystal ? INV_ADDR.CRYSTALS : INV_ADDR.PENDANTS];
1830                         state[`${dungeon.id}-prize-acquired`] = !!(prizeFlags & prizeMap[dungeon.offset].mask);
1831                 }
1832         });
1833 };
1834
1835 const collectOverworld = (state, data) => {
1836         OVERWORLD_LOCATIONS.forEach(location => {
1837                 state[location.id] = !!(data[location.address] & location.mask);
1838         });
1839 };
1840
1841 const collectUnderworld = (state, data) => {
1842         UNDERWORLD_LOCATIONS.forEach(location => {
1843                 state[location.id] = isChestOpen(data, location.room, location.chest);
1844         });
1845         DUNGEONS.forEach(dungeon => {
1846                 state[`${dungeon.id}-boss-defeated`] = isBossDefeated(data, dungeon.bossRoom);
1847         });
1848 };
1849
1850 export const computeState = (config, data, prizeMap) => {
1851         const state = {};
1852         collectInventory(state, data.slice(SRAM_ADDR.INV_START), prizeMap);
1853         collectOverworld(state, data);
1854         collectUnderworld(state, data.slice(SRAM_ADDR.ROOM_DATA_START));
1855         const amounts = getDungeonAmounts(config, state);
1856         DUNGEONS.forEach(dungeon => {
1857                 state[`${dungeon.id}-checks`] = amounts[dungeon.id];
1858         });
1859         return state;
1860 };
1861
1862 const getDungeonAmounts = (config, state) => {
1863         const amounts = {};
1864         DUNGEONS.forEach(dungeon => {
1865                 let amount = 0;
1866                 let total = dungeon.checks.length;
1867                 dungeon.checks.forEach(check => {
1868                         if (state[check]) {
1869                                 ++amount;
1870                         }
1871                 });
1872                 if (!config.wildMap && state[`${dungeon.id}-map`]) {
1873                         --amount;
1874                         --total;
1875                 }
1876                 if (!config.wildCompass && state[`${dungeon.id}-compass`]) {
1877                         --amount;
1878                         --total;
1879                 }
1880                 if (!config.wildSmall) {
1881                         amount -= Math.min(state[`${dungeon.id}-small-key`], dungeon.sk);
1882                         total -= dungeon.sk;
1883                 }
1884                 if (!config.wildBig && !dungeon.dropBk && state[`${dungeon.id}-big-key`]) {
1885                         --amount;
1886                         --total;
1887                 }
1888                 amounts[dungeon.id] = Math.min(total, amount);
1889         });
1890         return amounts;
1891 };
1892
1893 export const mergeStates = (autoState, manualState) => {
1894         const next = { ...autoState };
1895         BOOLEAN_STATES.forEach(name => {
1896                 if (manualState[name]) {
1897                         next[name] = true;
1898                 }
1899         });
1900         INTEGER_STATES.forEach(name => {
1901                 next[name] = Math.max(autoState[name] || 0, manualState[name] || 0);
1902         });
1903         DUNGEONS.forEach(dungeon => {
1904                 next[`${dungeon.id}-small-key`] += manualState[`${dungeon.id}-small-key`] || 0;
1905                 next[`${dungeon.id}-checks`] += manualState[`${dungeon.id}-checks`] || 0;
1906                 if (manualState[`${dungeon.id}-big-key`]) {
1907                         next[`${dungeon.id}-big-key`] = true;
1908                 }
1909                 if (manualState[`${dungeon.id}-compass`]) {
1910                         next[`${dungeon.id}-compass`] = true;
1911                 }
1912                 if (manualState[`${dungeon.id}-map`]) {
1913                         next[`${dungeon.id}-map`] = true;
1914                 }
1915                 if (manualState[`${dungeon.id}-boss-defeated`]) {
1916                         next[`${dungeon.id}-boss-defeated`] = true;
1917                 }
1918                 if (manualState[`${dungeon.id}-prize`] &&
1919                         manualState[`${dungeon.id}-prize`] !== 'crystal'
1920                 ) {
1921                         next[`${dungeon.id}-prize`] = manualState[`${dungeon.id}-prize`];
1922                 } else if (!next[`${dungeon.id}-prize`]) {
1923                         next[`${dungeon.id}-prize`] = 'crystal';
1924                 }
1925                 if (manualState[`${dungeon.id}-prize-acquired`]) {
1926                         next[`${dungeon.id}-prize-acquired`] = true;
1927                 }
1928         });
1929         OVERWORLD_LOCATIONS.forEach(loc => {
1930                 if (manualState[loc.id]) {
1931                         next[loc.id] = true;
1932                 }
1933         });
1934         UNDERWORLD_LOCATIONS.forEach(loc => {
1935                 if (manualState[loc.id]) {
1936                         next[loc.id] = true;
1937                 }
1938         });
1939         next['mm-medallion'] = manualState['mm-medallion'];
1940         next['tr-medallion'] = manualState['tr-medallion'];
1941         next['gt-crystals'] = manualState['gt-crystals'];
1942         next['ganon-crystals'] = manualState['ganon-crystals'];
1943         next['gt-bot-boss'] = manualState['gt-bot-boss'];
1944         next['gt-mid-boss'] = manualState['gt-mid-boss'];
1945         next['gt-top-boss'] = manualState['gt-top-boss'];
1946         //console.log(next);
1947         return next;
1948 };