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