Files
Jonathan Tinney 7971961166
Some checks failed
Analyze modified files / flake8 (push) Failing after 2m28s
Build / build-win (push) Has been cancelled
Build / build-ubuntu2204 (push) Has been cancelled
ctest / Test C++ ubuntu-latest (push) Has been cancelled
ctest / Test C++ windows-latest (push) Has been cancelled
Analyze modified files / mypy (push) Has been cancelled
Build and Publish Docker Images / Push Docker image to Docker Hub (push) Successful in 5m4s
Native Code Static Analysis / scan-build (push) Failing after 5m2s
type check / pyright (push) Successful in 1m7s
unittests / Test Python 3.11.2 ubuntu-latest (push) Failing after 16m23s
unittests / Test Python 3.12 ubuntu-latest (push) Failing after 28m19s
unittests / Test Python 3.13 ubuntu-latest (push) Failing after 14m49s
unittests / Test hosting with 3.13 on ubuntu-latest (push) Successful in 5m0s
unittests / Test Python 3.13 macos-latest (push) Has been cancelled
unittests / Test Python 3.11 windows-latest (push) Has been cancelled
unittests / Test Python 3.13 windows-latest (push) Has been cancelled
add schedule I, sonic 1/frontiers/heroes, spirit island
2026-04-02 23:46:36 -07:00

381 lines
13 KiB
Lua

