Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- -- V1.87:
- -- By Warepire, Spikestuff, Fog, Tremane
- -- Slightly Less Shitty Script
- -- Prints Zook position, charge shot timer, weapons cooldown timer, invulnerable timer
- -- Enemy position (different coordinate system because ... fuck you!?), HP, action timer and active flag, invulnerable timer
- -- Active item drop, and next five item drops
- -- fixed: Re-positioned the boss data on the GUI
- --
- -- TODO: Hitboxes
- -- Currently no speed value, because there seems to be only 2 speeds: Standing still and moving.
- -- If speed is discovered to be more complex, speed value can be added.
- client.SetGameExtraPadding(12, 58, 12, 12)
- camera_x = 0
- camera_y = 0
- local_x = 0
- local_y = 0
- -- Level layer positions addresses in IWRAM:
- zook_ukn_layer_x = 0x14F0
- zook_ukn_layer_y = 0x14F4
- zook_fg_layer_x = 0x14F8
- zook_fg_layer_y = 0x14FC
- zook_lvl_layer_x = 0x1500
- zook_lvl_layer_y = 0x1504
- zook_bg_layer_x = 0x1508
- zook_bg_layer_y = 0x150C
- function UpdateCamera()
- -- using lvl layer as "camera":
- memory.usememorydomain("IWRAM")
- camera_x = memory.read_u32_le(zook_lvl_layer_x)
- camera_y = memory.read_u32_le(zook_lvl_layer_y)
- end
- function PrintZookData()
- -- 0x15E0: Cooldown timer, can only shoot when 0.
- local zook_x_addr = 0x1560
- local zook_y_addr = 0x1564
- local zook_wpn_cooldown_timer_addr = 0x15E0
- local zook_charge_timer_addr = 0x1608
- local zook_invuln_timer_addr = 0x1628
- -- These are some odd values, related to movement, goes from 0-31, wraps at 32
- -- local zook_subx_addr = 0x1568
- -- local zook_suby_addr = 0x156C
- memory.usememorydomain("IWRAM")
- local zook_x = memory.read_u32_le(zook_x_addr)
- local zook_y = memory.read_u32_le(zook_y_addr)
- local zook_wpn_cooldown_timer = memory.read_u32_le(zook_wpn_cooldown_timer_addr)
- local zook_charge_timer = memory.read_u16_le(zook_charge_timer_addr)
- local zook_invuln_timer = memory.read_u32_le(zook_invuln_timer_addr)
- -- the charge timer is special
- local zook_charge_timer_base = 60 - zook_charge_timer
- local zook_charge_timer_extra = 80
- if zook_charge_timer_base <= 0 then
- zook_charge_timer_extra = zook_charge_timer_extra + zook_charge_timer_base
- zook_charge_timer_base = 0
- end
- --gui.drawText(local_x+10, local_y+30, string.format("X=%d,Y=%d\nCharge Shot=%d,Extra=%d\nBuster Cooldown=%d\nInvulnerable timer=%d", zook_x, zook_y, zook_charge_timer_base, zook_charge_timer_extra, zook_wpn_cooldown_timer, zook_invuln_timer), "red", null, 10)
- local x, y, dy = 8, 56, 14
- local function print_info(format, ...)
- gui.text(x, y, string.format(format, ...),"aqua")
- y = y + dy
- end
- print_info("X=%d, Y=%d", zook_x, zook_y)
- print_info("Charge Shot=%d, Extra=%d", zook_charge_timer_base, zook_charge_timer_extra)
- print_info("Buster Cooldown=%d", zook_wpn_cooldown_timer)
- print_info("Invulnerable timer=%d", zook_invuln_timer)
- end
- initial_boss_bar_needed_hits = 0
- function PrintBossData()
- memory.usememorydomain("IWRAM")
- local boss_can_be_damaged = memory.read_u32_le(0x16F4)
- local boss_invuln_timer = memory.read_u32_le(0x16F8)
- local boss_hp_bar_count = memory.read_u32_le(0x1708)
- local boss_hp_bar_needed_hits = memory.read_u32_le(0x170C)
- if initial_boss_bar_needed_hits == 0 then
- initial_boss_bar_needed_hits = boss_hp_bar_needed_hits
- end
- local boss_damage_flag = " "
- if boss_can_be_damaged == 6 then -- so far known: 6 = yes, 7 = no
- boss_damage_flag = "*"
- end
- if boss_hp_bar_count == 0 then
- initial_boss_bar_needed_hits = 0
- return
- end
- local boss_hp = ((boss_hp_bar_count - 1) * initial_boss_bar_needed_hits) + boss_hp_bar_needed_hits
- --gui.drawText(10, 75, string.format("Boss HP=%d %s\nInvulnerable timer=%d", boss_hp, boss_damage_flag, boss_invuln_timer), "red", null, 10)
- local x, y, dy = 8, 112, 14
- local function print_info(format, ...)
- gui.text(x, y, string.format(format, ...),"red")
- y = y + dy
- end
- print_info("Boss HP=%d %s", boss_hp, boss_damage_flag)
- print_info("Invulnerable timer=%d", boss_invuln_timer)
- end
- function PrintItemDrop()
- local active_frame_count = memory.read_u32_le(0x17A0, "IWRAM")
- local item_drop_table = memory.readbyterange(0x3E8880, 132, "ROM") -- 33 entries of four bytes each
- local active_item_drop = item_drop_table[bit.band(active_frame_count, 0x1F) * 4] -- multiplied by four to read the four byte drop table
- local active_item_drop_strings = {"Nothing", "Small Health", "Medium Health", "Large Health", "Small Energy", "Medium Energy", "Large Energy", "Extra Life"}
- --gui.drawText(10, 100, string.format("Active Item Drop:\n%s", active_item_drop_strings[active_item_drop + 1]), "red", null, 10)
- local x, y, dy = 320, 14, 14
- local function print_info(format, ...)
- gui.text(x, y, string.format(format, ...),"lightgreen")
- y = y + dy
- end
- print_info("AID: %s", active_item_drop_strings[active_item_drop + 1]) --Active Item Drop
- print_info("Next Five Drops:", 0)
- for i=1,5 do
- local next_item_drop = item_drop_table[bit.band(active_frame_count + i, 0x1F) * 4] -- multiplied by four to read the four byte drop table
- print_info("%s", active_item_drop_strings[next_item_drop + 1])
- end
- end
- -- FOV Work
- -- -----------------------------------
- -- Globals
- -- -----------------------------------
- local current_entity_struct_data
- -- ---------------------------------
- -- Constants
- -- ---------------------------------
- local max_entries = 60
- local enemies_index_begin = 30 -- enemies start at position 30, first 6 reserved for Zook?
- local entity_struct_addr = 0x1DE4
- local entity_struct_size = 0x74
- local entity_x_offset = 0x0
- local entity_y_offset = 0x4
- local entity_direction_offset = 0xC
- local entity_state_offset = 0x14
- local entity_action_timer_offset = 0x16
- -- maps enemy type(?) to box color, if a color sucks, change it!
- -- when a new enemy is identified to map to one of these boxes, update the enemy name in the list!
- local color_map = {}
- color_map[0x0F] = "AliceBlue" -- red tank (intro)
- color_map[0x17] = "AntiqueWhite" -- blue tank (intro)
- color_map[0x1E] = "Aqua" -- cone eneny (intro)
- color_map[0x1B] = "Aquamarine" -- speedy spikey thing (intro)
- color_map[0x25] = "Azure" -- no clue
- color_map[0x4B] = "Beige" -- no clue
- color_map[0x56] = "Bisque" -- no clue
- color_map[0x58] = "BlanchedAlmond" -- no clue
- color_map[0x5B] = "Blue" -- no clue
- color_map[0x5E] = "BlueViolet" -- no clue
- color_map[0x62] = "Brown" -- no clue
- color_map[0x71] = "BurlyWood" -- no clue
- color_map[0x72] = "CadetBlue" -- no clue
- color_map[0x74] = "Chartreuse" -- no clue
- color_map[0x87] = "Chocolate" -- no clue
- color_map[0x8A] = "Coral" -- no clue
- color_map[0x8B] = "CornflowerBlue" -- no clue
- color_map[0x8C] = "Cornsilk" -- no clue
- color_map[0x8D] = "Crimson" -- no clue
- color_map[0xA2] = "Cyan" -- no clue
- color_map[0xA4] = "DarkBlue" -- no clue
- color_map[0xAB] = "DarkCyan" -- no clue
- color_map[0xAF] = "DarkGoldenrod" -- no clue
- color_map[0xBA] = "DarkGray" -- no clue ... like really... no clue
- color_map[0xC0] = "DarkGreen" -- no clue
- color_map[0xC1] = "DarkKhaki" -- no clue
- color_map[0xC2] = "DarkMagenta" -- no clue
- color_map[0xC3] = "DarkOliveGreen" -- no clue
- color_map[0xC8] = "DarkOrange" -- no clue ... like really... no clue
- color_map[0xD0] = "DarkOrchid" -- no clue
- color_map[0xD5] = "DarkViolet" -- no clue
- color_map[0xDE] = "DarkSalmon" -- no clue
- color_map[0xDF] = "DarkSeaGreen" -- no clue
- color_map[0xE2] = "DarkSlateBlue" -- no clue
- color_map[0xE3] = "DarkSlateGray" -- no clue
- color_map[0xE6] = "DarkTurquoise" -- no clue
- -- ----------------------------------
- -- Utility functions
- -- ----------------------------------
- local function GetWordFromMemTable(table, offset)
- local low_byte = table[offset]
- local high_byte = table[offset+1]
- local word = low_byte + (high_byte * 0x100)
- return word
- end
- local function GetDwordFromMemTable(table, offset)
- local low_word = GetWordFromMemTable(table, offset)
- local high_word = GetWordFromMemTable(table, offset + 2)
- local dword = low_word + (high_word * 0x10000)
- return dword
- end
- -- exactly how the game computes it, every time. I know IDA says differently sometimes in the pseudocode view.
- function GetOffsetFromIndex(index)
- return 4 * (29 * index)
- end
- -- args: color_id, left + 12, right + 12, top + 58, bottom + 58
- function DrawFieldOfViewBox(args)
- assert(args.color_id, "BUG! color_id == nil")
- local x_left = 16 + (args.left or 59) + 12
- local x_right = 16 + (args.right or (239 - 16)) + 12
- local y_top = (args.top or 0) + 58
- local y_bottom = (args.bottom or 159) + 58
- gui.drawBox(x_left, y_top, x_right, y_bottom, color_map[args.color_id])
- end
- -- -----------------------------------
- -- Draw logic
- -- -----------------------------------
- -- Amazingly enough all the field of view tests are conducted versus the position of Zooks left foot big toe.
- -- Note: Some boxes may be inversed, if they are, swap the left/right values!
- function FieldOfViewBox()
- -- Function pointers whose detection logic are implemented below, start at 0x1818 in IWRAM and seem to go on for about 256 entries
- local entity_state = GetWordFromMemTable(current_entity_struct_data, entity_state_offset)
- local x = GetDwordFromMemTable(current_entity_struct_data, entity_x_offset)
- local y = GetDwordFromMemTable(current_entity_struct_data, entity_y_offset)
- if entity_state == 0xF or entity_state == 0x17 or entity_state == 0x1E then -- IDA functions: sub_8019208, sub_8018BA8, sub_80185C0
- DrawFieldOfViewBox{color_id=entity_state, left=x-48, right=x+48}
- elseif entity_state == 0x1B then -- IDA functions: sub_8018884
- DrawFieldOfViewBox{color_id=entity_state, left=12+x-96, right=x+48}
- elseif entity_state == 0x25 then -- IDA functions: sub_80173CC
- DrawFieldOfViewBox{color_id=entity_state, left=12+x-56, right=x+64}
- DrawFieldOfViewBox{color_id=entity_state, left=12+x-10, right=x+10, top=y+10, bottom=x-10} -- some sort of inner attack box...?
- elseif entity_state == 0x4B then -- IDA functions: sub_801431C
- DrawFieldOfViewBox{color_id=entity_state, left=12+48, right=144}
- elseif entity_state == 0x56 then -- IDA functions: sub_8013374
- DrawFieldOfViewBox{color_id=entity_state, left=12+x-64, right=x+32}
- elseif entity_state == 0x58 then -- IDA functions: sub_80130D8
- DrawFieldOfViewBox{color_id=entity_state, left=12+x-80, right=x+32}
- elseif entity_state == 0x5B or entity_state == 0x62 then -- IDA functions: sub_8012FE8, sub_8012AAC
- DrawFieldOfViewBox{color_id=entity_state, left=12+x-80, right=x+80}
- elseif entity_state == 0x5E or entity_state == 0xC3 then -- IDA functions: sub_8012C80, sub_8009FD4
- local dir = GetWordFromMemTable(current_entity_struct_data, entity_direction_offset)
- local left = 0
- if dir == 1 then
- left = 32
- end
- DrawFieldOfViewBox{color_id=entity_state, left=12+x-left, right=x+112}
- elseif entity_state == 0x71 or entity_state == 0x72 then -- IDA functions: sub_8011708 (0x8011924 is a "subfunction" of that)
- local action_timer = GetWordFromMemTable(current_entity_struct_data, entity_action_timer_offset)
- if entity_state == 0x71 and action_timer == 1 then
- DrawFieldOfViewBox{color_id=entity_state, left=12+x-112, right=x+96}
- else
- DrawFieldOfViewBox{color_id=entity_state, left=12+x-80, right=x+64}
- end
- elseif entity_state == 0x74 then -- IDA functions: sub_8011278
- DrawFieldOfViewBox{color_id=entity_state, left=12+x-48, right=x+48}
- DrawFieldOfViewBox{color_id=entity_state, left=12+x-20, right=x-48}
- elseif entity_state == 0x87 then -- IDA functions: sub_800F920
- DrawFieldOfViewBox{color_id=entity_state, left=12+x-88, right=x+48}
- elseif entity_state == 0x8A then -- IDA functions: sub_800F4D4
- DrawFieldOfViewBox{color_id=entity_state, left=12+x-80, right=x+48}
- elseif entity_state == 0x8B then -- IDA functions: sub_800F394
- DrawFieldOfViewBox{color_id=entity_state, left=12+x-24, right=x+8}
- elseif entity_state == 0x8C then -- IDA functions: sub_800F298
- DrawFieldOfViewBox{color_id=entity_state, left=12+x-32, right=x+48}
- elseif entity_state == 0x8D or entity_state == 0xAF then -- IDA functions: sub_800F130, sub_800BAE8
- DrawFieldOfViewBox{color_id=entity_state, left=12+x-64, right=x+48}
- elseif entity_state == 0xA2 then -- IDA functions: sub_800D514
- DrawFieldOfViewBox{color_id=entity_state, top=y-16, bottom=y-32}
- elseif entity_state == 0xA4 then -- IDA functions: sub_800D234
- DrawFieldOfViewBox{color_id=entity_state, left=12+x-96, right=x+64, top=y+96, bottom=y-64}
- elseif entity_state == 0xAB then -- IDA functions: sub_800C114
- DrawFieldOfViewBox{color_id=entity_state, top=y-16, bottom=y-40}
- elseif entity_state == 0xBA then -- IDA functions: sub_8017F18
- print("ALERT: state 0xBA found!") -- What does this entity do? It does some math if Zook is in certain parts of the screen.
- x = memory.read_s32_le(entity_struct_addr + GetOffsetFromIndex(1) + entity_x_offset)
- DrawFieldOfViewBox{color_id=entity_state, left=12+x+90, right=x+200}
- DrawFieldOfViewBox{color_id=entity_state, left=12+x+40, right=x+80}
- elseif entity_state == 0xC0 then -- IDA functions: sub_800A380
- DrawFieldOfViewBox{color_id=entity_state, left=12+x-16, right=x+16}
- elseif entity_state == 0xC1 or entity_state == 0xD0 then -- IDA functions: sub_800A27C, sub_8008A18
- DrawFieldOfViewBox{color_id=entity_state, left=12+x-32, right=x+16}
- elseif entity_state == 0xC2 then -- IDA functions: sub_800A128
- DrawFieldOfViewBox{color_id=entity_state, left=12+x-72, right=x+48}
- elseif entity_state == 0xC8 then -- IDA functions: sub_8008D28
- print("ALERT: state 0xC8 found!") -- What does this entity do? It does some math depending on which zone of the screen Zook's in.
- y = memory.read_s32_le(entity_struct_addr + GetOffsetFromIndex(1) + entity_y_offset)
- DrawFieldOfViewBox{color_id=entity_state, bottom=40}
- DrawFieldOfViewBox{color_id=entity_state, top=40, bottom=72}
- DrawFieldOfViewBox{color_id=entity_state, top=72}
- elseif entity_state == 0xD5 then -- IDA functions: sub_8008654
- DrawFieldOfViewBox{color_id=entity_state, left=12+x-80, right=x+32}
- elseif entity_state == 0xDE then -- IDA functions: sub_800728C
- print("ALERT: state 0xDE found!")
- DrawFieldOfViewBox{color_id=entity_state, bottom=y-32}
- elseif entity_state == 0xDF then -- IDA functions: sub_800703C
- -- What does this entity do? It does some math if Zook is in certain parts of the screen.
- DrawFieldOfViewBox{color_id=entity_state, left=12+48, right=96}
- DrawFieldOfViewBox{color_id=entity_state, left=12+96, right=144}
- elseif entity_state == 0xE2 then -- IDA functions: sub_8006C6C
- DrawFieldOfViewBox{color_id=entity_state, left=12+x-58, right=x+88}
- elseif entity_state == 0xE3 then -- IDA functions: sub_8006A78
- DrawFieldOfViewBox{color_id=entity_state, left=12+x-64, right=192}
- DrawFieldOfViewBox{color_id=entity_state, left=12+8, right=x-16}
- DrawFieldOfViewBox{color_id=entity_state, top=y+8, bottom=y-24}
- elseif entity_state == 0xE6 then -- IDA functions: sub_8006248
- DrawFieldOfViewBox{color_id=entity_state, top=72, bottom=40}
- end
- -- stopped at address 0x1B38
- end
- function DrawStuff()
- local zook_x = memory.read_s32_le(entity_struct_addr + GetOffsetFromIndex(1) + entity_x_offset)
- gui.drawLine(zook_x + 12 + 16, 58, zook_x + 12 + 16, 159 + 58, "orange") -- Test pixel if zook is in field of view. Since height is not used, ignore it and draw a line.
- for i=enemies_index_begin,max_entries do
- current_entity_struct_data = memory.readbyterange(entity_struct_addr + GetOffsetFromIndex(i), entity_struct_size, "IWRAM")
- FieldOfViewBox()
- end
- end
- function PrintEnemyData()
- local enemy_data_size = 0x74
- local enemy_data_count = 40 -- dummy assumption
- local enemy_data_start = 0x2B7C
- local enemy_x_offset = 0x0
- local enemy_y_offset = 0x4
- local enemy_active_flag_offset = 0x16
- local enemy_action_timer_offset = 0x18
- local enemy_hp_offset = 0x2C
- local enemy_invuln_timer_offset = 0x58
- memory.usememorydomain("IWRAM")
- for i=0,enemy_data_count do
- local enemy_x = memory.read_s32_le(enemy_data_start + (i * enemy_data_size) + enemy_x_offset)
- local enemy_y = memory.read_s32_le(enemy_data_start + (i * enemy_data_size) + enemy_y_offset)
- local enemy_active_flag = memory.read_u16_le(enemy_data_start + (i * enemy_data_size) + enemy_active_flag_offset)
- local enemy_action_timer = memory.read_u16_le(enemy_data_start + (i * enemy_data_size) + enemy_action_timer_offset)
- local enemy_hp = memory.read_s16_le(enemy_data_start + (i * enemy_data_size) + enemy_hp_offset)
- local enemy_invuln_timer = memory.read_u32_le(enemy_data_start + (i * enemy_data_size) + enemy_invuln_timer_offset)
- local enemy_state = memory.read_u16_le(entity_struct_addr + GetOffsetFromIndex(i) + entity_state_offset)
- if enemy_x ~= 0 and enemy_y ~= 0 and enemy_hp ~= 0 and enemy_hp ~= -1 then -- remove to print data for bullets
- active = " "
- if enemy_active_flag ~= 0 then active = "*" end
- --gui.drawText(enemy_x + 10, enemy_y, string.format("X=%d,Y=%d\nHP=%d\n%sA.T.=%d\nI.T=%d", enemy_x, enemy_y, enemy_hp, active, enemy_action_timer, enemy_invuln_timer), "red", null, 10)
- gui.pixelText(enemy_x + 16, enemy_y, string.format("addr=%X\nX=%d,Y=%d\nS=0x%02X", entity_struct_addr + GetOffsetFromIndex(i), enemy_x, enemy_y, enemy_state), "blue", null)
- local x, y, dy = enemy_x+10, enemy_y+40, 7
- local function print_info(format, ...)
- gui.pixelText(x + 0, y, string.format(format, ...),"red")
- y = y + dy
- end
- print_info("X=%d, Y=%d", enemy_x, enemy_y)
- print_info("HP=%d", enemy_hp)
- print_info("%sA.T.=%d", active, enemy_action_timer)
- print_info("I.T=%d", enemy_invuln_timer)
- end
- end
- end
- -- debug shit
- function PrintEnemyData2()
- memory.usememorydomain("IWRAM")
- for i=30,max_entries do
- local enemy_x = memory.read_s32_le(entity_struct_addr + GetOffsetFromIndex(i) + entity_x_offset)
- local enemy_y = memory.read_s32_le(entity_struct_addr + GetOffsetFromIndex(i) + entity_y_offset)
- local enemy_state = memory.read_u16_le(entity_struct_addr + GetOffsetFromIndex(i) + entity_state_offset)
- if enemy_x ~= 0 and enemy_y ~= 0 then -- remove to print data for bullets
- gui.pixelText(enemy_x -80, enemy_y, string.format("addr=%X\nX=%d,Y=%d\nS=0x%02X", entity_struct_addr + GetOffsetFromIndex(i), enemy_x, enemy_y, enemy_state), "pink")
- end
- end
- end
- ----------------------------------------------------------
- -- Main:
- ----------------------------------------------------------
- function main()
- while true do
- UpdateCamera()
- PrintZookData()
- PrintEnemyData()
- -- PrintEnemyData2() -- "debug shit"
- PrintBossData()
- PrintItemDrop()
- DrawStuff()
- emu.frameadvance()
- end
- end
- main()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement