739 lines
28 KiB
Lua
739 lines
28 KiB
Lua
local socket = require("socket")
|
|
local json = require('json')
|
|
local math = require('math')
|
|
require("common")
|
|
|
|
local STATE_OK = "Ok"
|
|
local STATE_TENTATIVELY_CONNECTED = "Tentatively Connected"
|
|
local STATE_INITIAL_CONNECTION_MADE = "Initial Connection Made"
|
|
local STATE_UNINITIALIZED = "Uninitialized"
|
|
|
|
local SCRIPT_VERSION = 1
|
|
|
|
local APItemValue = 0xA2
|
|
local APItemRam = 0xE7
|
|
local BatAPItemValue = 0xAB
|
|
local BatAPItemRam = 0xEA
|
|
local PlayerRoomAddr = 0x8A -- if in number room, we're not in play mode
|
|
local WinAddr = 0xDE -- if not 0 (I think if 0xff specifically), we won (and should update once, immediately)
|
|
|
|
-- If any of these are 2, that dragon ate the player (should send update immediately
|
|
-- once, and reset that when none of them are 2 again)
|
|
|
|
local DragonState = {0xA8, 0xAD, 0xB2}
|
|
local last_dragon_state = {0, 0, 0}
|
|
local carryAddress = 0x9D -- uses rom object table
|
|
local batRoomAddr = 0xCB
|
|
local batCarryAddress = 0xD0 -- uses ram object location
|
|
local batInvalidCarryItem = 0x78
|
|
local batItemCheckAddr = 0xf69f
|
|
local batMatrixLen = 11 -- number of pairs
|
|
local last_carry_item = 0xB4
|
|
local frames_with_no_item = 0
|
|
local ItemTableStart = 0xfe9d
|
|
local PlayerSlotAddress = 0xfff9
|
|
|
|
local nullObjectId = 0xB4
|
|
local ItemsReceived = nil
|
|
local sha256hash = nil
|
|
local foreign_items = nil
|
|
local foreign_items_by_room = {}
|
|
local bat_no_touch_locations_by_room = {}
|
|
local bat_no_touch_items = {}
|
|
local autocollect_items = {}
|
|
local localItemLocations = {}
|
|
|
|
local prev_bat_room = 0xff
|
|
local prev_player_room = 0
|
|
local prev_ap_room_index = nil
|
|
|
|
local pending_foreign_items_collected = {}
|
|
local pending_local_items_collected = {}
|
|
local rendering_foreign_item = nil
|
|
local skip_inventory_items = {}
|
|
|
|
local inventory = {}
|
|
local next_inventory_item = nil
|
|
|
|
local input_button_address = 0xD7
|
|
|
|
local deathlink_rec = nil
|
|
local deathlink_send = 0
|
|
|
|
local deathlink_sent = false
|
|
|
|
local prevstate = ""
|
|
local curstate = STATE_UNINITIALIZED
|
|
local atariSocket = nil
|
|
local frame = 0
|
|
|
|
local ItemIndex = 0
|
|
|
|
local yorgle_speed_address = 0xf725
|
|
local grundle_speed_address = 0xf740
|
|
local rhindle_speed_address = 0xf70A
|
|
|
|
local read_switch_a = 0xf780
|
|
local read_switch_b = 0xf764
|
|
|
|
local yorgle_speed = nil
|
|
local grundle_speed = nil
|
|
local rhindle_speed = nil
|
|
|
|
local slow_yorgle_id = tostring(118000000 + 0x103)
|
|
local slow_grundle_id = tostring(118000000 + 0x104)
|
|
local slow_rhindle_id = tostring(118000000 + 0x105)
|
|
|
|
local yorgle_dead = false
|
|
local grundle_dead = false
|
|
local rhindle_dead = false
|
|
|
|
local diff_a_locked = false
|
|
local diff_b_locked = false
|
|
|
|
local bat_logic = 0
|
|
|
|
local is_dead = 0
|
|
local freeincarnates_available = 0
|
|
local send_freeincarnate_used = false
|
|
local current_bat_ap_item = nil
|
|
|
|
local was_in_number_room = false
|
|
|
|
function uRangeRam(address, bytes)
|
|
data = memory.read_bytes_as_array(address, bytes, "Main RAM")
|
|
return data
|
|
end
|
|
function uRangeRom(address, bytes)
|
|
data = memory.read_bytes_as_array(address+0xf000, bytes, "System Bus")
|
|
return data
|
|
end
|
|
function uRangeAddress(address, bytes)
|
|
data = memory.read_bytes_as_array(address, bytes, "System Bus")
|
|
return data
|
|
end
|
|
|
|
local function createForeignItemsByRoom()
|
|
foreign_items_by_room = {}
|
|
if foreign_items == nil then
|
|
return
|
|
end
|
|
for _, foreign_item in pairs(foreign_items) do
|
|
if foreign_items_by_room[foreign_item.room_id] == nil then
|
|
foreign_items_by_room[foreign_item.room_id] = {}
|
|
end
|
|
new_foreign_item = {}
|
|
new_foreign_item.room_id = foreign_item.room_id
|
|
new_foreign_item.room_x = foreign_item.room_x
|
|
new_foreign_item.room_y = foreign_item.room_y
|
|
new_foreign_item.short_location_id = foreign_item.short_location_id
|
|
|
|
table.insert(foreign_items_by_room[foreign_item.room_id], new_foreign_item)
|
|
end
|
|
end
|
|
|
|
function debugPrintNoTouchLocations()
|
|
for room_id, list in pairs(bat_no_touch_locations_by_room) do
|
|
for index, notouch_location in ipairs(list) do
|
|
print("ROOM "..tostring(room_id).. "["..tostring(index).."]: "..tostring(notouch_location.short_location_id))
|
|
end
|
|
end
|
|
end
|
|
|
|
function processBlock(block)
|
|
if block == nil then
|
|
return
|
|
end
|
|
local block_identified = 0
|
|
local msgBlock = block['messages']
|
|
if msgBlock ~= nil then
|
|
block_identified = 1
|
|
for i, v in pairs(msgBlock) do
|
|
if itemMessages[i] == nil then
|
|
local msg = {TTL=450, message=v, color=0xFFFF0000}
|
|
itemMessages[i] = msg
|
|
end
|
|
end
|
|
end
|
|
local itemsBlock = block["items"]
|
|
if itemsBlock ~= nil then
|
|
block_identified = 1
|
|
ItemsReceived = itemsBlock
|
|
end
|
|
local apItemsBlock = block["foreign_items"]
|
|
if apItemsBlock ~= nil then
|
|
block_identified = 1
|
|
print("got foreign items block")
|
|
foreign_items = apItemsBlock
|
|
createForeignItemsByRoom()
|
|
end
|
|
local autocollectItems = block["autocollect_items"]
|
|
if autocollectItems ~= nil then
|
|
block_identified = 1
|
|
autocollect_items = {}
|
|
for _, acitem in pairs(autocollectItems) do
|
|
if autocollect_items[acitem.room_id] == nil then
|
|
autocollect_items[acitem.room_id] = {}
|
|
end
|
|
table.insert(autocollect_items[acitem.room_id], acitem)
|
|
end
|
|
end
|
|
local localLocalItemLocations = block["local_item_locations"]
|
|
if localLocalItemLocations ~= nil then
|
|
block_identified = 1
|
|
localItemLocations = localLocalItemLocations
|
|
print("got local item locations")
|
|
end
|
|
local checkedLocationsBlock = block["checked_locations"]
|
|
if checkedLocationsBlock ~= nil then
|
|
block_identified = 1
|
|
for room_id, foreign_item_list in pairs(foreign_items_by_room) do
|
|
for i, foreign_item in pairs(foreign_item_list) do
|
|
short_id = foreign_item.short_location_id
|
|
for j, checked_id in pairs(checkedLocationsBlock) do
|
|
if checked_id == short_id then
|
|
table.remove(foreign_item_list, i)
|
|
break
|
|
end
|
|
end
|
|
end
|
|
end
|
|
if foreign_items ~= nil then
|
|
for i, foreign_item in pairs(foreign_items) do
|
|
short_id = foreign_item.short_location_id
|
|
for j, checked_id in pairs(checkedLocationsBlock) do
|
|
if checked_id == short_id then
|
|
foreign_items[i] = nil
|
|
break
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
local dragon_speeds_block = block["dragon_speeds"]
|
|
if dragon_speeds_block ~= nil then
|
|
block_identified = 1
|
|
yorgle_speed = dragon_speeds_block[slow_yorgle_id]
|
|
grundle_speed = dragon_speeds_block[slow_grundle_id]
|
|
rhindle_speed = dragon_speeds_block[slow_rhindle_id]
|
|
end
|
|
local diff_a_block = block["difficulty_a_locked"]
|
|
if diff_a_block ~= nil then
|
|
block_identified = 1
|
|
diff_a_locked = diff_a_block
|
|
end
|
|
local diff_b_block = block["difficulty_b_locked"]
|
|
if diff_b_block ~= nil then
|
|
block_identified = 1
|
|
diff_b_locked = diff_b_block
|
|
end
|
|
local freeincarnates_available_block = block["freeincarnates_available"]
|
|
if freeincarnates_available_block ~= nil then
|
|
block_identified = 1
|
|
if freeincarnates_available ~= freeincarnates_available_block then
|
|
freeincarnates_available = freeincarnates_available_block
|
|
local msg = {TTL=450, message="freeincarnates: "..tostring(freeincarnates_available), color=0xFFFF0000}
|
|
itemMessages[-2] = msg
|
|
end
|
|
end
|
|
local bat_logic_block = block["bat_logic"]
|
|
if bat_logic_block ~= nil then
|
|
block_identified = 1
|
|
bat_logic = bat_logic_block
|
|
end
|
|
local bat_no_touch_locations_block = block["bat_no_touch_locations"]
|
|
if bat_no_touch_locations_block ~= nil then
|
|
block_identified = 1
|
|
for _, notouch_location in pairs(bat_no_touch_locations_block) do
|
|
local room_id = tonumber(notouch_location.room_id)
|
|
if bat_no_touch_locations_by_room[room_id] == nil then
|
|
bat_no_touch_locations_by_room[room_id] = {}
|
|
end
|
|
table.insert(bat_no_touch_locations_by_room[room_id], notouch_location)
|
|
|
|
if notouch_location.local_item ~= nil and notouch_location.local_item ~= 255 then
|
|
bat_no_touch_items[tonumber(notouch_location.local_item)] = true
|
|
-- print("no touch: "..tostring(notouch_location.local_item))
|
|
end
|
|
end
|
|
-- debugPrintNoTouchLocations()
|
|
end
|
|
deathlink_rec = deathlink_rec or block["deathlink"]
|
|
if( block_identified == 0 ) then
|
|
print("unidentified block")
|
|
print(block)
|
|
end
|
|
end
|
|
|
|
function getAllRam()
|
|
uRangeRAM(0,128);
|
|
return data
|
|
end
|
|
|
|
local function alive_mode()
|
|
return (u8(PlayerRoomAddr) ~= 0x00 and u8(WinAddr) == 0x00)
|
|
end
|
|
|
|
local function generateLocationsChecked()
|
|
list_of_locations = {}
|
|
for s, f in pairs(pending_foreign_items_collected) do
|
|
table.insert(list_of_locations, f.short_location_id + 118000000)
|
|
end
|
|
for s, f in pairs(pending_local_items_collected) do
|
|
table.insert(list_of_locations, f + 118000000)
|
|
end
|
|
return list_of_locations
|
|
end
|
|
|
|
function receive()
|
|
l, e = atariSocket:receive()
|
|
if e == 'closed' then
|
|
if curstate == STATE_OK then
|
|
print("Connection closed")
|
|
end
|
|
curstate = STATE_UNINITIALIZED
|
|
return
|
|
elseif e == 'timeout' then
|
|
return
|
|
elseif e ~= nil then
|
|
print(e)
|
|
curstate = STATE_UNINITIALIZED
|
|
return
|
|
end
|
|
if l ~= nil then
|
|
processBlock(json.decode(l))
|
|
end
|
|
-- Determine Message to send back
|
|
|
|
newSha256 = memory.hash_region(0xF000, 0x1000, "System Bus")
|
|
if (sha256hash ~= nil and sha256hash ~= newSha256) then
|
|
print("ROM changed, quitting")
|
|
curstate = STATE_UNINITIALIZED
|
|
return
|
|
end
|
|
sha256hash = newSha256
|
|
local retTable = {}
|
|
retTable["scriptVersion"] = SCRIPT_VERSION
|
|
retTable["romhash"] = sha256hash
|
|
if (alive_mode()) then
|
|
retTable["locations"] = generateLocationsChecked()
|
|
end
|
|
if (u8(WinAddr) ~= 0x00) then
|
|
retTable["victory"] = 1
|
|
end
|
|
if( deathlink_sent or deathlink_send == 0 ) then
|
|
retTable["deathLink"] = 0
|
|
else
|
|
print("Sending deathlink "..tostring(deathlink_send))
|
|
retTable["deathLink"] = deathlink_send
|
|
deathlink_sent = true
|
|
end
|
|
deathlink_send = 0
|
|
|
|
if send_freeincarnate_used == true then
|
|
print("Sending freeincarnate used")
|
|
retTable["freeincarnate"] = true
|
|
send_freeincarnate_used = false
|
|
end
|
|
|
|
msg = json.encode(retTable).."\n"
|
|
local ret, error = atariSocket:send(msg)
|
|
if ret == nil then
|
|
print(error)
|
|
elseif curstate == STATE_INITIAL_CONNECTION_MADE then
|
|
curstate = STATE_TENTATIVELY_CONNECTED
|
|
elseif curstate == STATE_TENTATIVELY_CONNECTED then
|
|
print("Connected!")
|
|
curstate = STATE_OK
|
|
end
|
|
end
|
|
|
|
function AutocollectFromRoom()
|
|
if autocollect_items ~= nil and autocollect_items[prev_player_room] ~= nil then
|
|
for _, item in pairs(autocollect_items[prev_player_room]) do
|
|
pending_foreign_items_collected[item.short_location_id] = item
|
|
end
|
|
end
|
|
end
|
|
|
|
function SetYorgleSpeed()
|
|
if yorgle_speed ~= nil then
|
|
emu.setregister("A", yorgle_speed);
|
|
end
|
|
end
|
|
|
|
function SetGrundleSpeed()
|
|
if grundle_speed ~= nil then
|
|
emu.setregister("A", grundle_speed);
|
|
end
|
|
end
|
|
|
|
function SetRhindleSpeed()
|
|
if rhindle_speed ~= nil then
|
|
emu.setregister("A", rhindle_speed);
|
|
end
|
|
end
|
|
|
|
function SetDifficultySwitchB()
|
|
if diff_b_locked then
|
|
local a = emu.getregister("A")
|
|
if a < 128 then
|
|
emu.setregister("A", a + 128)
|
|
end
|
|
end
|
|
end
|
|
|
|
function SetDifficultySwitchA()
|
|
if diff_a_locked then
|
|
local a = emu.getregister("A")
|
|
if (a > 128 and a < 128 + 64) or (a < 64) then
|
|
emu.setregister("A", a + 64)
|
|
end
|
|
end
|
|
end
|
|
|
|
function TryFreeincarnate()
|
|
if freeincarnates_available > 0 then
|
|
freeincarnates_available = freeincarnates_available - 1
|
|
for index, state_addr in pairs(DragonState) do
|
|
if last_dragon_state[index] == 1 then
|
|
send_freeincarnate_used = true
|
|
memory.write_u8(state_addr, 1, "System Bus")
|
|
local msg = {TTL=450, message="used freeincarnate", color=0xFF00FF00}
|
|
itemMessages[-1] = msg
|
|
end
|
|
end
|
|
|
|
end
|
|
end
|
|
|
|
function GetLinkedObject()
|
|
if emu.getregister("X") == batRoomAddr then
|
|
bat_interest_item = emu.getregister("A")
|
|
-- if the bat can't touch that item, we'll switch it to the number item, which should never be
|
|
-- in the same room as the bat.
|
|
if bat_no_touch_items[bat_interest_item] ~= nil then
|
|
emu.setregister("A", 0xDD )
|
|
emu.setregister("Y", 0xDD )
|
|
end
|
|
end
|
|
end
|
|
|
|
function CheckCollectAPItem(carry_item, target_item_value, target_item_ram, rendering_foreign_item)
|
|
if( carry_item == target_item_value and rendering_foreign_item ~= nil ) then
|
|
memory.write_u8(carryAddress, nullObjectId, "System Bus")
|
|
memory.write_u8(target_item_ram, 0xFF, "System Bus")
|
|
pending_foreign_items_collected[rendering_foreign_item.short_location_id] = rendering_foreign_item
|
|
for index, fi in pairs(foreign_items_by_room[rendering_foreign_item.room_id]) do
|
|
if( fi.short_location_id == rendering_foreign_item.short_location_id ) then
|
|
table.remove(foreign_items_by_room[rendering_foreign_item.room_id], index)
|
|
break
|
|
end
|
|
end
|
|
for index, fi in pairs(foreign_items) do
|
|
if( fi.short_location_id == rendering_foreign_item.short_location_id ) then
|
|
foreign_items[index] = nil
|
|
break
|
|
end
|
|
end
|
|
prev_ap_room_index = 0
|
|
return true
|
|
end
|
|
return false
|
|
end
|
|
|
|
function BatCanTouchForeign(foreign_item, bat_room)
|
|
if bat_no_touch_locations_by_room[bat_room] == nil or bat_no_touch_locations_by_room[bat_room][1] == nil then
|
|
return true
|
|
end
|
|
|
|
for index, location in ipairs(bat_no_touch_locations_by_room[bat_room]) do
|
|
if location.short_location_id == foreign_item.short_location_id then
|
|
return false
|
|
end
|
|
end
|
|
return true;
|
|
end
|
|
|
|
function main()
|
|
memory.usememorydomain("System Bus")
|
|
if not checkBizHawkVersion() then
|
|
return
|
|
end
|
|
local playerSlot = memory.read_u8(PlayerSlotAddress)
|
|
local port = 17242 + playerSlot
|
|
print("Using port"..tostring(port))
|
|
server, error = socket.bind('localhost', port)
|
|
if( error ~= nil ) then
|
|
print(error)
|
|
end
|
|
event.onmemoryexecute(SetYorgleSpeed, yorgle_speed_address);
|
|
event.onmemoryexecute(SetGrundleSpeed, grundle_speed_address);
|
|
event.onmemoryexecute(SetRhindleSpeed, rhindle_speed_address);
|
|
event.onmemoryexecute(SetDifficultySwitchA, read_switch_a)
|
|
event.onmemoryexecute(SetDifficultySwitchB, read_switch_b)
|
|
event.onmemoryexecute(GetLinkedObject, batItemCheckAddr)
|
|
-- TODO: Add an onmemoryexecute event to intercept the bat reading item rooms, and don't 'see' an item in the
|
|
-- room if it is in bat_no_touch_locations_by_room. Although realistically, I may have to handle this in the rom
|
|
-- for it to be totally reliable, because it won't work before the script connects (I might have to reset them?)
|
|
-- TODO: Also remove those items from the bat_no_touch_locations_by_room if they have been collected
|
|
while true do
|
|
frame = frame + 1
|
|
drawMessages()
|
|
if not (curstate == prevstate) then
|
|
print("Current state: "..curstate)
|
|
prevstate = curstate
|
|
end
|
|
|
|
local current_player_room = u8(PlayerRoomAddr)
|
|
local bat_room = u8(batRoomAddr)
|
|
local bat_carrying_item = u8(batCarryAddress)
|
|
local bat_carrying_ap_item = (BatAPItemRam == bat_carrying_item)
|
|
|
|
if current_player_room == 0x1E then
|
|
if u8(PlayerRoomAddr + 1) > 0x4B then
|
|
memory.write_u8(PlayerRoomAddr + 1, 0x4B)
|
|
end
|
|
end
|
|
|
|
if current_player_room == 0x00 then
|
|
if not was_in_number_room then
|
|
print("reset "..tostring(bat_carrying_ap_item).." "..tostring(bat_carrying_item))
|
|
memory.write_u8(batCarryAddress, batInvalidCarryItem)
|
|
memory.write_u8(batCarryAddress+ 1, 0)
|
|
createForeignItemsByRoom()
|
|
memory.write_u8(BatAPItemRam, 0xff)
|
|
memory.write_u8(APItemRam, 0xff)
|
|
prev_ap_room_index = 0
|
|
prev_player_room = 0
|
|
rendering_foreign_item = nil
|
|
was_in_number_room = true
|
|
end
|
|
else
|
|
was_in_number_room = false
|
|
end
|
|
|
|
if bat_room ~= prev_bat_room then
|
|
if bat_carrying_ap_item then
|
|
if foreign_items_by_room[prev_bat_room] ~= nil then
|
|
for r,f in pairs(foreign_items_by_room[prev_bat_room]) do
|
|
if f.short_location_id == current_bat_ap_item.short_location_id then
|
|
-- print("removing item from "..tostring(r).." in "..tostring(prev_bat_room))
|
|
table.remove(foreign_items_by_room[prev_bat_room], r)
|
|
break
|
|
end
|
|
end
|
|
end
|
|
if foreign_items_by_room[bat_room] == nil then
|
|
foreign_items_by_room[bat_room] = {}
|
|
end
|
|
-- print("adding item to "..tostring(bat_room))
|
|
table.insert(foreign_items_by_room[bat_room], current_bat_ap_item)
|
|
else
|
|
-- set AP item room and position for new room, or to invalid room
|
|
if foreign_items_by_room[bat_room] ~= nil and foreign_items_by_room[bat_room][1] ~= nil
|
|
and BatCanTouchForeign(foreign_items_by_room[bat_room][1], bat_room) then
|
|
if current_bat_ap_item ~= foreign_items_by_room[bat_room][1] then
|
|
current_bat_ap_item = foreign_items_by_room[bat_room][1]
|
|
-- print("Changing bat item to "..tostring(current_bat_ap_item.short_location_id))
|
|
end
|
|
memory.write_u8(BatAPItemRam, bat_room)
|
|
memory.write_u8(BatAPItemRam + 1, current_bat_ap_item.room_x)
|
|
memory.write_u8(BatAPItemRam + 2, current_bat_ap_item.room_y)
|
|
else
|
|
memory.write_u8(BatAPItemRam, 0xff)
|
|
if current_bat_ap_item ~= nil then
|
|
-- print("clearing bat item")
|
|
end
|
|
current_bat_ap_item = nil
|
|
end
|
|
end
|
|
end
|
|
prev_bat_room = bat_room
|
|
|
|
-- update foreign_items_by_room position and room id for bat item if bat carrying an item
|
|
if bat_carrying_ap_item then
|
|
-- this is setting the item using the bat's position, which is somewhat wrong, but I think
|
|
-- there will be more problems with the room not matching sometimes if I use the actual item position
|
|
current_bat_ap_item.room_id = bat_room
|
|
current_bat_ap_item.room_x = u8(batRoomAddr + 1)
|
|
current_bat_ap_item.room_y = u8(batRoomAddr + 2)
|
|
end
|
|
|
|
if (alive_mode()) then
|
|
if (current_player_room ~= prev_player_room) then
|
|
memory.write_u8(APItemRam, 0xFF, "System Bus")
|
|
prev_ap_room_index = 0
|
|
prev_player_room = current_player_room
|
|
AutocollectFromRoom()
|
|
end
|
|
local carry_item = memory.read_u8(carryAddress, "System Bus")
|
|
bat_no_touch_items[carry_item] = nil
|
|
if (next_inventory_item ~= nil) then
|
|
if ( carry_item == nullObjectId and last_carry_item == nullObjectId ) then
|
|
frames_with_no_item = frames_with_no_item + 1
|
|
if (frames_with_no_item > 10) then
|
|
frames_with_no_item = 10
|
|
local input_value = memory.read_u8(input_button_address, "System Bus")
|
|
if( input_value >= 64 and input_value < 128 ) then -- high bit clear, second highest bit set
|
|
memory.write_u8(carryAddress, next_inventory_item)
|
|
local item_ram_location = memory.read_u8(ItemTableStart + next_inventory_item)
|
|
if( memory.read_u8(batCarryAddress) ~= 0x78 and
|
|
memory.read_u8(batCarryAddress) == item_ram_location) then
|
|
memory.write_u8(batCarryAddress, batInvalidCarryItem)
|
|
memory.write_u8(batCarryAddress+ 1, 0)
|
|
memory.write_u8(item_ram_location, current_player_room)
|
|
memory.write_u8(item_ram_location + 1, memory.read_u8(PlayerRoomAddr + 1))
|
|
memory.write_u8(item_ram_location + 2, memory.read_u8(PlayerRoomAddr + 2))
|
|
end
|
|
ItemIndex = ItemIndex + 1
|
|
next_inventory_item = nil
|
|
end
|
|
end
|
|
else
|
|
frames_with_no_item = 0
|
|
end
|
|
end
|
|
if( carry_item ~= last_carry_item ) then
|
|
if ( localItemLocations ~= nil and localItemLocations[tostring(carry_item)] ~= nil ) then
|
|
pending_local_items_collected[localItemLocations[tostring(carry_item)]] =
|
|
localItemLocations[tostring(carry_item)]
|
|
localItemLocations[tostring(carry_item)] = nil
|
|
skip_inventory_items[carry_item] = carry_item
|
|
end
|
|
end
|
|
last_carry_item = carry_item
|
|
|
|
CheckCollectAPItem(carry_item, APItemValue, APItemRam, rendering_foreign_item)
|
|
if CheckCollectAPItem(carry_item, BatAPItemValue, BatAPItemRam, current_bat_ap_item) and bat_carrying_ap_item then
|
|
memory.write_u8(batCarryAddress, batInvalidCarryItem)
|
|
memory.write_u8(batCarryAddress+ 1, 0)
|
|
end
|
|
|
|
|
|
rendering_foreign_item = nil
|
|
if( foreign_items_by_room[current_player_room] ~= nil ) then
|
|
if( foreign_items_by_room[current_player_room][prev_ap_room_index] ~= nil ) and memory.read_u8(APItemRam) ~= 0xff then
|
|
foreign_items_by_room[current_player_room][prev_ap_room_index].room_x = memory.read_u8(APItemRam + 1)
|
|
foreign_items_by_room[current_player_room][prev_ap_room_index].room_y = memory.read_u8(APItemRam + 2)
|
|
end
|
|
prev_ap_room_index = prev_ap_room_index + 1
|
|
local invalid_index = -1
|
|
if( foreign_items_by_room[current_player_room][prev_ap_room_index] == nil ) then
|
|
prev_ap_room_index = 1
|
|
end
|
|
if( foreign_items_by_room[current_player_room][prev_ap_room_index] ~= nil and current_bat_ap_item ~= nil and
|
|
foreign_items_by_room[current_player_room][prev_ap_room_index].short_location_id == current_bat_ap_item.short_location_id) then
|
|
invalid_index = prev_ap_room_index
|
|
prev_ap_room_index = prev_ap_room_index + 1
|
|
if( foreign_items_by_room[current_player_room][prev_ap_room_index] == nil ) then
|
|
prev_ap_room_index = 1
|
|
end
|
|
end
|
|
|
|
if( foreign_items_by_room[current_player_room][prev_ap_room_index] ~= nil and prev_ap_room_index ~= invalid_index ) then
|
|
memory.write_u8(APItemRam, current_player_room)
|
|
rendering_foreign_item = foreign_items_by_room[current_player_room][prev_ap_room_index]
|
|
memory.write_u8(APItemRam + 1, rendering_foreign_item.room_x)
|
|
memory.write_u8(APItemRam + 2, rendering_foreign_item.room_y)
|
|
else
|
|
memory.write_u8(APItemRam, 0xFF, "System Bus")
|
|
end
|
|
end
|
|
if is_dead == 0 then
|
|
dragons_revived = false
|
|
player_dead = false
|
|
new_dragon_state = {0,0,0}
|
|
for index, dragon_state_addr in pairs(DragonState) do
|
|
new_dragon_state[index] = memory.read_u8(dragon_state_addr, "System Bus" )
|
|
if last_dragon_state[index] == 1 and new_dragon_state[index] ~= 1 then
|
|
dragons_revived = true
|
|
elseif last_dragon_state[index] ~= 1 and new_dragon_state[index] == 1 then
|
|
dragon_real_index = index - 1
|
|
print("Killed dragon: "..tostring(dragon_real_index))
|
|
local dragon_item = {}
|
|
dragon_item["short_location_id"] = 0xD0 + dragon_real_index
|
|
pending_foreign_items_collected[dragon_item.short_location_id] = dragon_item
|
|
end
|
|
if new_dragon_state[index] == 2 then
|
|
player_dead = true
|
|
end
|
|
end
|
|
if dragons_revived and player_dead == false then
|
|
TryFreeincarnate()
|
|
end
|
|
last_dragon_state = new_dragon_state
|
|
end
|
|
elseif (u8(PlayerRoomAddr) == 0x00) then -- not alive mode, in number room
|
|
ItemIndex = 0 -- reset our inventory
|
|
next_inventory_item = nil
|
|
skip_inventory_items = {}
|
|
end
|
|
if (curstate == STATE_OK) or (curstate == STATE_INITIAL_CONNECTION_MADE) or (curstate == STATE_TENTATIVELY_CONNECTED) then
|
|
if (frame % 5 == 0) then
|
|
receive()
|
|
if alive_mode() then
|
|
local was_dead = is_dead
|
|
is_dead = 0
|
|
for index, dragonStateAddr in pairs(DragonState) do
|
|
local dragonstateval = memory.read_u8(dragonStateAddr, "System Bus")
|
|
if ( dragonstateval == 2) then
|
|
is_dead = index
|
|
end
|
|
end
|
|
if was_dead ~= 0 and is_dead == 0 then
|
|
TryFreeincarnate()
|
|
end
|
|
if deathlink_rec == true and is_dead == 0 then
|
|
print("setting dead from deathlink")
|
|
deathlink_rec = false
|
|
deathlink_sent = true
|
|
is_dead = 1
|
|
memory.write_u8(carryAddress, nullObjectId, "System Bus")
|
|
memory.write_u8(DragonState[1], 2, "System Bus")
|
|
end
|
|
if (is_dead > 0 and deathlink_send == 0 and not deathlink_sent) then
|
|
deathlink_send = is_dead
|
|
print("setting deathlink_send to "..tostring(is_dead))
|
|
elseif (is_dead == 0) then
|
|
deathlink_send = 0
|
|
deathlink_sent = false
|
|
end
|
|
if ItemsReceived ~= nil and ItemsReceived[ItemIndex + 1] ~= nil then
|
|
while ItemsReceived[ItemIndex + 1] ~= nil and skip_inventory_items[ItemsReceived[ItemIndex + 1]] ~= nil do
|
|
print("skip")
|
|
ItemIndex = ItemIndex + 1
|
|
end
|
|
local static_id = ItemsReceived[ItemIndex + 1]
|
|
if static_id ~= nil then
|
|
inventory[static_id] = 1
|
|
if next_inventory_item == nil then
|
|
next_inventory_item = static_id
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
elseif (curstate == STATE_UNINITIALIZED) then
|
|
if (frame % 60 == 0) then
|
|
|
|
print("Waiting for client.")
|
|
|
|
emu.frameadvance()
|
|
server:settimeout(2)
|
|
print("Attempting to connect")
|
|
local client, timeout = server:accept()
|
|
if timeout == nil then
|
|
print("Initial connection made")
|
|
curstate = STATE_INITIAL_CONNECTION_MADE
|
|
atariSocket = client
|
|
atariSocket:settimeout(0)
|
|
end
|
|
end
|
|
end
|
|
emu.frameadvance()
|
|
end
|
|
end
|
|
|
|
main()
|