X-Git-Url: https://git.localhorst.tv/?a=blobdiff_plain;f=resources%2Fjs%2Fhelpers%2Ftracker.js;h=8b210d2632f266c94e629d204ec2715436badfe9;hb=6a65eac02f94f00fdd2d56ad8feddf5d9476aa1e;hp=e4b0ebe9f765a33d497ff2d994537a64168860ae;hpb=249e06be11d0f7778d99956c87d4f0a8ac7e69f7;p=alttp.git diff --git a/resources/js/helpers/tracker.js b/resources/js/helpers/tracker.js index e4b0ebe..8b210d2 100644 --- a/resources/js/helpers/tracker.js +++ b/resources/js/helpers/tracker.js @@ -7,6 +7,7 @@ import { isBossDefeated, isChestOpen, } from './alttp-ram'; +import Logic from './logic'; export const BOOLEAN_STATES = [ 'blue-boomerang', @@ -42,7 +43,10 @@ export const BOOLEAN_STATES = [ ]; export const INTEGER_STATES = [ - 'bottle', + 'bottle-1', + 'bottle-2', + 'bottle-3', + 'bottle-4', 'heart-piece', 'lift', 'mail', @@ -54,6 +58,17 @@ export const INITIAL = { mail: 1, }; +export const BOTTLE_CONTENTS = [ + 'mushroom', + 'bottle', + 'red-potion', + 'green-potion', + 'blue-potion', + 'fairy', + 'bottle-bee', + 'bottle-bee', +]; + export const BOSSES = [ 'armos', 'lanmolas', @@ -68,6 +83,8 @@ export const BOSSES = [ ]; export const CONFIG = { + bossShuffle: false, + glitches: 'none', showMap: 'situational', showCompass: 'situational', showSmall: 'always', @@ -76,7 +93,7 @@ export const CONFIG = { wildCompass: false, wildSmall: false, wildBig: false, - bossShuffle: false, + worldState: 'open', }; export const DUNGEONS = [ @@ -1556,6 +1573,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 +1648,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 => ['unavailable', 'cleared'].includes(s)).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 +1706,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 +1762,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 +1776,8 @@ export const makeEmptyState = () => { }); state['mm-medallion'] = null; state['tr-medallion'] = null; + state['gt-crystals'] = 7; + state['ganon-crystals'] = 7; return state; }; @@ -1725,19 +1803,10 @@ const collectInventory = (state, data, prizeMap) => { state.duck = !!(data[INV_ADDR.RANDO_FLUTE] & 0x01); state.bugnet = !!data[INV_ADDR.BUGNET]; state.book = !!data[INV_ADDR.BOOK]; - state.bottle = 0; - if (data[INV_ADDR.BOTTLE_1]) { - ++state.bottle; - } - if (data[INV_ADDR.BOTTLE_2]) { - ++state.bottle; - } - if (data[INV_ADDR.BOTTLE_3]) { - ++state.bottle; - } - if (data[INV_ADDR.BOTTLE_4]) { - ++state.bottle; - } + state['bottle-1'] = data[INV_ADDR.BOTTLE_1]; + state['bottle-2'] = data[INV_ADDR.BOTTLE_2]; + state['bottle-3'] = data[INV_ADDR.BOTTLE_3]; + state['bottle-4'] = data[INV_ADDR.BOTTLE_4]; state.somaria = !!data[INV_ADDR.SOMARIA]; state.byrna = !!data[INV_ADDR.BYRNA]; state.cape = !!data[INV_ADDR.CAPE]; @@ -1872,8 +1941,19 @@ export const mergeStates = (autoState, manualState) => { next[loc.id] = true; } }); + // prefer auto + next['bottle-1'] = autoState['bottle-1'] || manualState['bottle-1'] || 0; + next['bottle-2'] = autoState['bottle-2'] || manualState['bottle-2'] || 0; + next['bottle-3'] = autoState['bottle-3'] || manualState['bottle-3'] || 0; + next['bottle-4'] = autoState['bottle-4'] || manualState['bottle-4'] || 0; + // force manual next['mm-medallion'] = manualState['mm-medallion']; next['tr-medallion'] = manualState['tr-medallion']; + next['gt-crystals'] = manualState['gt-crystals']; + next['ganon-crystals'] = manualState['ganon-crystals']; + next['gt-bot-boss'] = manualState['gt-bot-boss']; + next['gt-mid-boss'] = manualState['gt-mid-boss']; + next['gt-top-boss'] = manualState['gt-top-boss']; //console.log(next); return next; };