]> git.localhorst.tv Git - alttp.git/blobdiff - resources/js/helpers/tracker.js
simple logic tracking
[alttp.git] / resources / js / helpers / tracker.js
index e4b0ebe9f765a33d497ff2d994537a64168860ae..47a34f135bbd55e7ec3eb31f2efccc7a824eccfe 100644 (file)
@@ -7,6 +7,7 @@ import {
        isBossDefeated,
        isChestOpen,
 } from './alttp-ram';
+import Logic from './logic';
 
 export const BOOLEAN_STATES = [
        'blue-boomerang',
@@ -68,6 +69,8 @@ export const BOSSES = [
 ];
 
 export const CONFIG = {
+       bossShuffle: false,
+       glitches: 'none',
        showMap: 'situational',
        showCompass: 'situational',
        showSmall: 'always',
@@ -76,7 +79,7 @@ export const CONFIG = {
        wildCompass: false,
        wildSmall: false,
        wildBig: false,
-       bossShuffle: false,
+       worldState: 'open',
 };
 
 export const DUNGEONS = [
@@ -1556,6 +1559,15 @@ export const UNDERWORLD_LOCATIONS = [
        },
 ];
 
+export const applyLogic = (config, dungeons, state) => {
+       const logic = Logic[config.worldState];
+       const map = {};
+       for (const name in logic) {
+               map[name] = logic[name](config, dungeons, state);
+       }
+       return map;
+};
+
 export const shouldShowDungeonItem = (config, which) => {
        const show = config[`show${which}`] || 'always';
        const wild = config[`wild${which}`] || false;
@@ -1622,9 +1634,39 @@ export const countClearedLocations = (state, locations) =>
 export const hasClearedLocations = (state, locations) =>
        countClearedLocations(state, locations) === locations.length;
 
+export const getLocationStatus = (name, logic, state) => {
+       if (state[name]) return 'cleared';
+       if (logic[name]) return logic[name];
+       return logic.fallback;
+};
+
+export const getCombinedStatus = statuses => {
+       if (statuses.filter(s => s === 'cleared').length === statuses.length) {
+               return 'cleared';
+       }
+       if (statuses.filter(s => ['available', 'cleared'].includes(s)).length === statuses.length) {
+               return 'available';
+       }
+       if (statuses.filter(s => s === 'unavailable').length === statuses.length) {
+               return 'unavailable';
+       }
+       return 'partial';
+};
+
+export const aggregateLocationStatus = (names, logic, state) => {
+       const statuses = names.map(name => getLocationStatus(name, logic, state));
+       return getCombinedStatus(statuses);
+};
+
 export const countRemainingLocations = (state, locations) =>
        locations.reduce((acc, cur) => state[cur] ? acc : acc + 1, 0);
 
+export const getGanonCrystals = (state) => state['ganon-crystals'];
+
+export const getGTCrystals = (state) => state['gt-crystals'];
+
+export const getGTBoss = (state, which) => state[`gt-${which}-boss`];
+
 export const hasDungeonBoss = (state, dungeon) =>
        !dungeon.boss || !!state[`${dungeon.id}-boss-defeated`];
 
@@ -1650,6 +1692,21 @@ export const isDungeonCleared = (state, dungeon) => {
        return hasItems && hasBoss && hasPrize;
 };
 
+export const aggregateDungeonStatus = (dungeon, logic, state) => {
+       if (isDungeonCleared(state, dungeon)) {
+               return 'cleared';
+       }
+       if (logic[dungeon.id] === 'unavailable') {
+               return 'unavailable';
+       }
+       const checks = [...dungeon.checks];
+       if (['ct', 'gt'].includes(dungeon.id)) {
+               checks.push(`${dungeon.id}-boss-killable`);
+       }
+       const statuses = checks.map(name => getLocationStatus(name, logic, state));
+       return getCombinedStatus(statuses);
+};
+
 export const toggleBossDefeated = dungeon => toggleBoolean(`${dungeon.id}-boss-defeated`);
 
 export const setBossDefeated = (dungeon, defeated) =>
@@ -1691,6 +1748,11 @@ export const makeEmptyState = () => {
                        state[`${dungeon.id}-prize`] = 'crystal';
                        state[`${dungeon.id}-prize-acquired`] = false;
                }
+               if (dungeon.id === 'gt') {
+                       state['gt-bot-boss'] = 'armos';
+                       state['gt-mid-boss'] = 'lanmolas';
+                       state['gt-top-boss'] = 'moldorm';
+               }
        });
        OVERWORLD_LOCATIONS.forEach(location => {
                state[location.id] = false;
@@ -1700,6 +1762,8 @@ export const makeEmptyState = () => {
        });
        state['mm-medallion'] = null;
        state['tr-medallion'] = null;
+       state['gt-crystals'] = 7;
+       state['ganon-crystals'] = 7;
        return state;
 };
 
@@ -1874,6 +1938,8 @@ export const mergeStates = (autoState, manualState) => {
        });
        next['mm-medallion'] = manualState['mm-medallion'];
        next['tr-medallion'] = manualState['tr-medallion'];
+       next['gt-crystals'] = manualState['gt-crystals'];
+       next['ganon-crystals'] = manualState['ganon-crystals'];
        //console.log(next);
        return next;
 };