]> git.localhorst.tv Git - alttp.git/blob - resources/js/helpers/logic.js
separate bottle tracking
[alttp.git] / resources / js / helpers / logic.js
1 import {
2         getDungeonBoss,
3         getDungeonPrize,
4         getGTBoss,
5         getGTCrystals,
6         hasDungeonBoss,
7         hasDungeonPrize,
8 } from './tracker';
9
10 const and = (...predicates) => (...args) =>
11         predicates.reduce((acc, cur) => acc && cur(...args), true);
12
13 const or = (...predicates) => (...args) =>
14         predicates.reduce((acc, cur) => acc || cur(...args), false);
15
16 const fromBool = b => (...args) => b(...args) ? 'available' : 'unavailable';
17
18 const agaDead = (config, dungeons, state) =>
19         hasDungeonBoss(state, dungeons.find(d => d.id === 'ct'));
20
21 const countCrystals = (config, dungeons, state) => dungeons
22         .filter(dungeon =>
23                 (getDungeonPrize(state, dungeon) || 'crystal').endsWith('crystal') &&
24                 dungeon.prize &&
25                 hasDungeonPrize(state, dungeon)
26         ).length;
27
28 const countRedCrystals = (config, dungeons, state) => dungeons
29         .filter(dungeon =>
30                 getDungeonPrize(state, dungeon) === 'red-crystal' &&
31                 hasDungeonPrize(state, dungeon)
32         ).length;
33
34 const hasRedCrystals = n => (...args) => countRedCrystals(...args) >= n;
35
36 const hasGTCrystals = (config, dungeons, state) =>
37         countCrystals(config, dungeons, state) >= getGTCrystals(state);
38
39 const countPendants = (config, dungeons, state) => dungeons
40         .filter(dungeon =>
41                 (getDungeonPrize(state, dungeon) || '').endsWith('pendant') &&
42                 hasDungeonPrize(state, dungeon)
43         ).length;
44
45 const hasGreenPendant = (config, dungeons, state) => dungeons
46         .filter(dungeon =>
47                 getDungeonPrize(state, dungeon) === 'green-pendant' &&
48                 hasDungeonPrize(state, dungeon)
49         ).length >= 1;
50
51 const hasPendants = n => (...args) => countPendants(...args) >= n;
52
53 // Equipment
54
55 const countBottles = (config, dungeons, state) =>
56         ['bottle-1', 'bottle-2', 'bottle-3', 'bottle-4'].filter(b => !!state[b]).length;
57
58 const hasBig = dungeon => (config, dungeons, state) =>
59         !config.wildBig || !!state[`${dungeon}-big-key`];
60
61 const hasBird = (config, dungeons, state) => !!state['bird'];
62
63 const hasBombos = (config, dungeons, state) => !!state['bombos'];
64
65 const hasBook = (config, dungeons, state) => !!state['book'];
66
67 const hasBoom = (config, dungeons, state) => !!(state['blue-boomerang'] || state['red-boomerang']);
68
69 const hasBoots = (config, dungeons, state) => !!state['boots'];
70
71 const hasBottle = n => (...args) => countBottles(...args) >= (n || 1);
72
73 const hasBow = (config, dungeons, state) => !!state['bow'];
74
75 const hasBugnet = (config, dungeons, state) => !!state['bugnet'];
76
77 const hasByrna = (config, dungeons, state) => !!state['byrna'];
78
79 const hasCape = (config, dungeons, state) => !!state['cape'];
80
81 const hasFireRod = (config, dungeons, state) => !!state['fire-rod'];
82
83 const hasFlute = (config, dungeons, state) => !!state['flute'];
84
85 const hasHammer = (config, dungeons, state) => !!state['hammer'];
86
87 const hasHookshot = (config, dungeons, state) => !!state['hookshot'];
88
89 const hasIceRod = (config, dungeons, state) => !!state['ice-rod'];
90
91 const hasLamp = (config, dungeons, state) => !!state['lamp'];
92
93 const hasMagicBars = n => (config, dungeons, state) => {
94         let bars = 1 + (state['bottle'] || 0);
95         if (state['half-magic']) {
96                 bars *= 2;
97         }
98         if (state['quarter-magic']) {
99                 bars *= 2;
100         }
101         return bars >= (n || 1);
102 };
103
104 const hasMirror = (config, dungeons, state) => !!state['mirror'];
105
106 const hasMMMedallion = (config, dungeons, state) =>
107         !!state['mm-medallion'] && !!state[state['mm-medallion']];
108
109 const hasMoonpearl = (config, dungeons, state) => !!state['moonpearl'];
110
111 const hasMushroom = (config, dungeons, state) => !!state['mushroom'];
112
113 const hasPowder = (config, dungeons, state) => !!state['powder'];
114
115 const hasQuake = (config, dungeons, state) => !!state['quake'];
116
117 const hasShovel = (config, dungeons, state) => !!state['shovel'];
118
119 const hasSmall = (dungeon, amount) => (config, dungeons, state) =>
120         !config.wildSmall || state[`${dungeon}-small-key`] >= (amount || 1);
121
122 const hasSomaria = (config, dungeons, state) => !!state['somaria'];
123
124 const hasSword = n => (config, dungeons, state) => state['sword'] >= (n || 1);
125
126 const hasTRMedallion = (config, dungeons, state) =>
127         !!state['tr-medallion'] && !!state[state['tr-medallion']];
128
129 // Abilities
130
131 const canActivateFlute = () => true;
132
133 const canBomb = () => true;
134
135 const canBonk = hasBoots;
136
137 const canDarkRoom = hasLamp;
138
139 const canFlipSwitches = or(
140         canBomb,
141         hasBoom,
142         canShootArrows,
143         hasSword(),
144         hasHammer,
145         hasHookshot,
146         hasSomaria,
147         hasByrna,
148         hasFireRod,
149         hasIceRod,
150 );
151
152 const canFly = or(hasBird, and(hasFlute, canActivateFlute));
153
154 const canGetGoodBee = and(hasBugnet, hasBottle(), or(canBonk, and(hasSword(), hasQuake)));
155
156 const canLift = (config, dungeons, state) => state['lift'] >= 1;
157
158 const canHeavyLift = (config, dungeons, state) => state['lift'] >= 2;
159
160 const canKill = damage => damage && damage < 6
161         ? or(hasBow, hasFireRod, hasHammer, hasSomaria, hasSword(1), canBomb, hasByrna)
162         : or(hasBow, hasFireRod, hasHammer, hasSomaria, hasSword(1));
163
164 const canMedallion = hasSword();
165
166 const canMeltThings = or(hasFireRod, and(hasBombos, canMedallion));
167
168 const canPassCurtains = hasSword();
169
170 const canShootArrows = hasBow;
171
172 const canSwim = (config, dungeons, state) => !!state['flippers'];
173
174 const canTablet = and(hasBook, hasSword(2));
175
176 const canTorch = or(hasFireRod, hasLamp);
177
178 const canTorchDarkRoom = or(canDarkRoom, canTorch);
179
180 // Regions
181
182 const westDeathMountain = or(
183         canFly,
184         and(canLift, canDarkRoom),
185 );
186
187 const eastDeathMountain = and(
188         westDeathMountain,
189         or(
190                 hasHookshot,
191                 and(hasHammer, hasMirror),
192         ),
193 );
194
195 const northDeathMountain = and(
196         westDeathMountain,
197         or(
198                 hasMirror,
199                 and(hasHammer, hasHookshot),
200         ),
201 );
202
203 const eastDarkDeathMountain = and(
204         eastDeathMountain,
205         canHeavyLift,
206 );
207
208 const westDarkDeathMountain = westDeathMountain;
209
210 const eastDarkWorld = and(
211         hasMoonpearl,
212         or(
213                 agaDead,
214                 canHeavyLift,
215                 and(canLift, hasHammer),
216         ),
217 );
218
219 const westDarkWorld = and(
220         hasMoonpearl,
221         or(
222                 and(canLift, hasHammer),
223                 canHeavyLift,
224                 and(eastDarkWorld, hasHookshot, or(canSwim, canLift, hasHammer)),
225         ),
226 );
227
228 const southDarkWorld = or(
229         westDarkWorld,
230         and(eastDarkWorld, hasMoonpearl, hasHammer),
231 );
232
233 const mireArea = and(canFly, canHeavyLift);
234
235 // Bosses
236
237 const BOSS_RULES = {
238         aga: or(hasBugnet, hasHammer, hasSword()),
239         armos: or(
240                 hasSword(), hasHammer, canShootArrows, hasBoom,
241                 and(hasMagicBars(4), or(hasFireRod, hasIceRod)),
242                 and(hasMagicBars(2), or(hasByrna, hasSomaria)),
243         ),
244         arrghus: and(hasHookshot, or(
245                 hasSword(),
246                 hasHammer,
247                 and(or(hasMagicBars(2), canShootArrows), or(hasFireRod, hasIceRod)),
248         )),
249         blind: or(hasSword(), hasHammer, hasSomaria, hasByrna),
250         helma: and(or(canBomb, hasHammer), or(hasSword(), canShootArrows)),
251         kholdstare: and(canMeltThings, or(
252                 hasHammer,
253                 hasSword(),
254                 and(hasFireRod, hasMagicBars(3)),
255                 and(hasFireRod, hasBombos, hasMagicBars(2), canMedallion),
256         )),
257         lanmolas: or(
258                 hasSword(), hasHammer, canShootArrows, hasFireRod, hasIceRod, hasByrna, hasSomaria,
259         ),
260         moldorm: or(hasSword(), hasHammer),
261         mothula: or(
262                 hasSword(),
263                 hasHammer,
264                 and(hasMagicBars(2), or(hasFireRod, hasSomaria, hasByrna)),
265                 canGetGoodBee,
266         ),
267         trinexx: and(hasFireRod, hasIceRod, or(
268                 hasSword(3),
269                 hasHammer,
270                 and(hasMagicBars(2), hasSword(2)),
271                 and(hasMagicBars(4), hasSword(1)),
272         )),
273         vitreous: or(hasSword(), hasHammer, canShootArrows),
274 };
275
276 const canKillBoss = dungeon => (config, dungeons, state) => {
277         const boss = getDungeonBoss(state, dungeons.find(d => d.id === dungeon));
278         return BOSS_RULES[boss](config, dungeons, state);
279 };
280
281 const canKillGTBoss = which => (config, dungeons, state) => {
282         const boss = getGTBoss(state, which);
283         return BOSS_RULES[boss](config, dungeons, state);
284 };
285
286 // Dungeons
287
288 const canEnterCT = or(hasCape, hasSword(2));
289
290 const canEnterGT = and(eastDarkDeathMountain, hasGTCrystals, hasMoonpearl);
291
292 const canEnterDPFront = or(hasBook, and(mireArea, hasMirror));
293 const canEnterDPBack = or(and(canEnterDPFront, canLift), and(mireArea, hasMirror));
294
295 const canEnterTH = northDeathMountain;
296
297 const canEnterPD = and(eastDarkWorld, hasMoonpearl);
298
299 const canEnterSP = and(southDarkWorld, hasMirror, hasMoonpearl, canSwim);
300
301 const canEnterSWFront = and(westDarkWorld, hasMoonpearl);
302 const canEnterSWMid = and(westDarkWorld, hasMoonpearl);
303 const canEnterSWBack = and(westDarkWorld, hasMoonpearl, hasFireRod);
304
305 const canEnterTT = and(westDarkWorld, hasMoonpearl);
306
307 const canEnterIP = and(canSwim, canHeavyLift, hasMoonpearl, canMeltThings);
308 const rightSideIP = or(hasHookshot, hasSmall('ip'));
309
310 const canEnterMM = and(
311         mireArea,
312         hasMoonpearl,
313         hasMMMedallion,
314         canMedallion,
315         or(canBonk, hasHookshot),
316         canKill(8),
317 );
318
319 const canEnterTRFront = and(
320         eastDeathMountain,
321         canHeavyLift,
322         hasHammer,
323         hasMoonpearl,
324         canMedallion,
325         hasTRMedallion,
326 );
327 const canEnterTRWest = and(canEnterTRFront, canBomb, hasSmall('tr', 2));
328 const canEnterTREast = and(canEnterTRWest, or(hasHookshot, hasSomaria));
329 const canEnterTRBack = and(
330         or(canEnterTRWest, canEnterTREast),
331         or(canBomb, canBonk),
332         hasBig('tr'),
333         hasSmall('tr', 3),
334         hasSomaria,
335         canDarkRoom,
336 );
337 const laserBridge = or(
338         and(
339                 or(canEnterDPFront, canEnterTRWest, canEnterTREast),
340                 canDarkRoom,
341                 hasSomaria,
342                 hasBig('tr'),
343                 hasSmall('tr', 3),
344         ),
345         canEnterTRBack,
346 );
347
348 // Misc Macros
349
350 const paradoxLower = and(eastDeathMountain, or(canBomb, hasBoom, canShootArrows, hasSomaria));
351
352 const canBridgeRedBomb = or(
353         and(hasMoonpearl, hasHammer),
354         and(agaDead, hasMirror),
355 );
356
357 const canRescueSmith = and(westDarkWorld, hasMoonpearl, canHeavyLift);
358
359 const Logic = {};
360
361 Logic.open = {
362         fallback: () => 'available',
363         aginah: fromBool(canBomb),
364         blacksmith: fromBool(canRescueSmith),
365         'blinds-hut-top': fromBool(canBomb),
366         'bombos-tablet': fromBool(and(southDarkWorld, hasMirror, canTablet)),
367         'bonk-rocks': fromBool(canBonk),
368         brewery: fromBool(and(westDarkWorld, canBomb, hasMoonpearl)),
369         'bumper-cave': fromBool(and(westDarkWorld, hasMoonpearl, canLift, hasCape)),
370         'c-house': fromBool(and(westDarkWorld, hasMoonpearl)),
371         catfish: fromBool(and(eastDarkWorld, hasMoonpearl)),
372         'cave-45': fromBool(and(southDarkWorld, hasMirror)),
373         checkerboard: fromBool(and(mireArea, hasMirror)),
374         'chest-game': fromBool(and(westDarkWorld, hasMoonpearl)),
375         'chicken-house': fromBool(canBomb),
376         'desert-ledge': fromBool(canEnterDPFront),
377         'digging-game': fromBool(and(southDarkWorld, hasMoonpearl)),
378         'ether-tablet': fromBool(and(northDeathMountain, canTablet)),
379         'floating-island': fromBool(
380                 and(eastDarkDeathMountain, hasMoonpearl, canLift, canBomb, hasMirror),
381         ),
382         'flute-spot': fromBool(hasShovel),
383         'graveyard-ledge': fromBool(and(westDarkWorld, hasMoonpearl, hasMirror)),
384         'hammer-pegs': fromBool(and(westDarkWorld, hasHammer, hasMoonpearl, canHeavyLift)),
385         hobo: fromBool(canSwim),
386         'hookshot-cave-tl': fromBool(and(eastDarkDeathMountain, hasMoonpearl, canLift, hasHookshot)),
387         'hookshot-cave-tr': fromBool(and(eastDarkDeathMountain, hasMoonpearl, canLift, hasHookshot)),
388         'hookshot-cave-bl': fromBool(and(eastDarkDeathMountain, hasMoonpearl, canLift, hasHookshot)),
389         'hookshot-cave-br': fromBool(
390                 and(eastDarkDeathMountain, hasMoonpearl, canLift, or(hasHookshot, canBonk)),
391         ),
392         'hype-cave-npc': fromBool(and(southDarkWorld, hasMoonpearl, canBomb)),
393         'hype-cave-top': fromBool(and(southDarkWorld, hasMoonpearl, canBomb)),
394         'hype-cave-right': fromBool(and(southDarkWorld, hasMoonpearl, canBomb)),
395         'hype-cave-left': fromBool(and(southDarkWorld, hasMoonpearl, canBomb)),
396         'hype-cave-bottom': fromBool(and(southDarkWorld, hasMoonpearl, canBomb)),
397         'ice-rod-cave': fromBool(canBomb),
398         'kak-well-top': fromBool(canBomb),
399         'kings-tomb': fromBool(and(canBonk, or(canHeavyLift, and(westDarkWorld, hasMirror)))),
400         'lake-hylia-island': fromBool(
401                 and(canSwim, hasMirror, hasMoonpearl, or(eastDarkWorld, southDarkWorld)),
402         ),
403         library: fromBool(canBonk),
404         lumberjack: fromBool(and(canBonk, agaDead)),
405         'magic-bat': fromBool(and(hasPowder,
406                 or(hasHammer, and(westDarkWorld, hasMoonpearl, canHeavyLift, hasMirror)),
407         )),
408         'mimic-cave': fromBool(and(canEnterTREast, hasMirror, hasHammer)),
409         'mini-moldorm-left': fromBool(canBomb),
410         'mini-moldorm-right': fromBool(canBomb),
411         'mini-moldorm-far-left': fromBool(canBomb),
412         'mini-moldorm-far-right': fromBool(canBomb),
413         'mini-moldorm-npc': fromBool(canBomb),
414         'mire-shed-left': fromBool(and(mireArea, hasMoonpearl)),
415         'mire-shed-right': fromBool(and(mireArea, hasMoonpearl)),
416         'old-man': fromBool(and(westDeathMountain, canDarkRoom)),
417         'paradox-lower-far-left': fromBool(paradoxLower),
418         'paradox-lower-left': fromBool(paradoxLower),
419         'paradox-lower-right': fromBool(paradoxLower),
420         'paradox-lower-far-right': fromBool(paradoxLower),
421         'paradox-lower-mid': fromBool(paradoxLower),
422         'paradox-upper-left': fromBool(and(eastDeathMountain, canBomb)),
423         'paradox-upper-right': fromBool(and(eastDeathMountain, canBomb)),
424         pedestal: fromBool(hasPendants(3)),
425         'potion-shop': fromBool(hasMushroom),
426         'purple-chest': fromBool(and(canRescueSmith, hasMoonpearl, canHeavyLift)),
427         pyramid: fromBool(eastDarkWorld),
428         'pyramid-fairy-left': fromBool(and(hasRedCrystals(2), southDarkWorld, canBridgeRedBomb)),
429         'pyramid-fairy-right': fromBool(and(hasRedCrystals(2), southDarkWorld, canBridgeRedBomb)),
430         'race-game': fromBool(or(canBomb, canBonk)),
431         saha: fromBool(hasGreenPendant),
432         'saha-left': fromBool(or(canBomb, canBonk)),
433         'saha-mid': fromBool(or(canBomb, canBonk)),
434         'saha-right': fromBool(or(canBomb, canBonk)),
435         'sick-kid': fromBool(hasBottle(1)),
436         'spec-rock': fromBool(and(westDeathMountain, hasMirror)),
437         'spec-rock-cave': fromBool(westDeathMountain),
438         'spike-cave': fromBool(and(
439                 westDarkDeathMountain,
440                 hasMoonpearl,
441                 hasHammer,
442                 canLift,
443                 or(hasByrna, and(hasCape, hasMagicBars(2))),
444         )),
445         'spiral-cave': fromBool(eastDeathMountain),
446         stumpy: fromBool(and(southDarkWorld, hasMoonpearl)),
447         'super-bunny-top': fromBool(and(eastDarkDeathMountain, hasMoonpearl)),
448         'super-bunny-bottom': fromBool(and(eastDarkDeathMountain, hasMoonpearl)),
449         'waterfall-fairy-left': fromBool(canSwim),
450         'waterfall-fairy-right': fromBool(canSwim),
451         zora: fromBool(or(canLift, canSwim)),
452         'zora-ledge': fromBool(canSwim),
453         'hc-boom': fromBool(and(hasSmall('hc'), canKill())),
454         'hc-cell': fromBool(and(hasSmall('hc'), canKill())),
455         'dark-cross': fromBool(canTorchDarkRoom),
456         'sewers-left': fromBool(or(canLift, and(canTorchDarkRoom, hasSmall('hc'), canKill()))),
457         'sewers-mid': fromBool(or(canLift, and(canTorchDarkRoom, hasSmall('hc'), canKill()))),
458         'sewers-right': fromBool(or(canLift, and(canTorchDarkRoom, hasSmall('hc'), canKill()))),
459         ct: fromBool(canEnterCT),
460         'ct-1': fromBool(canKill()),
461         'ct-2': fromBool(and(canKill(), hasSmall('ct'), canDarkRoom)),
462         'ct-boss-killable': fromBool(and(
463                 canKill(), hasSmall('ct', 2), canDarkRoom, canPassCurtains, canKillBoss('ct'),
464         )),
465         gt: fromBool(canEnterGT),
466         'gt-tile-room': fromBool(hasSomaria),
467         'gt-compass-tl': fromBool(and(hasSomaria, hasFireRod, hasSmall('gt', 4))),
468         'gt-compass-tr': fromBool(and(hasSomaria, hasFireRod, hasSmall('gt', 4))),
469         'gt-compass-bl': fromBool(and(hasSomaria, hasFireRod, hasSmall('gt', 4))),
470         'gt-compass-br': fromBool(and(hasSomaria, hasFireRod, hasSmall('gt', 4))),
471         'gt-torch': fromBool(canBonk),
472         'gt-dm-tl': fromBool(and(hasHammer, hasHookshot)),
473         'gt-dm-tr': fromBool(and(hasHammer, hasHookshot)),
474         'gt-dm-bl': fromBool(and(hasHammer, hasHookshot)),
475         'gt-dm-br': fromBool(and(hasHammer, hasHookshot)),
476         'gt-map-chest': fromBool(and(hasHammer, or(hasHookshot, canBonk), hasSmall('gt', 4))),
477         'gt-firesnake': fromBool(and(hasHammer, hasHookshot, hasSmall('gt', 3))),
478         'gt-rando-tl': fromBool(and(hasHammer, hasHookshot, hasSmall('gt', 4))),
479         'gt-rando-tr': fromBool(and(hasHammer, hasHookshot, hasSmall('gt', 4))),
480         'gt-rando-bl': fromBool(and(hasHammer, hasHookshot, hasSmall('gt', 4))),
481         'gt-rando-br': fromBool(and(hasHammer, hasHookshot, hasSmall('gt', 4))),
482         'gt-bobs-chest': fromBool(and(
483                 or(and(hasHammer, hasHookshot), and(hasFireRod, hasSomaria)),
484                 hasSmall('gt', 3),
485         )),
486         'gt-ice-left': fromBool(and(
487                 or(and(hasHammer, hasHookshot), and(hasFireRod, hasSomaria)),
488                 hasSmall('gt', 3),
489                 canKillGTBoss('bot'),
490         )),
491         'gt-ice-mid': fromBool(and(
492                 or(and(hasHammer, hasHookshot), and(hasFireRod, hasSomaria)),
493                 hasSmall('gt', 3),
494                 canKillGTBoss('bot'),
495         )),
496         'gt-ice-right': fromBool(and(
497                 or(and(hasHammer, hasHookshot), and(hasFireRod, hasSomaria)),
498                 hasSmall('gt', 3),
499                 canKillGTBoss('bot'),
500         )),
501         'gt-big-chest': fromBool(and(
502                 or(and(hasHammer, hasHookshot), and(hasFireRod, hasSomaria)),
503                 hasSmall('gt', 3),
504                 hasBig('gt'),
505         )),
506         'gt-helma-left': fromBool(and(
507                 hasBig('gt'),
508                 hasSmall('gt', 3),
509                 canShootArrows,
510                 canTorch,
511                 canKillGTBoss('mid'),
512         )),
513         'gt-helma-right': fromBool(and(
514                 hasBig('gt'),
515                 hasSmall('gt', 3),
516                 canShootArrows,
517                 canTorch,
518                 canKillGTBoss('mid'),
519         )),
520         'gt-pre-moldorm': fromBool(and(
521                 hasBig('gt'),
522                 hasSmall('gt', 3),
523                 canShootArrows,
524                 canTorch,
525                 canKillGTBoss('mid'),
526         )),
527         'gt-post-moldorm': fromBool(and(
528                 hasBig('gt'),
529                 hasSmall('gt', 4),
530                 canShootArrows,
531                 canTorch,
532                 canKillGTBoss('mid'),
533                 canKillGTBoss('top'),
534                 hasHookshot,
535         )),
536         'gt-boss-killable': fromBool(and(
537                 hasBig('gt'),
538                 hasSmall('gt', 4),
539                 canShootArrows,
540                 canTorch,
541                 canKillGTBoss('mid'),
542                 canKillGTBoss('top'),
543                 hasHookshot,
544                 canKillBoss('ct'),
545         )),
546         'ep-big-chest': fromBool(hasBig('ep')),
547         'ep-big-key-chest': fromBool(canDarkRoom),
548         'ep-boss-defeated': fromBool(and(
549                 canShootArrows, canTorchDarkRoom, hasBig('ep'), canKillBoss('ep'),
550         )),
551         dp: fromBool(or(canEnterDPFront, canEnterDPBack)),
552         'dp-big-chest': fromBool(and(canEnterDPFront, hasBig('dp'))),
553         'dp-big-key-chest': fromBool(and(canEnterDPFront, hasSmall('dp'), canKill())),
554         'dp-compass-chest': fromBool(and(canEnterDPFront, hasSmall('dp'))),
555         'dp-map-chest': fromBool(canEnterDPFront),
556         'dp-torch': fromBool(and(canEnterDPFront, canBonk)),
557         'dp-boss-defeated': fromBool(and(
558                 canEnterDPBack,
559                 canTorch,
560                 hasBig('dp'),
561                 hasSmall('dp'),
562                 canKillBoss('dp'),
563         )),
564         th: fromBool(canEnterTH),
565         'th-basement-cage': fromBool(canFlipSwitches),
566         'th-map-chest': fromBool(canFlipSwitches),
567         'th-big-key-chest': fromBool(and(canFlipSwitches, hasSmall('th'), canTorch)),
568         'th-compass-chest': fromBool(and(canFlipSwitches, hasBig('th'))),
569         'th-big-chest': fromBool(and(canFlipSwitches, hasBig('th'))),
570         'th-boss-defeated': fromBool(and(
571                 canFlipSwitches,
572                 hasBig('th'),
573                 canKillBoss('th'),
574         )),
575         pd: fromBool(canEnterPD),
576         'pd-stalfos-basement': fromBool(or(hasSmall('pd', 1), and(canShootArrows, hasHammer))),
577         'pd-big-key-chest': fromBool(hasSmall('pd', 6)),
578         'pd-arena-bridge': fromBool(or(hasSmall('pd', 1), and(canShootArrows, hasHammer))),
579         'pd-arena-ledge': fromBool(canShootArrows),
580         'pd-map-chest': fromBool(canShootArrows),
581         'pd-compass-chest': fromBool(hasSmall('pd', 4)),
582         'pd-basement-left': fromBool(and(canTorchDarkRoom, hasSmall('pd', 4))),
583         'pd-basement-right': fromBool(and(canTorchDarkRoom, hasSmall('pd', 4))),
584         'pd-harmless-hellway': fromBool(hasSmall('pd', 6)),
585         'pd-maze-top': fromBool(and(canDarkRoom, hasSmall('pd', 6))),
586         'pd-maze-bottom': fromBool(and(canDarkRoom, hasSmall('pd', 6))),
587         'pd-big-chest': fromBool(and(canDarkRoom, hasBig('pd'), hasSmall('pd', 6))),
588         'pd-boss-defeated': fromBool(and(
589                 canDarkRoom, hasBig('pd'), hasSmall('pd', 6), canShootArrows, hasHammer, canKillBoss('pd'),
590         )),
591         sp: fromBool(canEnterSP),
592         'sp-map-chest': fromBool(and(hasSmall('sp'), canBomb)),
593         'sp-big-chest': fromBool(and(hasSmall('sp'), hasHammer, hasBig('sp'))),
594         'sp-compass-chest': fromBool(and(hasSmall('sp'), hasHammer)),
595         'sp-west-chest': fromBool(and(hasSmall('sp'), hasHammer)),
596         'sp-big-key-chest': fromBool(and(hasSmall('sp'), hasHammer)),
597         'sp-flooded-left': fromBool(and(hasSmall('sp'), hasHammer, hasHookshot)),
598         'sp-flooded-right': fromBool(and(hasSmall('sp'), hasHammer, hasHookshot)),
599         'sp-waterfall': fromBool(and(hasSmall('sp'), hasHammer, hasHookshot)),
600         'sp-boss-defeated': fromBool(and(hasSmall('sp'), hasHammer, hasHookshot, canKillBoss('sp'))),
601         sw: fromBool(or(canEnterSWFront, canEnterSWMid, canEnterSWBack)),
602         'sw-big-chest': fromBool(and(canEnterSWFront, hasBig('sw'))),
603         'sw-bridge-chest': fromBool(canEnterSWBack),
604         'sw-boss-defeated': fromBool(and(
605                 canEnterSWBack, canPassCurtains, hasFireRod, hasSmall('sw', 3), canKillBoss('sw'),
606         )),
607         tt: fromBool(canEnterTT),
608         'tt-attic': fromBool(and(hasBig('tt'), hasSmall('tt'), canBomb)),
609         'tt-cell': fromBool(hasBig('tt')),
610         'tt-big-chest': fromBool(and(hasBig('tt'), hasSmall('tt'), hasHammer)),
611         'tt-boss-defeated': fromBool(and(hasBig('tt'), hasSmall('tt'), canKillBoss('tt'))),
612         ip: fromBool(canEnterIP),
613         'ip-big-key-chest': fromBool(and(rightSideIP, hasHammer, canLift)),
614         'ip-map-chest': fromBool(and(rightSideIP, hasHammer, canLift)),
615         'ip-spike-chest': fromBool(rightSideIP),
616         'ip-freezor-chest': fromBool(canMeltThings),
617         'ip-big-chest': fromBool(hasBig('ip')),
618         'ip-boss-defeated': fromBool(and(
619                 hasBig('ip'),
620                 hasHammer,
621                 canLift,
622                 or(hasSmall('ip', 2), and(hasSomaria, hasSmall('ip'))),
623                 canKillBoss('ip'),
624         )),
625         mm: fromBool(canEnterMM),
626         'mm-lobby-chest': fromBool(or(hasBig('mm'), hasSmall('mm'))),
627         'mm-compass-chest': fromBool(and(canTorch, hasSmall('mm', 3))),
628         'mm-big-key-chest': fromBool(and(canTorch, hasSmall('mm', 3))),
629         'mm-big-chest': fromBool(hasBig('mm')),
630         'mm-map-chest': fromBool(or(hasBig('mm'), hasSmall('mm'))),
631         'mm-boss-defeated': fromBool(and(hasBig('mm'), canDarkRoom, hasSomaria, canKillBoss('mm'))),
632         tr: fromBool(or(canEnterTRFront, canEnterTRWest, canEnterTREast, canEnterTRBack)),
633         'tr-roller-left': fromBool(and(hasFireRod, hasSomaria, or(
634                 canEnterTRFront,
635                 and(or(canEnterTRWest, canEnterTREast), hasSmall('tr', 4)),
636                 and(canEnterTRBack, canDarkRoom, hasSmall('tr', 4)),
637         ))),
638         'tr-roller-right': fromBool(and(hasFireRod, hasSomaria, or(
639                 canEnterTRFront,
640                 and(or(canEnterTRWest, canEnterTREast), hasSmall('tr', 4)),
641                 and(canEnterTRBack, canDarkRoom, hasSmall('tr', 4)),
642         ))),
643         'tr-compass-chest': fromBool(and(hasSomaria, or(
644                 canEnterTRFront,
645                 and(or(canEnterTRWest, canEnterTREast), hasSmall('tr', 4)),
646                 and(canEnterTRBack, canDarkRoom, hasSmall('tr', 4)),
647         ))),
648         'tr-chomps': fromBool(or(
649                 and(canEnterTRFront, hasSmall('tr')),
650                 canEnterTRWest,
651                 canEnterTREast,
652                 and(canEnterTRBack, canDarkRoom, hasSomaria),
653         )),
654         'tr-big-key-chest': fromBool(and(hasSmall('tr', 4), or(
655                 and(canEnterTRFront, hasSomaria),
656                 canEnterTRWest,
657                 canEnterTREast,
658                 and(canEnterTRBack, canDarkRoom, hasSomaria),
659         ))),
660         'tr-big-chest': fromBool(canEnterTREast),
661         'tr-crysta-roller': fromBool(or(
662                 and(hasBig('tr'), or(
663                         and(canEnterTRFront, hasSomaria, hasSmall('tr', 2)),
664                         canEnterTRWest,
665                         canEnterTREast,
666                 )),
667                 and(canEnterTRBack, canDarkRoom, hasSomaria),
668         )),
669         'tr-laser-bridge-top': fromBool(laserBridge),
670         'tr-laser-bridge-left': fromBool(laserBridge),
671         'tr-laser-bridge-right': fromBool(laserBridge),
672         'tr-laser-bridge-bottom': fromBool(laserBridge),
673         'tr-boss-defeated': fromBool(and(
674                 laserBridge,
675                 hasSmall('tr', 4),
676                 hasBig('tr'),
677                 hasSomaria,
678                 canKillBoss('tr'),
679         )),
680 };
681
682 export default Logic;