forked from mirror/Archipelago
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
381 lines
13 KiB
Lua
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,
|
|
-- }
|