--[[ $0F78 - enemy pointer $0F7A - enemy X pos (from room pop) $0F7C - enemy sub-pixel X pos. Often unused. $0F7E - enemy Y pos (from room pop_) $0F80 - enemy sub-pixel Y pos. Often unused. $0F82 - enemy collision width (1/2 pixel value from center) $0F84 - enemy collision height (1/2 pixel value from center) $0F86 - Property bits (from room pop: prop bits) (FEDC BA98 7654 3210) F makes their hitbox solid to Samus, E respawns the enemies if they die, D tells the game to process the enemy's graphic AI, C makes the enemy block Plasma shots B makes the enemy process even when offscreen, A makes the enemy ignore Samus/Projectiles, 9 instantly deletes the enemy, 8 makes the enemy invisible? 1 and 0 used by geemers as orientation $0F88 - extra property bits (FEDC BA98 7654 3210) F signifies that the enemy processed a new enemy instruction with $0F92, update graphics. 2 enables multiple hitbox/reactions (indepth $0F8E) 0 disables processing of the enemy's movement AI, I think. Isn't disabled if 0F86 A is set (ignore Samus/Projectiles) $0F8A - AI handler. Lowest bit set determines which AI pointer in enemy data to use (None = 18, 1 = 1A, 2 = 1C, 4 = 1E, 8 = 20) $0F8C - Enemy HP $0F8E - Main graphics/hitbox pointer Byte 0 is a counter of some sort. Byte 1 is unused, I think. Bytes 2-3 are X pixel offset. Bytes 4-5 are Y pixel offset. Bytes 6-7 are a pointer to a tilemap, I think. Bytes 8-9 are a pointer to collision detection: Byte 0 is a counter of some sort. Byte 1 is unused, I think. Bytes 2-3 are X pixel offset to left border. Bytes 4-5 are Y pixel offset to bottom border. Bytes 6-7 are X pixel offset to right border. Bytes 8-9 are Y pixel offset to top border. Bytes A-B are for collisions with Samus. Bytes C-D bytes are pointer to code for collision with projectiles. Bytes 2-D repeat 'byte 0' times. Total length is 2 + (n*C), n = byte 0. Bytes 2-9 repeat 'byte 0' times. Total length is 2 + (n*8), n = byte 0 $0F90 - ??? (Used by Mochtroid) (LN Chozo uses it as a loop counter) $0F92 - pointer to AI structure. Acts like PLMs instruction pointer ($1D27,X). Positive Enemy instructions set delay timer and 0F8E, and highest bit of 0F88 $0F94 - action delay (apparantly) (Used with above?) $0F96 - Which SNES palette the enemy uses (when drawing the sprite, from enemy set number). ORAed with other data to stick directly into OAM. $0F98 - Index to graphics in VRAM $0F9A - Layer control $0F9C - Set to (0F78),#$0D + #$08 when shot? This - 8 = timer for using Hurt AI. $0F9E - Enemy frozen timer $0FA0 - Counter, forces a different kind of processing. Used when hit by Plasma Beam (powerbombs?) $0FA2 - A value that works concurrently with $0FA4 to modify vertical position of sprite $0FA4 - Value that determines if sprite vertical position is lowered or raised (with $0FA2). For many enemies it's used as come sort of counter though $0FA6 - Bank of enemy data $0FA7 - it was 04 during the spore spawn battle. Will look into $0FA8 - Used by AI routines. $0FAA - Used by AI routines. $0FAC - Used by AI routines. Example: air time? vertical jump distance, etc.? $0FAE - Used by AI routines. Example: all-purpose counter, direction and speed, etc. $0FB0 - Used by AI routines. Example: current action of enemy? $0FB2 - Used by AI routines $0FB4 - Used by AI routines. Speed in SMILE $0FB6 - Used by AI routines. Speed2 in SMILE ]] local ENEMY_NAMES = { -- {{{ [0xB5BF] = 'destroyable timed shutter', [0xCEBF] = 'bouncing gooball', [0xCEFF] = 'mini-Crocomire', [0xCF3F] = 'Maridia beyblade turtle', [0xCF7F] = 'Maridia beyblade turtle', [0xCFBF] = 'thin hopping blobs', [0xCFFF] = 'spike shooting plant', [0xD03F] = 'Maridia spikey shell', [0xD07F] = 'gunship top', [0xD0BF] = 'gunship bottom', [0xD0FF] = 'pre-Bomb Torizo fly', [0xD13F] = 'under ice beam fly', [0xD17F] = 'pre-spring ball fly', [0xD1BF] = 'Norfair erratic fireball', [0xD1FF] = 'lavaquake rocks', [0xD23F] = 'rinka', [0xD27F] = 'rio', [0xD2BF] = 'Norfair lava-jumping enemy', [0xD2FF] = 'Norfair rio', [0xD33F] = 'Lower Norfair rio', [0xD37F] = 'Maridia large indestructable snails', [0xD3BF] = 'high-rising slow-falling enemy', [0xD3FF] = 'rippers', [0xD43F] = 'jet powered ripper', [0xD47F] = 'ripper', [0xD4BF] = 'lava seahorse', [0xD4FF] = 'timed shutter', [0xD53F] = 'shutter', [0xD57F] = 'horizontal shootable shutter', [0xD5BF] = 'shutter', [0xD5FF] = 'rising and falling platform', [0xD63F] = 'waver', [0xD67F] = 'metal skree', [0xD6BF] = 'fireflea', [0xD6FF] = 'Maridia fish', [0xD73F] = 'elevator', [0xD77F] = 'crab', [0xD7BF] = 'slug', [0xD7FF] = 'fast-moving slowly-sinking platform', [0xD83F] = 'sinking platform', [0xD87F] = 'roach', [0xD8BF] = 'roach', [0xD8FF] = 'mochtroid', [0xD93F] = 'sidehopper', [0xD97F] = 'desgeega', [0xD9BF] = 'super-sidehopper', [0xD9FF] = 'Tourian invincible super-sidehopper', [0xDA3F] = 'super-desgeega', [0xDA7F] = 'Maridia refill candy', [0xDABF] = 'Norfair slow fireball', [0xDB3F] = 'bang', [0xDB7F] = 'skree', [0xDBBF] = 'Maridia snail', [0xDBFF] = 'reflec', [0xDC3F] = 'Wrecked Ship orange zoomer', [0xDC7F] = 'big eye bugs', [0xDCBF] = 'fire zoomer', [0xDCFF] = 'zoomer', [0xDD3F] = 'stone zoomer', [0xDD7F] = 'metroid', [0xDD8F] = 'Crocomire', [0xDDBF] = 'Crocomire', [0xDDFF] = 'Crocomire\'s tongue', [0xDE3F] = 'Draygon', [0xDE7F] = 'Draygon\'s eye', [0xDEBF] = 'Draygon\'s tail', [0xDEFF] = 'Draygon\'s arms', [0xDF3F] = 'Spore Spawn', [0xDF7F] = 'Spore Spawn', [0xDFBF] = 'boulder', [0xDFFF] = 'spikey platform', [0xE03F] = 'spikey platform', [0xE07F] = 'fire geyser', [0xE0BF] = 'nuclear waffle', [0xE0FF] = 'fake Kraid', [0xE13F] = 'Ceres Ridley', [0xE17F] = 'Ridley', [0xE1BF] = 'Ridley\'s explosion', [0xE1FF] = 'Ceres steam', [0xE23F] = 'Ceres door', [0xE27F] = 'zebetites', [0xE2BF] = 'Kraid', [0xE2FF] = 'Kraid\'s arm', [0xE33F] = 'Kraid top lint', [0xE37F] = 'Kraid middle lint', [0xE3BF] = 'Kraid bottom lint', [0xE3FF] = 'Kraid\'s foot', [0xE43F] = 'Kraid fingernail_A', [0xE47F] = 'Kraid fingernail_B', [0xE4BF] = 'Phantoon', [0xE4FF] = 'Phantoon', [0xE53F] = 'Phantoon', [0xE57F] = 'Phantoon', [0xE5BF] = 'etecoon', [0xE5FF] = 'dachora', [0xE63F] = 'Maridia mini-Draygon', [0xE67F] = 'evir projectile', [0xE6BF] = 'morph ball eye', [0xE6FF] = 'fune', [0xE73F] = 'fune with eyes', [0xE77F] = 'Wrecked Ship ghost', [0xE7BF] = 'yapping maw', [0xE7FF] = 'kago', [0xE83F] = 'Norfair lava creature', [0xE87F] = 'beetom', [0xE8BF] = 'Maridia floater', [0xE8FF] = 'Wrecked Ship robot', [0xE93F] = 'Wrecked Ship robot, deactivated', [0xE97F] = 'Mardia puffer', [0xE9BF] = 'walking lava seahorse', [0xE9FF] = 'Wrecked Ship orbs', [0xEA3F] = 'Wrecked Ship spark', [0xEA7F] = 'blue Brinstar face block', [0xEABF] = 'ki-hunter', [0xEAFF] = 'ki-hunter', [0xEB3F] = 'ki-hunter', [0xEB7F] = 'ki-hunter', [0xEBBF] = 'ki-hunter', [0xEBFF] = 'ki-hunter', [0xEC3F] = 'Mother Brain', [0xEC7F] = 'Mother Brain', [0xECBF] = 'Shitroid in cutscene', [0xECFF] = 'Mother Brain', [0xED3F] = 'dead Torizo', [0xED7F] = 'dead monsters', [0xEDBF] = 'dead monsters', [0xEDFF] = 'dead monsters', [0xEE3F] = 'dead monsters', [0xEE7F] = 'dead monsters', [0xEEBF] = 'Shitroid', [0xEEFF] = 'Bomb Torizo', [0xEF3F] = 'Bomb Torizo', [0xEF7F] = 'Gold Torizo', [0xEFBF] = 'Gold Torizo', [0xEFFF] = 'Tourian entrance statue', [0xF03F] = 'Tourian entrance statue ghost', [0xF07F] = 'DORI, Shaktool', [0xF0BF] = 'n00b tube cracks', [0xF0FF] = 'Chozo statue', [0xF153] = 'unused spinning turtle eye', [0xF193] = 'Brinstar red pipe bug', [0xF1D3] = 'Brinstar green pipe bug', [0xF213] = 'Norfair pipe bug', [0xF225] = 'dachora', [0xF253] = 'Brinstar yellow pipe bug', [0xF293] = 'Botwoon', [0xF2D3] = 'escape etecoon', [0xF313] = 'escape dachora', [0xF353] = 'wall space pirates', [0xF393] = 'Brinstar green wall space pirate', [0xF3D3] = 'Norfair red wall space pirate', [0xF413] = 'Lower Norfair gold wall space pirate', [0xF453] = 'Maridia magenta wall space pirate', [0xF493] = 'escape silver wall space pirate', [0xF4D3] = 'Old Tourian grey wall space pirate', [0xF513] = 'ninja space pirates', [0xF553] = 'ninja space pirates', [0xF593] = 'ninja space pirates', [0xF5D3] = 'ninja space pirates', [0xF613] = 'ninja space pirates', [0xF653] = 'Old Tourian grey wall space pirate', [0xF693] = 'walking space pirates', [0xF6D3] = 'walking space pirates', [0xF713] = 'walking space pirates', [0xF753] = 'walking space pirates', [0xF793] = 'walking space pirates', } -- }}} local function tohex(n, size) size = size or 0 return string.format("$%0" .. tostring(size) .. "X", n) end local function get_enemies() local enemies = {} for i=0,0x1F do local ptr = memory.readwordunsigned(0x7E0F78 + 0x40 * i) local xpos = memory.readwordunsigned(0x7E0F7A + 0x40 * i) local xsub = memory.readwordunsigned(0x7E0F7C + 0x40 * i) local ypos = memory.readwordunsigned(0x7E0F7E + 0x40 * i) local ysub = memory.readwordunsigned(0x7E0F80 + 0x40 * i) local props = memory.readwordunsigned(0x7E0F86 + 0x40 * i) local props2 = memory.readwordunsigned(0x7E0F88 + 0x40 * i) local hp = memory.readwordunsigned(0x7E0F8C + 0x40 * i) local ai = memory.readwordunsigned(0x7E0F8A + 0x40 * i) local colwidth = memory.readwordunsigned(0x7E0F82 + 0x40 * i) local colheight = memory.readwordunsigned(0x7E0F84 + 0x40 * i) local gfx = memory.readwordunsigned(0x7E0F8E + 0x40 * i) local unk = memory.readwordunsigned(0x7E0F90 + 0x40 * i) local plmai = memory.readwordunsigned(0x7E0F92 + 0x40 * i) local delay = memory.readwordunsigned(0x7E0F94 + 0x40 * i) local palette = memory.readwordunsigned(0x7E0F96 + 0x40 * i) local gfxidx = memory.readwordunsigned(0x7E0F98 + 0x40 * i) local layer = memory.readwordunsigned(0x7E0F9A + 0x40 * i) local timer = memory.readwordunsigned(0x7E0F9C + 0x40 * i) local frozen_timer = memory.readwordunsigned(0x7E0F9E + 0x40 * i) local counter = memory.readwordunsigned(0x7E0FA0 + 0x40 * i) local unk2 = memory.readwordunsigned(0x7E0FA2 + 0x40 * i) local unk3 = memory.readwordunsigned(0x7E0FA4 + 0x40 * i) local edata = memory.readwordunsigned(0x7E0FA6 + 0x40 * i) local unk3 = memory.readwordunsigned(0x7E0FA7 + 0x40 * i) local ai2 = memory.readwordunsigned(0x7E0FA8 + 0x40 * i) local ai3 = memory.readwordunsigned(0x7E0FAA + 0x40 * i) local ai4 = memory.readwordunsigned(0x7E0FAC + 0x40 * i) local ai4 = memory.readwordunsigned(0x7E0FAE + 0x40 * i) local ai5 = memory.readwordunsigned(0x7E0FB0 + 0x40 * i) local ai6 = memory.readwordunsigned(0x7E0FB2 + 0x40 * i) local ai7 = memory.readwordunsigned(0x7E0FB4 + 0x40 * i) local ai8 = memory.readwordunsigned(0x7E0FB6 + 0x40 * i) if ptr ~= 0 then table.insert(enemies, { ['slot'] = i, ['ptr'] = ptr, ['name'] = ENEMY_NAMES[ptr] or 'Unknown', ['xpos'] = xpos, ['xsub'] = xsub, ['ypos'] = ypos, ['ysub'] = ysub, ['props'] = props, ['props2'] = props2, ['ai'] = ai, ['hp'] = hp, ['colwidth'] = colwidth, ['colheight'] = colheight, ['gfx'] = gfx, ['unk'] = unk, ['plmai'] = plmai, ['delay'] = delay, ['palette'] = palette, ['gfxidx'] = gfxidx, ['layer'] = layer, ['timer'] = timer, ['frozen_timer'] = frozen_timer, ['counter'] = counter, ['unk2'] = unk2, ['unk3'] = unk3, ['edata'] = edata, ['unk3'] = unk3, ['ai2'] = ai2, ['ai3'] = ai3, ['ai4'] = ai4, ['ai4'] = ai4, ['ai5'] = ai5, ['ai6'] = ai6, ['ai7'] = ai7, ['ai8'] = ai8, }) end end return enemies end local function draw_enemies(enemies) for i, enemy in pairs(enemies) do local x = (i - 1) % 4 local y = math.floor((i - 1) / 4) * (7 * 10) gui.text(x * 64, y + 7 * 0, '#' .. tohex(enemy['slot']) .. ': ' .. tohex(enemy['ptr'])) gui.text(x * 64, y + 7 * 1, enemy['name']:sub(1, 15)) gui.text(x * 64, y + 7 * 2, 'X: ' .. tohex(enemy['xpos']) .. ' ' .. tohex(enemy['xsub'])) gui.text(x * 64, y + 7 * 3, 'Y: ' .. tohex(enemy['ypos']) .. ' ' .. tohex(enemy['ysub'])) gui.text(x * 64, y + 7 * 4, 'Props: ' .. tohex(enemy['props'])) gui.text(x * 64, y + 7 * 5, 'Props: ' .. tohex(enemy['props2'])) gui.text(x * 64, y + 7 * 6, 'AI/HP: ' .. tohex(enemy['ai']) .. ' ' .. tohex(enemy['hp'])) -- gui.text(x * 64, y + 7 * 7, 'colwidth/colheight: ' .. tohex(enemy['colwidth']) .. ' ' .. tohex(enemy['colheight'])) -- gui.text(x * 64, y + 7 * 8, 'gfx/unk: ' .. tohex(enemy['gfx']) .. ' ' .. tohex(enemy['unk'])) -- gui.text(x * 64, y + 7 * 9, 'plmai/delay: ' .. tohex(enemy['plmai']) .. ' ' .. tohex(enemy['delay'])) -- gui.text(x * 64, y + 7 * 10, 'palette/gfxidx: ' .. tohex(enemy['palette']) .. ' ' .. tohex(enemy['gfxidx'])) -- gui.text(x * 64, y + 7 * 11, 'layer/timer: ' .. tohex(enemy['layer']) .. ' ' .. tohex(enemy['timer'])) -- gui.text(x * 64, y + 7 * 12, 'frozen_timer/counter: ' .. tohex(enemy['frozen_timer']) .. ' ' .. tohex(enemy['counter'])) -- gui.text(x * 64, y + 7 * 13, 'unk2/unk3: ' .. tohex(enemy['unk2']) .. ' ' .. tohex(enemy['unk3'])) -- gui.text(x * 64, y + 7 * 14, 'edata/unk3: ' .. tohex(enemy['edata']) .. ' ' .. tohex(enemy['unk3'])) -- gui.text(x * 64, y + 7 * 15, 'ai2/ai3: ' .. tohex(enemy['ai2']) .. ' ' .. tohex(enemy['ai3'])) -- gui.text(x * 64, y + 7 * 16, 'ai4/ai4: ' .. tohex(enemy['ai4']) .. ' ' .. tohex(enemy['ai4'])) -- gui.text(x * 64, y + 7 * 17, 'ai5/ai6: ' .. tohex(enemy['ai5']) .. ' ' .. tohex(enemy['ai6'])) -- gui.text(x * 64, y + 7 * 18, 'ai7/ai8: ' .. tohex(enemy['ai7']) .. ' ' .. tohex(enemy['ai8'])) -- return end end function print_write(addr, size) if addr < 0x200000 then addr = bit.band(addr, 0xFFFF) addr = 0x7E0000 + addr end local pb = memory.getregister("pb") local pc = memory.getregister("pc") local val = size == 1 and memory.readbyte(addr) or memory.readword(addr) if (pb == 0x80 and pc == 0x8145) or (pb == 0x88 and pc == 0xB451) then return end local line = "[" .. tohex(pb, 2) .. ":" .. tohex(pc, 4) .. "] " .. tohex(addr, 6) .. "[" .. tostring(size) .. "] = " .. tohex(val, size == 1 and 2 or 4) .. (size == 1 and " | " or " | ") .. " F=" .. emu.framecount() print(line) end local function call_for_each_bank(address, fn, ...) for i = 0x00, 0xFF do if i ~= 0x7F and not (i >= 0x70 and i <= 0x80) then fn(bit.lshift(i, 16) + address, unpack(arg)) end end end call_for_each_bank(0x0000, function (bank_only) -- memory.registerwrite(bank_only + 0x05E5, 0x2, print_write) end) call_for_each_bank(0x0000, function (bank_only) memory.registerwrite(bank_only + 0x0FA8, 0x2, print_write) end) while true do local enemies = get_enemies() draw_enemies(enemies) emu.frameadvance() end