require("scripts/autotracking/item_mapping")
require("scripts/autotracking/location_mapping")
require("scripts/autotracking/map_mapping")
Tracker:FindObjectForCode("blueemerald(#1)"):SetOverlay("Blue")
Tracker:FindObjectForCode("yellowemerald(#2)"):SetOverlay("Yellow")
Tracker:FindObjectForCode("pinkemerald(#3)"):SetOverlay("Pink")
Tracker:FindObjectForCode("greenemerald(#4)"):SetOverlay("Green")
Tracker:FindObjectForCode("redemerald(#5)"):SetOverlay("Red")
Tracker:FindObjectForCode("greyemerald(#6)"):SetOverlay("Grey")
Tracker:FindObjectForCode("disablegoalblocks"):SetOverlay("Buff")
Tracker:FindObjectForCode("disablerblocks"):SetOverlay("Buff")
Tracker:FindObjectForCode("greenhillkey"):SetOverlay("GHZ")
Tracker:FindObjectForCode("marblezonekey"):SetOverlay("MZ")
Tracker:FindObjectForCode("springyardkey"):SetOverlay("SYZ")
Tracker:FindObjectForCode("labyrinthkey"):SetOverlay("LZ")
Tracker:FindObjectForCode("starlightkey"):SetOverlay("SLZ")
Tracker:FindObjectForCode("scrapbrainkey"):SetOverlay("SBZ")
Tracker:FindObjectForCode("finalzonekey"):SetOverlay("FZ")
Tracker:FindObjectForCode("specialstagekey"):SetOverlay("SS")
CUR_INDEX = -1
--SLOT_DATA = nil
SLOT_DATA = {}
AREA_KEY = ""
BOSS_KEY = ""
BOSS_DATA = nil
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 = '{'
for k, v in pairs(o) do
if type(k) ~= 'number' then
k = '"' .. k .. '"'
end
s = s .. tabs2 .. '[' .. k .. '] = ' .. dump_table(v, depth + 1) .. ','
end
return s .. tabs .. '}'
else
return tostring(o)
end
end
function forceUpdate()
-- local update = Tracker:FindObjectForCode("update")
-- update.Active = not update.Active
end
function onClearHandler(slot_data)
local clear_timer = os.clock()
--ScriptHost:RemoveWatchForCode("StateChange")
-- Disable tracker updates.
Tracker.BulkUpdate = true
-- Use a protected call so that tracker updates always get enabled again, even if an error occurred.
local ok, err = pcall(onClear, slot_data)
-- Enable tracker updates again.
if ok then
-- Defer re-enabling tracker updates until the next frame, which doesn't happen until all received items/cleared
-- locations from AP have been processed.
local handlerName = "AP onClearHandler"
local function frameCallback()
--ScriptHost:AddWatchForCode("StateChange", "*", StateChange)
ScriptHost:RemoveOnFrameHandler(handlerName)
Tracker.BulkUpdate = false
forceUpdate()
print(string.format("Time taken total: %.2f", os.clock() - clear_timer))
end
ScriptHost:AddOnFrameHandler(handlerName, frameCallback)
else
Tracker.BulkUpdate = false
print("Error: onClear failed:")
print(err)
end
end
function onClear(slot_data)
CUR_INDEX = -1
-- reset locations
for _, location_array in pairs(LOCATION_MAPPING) do
for _, location in pairs(location_array) do
if location then
local lookingat = string.format("@%s/%s",location, location)
local location_obj = Tracker:FindObjectForCode(lookingat)
if location_obj then
location_obj.AvailableChestCount = 1
end
end
end
end
-- reset items
for _, item_tuple in pairs(ITEM_MAPPING) do
local item_obj = Tracker:FindObjectForCode(item_tuple[1])
if item_obj then
if item_obj.Type == "toggle" then
item_obj.Active = false
elseif item_obj.Type == "progressive" then
item_obj.CurrentStage = 0
item_obj.Active = false
elseif item_obj.Type == "consumable" then
item_obj.AcquiredCount = 0
end
end
end
PLAYER_ID = Archipelago.PlayerNumber or -1
TEAM_NUMBER = Archipelago.TeamNumber or 0
SLOT_DATA = slot_data
print(dump_table(SLOT_DATA))
-- if Tracker:FindObjectForCode("autofill_settings").Active == true then
-- autoFill(slot_data)
-- end
-- print(PLAYER_ID, TEAM_NUMBER)
if Archipelago.PlayerNumber > -1 then
HINTS_ID = "_read_hints_"..TEAM_NUMBER.."_"..PLAYER_ID
Archipelago:SetNotify({HINTS_ID})
Archipelago:Get({HINTS_ID})
AREA_KEY = string.format("%s_%s_sonic1_area", PLAYER_ID, TEAM_NUMBER)
Archipelago:SetNotify({AREA_KEY})
Archipelago:Get({AREA_KEY})
BOSS_KEY = string.format("%s_%s_sonic1_bosses", PLAYER_ID, TEAM_NUMBER)
Archipelago:SetNotify({BOSS_KEY})
Archipelago:Get({BOSS_KEY})
end
end
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 item = ITEM_MAPPING[item_id]
print(string.format("handling %s - %s", item_id, item_name))
if not item or not item[1] then
--print(string.format("onItem: could not find item mapping for id %s", item_id))
return
end
local item_obj = Tracker:FindObjectForCode(item[1])
if item_obj then
if item_obj.Type == "toggle" then
-- print("toggle")
item_obj.Active = true
elseif item_obj.Type == "consumable" then
-- print("toggle")
item_obj.AcquiredCount = item_obj.AcquiredCount + 1
end
else
print(string.format("onItem: could not find object for code %s", item_code[1]))
end
end
function ssKeyCheck(howmany)
local item_obj = Tracker:FindObjectForCode("Special Stage Key")
if item_obj then
if item_obj.AcquiredCount >= tonumber(howmany) then
return true
end
else
print(string.format("onItem: could not find object for code %s", item_code[1]))
end
return false
end
function fzOpenCheck()
local item_obj = Tracker:FindObjectForCode("Final Zone Key")
if item_obj and item_obj.Active == true then
if SLOT_DATA["final_zone_last"] == 0 then
return true
else
local ems = 0
for _,em in pairs({Tracker:FindObjectForCode("blueemerald(#1)"),
Tracker:FindObjectForCode("yellowemerald(#2)"),
Tracker:FindObjectForCode("pinkemerald(#3)"),
Tracker:FindObjectForCode("greenemerald(#4)"),
Tracker:FindObjectForCode("redemerald(#5)"),
Tracker:FindObjectForCode("greyemerald(#6)")}) do
if em.Active == true then ems = ems + 1 end
end
if ems < SLOT_DATA["emerald_goal"] then return false end
if (Tracker:FindObjectForCode("Gold Ring").AcquiredCount +
Tracker:FindObjectForCode("Shiny Ring").AcquiredCount) < SLOT_DATA["ring_goal"] then
return false
end
if BOSS_DATA and BOSS_DATA + 1 < SLOT_DATA["boss_goal"] then return false end
return true
end
else
print("Could not find active FZ key")
end
return false
end
function mzSequenceBreakCheck()
local mzk = Tracker:FindObjectForCode("Marble Zone Key")
if mzk and mzk.Active == true then
return AccessibilityLevel.Normal
elseif fzOpenCheck() then
return AccessibilityLevel.SequenceBreak
end
return AccessibilityLevel.None
end
--called when a location gets cleared
function onLocation(location_id, location_name)
local location_array = LOCATION_MAPPING[location_id]
if not location_array or not location_array[1] then
print(string.format("onLocation: could not find location mapping for id %s", location_id))
return
end
for _, location in pairs(location_array) do
print(string.format("handling %s - %s", location_id, location))
local location_obj = Tracker:FindObjectForCode(string.format("@%s/%s",location, location))
-- print(location, location_obj)
if location_obj then
location_obj.AvailableChestCount = 0
else
print(string.format("onLocation: could not find location_object for code %s", location))
end
end
--canFinish()
end
function onEvent(key, value, old_value)
updateEvents(value)
end
function onEventsLaunch(key, value)
updateEvents(value)
end
-- this Autofill function is meant as an example on how to do the reading from slotdata and mapping the values to
-- your own settings
-- function autoFill()
-- if SLOT_DATA == nil then
-- print("its fucked")
-- return
-- end
-- -- print(dump_table(SLOT_DATA))
-- mapToggle={[0]=0,[1]=1,[2]=1,[3]=1,[4]=1}
-- mapToggleReverse={[0]=1,[1]=0,[2]=0,[3]=0,[4]=0}
-- mapTripleReverse={[0]=2,[1]=1,[2]=0}
-- slotCodes = {
-- map_name = {code="", mapping=mapToggle...}
-- }
-- -- print(dump_table(SLOT_DATA))
-- -- print(Tracker:FindObjectForCode("autofill_settings").Active)
-- if Tracker:FindObjectForCode("autofill_settings").Active == true then
-- for settings_name , settings_value in pairs(SLOT_DATA) do
-- -- print(k, v)
-- if slotCodes[settings_name] then
-- item = Tracker:FindObjectForCode(slotCodes[settings_name].code)
-- if item.Type == "toggle" then
-- item.Active = slotCodes[settings_name].mapping[settings_value]
-- else
-- -- print(k,v,Tracker:FindObjectForCode(slotCodes[k].code).CurrentStage, slotCodes[k].mapping[v])
-- item.CurrentStage = slotCodes[settings_name].mapping[settings_value]
-- end
-- end
-- end
-- end
-- end
function onNotify(key, value, old_value)
print("onNotify", key, value, old_value)
--[[ if value ~= old_value and key == HINTS_ID then
for _, hint in ipairs(value) do
if hint.finding_player == Archipelago.PlayerNumber then
if hint.found then
updateHints(hint.location, true)
else
updateHints(hint.location, false)
end
end
end
end ]]
if key == AREA_KEY and AREA_MAPPING[value] then
Tracker:UiHint("ActivateTab", AREA_MAPPING[value][1])
if AREA_MAPPING[value][2] then
Tracker:UiHint("ActivateTab", AREA_MAPPING[value][2])
end
elseif key == BOSS_KEY then
BOSS_DATA = 0
if value then
for _,bit in pairs({1,2,4,8,16,32}) do
if value&bit == bit then BOSS_DATA = BOSS_DATA + 1 end
end
end
end
end
function onNotifyLaunch(key, value)
print("onNotifyLaunch", key, value)
--[[ if key == HINTS_ID then
for _, hint in ipairs(value) do
print("hint", hint, hint.fount)
print(dump_table(hint))
if hint.finding_player == Archipelago.PlayerNumber then
if hint.found then
updateHints(hint.location, true)
else
updateHints(hint.location, false)
end
end
end
end ]]
if key == AREA_KEY and AREA_MAPPING[value] then
Tracker:UiHint("ActivateTab", AREA_MAPPING[value][1])
if AREA_MAPPING[value][2] then
Tracker:UiHint("ActivateTab", AREA_MAPPING[value][2])
end
elseif key == BOSS_KEY then
BOSS_DATA = 0
if value then
for _,bit in pairs({1,2,4,8,16,32}) do
if value&bit == bit then BOSS_DATA = BOSS_DATA + 1 end
end
end
end
end
function updateHints(locationID, clear)
local item_codes = HINTS_MAPPING[locationID]
for _, item_table in ipairs(item_codes, clear) do
for _, item_code in ipairs(item_table) do
local obj = Tracker:FindObjectForCode(item_code)
if obj then
if not clear then
obj.Active = true
else
obj.Active = false
end
else
print(string.format("No object found for code: %s", item_code))
end
end
end
end
-- ScriptHost:AddWatchForCode("settings autofill handler", "autofill_settings", autoFill)
Archipelago:AddClearHandler("clear handler", onClearHandler)
Archipelago:AddItemHandler("item handler", onItem)
Archipelago:AddLocationHandler("location handler", onLocation)
Archipelago:AddSetReplyHandler("notify handler", onNotify)
Archipelago:AddRetrievedHandler("notify launch handler", onNotifyLaunch)
--doc
--hint layout
-- {
-- ["receiving_player"] = 1,
-- ["class"] = Hint,
-- ["finding_player"] = 1,
-- ["location"] = 67361,
-- ["found"] = false,
-- ["item_flags"] = 2,
-- ["entrance"] = ,
-- ["item"] = 66062,
-- }