local socket = require("socket") local json = require('json') local math = require('math') 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 itemMessages = {} 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 local u8 = nil local wU8 = nil local u16 local bizhawk_version = client.getversion() local is23Or24Or25 = (bizhawk_version=="2.3.1") or (bizhawk_version:sub(1,3)=="2.4") or (bizhawk_version:sub(1,3)=="2.5") local is26To28 = (bizhawk_version:sub(1,3)=="2.6") or (bizhawk_version:sub(1,3)=="2.7") or (bizhawk_version:sub(1,3)=="2.8") u8 = memory.read_u8 wU8 = memory.write_u8 u16 = memory.read_u16_le 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 function table.empty (self) for _, _ in pairs(self) do return false end return true end function slice (tbl, s, e) local pos, new = 1, {} for i = s + 1, e do new[pos] = tbl[i] pos = pos + 1 end return new 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 local function clearScreen() if is23Or24Or25 then return elseif is26To28 then drawText(0, 0, "", "black") end end local function getMaxMessageLength() if is23Or24Or25 then return client.screenwidth()/11 elseif is26To28 then return client.screenwidth()/12 end end function drawText(x, y, message, color) if is23Or24Or25 then gui.addmessage(message) elseif is26To28 then gui.drawText(x, y, message, color, 0xB0000000, 18, "Courier New", nil, nil, nil, "client") end end local function drawMessages() if table.empty(itemMessages) then clearScreen() return end local y = 10 found = false maxMessageLength = getMaxMessageLength() for k, v in pairs(itemMessages) do if v["TTL"] > 0 then message = v["message"] while true do drawText(5, y, message:sub(1, maxMessageLength), v["color"]) y = y + 16 message = message:sub(maxMessageLength + 1, message:len()) if message:len() == 0 then break end end newTTL = 0 if is26To28 then newTTL = itemMessages[k]["TTL"] - 1 end itemMessages[k]["TTL"] = newTTL found = true end end if found == false then clearScreen() end end function difference(a, b) local aa = {} for k,v in pairs(a) do aa[v]=true end for k,v in pairs(b) do aa[v]=nil end local ret = {} local n = 0 for k,v in pairs(a) do if aa[v] then n=n+1 ret[n]=v end end return ret end function getAllRam() uRangeRAM(0,128); return data end local function arrayEqual(a1, a2) if #a1 ~= #a2 then return false end for i, v in ipairs(a1) do if v ~= a2[i] then return false end end return true 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 (is23Or24Or25 or is26To28) == false then print("Must use a version of bizhawk 2.3.1 or higher") 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)] table.remove(localItemLocations, tostring(carry_item)) 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()