brunovalads

Yoshi's Island Utilities

Mar 22nd, 2016
239
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 194.29 KB | None | 0 0
  1. ---------------------------------------------------------------------------
  2. --  Super Mario World 2 - Yoshi's Island (U) Utility Script for Snes9x - rr
  3. --  http://tasvideos.org/GameResources/SNES/YoshisIsland.html
  4. --  
  5. --  Author: BrunoValads
  6. --  Git repository: https://github.com/brunovalads/yoshis-island-stuff -- TODO
  7. --
  8. --  Based on Amaraticando's Super Mario World script for Snes9x-rr
  9. --  http://github.com/rodamaral/smw-tas/blob/master/Snes9x/smw-snes9x.lua
  10. ---------------------------------------------------------------------------
  11.  
  12. --#############################################################################
  13. -- CONFIG:
  14.  
  15. local INI_CONFIG_FILENAME = "Yoshi's Island Utilities Config.ini"  -- relative to the folder of the script
  16.  
  17. local DEFAULT_OPTIONS = {
  18.     -- Hotkeys
  19.     -- make sure that the hotkeys below don't conflict with previous bindings
  20.     hotkey_decrease_opacity = "numpad-",   -- to decrease the opacity of the text
  21.     hotkey_increase_opacity = "numpad+",  -- to increase the opacity of the text
  22.    
  23.     -- Display
  24.     display_movie_info = true,
  25.     display_misc_info = true,
  26.     display_player_info = true,
  27.     display_player_hitbox = true,  -- can be changed by right-clicking on player
  28.     display_interaction_points = true,  -- can be changed by right-clicking on player
  29.     display_throw_info = true,
  30.     display_blocked_status = true,
  31.     display_sprite_info = true,
  32.     display_sprite_hitbox = true,  -- you still have to select the sprite with the mouse
  33.     display_extended_sprite_info = false,
  34.     display_cluster_sprite_info = false,
  35.     display_minor_extended_sprite_info = false,
  36.     display_bounce_sprite_info = false,
  37.     display_level_info = true,
  38.     display_yoshi_info = true,
  39.     display_counters = true,
  40.     display_controller_input = true,
  41.     display_static_camera_region = false,  -- shows the region in which the camera won't scroll horizontally
  42.     draw_tiles_with_click = true,
  43.    
  44.     -- Some extra/debug info
  45.     display_debug_info = false,  -- shows useful info while investigating the game, but not very useful while TASing
  46.     display_debug_player_extra = true,
  47.     display_debug_sprite_extra = true,
  48.     display_debug_sprite_tweakers = true,
  49.     display_debug_extended_sprite = true,
  50.     display_debug_cluster_sprite = true,
  51.     display_debug_minor_extended_sprite = true,
  52.     display_debug_bounce_sprite = true,
  53.     display_debug_controller_data = false,  -- Snes9x: might cause desyncs
  54.     display_miscellaneous_sprite_table = false,
  55.     miscellaneous_sprite_table_number = {[1] = true, [2] = true, [3] = true, [4] = true, [5] = true, [6] = true, [7] = true, [8] = true, [9] = true,
  56.                     [10] = true, [11] = true, [12] = true, [13] = true, [14] = true, [15] = true, [16] = true, [17] = true, [18] = true, [19] = true
  57.     },
  58.     display_mouse_coordinates = false,
  59.     draw_tile_map_grid = false,
  60.     draw_tile_map_type = false,
  61.     draw_tile_map_gfx_type = false,
  62.     draw_tile_map_phy_type = false,
  63.    
  64.     -- Memory edit function
  65.     address = 0x7E0000,
  66.     size = 1,
  67.     value = 0,
  68.     edit_method = "Poke",
  69.     edit_sprite_table = false,
  70.     edit_sprite_table_number = {[1] = false, [2] = false, [3] = false, [4] = false, [5] = false, [6] = false, [7] = false, [8] = false, [9] = false,
  71.                                 [10] = false, [11] = false, [12] = false, [13] = false, [14] = false, [15] = false, [16] = false, [17] = false, [18] = false,
  72.                                 [19] = false, [20] = false, [21] = false, [22] = false, [23] = false, [24] = false},
  73.    
  74.     -- Script settings
  75.     max_tiles_drawn = 20,  -- the max number of tiles to be drawn/registered by the script
  76. }
  77.  
  78. -- Colour settings
  79. local DEFAULT_COLOUR = {
  80.     -- Text
  81.     default_text_opacity = 1.0,
  82.     default_bg_opacity = 0.7,
  83.     text = "#ffffff", -- white
  84.     background = "#000000", -- black
  85.     halo = "#000040",
  86.     positive = "#00ff00", -- green
  87.     warning = "#ff0000", -- red
  88.     warning_bg = "#000000ff",
  89.     warning2 = "#ff00ff", -- purple
  90.     warning_soft = "#ffa500", -- orange
  91.     weak = "#00a9a9a9",
  92.     weak2 = "#555555", -- gray
  93.     very_weak = "#a0ffffff",
  94.     memory = "#00ffff", -- cyan
  95.     joystick_input = "#ffff00ff",
  96.     joystick_input_bg = "#ffffff30",
  97.     button_text = "#300030ff",
  98.     mainmenu_outline = "#ffffffc0",
  99.     mainmenu_bg = "#000000c0",
  100.    
  101.     -- Counters
  102.     counter_pipe = "#00ff00ff",
  103.     counter_multicoin = "#ffff00ff",
  104.     counter_gray_pow = "#a5a5a5ff",
  105.     counter_blue_pow = "#4242deff",
  106.     counter_dircoin = "#8c5a19ff",
  107.     counter_pballoon = "#f8d870ff",
  108.     counter_star = "#ffd773ff",
  109.     counter_fireflower = "#ff8c00ff",
  110.    
  111.     -- hitbox and related text
  112.     mario = "#ff0000ff",
  113.     mario_bg = "#00000000",
  114.     mario_mounted_bg = "#00000000",
  115.     interaction = "#ffffffff",
  116.     interaction_bg = "#00000020",
  117.     interaction_nohitbox = "#000000a0",
  118.     interaction_nohitbox_bg = "#00000070",
  119.    
  120.     sprites = {
  121.         "#80ffff", -- cyan
  122.         "#a0a0ff", -- blue
  123.         "#ff6060", -- red
  124.         "#ff80ff", -- magenta
  125.         "#ffa100", -- orange
  126.         "#ffff80", -- yellow
  127.         "#40ff40"  -- green
  128.     },
  129.     sprites_bg = "#00ff00",
  130.     sprites_interaction_pts = "#ffffffff",
  131.     sprites_clipping_bg = "#000000a0",
  132.     extended_sprites = {
  133.         "#ff3700", -- orange to red gradient 6
  134.         "#ff5b00", -- orange to red gradient 4
  135.         "#ff8000", -- orange to red gradient 2
  136.         "#ffa500" -- orange to red gradient 0 (orange)
  137.     },
  138.     extended_sprites_bg = "#00ff0050",
  139.     special_extended_sprite_bg = "#00ff0060",
  140.     goal_tape_bg = "#ffff0050",
  141.     fireball = "#b0d0ffff",
  142.     baseball = "#0040a0ff",
  143.     cluster_sprites = "#ff80a0ff",
  144.     sumo_brother_flame = "#0040a0ff",
  145.     minor_extended_sprites = "#ff90b0ff",
  146.     awkward_hitbox = "#204060ff",
  147.     awkward_hitbox_bg = "#ff800060",
  148.    
  149.     yoshi = "#00ffffff",
  150.     yoshi_bg = "#00ffff40",
  151.     yoshi_mounted_bg = "#00000000",
  152.     tongue_line = "#ffa000ff",
  153.     tongue_bg = "#00000060",
  154.    
  155.     cape = "#ffd700ff",
  156.     cape_bg = "#ffd70060",
  157.    
  158.     block = "#00008bff",
  159.     blank_tile = "#ffffff70",
  160.     block_bg = "#22cc88a0",
  161.     layer2_line = "#ff2060ff",
  162.     layer2_bg = "#ff206040",
  163.     static_camera_region = "#40002040",
  164. }
  165.  
  166. -- Font settings
  167. local SNES9X_FONT_HEIGHT = 8
  168. local SNES9X_FONT_WIDTH = 4
  169.  
  170. -- GD images dumps (encoded)
  171. -- Symbols
  172. local LEFT_ARROW = "<-"
  173. local RIGHT_ARROW = "->"
  174.  
  175. -- Others
  176. local Border_right, Border_left, Border_top, Border_bottom = 0, 0, 0, 0
  177. local Buffer_width, Buffer_height, Buffer_middle_x, Buffer_middle_y = 256, 224, 128, 112
  178. local Screen_width, Screen_height, AR_x, AR_y = 256, 224, 1, 1
  179. local Y_CAMERA_OFF = 1 -- small adjustment to display the tiles according to their actual graphics
  180.  
  181. -- Input key names
  182. local INPUT_KEYNAMES = { -- Snes9x
  183.     xmouse=0, ymouse=0, leftclick=false, rightclick=false, middleclick=false,
  184.     shift=false, control=false, alt=false, capslock=false, numlock=false, scrolllock=false,
  185.     ["false"]=false, ["1"]=false, ["2"]=false, ["3"]=false, ["4"]=false, ["5"]=false, ["6"]=false, ["7"]=false, ["8"]=false,["9"]=false,
  186.     A=false, B=false, C=false, D=false, E=false, F=false, G=false, H=false, I=false, J=false, K=false, L=false, M=false, N=false,
  187.     O=false, P=false, Q=false, R=false, S=false, T=false, U=false, V=false, W=false, X=false, Y=false, Z=false,
  188.     F1=false, F2=false, F3=false, F4=false, F5=false, F6=false, F7=false, F8=false, F9=false, F1false=false, F11=false, F12=false,
  189.     F13=false, F14=false, F15=false, F16=false, F17=false, F18=false, F19=false, F2false=false, F21=false, F22=false, F23=false, F24=false,
  190.     backspace=false, tab=false, enter=false, pause=false, escape=false, space=false,
  191.     pageup=false, pagedown=false, ["end"]=false, home=false, insert=false, delete=false,
  192.     left=false, up=false, right=false, down=false,
  193.     numpadfalse=false, numpad1=false, numpad2=false, numpad3=false, numpad4=false, numpad5=false, numpad6=false, numpad7=false, numpad8=false, numpad9=false,
  194.     ["numpad*"]=false, ["numpad+"]=false, ["numpad-"]=false, ["numpad."]=false, ["numpad/"]=false,
  195.     tilde=false, plus=false, minus=false, leftbracket=false, rightbracket=false,
  196.     semicolon=false, quote=false, comma=false, period=false, slash=false, backslash=false
  197. }
  198.  
  199. -- END OF CONFIG < < < < < < <
  200. --#############################################################################
  201. -- INITIAL STATEMENTS:
  202.  
  203.  
  204. print("Starting script")
  205.  
  206. -- Load environment
  207. local gui, input, joypad, emu, movie, memory = gui, input, joypad, emu, movie, memory
  208. local unpack = unpack or table.unpack
  209. local string, math, table, next, ipairs, pairs, io, os, type = string, math, table, next, ipairs, pairs, io, os, type
  210. local bit = require"bit"
  211.  
  212. -- Script tries to verify whether the emulator is indeed Snes9x-rr
  213. if snes9x == nil then
  214.     error("This script works with Snes9x-rr emulator.")
  215. end
  216.  
  217. -- TEST: INI library for handling an ini configuration file
  218. function file_exists(name)
  219.    local f = io.open(name, "r")
  220.    if f ~= nil then io.close(f) return true else return false end
  221. end
  222.  
  223. function copytable(orig)
  224.     local orig_type = type(orig)
  225.     local copy
  226.     if orig_type == 'table' then
  227.         copy = {}
  228.         for orig_key, orig_value in next, orig, nil do
  229.             copy[copytable(orig_key)] = copytable(orig_value) -- possible stack overflow
  230.         end
  231.         setmetatable(copy, copytable(getmetatable(orig)))
  232.     else -- number, string, boolean, etc
  233.         copy = orig
  234.     end
  235.     return copy
  236. end
  237.  
  238. function mergetable(source, t2)
  239.     for key, value in pairs(t2) do
  240.         if type(value) == "table" then
  241.             if type(source[key] or false) == "table" then
  242.                 mergetable(source[key] or {}, t2[key] or {}) -- possible stack overflow
  243.             else
  244.                 source[key] = value
  245.             end
  246.         else
  247.             source[key] = value
  248.         end
  249.     end
  250.     return source
  251. end
  252.  
  253. -- Creates a set from a list
  254. local function make_set(list)
  255.     local set = {}
  256.     for _, l in ipairs(list) do set[l] = true end
  257.     return set
  258. end
  259.  
  260. local INI = {}
  261.  
  262. function INI.arg_to_string(value)
  263.     local str
  264.     if type(value) == "string" then
  265.         str = "\"" .. value .. "\""
  266.     elseif type(value) == "number" or type(value) == "boolean" or value == nil then
  267.         str = tostring(value)
  268.     elseif type(value) == "table" then
  269.         local tmp = {"{"}  -- only arrays
  270.         for a, b in ipairs(value) do
  271.             table.insert(tmp, ("%s%s"):format(INI.arg_to_string(b), a ~= #value and ", " or "")) -- possible stack overflow
  272.         end
  273.         table.insert(tmp, "}")
  274.         str = table.concat(tmp)
  275.     else
  276.         str = "#BAD_VALUE"
  277.     end
  278.    
  279.     return str
  280. end
  281.  
  282. -- creates the string for ini
  283. function INI.data_to_string(data)
  284.     local sections = {}
  285.    
  286.     for section, prop in pairs(data) do
  287.         local properties = {}
  288.        
  289.         for key, value in pairs(prop) do
  290.             table.insert(properties, ("%s = %s\n"):format(key, INI.arg_to_string(value)))  -- properties
  291.         end
  292.        
  293.         table.sort(properties)
  294.         table.insert(sections, ("[%s]\n"):format(section) .. table.concat(properties) .. "\n")
  295.     end
  296.    
  297.     table.sort(sections)
  298.     return table.concat(sections)
  299. end
  300.  
  301. function INI.string_to_data(value)
  302.     local data
  303.    
  304.     if tonumber(value) then
  305.         data = tonumber(value)
  306.     elseif value == "true" then
  307.         data = true
  308.     elseif value == "false" then
  309.         data = false
  310.     elseif value == "nil" then
  311.         data = nil
  312.     else
  313.         local quote1, text, quote2 = value:match("(['\"{])(.+)(['\"}])")  -- value is surrounded by "", '' or {}?
  314.         if quote1 and quote2 and text then
  315.             if (quote1 == '"' or quote1 == "'") and quote1 == quote2 then
  316.                 data = text
  317.             elseif quote1 == "{" and quote2 == "}" then
  318.                 local tmp = {} -- test
  319.                 for words in text:gmatch("[^,%s]+") do
  320.                     tmp[#tmp + 1] = INI.string_to_data(words) -- possible stack overflow
  321.                 end
  322.                
  323.                 data = tmp
  324.             else
  325.                 data = value
  326.             end
  327.         else
  328.             data = value
  329.         end
  330.     end
  331.    
  332.     return data
  333. end
  334.  
  335. function INI.load(filename)
  336.     local file = io.open(filename, "r")
  337.     if not file then return false end
  338.    
  339.     local data, section = {}, nil
  340.    
  341.     for line in file:lines() do
  342.         local new_section = line:match("^%[([^%[%]]+)%]$")
  343.        
  344.         if new_section then
  345.             section = INI.string_to_data(new_section) and INI.string_to_data(new_section) or new_section
  346.             if data[section] then print("Duplicated section") end
  347.             data[section] = data[section] or {}
  348.         else
  349.            
  350.             local prop, value = line:match("^([%w_%-%.]+)%s*=%s*(.+)%s*$")  -- prop = value
  351.            
  352.             if prop and value then
  353.                 value = INI.string_to_data(value)
  354.                 prop = INI.string_to_data(prop) and INI.string_to_data(prop) or prop
  355.                
  356.                 if data[section] == nil then print(prop, value) ; error("Property outside section") end
  357.                 data[section][prop] = value
  358.             else
  359.                 local ignore = line:match("^;") or line == ""
  360.                 if not ignore then
  361.                     print("BAD LINE:", line, prop, value)
  362.                 end
  363.             end
  364.            
  365.         end
  366.        
  367.     end
  368.    
  369.     file:close()
  370.     return data
  371. end
  372.  
  373. function INI.retrieve(filename, data)
  374.     if type(data) ~= "table" then error"data must be a table" end
  375.     local previous_data
  376.    
  377.     -- Verifies if file already exists
  378.     if file_exists(filename) then
  379.         ini_data = INI.load(filename)
  380.     else return data
  381.     end
  382.    
  383.     -- Adds previous values to the new ini
  384.     local union_data = mergetable(data, ini_data)
  385.     return union_data
  386. end
  387.  
  388. function INI.overwrite(filename, data)
  389.     local file, err = assert(io.open(filename, "w"), "Error loading file :" .. filename)
  390.     if not file then print(err) ; return end
  391.    
  392.     file:write(INI.data_to_string(data))
  393.     file:close()
  394. end
  395.  
  396. function INI.save(filename, data)
  397.     if type(data) ~= "table" then error"data must be a table" end
  398.    
  399.     local tmp, previous_data
  400.     if file_exists(filename) then
  401.         previous_data = INI.load(filename)
  402.         tmp = mergetable(previous_data, data)
  403.     else
  404.         tmp = data
  405.     end
  406.    
  407.     INI.overwrite(filename, tmp)
  408. end
  409.  
  410. local OPTIONS = file_exists(INI_CONFIG_FILENAME) and INI.retrieve(INI_CONFIG_FILENAME, {["SNES9X OPTIONS"] = DEFAULT_OPTIONS}).OPTIONS or DEFAULT_OPTIONS
  411. local COLOUR = file_exists(INI_CONFIG_FILENAME) and INI.retrieve(INI_CONFIG_FILENAME, {["SNES9X COLOURS"] = DEFAULT_COLOUR}).COLOURS or DEFAULT_COLOUR
  412. INI.save(INI_CONFIG_FILENAME, {["SNES9X COLOURS"] = COLOUR})  -- Snes9x doesn't need to convert colour string to number
  413. INI.save(INI_CONFIG_FILENAME, {["SNES9X OPTIONS"] = OPTIONS})
  414.  
  415. function INI.save_options()
  416.     INI.save(INI_CONFIG_FILENAME, {["SNES9X OPTIONS"] = OPTIONS})
  417. end
  418.  
  419. --######################## -- end of test
  420.  
  421. -- Text/Background_max_opacity is only changed by the player using the hotkeys
  422. -- Text/Bg_opacity must be used locally inside the functions
  423. local Text_max_opacity = COLOUR.default_text_opacity
  424. local Background_max_opacity = COLOUR.default_bg_opacity
  425. local Text_opacity = 1
  426. local Bg_opacity = 1
  427.  
  428. local fmt = string.format
  429. local floor = math.floor
  430. local sqrt = math.sqrt
  431. local sin = math.sin
  432. local cos = math.cos
  433. local pi = math.pi
  434.  
  435. -- unsigned to signed (based in <bits> bits)
  436. local function signed(num, bits)
  437.     local maxval = 2^(bits - 1)
  438.     if num < maxval then return num else return num - 2*maxval end
  439. end
  440.  
  441. -- Compatibility of the memory read/write functions
  442. local u8 =  memory.readbyte
  443. local s8 =  memory.readbytesigned
  444. local w8 =  memory.writebyte
  445. local u16 = memory.readword
  446. local s16 = memory.readwordsigned
  447. local w16 = memory.writeword
  448. local u24 = function(address, value) return 256*u16(address + 1) + u8(address) end
  449. local s24 = function(address, value) return signed(256*u16(address + 1) + u8(address), 24) end
  450. local w24 = function(address, value) w16(address + 1, floor(value/256)) ; w8(address, value%256) end
  451.  
  452. -- Images (for gd library)
  453. local IMAGES = {}
  454. IMAGES.player_blocked_status = string.char(unpack(GD_IMAGES_DUMPS.player_blocked_status))
  455. IMAGES.goal_tape = string.char(unpack(GD_IMAGES_DUMPS.goal_tape))
  456.  
  457. -- Hotkeys availability
  458. if INPUT_KEYNAMES[OPTIONS.hotkey_increase_opacity] == nil then
  459.      print(string.format("Hotkey '%s' is not available, to increase opacity.", OPTIONS.hotkey_increase_opacity))
  460. else print(string.format("Hotkey '%s' set to increase opacity.", OPTIONS.hotkey_increase_opacity))
  461. end
  462. if INPUT_KEYNAMES[OPTIONS.hotkey_decrease_opacity] == nil then
  463.      print(string.format("Hotkey '%s' is not available, to decrease opacity.", OPTIONS.hotkey_decrease_opacity))
  464. else print(string.format("Hotkey '%s' set to decrease opacity.", OPTIONS.hotkey_decrease_opacity))
  465. end
  466.  
  467.  
  468. --#############################################################################
  469. -- GAME AND SNES SPECIFIC MACROS:
  470.  
  471.  
  472. local NTSC_FRAMERATE = 60.0
  473.  
  474. local SMW2 = {
  475.     -- Game Modes
  476.     game_mode_overworld = 0x0022,
  477.     game_mode_level = 0x000F,
  478.    
  479.     -- Sprites
  480.     sprite_max = 24,
  481.     extended_sprite_max = 16,
  482.     cluster_sprite_max = 20,
  483.     minor_extended_sprite_max = 12,
  484.     bounce_sprite_max = 4,
  485.     null_sprite_id = 0xff,
  486.    
  487.     -- Blocks
  488.     blank_tile_map16 = 0x25,
  489. }
  490.  
  491. SFXRAM = {  -- 700000~701FFF
  492.     -- General
  493.     level_timer = 0x701974, -- 2 bytes
  494.     screen_number_to_id = 0x700CAA, -- 128 bytes table
  495.     RNG = 0x701970, -- 2 bytes
  496.  
  497.     -- Player
  498.     x = 0x70008C, -- 2 bytes
  499.     y = 0x700090, -- 2 bytes
  500.     --previous_x = 0x7000d1,
  501.     --previous_y = 0x7000d3,
  502.     x_sub = 0x70008A,
  503.     y_sub = 0x70008E,
  504.     x_speed = 0x7000A9,
  505.     x_subspeed = 0x7000A8,
  506.     y_speed = 0x7000AB,
  507.     y_subspeed = 0x7000AA,
  508.     direction = 0x7000C4,
  509.     ground_pound_state = 0x7000D4,
  510.     ground_pound_timer = 0x7000D6,
  511.     egg_target_x = 0x7000E4, -- 2 bytes
  512.     egg_target_y = 0x7000E6, -- 2 bytes
  513.     egg_target_radial_pos = 0x7000EF,
  514.     egg_target_radial_subpos = 0x7000EE,
  515.     egg_throw_state = 0x7000DE,
  516.     egg_throw_state_timer = 0x7001E2,
  517.     player_blocked_status = 0x7000FC,
  518.     x_centered = 0x70011C, -- 2 bytes
  519.     y_centered = 0x70011E, -- 2 bytes
  520.     tongue_x = 0x700152, -- 2 bytes
  521.     tongue_y = 0x700154, -- 2 bytes
  522.     tongue_state = 0x700150,
  523.     ammo_in_mouth = 0x70016A,
  524.     is_frozen = 0x7001AE, -- 2 bytes
  525.     on_sprite_platform = 0x7001B4,
  526.     --is_ducking = 0x700073,
  527.     --p_meter = 0x7013e4,
  528.     --take_off = 0x70149f,
  529.     --powerup = 0x700019,
  530.     --diving_status = 0x701409,
  531.     --player_animation_trigger = 0x700071,
  532.     --climbing_status = 0x700074,
  533.     --on_ground = 0x7013ef,
  534.     --on_ground_delay = 0x70008d,
  535.     --on_air = 0x700072,
  536.     --can_jump_from_water = 0x7013fa,
  537.     --carrying_item = 0x70148f,
  538.     --player_looking_up = 0x7013de,
  539.    
  540.     -- Baby Mario
  541.     mario_status = 0x700F00,
  542.    
  543.    
  544.     -- Timer
  545.     invincibility_timer = 0x7001D6,
  546.     eat_timer = 0x7001EE,
  547.     transform_timer = 0x7001F4,
  548.     star_timer = 0x701E04,
  549.    
  550.     -- Sprites
  551.     sprite_status = 0x700F00,
  552.     sprite_type = 0x701360,
  553.     sprite_x = 0x7010E0, -- 2 bytes
  554.     sprite_y = 0x701180, -- 2 bytes
  555.     sprite_x_sub = 0x7010DF,
  556.     sprite_y_sub = 0x70117F,
  557.     sprite_x_speed = 0x701221,
  558.     sprite_x_subspeed = 0x701220,
  559.     sprite_y_speed = 0x701223,
  560.     sprite_y_subspeed = 0x701222,
  561.     sprite_hitbox_half_width = 0x701B56, -- 2 bytes
  562.     sprite_hitbox_half_height = 0x701B58, -- 2 bytes
  563.     sprite_x_center = 0x701CD6, -- 2 bytes
  564.     sprite_y_center = 0x701CD8 -- 2 bytes
  565.    
  566. }
  567. --[[
  568. for name, address in pairs(SFXRAM) do
  569.     address = address + 0x700000  -- Snes9x
  570. end]]
  571. local SFXRAM = SFXRAM
  572.  
  573. WRAM = {  -- 7E0000~7FFFFF
  574.     -- I/O
  575.     ctrl_1_1 = 0x0015,
  576.     ctrl_1_2 = 0x0017,
  577.     firstctrl_1_1 = 0x0016,
  578.     firstctrl_1_2 = 0x0018,
  579.    
  580.     -- General
  581.     game_mode = 0x0118,
  582.     --real_frame = 0x0013,
  583.     --effective_frame = 0x0014,
  584.     --lag_indicator = 0x01fe,
  585.     --timer_frame_counter = 0x0f30,
  586.     --RNG = 0x148d,
  587.     --current_level = 0x00fe,  -- plus 1
  588.     --lock_animation_flag = 0x009d, -- Most codes will still run if this is set, but almost nothing will move or animate.
  589.     --level_mode_settings = 0x1925,
  590.     red_coin_counter = 0x03B4,
  591.     star_counter = 0x03B6,
  592.     flower_counter = 0x03B8,
  593.     coin_counter = 0x037b,
  594.     is_paused = 0x0B10,
  595.     Map16_data = 0x18000, -- 32768 bytes table, in words
  596.    
  597.     -- Cheats
  598.     frozen = 0x13fb,
  599.     level_paused = 0x13d4,
  600.     level_index = 0x021A, -- 2 bytes
  601.     room_index = 0x00ce,
  602.     level_flag_table = 0x1ea2,
  603.     level_exit_type = 0x0dd5,
  604.     midway_point = 0x13ce,
  605.    
  606.     -- Camera
  607.     camera_x = 0x0039,
  608.     camera_y = 0x003B,
  609.     screens_number = 0x005d,
  610.     hscreen_number = 0x005e,
  611.     vscreen_number = 0x005f,
  612.     vertical_scroll_flag_header = 0x1412,  -- #$00 = Disable; #$01 = Enable; #$02 = Enable if flying/climbing/etc.
  613.     vertical_scroll_enabled = 0x13f1,
  614.     camera_scroll_timer = 0x1401,
  615.    
  616.     -- Sprites
  617.     sprite_status = 0x14c8,
  618.     sprite_number = 0x009e,
  619.     sprite_x_high = 0x14e0,
  620.     sprite_x_low = 0x00e4,
  621.     sprite_y_high = 0x14d4,
  622.     sprite_y_low = 0x00d8,
  623.     sprite_x_sub = 0x14f8,
  624.     sprite_y_sub = 0x14ec,
  625.     sprite_x_speed = 0x00b6,
  626.     sprite_y_speed = 0x00aa,
  627.     sprite_x_offscreen = 0x15a0,
  628.     sprite_y_offscreen = 0x186c,
  629.     sprite_miscellaneous1 = 0x00c2,
  630.     sprite_miscellaneous2 = 0x1504,
  631.     sprite_miscellaneous3 = 0x1510,
  632.     sprite_miscellaneous4 = 0x151c,
  633.     sprite_miscellaneous5 = 0x1528,
  634.     sprite_miscellaneous6 = 0x1534,
  635.     sprite_miscellaneous7 = 0x1540,
  636.     sprite_miscellaneous8 = 0x154c,
  637.     sprite_miscellaneous9 = 0x1558,
  638.     sprite_miscellaneous10 = 0x1564,
  639.     sprite_miscellaneous11 = 0x1570,
  640.     sprite_miscellaneous12 = 0x157c,
  641.     sprite_miscellaneous13 = 0x1594,
  642.     sprite_miscellaneous14 = 0x15ac,
  643.     sprite_miscellaneous15 = 0x1602,
  644.     sprite_miscellaneous16 = 0x160e,
  645.     sprite_miscellaneous17 = 0x1626,
  646.     sprite_miscellaneous18 = 0x163e,
  647.     sprite_miscellaneous19 = 0x187b,
  648.     sprite_underwater = 0x164a,
  649.     sprite_disable_cape = 0x1fe2,
  650.     sprite_1_tweaker = 0x1656,
  651.     sprite_2_tweaker = 0x1662,
  652.     sprite_3_tweaker = 0x166e,
  653.     sprite_4_tweaker = 0x167a,
  654.     sprite_5_tweaker = 0x1686,
  655.     sprite_6_tweaker = 0x190f,
  656.     sprite_tongue_wait = 0x14a3,
  657.     sprite_yoshi_squatting = 0x18af,
  658.     sprite_buoyancy = 0x190e,
  659.     toadies_relative_x = 0x0E38,
  660.     toadies_relative_y = 0x0E4A,
  661.    
  662.     -- Extended sprites
  663.     extspr_number = 0x170b,
  664.     extspr_x_high = 0x1733,
  665.     extspr_x_low = 0x171f,
  666.     extspr_y_high = 0x1729,
  667.     extspr_y_low = 0x1715,
  668.     extspr_x_speed = 0x1747,
  669.     extspr_y_speed = 0x173d,
  670.     extspr_suby = 0x1751,
  671.     extspr_subx = 0x175b,
  672.     extspr_table = 0x1765,
  673.     extspr_table2 = 0x176f,
  674.    
  675.     -- Cluster sprites
  676.     cluspr_flag = 0x18b8,
  677.     cluspr_number = 0x1892,
  678.     cluspr_x_high = 0x1e3e,
  679.     cluspr_x_low = 0x1e16,
  680.     cluspr_y_high = 0x1e2a,
  681.     cluspr_y_low = 0x1e02,
  682.     cluspr_timer = 0x0f9a,
  683.     cluspr_table_1 = 0x0f4a,
  684.     cluspr_table_2 = 0x0f72,
  685.     cluspr_table_3 = 0x0f86,
  686.     reappearing_boo_counter = 0x190a,
  687.    
  688.     -- Minor extended sprites
  689.     minorspr_number = 0x17f0,
  690.     minorspr_x_high = 0x18ea,
  691.     minorspr_x_low = 0x1808,
  692.     minorspr_y_high = 0x1814,
  693.     minorspr_y_low = 0x17fc,
  694.     minorspr_xspeed = 0x182c,
  695.     minorspr_yspeed = 0x1820,
  696.     minorspr_x_sub = 0x1844,
  697.     minorspr_y_sub = 0x1838,
  698.     minorspr_timer = 0x1850,
  699.    
  700.     -- Bounce sprites
  701.     bouncespr_number = 0x1699,
  702.     bouncespr_x_high = 0x16ad,
  703.     bouncespr_x_low = 0x16a5,
  704.     bouncespr_y_high = 0x16a9,
  705.     bouncespr_y_low = 0x16a1,
  706.     bouncespr_timer = 0x16c5,
  707.     bouncespr_last_id = 0x18cd,
  708.     turn_block_timer = 0x18ce,
  709.    
  710.     -- Player
  711.     x = 0x0094,
  712.     y = 0x0096,
  713.     previous_x = 0x00d1,
  714.     previous_y = 0x00d3,
  715.     x_sub = 0x13da,
  716.     y_sub = 0x13dc,
  717.     x_speed = 0x007b,
  718.     x_subspeed = 0x007a,
  719.     y_speed = 0x007d,
  720.     direction = 0x0076,
  721.     is_ducking = 0x0073,
  722.     p_meter = 0x13e4,
  723.     take_off = 0x149f,
  724.     powerup = 0x0019,
  725.     cape_spin = 0x14a6,
  726.     cape_fall = 0x14a5,
  727.     cape_interaction = 0x13e8,
  728.     flight_animation = 0x1407,
  729.     diving_status = 0x1409,
  730.     player_animation_trigger = 0x0071,
  731.     climbing_status = 0x0074,
  732.     spinjump_flag = 0x140d,
  733.     player_blocked_status = 0x0077,
  734.     player_item = 0x0dc2, --hex
  735.     cape_x = 0x13e9,
  736.     cape_y = 0x13eb,
  737.     on_ground = 0x13ef,
  738.     on_ground_delay = 0x008d,
  739.     on_air = 0x0072,
  740.     can_jump_from_water = 0x13fa,
  741.     carrying_item = 0x148f,
  742.     mario_score = 0x0f34,
  743.     player_coin = 0x0dbf,
  744.     player_looking_up = 0x13de,
  745.    
  746.     -- Yoshi
  747.     yoshi_riding_flag = 0x187a,  -- #$00 = No, #$01 = Yes, #$02 = Yes, and turning around.
  748.     yoshi_tile_pos = 0x0d8c,
  749.    
  750.     -- Timers
  751.     --pipe_entrance_timer = 0x0088,
  752.     end_level_timer = 0x1493,
  753.     --multicoin_block_timer = 0x186b,,
  754.     switch_timer = 0x0CEC, -- 2 bytes
  755.    
  756.     -- Layers
  757.     layer2_x_nextframe = 0x1466,
  758.     layer2_y_nextframe = 0x1468,
  759. }
  760. for name, address in pairs(WRAM) do
  761.     address = address + 0x7e0000  -- Snes9x
  762. end
  763. local WRAM = WRAM
  764.  
  765. local SOLID_BLOCKS = { -- solid and one-way solid blocks, via tests
  766.     0x01, 0x02, 0x03, 0x05, 0x06, 0x08, 0x0A, 0x0C, 0x0D, 0x0F,
  767.     0x10, 0x15, 0x1A, 0x1B, 0x1C ,
  768.     0x29, 0x2C, 0x2F,
  769.     0x33, 0x38, 0x39, 0x3E, 0x3F,
  770.     0x40, 0x41, 0x44, 0x45, 0x48, 0x49, 0x4B, 0x4C, 0x4E,
  771.     0x50, 0x53, 0x55, 0x57, 0x59, 0x5B, 0x5D, 0x5F,
  772.     0x66, 0x67, 0x6B, 0x6E,
  773.     0x79, 0x7D,
  774.     0x90, 0x95, 0x9A, 0x9D, 0x9F,
  775.     0xA0, 0xA1, 0xA2
  776. }
  777.  
  778. local X_INTERACTION_POINTS = {center = 0x8, left_side = 0x2 + 1, left_foot = 0x3, right_side = 0xe - 1, right_foot = 0xd}
  779.  
  780. local Y_INTERACTION_POINTS = {
  781.     {head = 0x10, center = 0x18, shoulder = 0x16, side = 0x1f, foot = 0x20, sprite = 0x15},
  782.     {head = 0x08, center = 0x12, shoulder = 0x0f, side = 0x1f, foot = 0x20, sprite = 0x07}, -- this one, for now
  783.     {head = 0x13, center = 0x1d, shoulder = 0x19, side = 0x28, foot = 0x30, sprite = 0x19},
  784.     {head = 0x10, center = 0x1a, shoulder = 0x16, side = 0x28, foot = 0x30, sprite = 0x11}
  785. }
  786.  
  787. local HITBOX_SPRITE = {  -- sprites' hitbox against player and other sprites
  788.     [0x00] = { xoff = 2, yoff = 3, width = 12, height = 10, oscillation = true },
  789.     [0x01] = { xoff = 2, yoff = 3, width = 12, height = 21, oscillation = true },
  790.     [0x02] = { xoff = 16, yoff = -2, width = 16, height = 18, oscillation = true },
  791.     [0x03] = { xoff = 20, yoff = 8, width = 8, height = 8, oscillation = true },
  792.     [0x04] = { xoff = 0, yoff = -2, width = 48, height = 14, oscillation = true },
  793.     [0x05] = { xoff = 0, yoff = -2, width = 80, height = 14, oscillation = true },
  794.     [0x06] = { xoff = 1, yoff = 2, width = 14, height = 24, oscillation = true },
  795.     [0x07] = { xoff = 8, yoff = 8, width = 40, height = 48, oscillation = true },
  796.     [0x08] = { xoff = -8, yoff = -2, width = 32, height = 16, oscillation = true },
  797.     [0x09] = { xoff = -2, yoff = 8, width = 20, height = 30, oscillation = true },
  798.     [0x0a] = { xoff = 3, yoff = 7, width = 1, height = 2, oscillation = true },
  799.     [0x0b] = { xoff = 6, yoff = 6, width = 3, height = 3, oscillation = true },
  800.     [0x0c] = { xoff = 1, yoff = -2, width = 13, height = 22, oscillation = true },
  801.     [0x0d] = { xoff = 0, yoff = -4, width = 15, height = 16, oscillation = true },
  802.     [0x0e] = { xoff = 6, yoff = 6, width = 20, height = 20, oscillation = true },
  803.     [0x0f] = { xoff = 2, yoff = -2, width = 36, height = 18, oscillation = true },
  804.     [0x10] = { xoff = 0, yoff = -2, width = 15, height = 32, oscillation = true },
  805.     [0x11] = { xoff = -24, yoff = -24, width = 64, height = 64, oscillation = true },
  806.     [0x12] = { xoff = -4, yoff = 16, width = 8, height = 52, oscillation = true },
  807.     [0x13] = { xoff = -4, yoff = 16, width = 8, height = 116, oscillation = true },
  808.     [0x14] = { xoff = 4, yoff = 2, width = 24, height = 12, oscillation = true },
  809.     [0x15] = { xoff = 0, yoff = -2, width = 15, height = 14, oscillation = true },
  810.     [0x16] = { xoff = -4, yoff = -12, width = 24, height = 24, oscillation = true },
  811.     [0x17] = { xoff = 2, yoff = 8, width = 12, height = 69, oscillation = true },
  812.     [0x18] = { xoff = 2, yoff = 19, width = 12, height = 58, oscillation = true },
  813.     [0x19] = { xoff = 2, yoff = 35, width = 12, height = 42, oscillation = true },
  814.     [0x1a] = { xoff = 2, yoff = 51, width = 12, height = 26, oscillation = true },
  815.     [0x1b] = { xoff = 2, yoff = 67, width = 12, height = 10, oscillation = true },
  816.     [0x1c] = { xoff = 0, yoff = 10, width = 10, height = 48, oscillation = true },
  817.     [0x1d] = { xoff = 2, yoff = -3, width = 28, height = 27, oscillation = true },
  818.     [0x1e] = { xoff = 6, yoff = -8, width = 3, height = 32, oscillation = true },  -- default: { xoff = -32, yoff = -8, width = 48, height = 32, oscillation = true },
  819.     [0x1f] = { xoff = -16, yoff = -4, width = 48, height = 18, oscillation = true },
  820.     [0x20] = { xoff = -4, yoff = -24, width = 8, height = 24, oscillation = true },
  821.     [0x21] = { xoff = -4, yoff = 16, width = 8, height = 24, oscillation = true },
  822.     [0x22] = { xoff = 0, yoff = 0, width = 16, height = 16, oscillation = true },
  823.     [0x23] = { xoff = -8, yoff = -24, width = 32, height = 32, oscillation = true },
  824.     [0x24] = { xoff = -12, yoff = 32, width = 56, height = 56, oscillation = true },
  825.     [0x25] = { xoff = -14, yoff = 4, width = 60, height = 20, oscillation = true },
  826.     [0x26] = { xoff = 0, yoff = 88, width = 32, height = 8, oscillation = true },
  827.     [0x27] = { xoff = -4, yoff = -4, width = 24, height = 24, oscillation = true },
  828.     [0x28] = { xoff = -14, yoff = -24, width = 28, height = 40, oscillation = true },
  829.     [0x29] = { xoff = -16, yoff = -4, width = 32, height = 27, oscillation = true },
  830.     [0x2a] = { xoff = 2, yoff = -8, width = 12, height = 19, oscillation = true },
  831.     [0x2b] = { xoff = 0, yoff = 2, width = 16, height = 76, oscillation = true },
  832.     [0x2c] = { xoff = -8, yoff = -8, width = 16, height = 16, oscillation = true },
  833.     [0x2d] = { xoff = 4, yoff = 4, width = 8, height = 4, oscillation = true },
  834.     [0x2e] = { xoff = 2, yoff = -2, width = 28, height = 34, oscillation = true },
  835.     [0x2f] = { xoff = 2, yoff = -2, width = 28, height = 32, oscillation = true },
  836.     [0x30] = { xoff = 8, yoff = -14, width = 16, height = 28, oscillation = true },
  837.     [0x31] = { xoff = 0, yoff = -2, width = 48, height = 18, oscillation = true },
  838.     [0x32] = { xoff = 0, yoff = -2, width = 48, height = 18, oscillation = true },
  839.     [0x33] = { xoff = 0, yoff = -2, width = 64, height = 18, oscillation = true },
  840.     [0x34] = { xoff = -4, yoff = -4, width = 8, height = 8, oscillation = true },
  841.     [0x35] = { xoff = 3, yoff = 0, width = 18, height = 32, oscillation = true },
  842.     [0x36] = { xoff = 8, yoff = 8, width = 52, height = 46, oscillation = true },
  843.     [0x37] = { xoff = 0, yoff = -8, width = 15, height = 20, oscillation = true },
  844.     [0x38] = { xoff = 8, yoff = 16, width = 32, height = 40, oscillation = true },
  845.     [0x39] = { xoff = 4, yoff = 3, width = 8, height = 10, oscillation = true },
  846.     [0x3a] = { xoff = -8, yoff = 16, width = 32, height = 16, oscillation = true },
  847.     [0x3b] = { xoff = 0, yoff = 0, width = 16, height = 13, oscillation = true },
  848.     [0x3c] = { xoff = 12, yoff = 10, width = 3, height = 6, oscillation = true },
  849.     [0x3d] = { xoff = 12, yoff = 21, width = 3, height = 20, oscillation = true },
  850.     [0x3e] = { xoff = 16, yoff = 18, width = 254, height = 16, oscillation = true },
  851.     [0x3f] = { xoff = 8, yoff = 8, width = 8, height = 24, oscillation = true }
  852. }
  853.  
  854. local OBJ_CLIPPING_SPRITE = {  -- sprites' interaction points against objects
  855.     [0x0] = {xright = 14, xleft =  2, xdown =  8, xup =  8, yright =  8, yleft =  8, ydown = 16, yup =  2},
  856.     [0x1] = {xright = 14, xleft =  2, xdown =  7, xup =  7, yright = 18, yleft = 18, ydown = 32, yup =  2},
  857.     [0x2] = {xright =  7, xleft =  7, xdown =  7, xup =  7, yright =  7, yleft =  7, ydown =  7, yup =  7},
  858.     [0x3] = {xright = 14, xleft =  2, xdown =  8, xup =  8, yright = 16, yleft = 16, ydown = 32, yup = 11},
  859.     [0x4] = {xright = 16, xleft =  0, xdown =  8, xup =  8, yright = 18, yleft = 18, ydown = 32, yup =  2},
  860.     [0x5] = {xright = 13, xleft =  2, xdown =  8, xup =  8, yright = 24, yleft = 24, ydown = 32, yup = 16},
  861.     [0x6] = {xright =  7, xleft =  0, xdown =  4, xup =  4, yright =  4, yleft =  4, ydown =  8, yup =  0},
  862.     [0x7] = {xright = 31, xleft =  1, xdown = 16, xup = 16, yright = 16, yleft = 16, ydown = 31, yup =  1},
  863.     [0x8] = {xright = 15, xleft =  0, xdown =  8, xup =  8, yright =  8, yleft =  8, ydown = 15, yup =  0},
  864.     [0x9] = {xright = 16, xleft =  0, xdown =  8, xup =  8, yright =  8, yleft =  8, ydown = 16, yup =  0},
  865.     [0xa] = {xright = 13, xleft =  2, xdown =  8, xup =  8, yright = 72, yleft = 72, ydown = 80, yup = 66},
  866.     [0xb] = {xright = 14, xleft =  2, xdown =  8, xup =  8, yright =  4, yleft =  4, ydown =  8, yup =  0},
  867.     [0xc] = {xright = 13, xleft =  2, xdown =  8, xup =  8, yright =  0, yleft =  0, ydown =  0, yup =  0},
  868.     [0xd] = {xright = 16, xleft =  0, xdown =  8, xup =  8, yright =  8, yleft =  8, ydown = 16, yup =  0},
  869.     [0xe] = {xright = 31, xleft =  0, xdown = 16, xup = 16, yright =  8, yleft =  8, ydown = 16, yup =  0},
  870.     [0xf] = {xright =  8, xleft =  8, xdown =  8, xup = 16, yright =  4, yleft =  1, ydown =  2, yup =  4}
  871. }
  872.  
  873. local HITBOX_EXTENDED_SPRITE = {  -- extended sprites' hitbox
  874.     -- To fill the slots...
  875.     --[0] ={ xoff = 3, yoff = 3, width = 64, height = 64},  -- Free slot
  876.     [0x01] ={ xoff = 3, yoff = 3, width =  0, height =  0},  -- Puff of smoke with various objects
  877.     [0x0e] ={ xoff = 3, yoff = 3, width =  0, height =  0},  -- Wiggler's flower
  878.     [0x0f] ={ xoff = 3, yoff = 3, width =  0, height =  0},  -- Trail of smoke
  879.     [0x10] ={ xoff = 3, yoff = 3, width =  0, height =  0},  -- Spinjump stars
  880.     [0x12] ={ xoff = 3, yoff = 3, width =  0, height =  0},  -- Water bubble
  881.     -- extracted from ROM:
  882.     [0x02] = { xoff = 3, yoff = 3, width = 1, height = 1, color_line = COLOUR.fireball },  -- Reznor fireball
  883.     [0x03] = { xoff = 3, yoff = 3, width = 1, height = 1, color_line = COLOUR.fireball},  -- Flame left by hopping flame
  884.     [0x04] = { xoff = 4, yoff = 4, width = 8, height = 8},  -- Hammer
  885.     [0x05] = { xoff = 3, yoff = 3, width = 1, height = 1, color_line = COLOUR.fireball },  -- Player fireball
  886.     [0x06] = { xoff = 4, yoff = 4, width = 8, height = 8},  -- Bone from Dry Bones
  887.     [0x07] = { xoff = 0, yoff = 0, width = 0, height = 0},  -- Lava splash
  888.     [0x08] = { xoff = 0, yoff = 0, width = 0, height = 0},  -- Torpedo Ted shooter's arm
  889.     [0x09] = { xoff = 0, yoff = 0, width = 15, height = 15},  -- Unknown flickering object
  890.     [0x0a] = { xoff = 4, yoff = 2, width = 8, height = 12},  -- Coin from coin cloud game
  891.     [0x0b] = { xoff = 3, yoff = 3, width = 1, height = 1, color_line = COLOUR.fireball },  -- Piranha Plant fireball
  892.     [0x0c] = { xoff = 3, yoff = 3, width = 1, height = 1, color_line = COLOUR.fireball },  -- Lava Lotus's fiery objects
  893.     [0x0d] = { xoff = 3, yoff = 3, width = 1, height = 1, color_line = COLOUR.baseball },  -- Baseball
  894.     -- got experimentally:
  895.     [0x11] = { xoff = -0x1, yoff = -0x4, width = 11, height = 19},  -- Yoshi fireballs
  896. }
  897.  
  898. -- Creates a set from a list
  899. local function make_set(list)
  900.     local set = {}
  901.     for _, l in ipairs(list) do set[l] = true end
  902.     return set
  903. end
  904.  
  905. -- from sprite number, returns oscillation flag
  906. -- A sprite must be here iff it processes interaction with player every frame AND this bit is not working in the sprite_4_tweaker WRAM(0x167a)
  907. local OSCILLATION_SPRITES = make_set{0x0e, 0x21, 0x29, 0x35, 0x54, 0x74, 0x75, 0x76, 0x77, 0x78, 0x81, 0x83, 0x87}
  908.  
  909. -- Sprites that have a custom hitbox drawing
  910. local ABNORMAL_HITBOX_SPRITES = make_set{0x62, 0x63, 0x6b, 0x6c}
  911.  
  912. -- Sprites whose clipping interaction points usually matter
  913. local GOOD_SPRITES_CLIPPING = make_set{
  914. 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xf, 0x10, 0x11, 0x13, 0x14, 0x18,
  915. 0x1b, 0x1d, 0x1f, 0x20, 0x26, 0x27, 0x29, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31,
  916. 0x32, 0x34, 0x35, 0x3d, 0x3e, 0x3f, 0x40, 0x46, 0x47, 0x48, 0x4d, 0x4e,
  917. 0x51, 0x53, 0x6e, 0x6f, 0x70, 0x80, 0x81, 0x86,
  918. 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa1, 0xa2, 0xa5, 0xa6, 0xa7, 0xab, 0xb2,
  919. 0xb4, 0xbb, 0xbc, 0xbd, 0xbf, 0xc3, 0xda, 0xdb, 0xdc, 0xdd, 0xdf
  920. }
  921.  
  922.  
  923. --#############################################################################
  924. -- SCRIPT UTILITIES:
  925.  
  926.  
  927. -- Variables used in various functions
  928. local Cheat = {}  -- family of cheat functions and variables
  929. local Previous = {}
  930. local User_input = INPUT_KEYNAMES -- Snes9x
  931. local Tiletable = {}
  932. local Joypad = {}
  933. local Layer1_tiles = {}
  934. local Layer2_tiles = {}
  935. local Is_lagged = nil
  936. local Options_menu = {show_menu = false, current_tab = "Show/hide options"}
  937. local Filter_opacity, Filter_color = 0, "#000000ff"  -- Snes9x specifc / unlisted color
  938. local Mario_boost_indicator = nil
  939. local Show_player_point_position = false
  940. local Sprites_info = {}  -- keeps track of useful sprite info that might be used outside the main sprite function
  941. local Sprite_hitbox = {}  -- keeps track of what sprite slots must display the hitbox
  942. local Memory = {} -- family of memory edit functions and variables
  943.  
  944. -- Initialization of some tables
  945. for i = 0, SMW2.sprite_max -1 do
  946.     Sprites_info[i] = {}
  947. end
  948. for key = 0, SMW2.sprite_max - 1 do
  949.     Sprite_hitbox[key] = {}
  950.     for number = 0, 0xff do
  951.         Sprite_hitbox[key][number] = {["sprite"] = true, ["block"] = GOOD_SPRITES_CLIPPING[number]}
  952.     end
  953. end
  954.  
  955. -- Sum of the digits of a integer
  956. local function sum_digits(number)
  957.     local sum = 0
  958.     while number > 0 do
  959.         sum = sum + number%10
  960.         number = floor(number*0.1)
  961.     end
  962.    
  963.     return sum
  964. end
  965.  
  966.  
  967. -- Returns the exact chosen digit of a number from the left to the right, in a given base
  968. -- E.g.: read_digit(654321, 2, 10) -> 5; read_digit(0x4B7A, 3, 16) -> 7
  969. local function read_digit(number, digit, base)
  970.     --assert(type(number) == "number" and number >= 0 and number%1 == 0, "Enter an integer number > 0")
  971.     --assert(type(digit) == "number" and digit > 0 and digit%1 == 0, "Enter an integer digit > 0")
  972.     --assert(type(base) == "number" and base > 1 and base%1 == 0, "Enter an integer base > 1")
  973.    
  974.     local copy = number
  975.     local digits_total = 0
  976.     while copy >= 1 do
  977.         copy = math.floor(copy/base)
  978.         digits_total = digits_total + 1
  979.     end
  980.    
  981.     if digit > digits_total then return false end
  982.    
  983.     local result = math.floor(number/base^(digits_total - digit))
  984.     return result%base
  985. end
  986.  
  987.  
  988. -- Transform the binary representation of base into a string
  989. -- For instance, if each bit of a number represents a char of base, then this function verifies what chars are on
  990. local function decode_bits(data, base)
  991.     local i = 1
  992.     local size = base:len()
  993.     local direct_concatenation = size <= 45  -- Performance: I found out that the .. operator is faster for 45 operations or less
  994.     local result
  995.    
  996.     if direct_concatenation then
  997.         result = ""
  998.         for ch in base:gmatch(".") do
  999.             if bit.test(data, size - i) then
  1000.                 result = result .. ch
  1001.             else
  1002.                 result = result .. " "
  1003.             end
  1004.             i = i + 1
  1005.         end
  1006.     else
  1007.         result = {}
  1008.         for ch in base:gmatch(".") do
  1009.             if bit.test(data, size-i) then
  1010.                 result[i] = ch
  1011.             else
  1012.                 result[i] = " "
  1013.             end
  1014.             i = i + 1
  1015.         end
  1016.         result = table.concat(result)
  1017.     end
  1018.    
  1019.     return result
  1020. end
  1021.  
  1022.  
  1023. function bit.test(value, bitnum)  -- Snes9x
  1024.     return bit.rshift(value, bitnum)%2 == 1
  1025. end
  1026.  
  1027.  
  1028. local function mouse_onregion(x1, y1, x2, y2)
  1029.     -- Reads external mouse coordinates
  1030.     local mouse_x = User_input.xmouse
  1031.     local mouse_y = User_input.ymouse
  1032.    
  1033.     -- From top-left to bottom-right
  1034.     if x2 < x1 then
  1035.         x1, x2 = x2, x1
  1036.     end
  1037.     if y2 < y1 then
  1038.         y1, y2 = y2, y1
  1039.     end
  1040.    
  1041.     if mouse_x >= x1 and mouse_x <= x2 and  mouse_y >= y1 and mouse_y <= y2 then
  1042.         return true
  1043.     else
  1044.         return false
  1045.     end
  1046. end
  1047.  
  1048.  
  1049. -- Register a function to be executed on key press or release
  1050. -- execution happens in the main loop
  1051. local Keys = {}
  1052. Keys.press = {}
  1053. Keys.release = {}
  1054. Keys.down, Keys.up, Keys.pressed, Keys.released = {}, {}, {}, {}
  1055. function Keys.registerkeypress(key, fn)
  1056.     Keys.press[key] = fn
  1057. end
  1058. function Keys.registerkeyrelease(key, fn)
  1059.     Keys.release[key] = fn
  1060. end
  1061.  
  1062.  
  1063. -- A cross sign with pos and size
  1064. gui.crosshair = gui.crosshair or function(x, y, size, color)
  1065.     gui.line(x - size, y, x + size, y, color)
  1066.     gui.line(x, y-size, x, y+size, color)
  1067. end
  1068.  
  1069.  
  1070. local Movie_active, Readonly, Framecount, Lagcount, Rerecords
  1071. local Lastframe_emulated, Starting_subframe_last_frame, Size_last_frame, Final_subframe_last_frame
  1072. local Nextframe, Starting_subframe_next_frame, Starting_subframe_next_frame, Final_subframe_next_frame
  1073. local function snes9x_status()
  1074.     Movie_active = movie.active()  -- Snes9x
  1075.     Readonly = movie.playing()  -- Snes9x
  1076.     Framecount = movie.length()
  1077.     Lagcount = emu.lagcount() -- Snes9x
  1078.     Rerecords = movie.rerecordcount()
  1079.    
  1080.     -- Last frame info
  1081.     Lastframe_emulated = emu.framecount()
  1082.    
  1083.     -- Next frame info (only relevant in readonly mode)
  1084.     Nextframe = Lastframe_emulated + 1
  1085.    
  1086. end
  1087.  
  1088.  
  1089. -- draw a pixel given (x,y) with SNES' pixel sizes
  1090. local draw_pixel = gui.pixel
  1091.  
  1092.  
  1093. -- draws a line given (x,y) and (x',y') with given scale and SNES' pixel thickness (whose scale is 2) -- EDIT
  1094. local function draw_line(x1, y1, x2, y2, scale, color)
  1095.     -- Draw from top-left to bottom-right
  1096.     if x2 < x1 then
  1097.         x1, x2 = x2, x1
  1098.     end
  1099.     if y2 < y1 then
  1100.         y1, y2 = y2, y1
  1101.     end
  1102.    
  1103.     x1, y1, x2, y2 = scale*x1, scale*y1, scale*x2, scale*y2
  1104.     gui.line(x1, y1, x2, y2, color)
  1105. end
  1106.  
  1107.  
  1108. -- draw an arrow given (x,y) and (x',y')
  1109. local function draw_arrow(x1, y1, x2, y2, color, head)
  1110.    
  1111.     local angle = math.atan((y2-y1)/(x2-x1)) -- in radians
  1112.    
  1113.     -- Arrow head
  1114.     local head_size = head or 10
  1115.     local angle1, angle2 = angle + math.pi/4, angle - math.pi/4 --0.785398163398, angle - 0.785398163398 -- 45° in radians
  1116.     local delta_x1, delta_y1 = floor(head_size*math.cos(angle1)), floor(head_size*math.sin(angle1))
  1117.     local delta_x2, delta_y2 = floor(head_size*math.cos(angle2)), floor(head_size*math.sin(angle2))
  1118.     local head1_x1, head1_y1 = x2, y2
  1119.     local head1_x2, head1_y2
  1120.     local head2_x1, head2_y1 = x2, y2
  1121.     local head2_x2, head2_y2
  1122.    
  1123.     if x1 < x2 then -- 1st and 4th quadrant
  1124.         head1_x2, head1_y2 = head1_x1 - delta_x1, head1_y1 - delta_y1
  1125.         head2_x2, head2_y2 = head2_x1 - delta_x2, head2_y1 - delta_y2
  1126.     elseif x1 == x2 then -- vertical arrow
  1127.         head1_x2, head1_y2 = head1_x1 - delta_x1, head1_y1 - delta_y1
  1128.         head2_x2, head2_y2 = head2_x1 - delta_x2, head2_y1 - delta_y2
  1129.     else
  1130.         head1_x2, head1_y2 = head1_x1 + delta_x1, head1_y1 + delta_y1
  1131.         head2_x2, head2_y2 = head2_x1 + delta_x2, head2_y1 + delta_y2
  1132.     end
  1133.    
  1134.     -- Draw
  1135.     gui.line(x1, y1, x2, y2, color)
  1136.     gui.line(head1_x1, head1_y1, head1_x2, head1_y2, color)
  1137.     gui.line(head2_x1, head2_y1, head2_x2, head2_y2, color)
  1138. end
  1139.  
  1140.  
  1141. -- draws a box given (x,y) and (x',y') with SNES' pixel sizes
  1142. local draw_box = function(x1, y1, x2, y2, line, fill)
  1143.     gui.box(x1, y1, x2, y2, fill, line)
  1144. end
  1145.  
  1146.  
  1147. -- draws a rectangle given (x,y) and dimensions, with SNES' pixel sizes
  1148. local draw_rectangle = function(x, y, w, h, line, fill)
  1149.     gui.box(x, y, x + w, y + h, fill, line)
  1150. end
  1151.  
  1152.  
  1153. -- Takes a position and dimensions of a rectangle and returns a new position if this rectangle has points outside the screen
  1154. local function put_on_screen(x, y, width, height)
  1155.     local x_screen, y_screen
  1156.     width = width or 0
  1157.     height = height or 0
  1158.    
  1159.     if x < - Border_left then
  1160.         x_screen = - Border_left
  1161.     elseif x > Buffer_width + Border_right - width then
  1162.         x_screen = Buffer_width + Border_right - width
  1163.     else
  1164.         x_screen = x
  1165.     end
  1166.    
  1167.     if y < - Border_top then
  1168.         y_screen = - Border_top
  1169.     elseif y > Buffer_height + Border_bottom - height then
  1170.         y_screen = Buffer_height + Border_bottom - height
  1171.     else
  1172.         y_screen = y
  1173.     end
  1174.    
  1175.     return x_screen, y_screen
  1176. end
  1177.  
  1178.  
  1179. -- returns the (x, y) position to start the text and its length:
  1180. -- number, number, number text_position(x, y, text, font_width, font_height[[[[, always_on_client], always_on_game], ref_x], ref_y])
  1181. -- x, y: the coordinates that the refereed point of the text must have
  1182. -- text: a string, don't make it bigger than the buffer area width and don't include escape characters
  1183. -- font_width, font_height: the sizes of the font
  1184. -- always_on_client, always_on_game: boolean
  1185. -- ref_x and ref_y: refer to the relative point of the text that must occupy the origin (x,y), from 0% to 100%
  1186. --                  for instance, if you want to display the middle of the text in (x, y), then use 0.5, 0.5
  1187. local function text_position(x, y, text, font_width, font_height, always_on_client, always_on_game, ref_x, ref_y)
  1188.     -- Reads external variables
  1189.     local border_left     = 0
  1190.     local border_right    = 0
  1191.     local border_top      = 0
  1192.     local border_bottom   = 0
  1193.     local buffer_width    = 256
  1194.     local buffer_height   = 224
  1195.    
  1196.     -- text processing
  1197.     local text_length = text and string.len(text)*font_width or font_width  -- considering another objects, like bitmaps
  1198.    
  1199.     -- actual position, relative to game area origin
  1200.     x = (not ref_x and x) or (ref_x == 0 and x) or x - floor(text_length*ref_x)
  1201.     y = (not ref_y and y) or (ref_y == 0 and y) or y - floor(font_height*ref_y)
  1202.    
  1203.     -- adjustment needed if text is supposed to be on screen area
  1204.     local x_end = x + text_length
  1205.     local y_end = y + font_height
  1206.    
  1207.     if always_on_game then
  1208.         if x < 0 then x = 0 end
  1209.         if y < 0 then y = 0 end
  1210.        
  1211.         if x_end > buffer_width  then x = buffer_width  - text_length end
  1212.         if y_end > buffer_height then y = buffer_height - font_height end
  1213.        
  1214.     elseif always_on_client then
  1215.         if x < -border_left then x = -border_left end
  1216.         if y < -border_top  then y = -border_top  end
  1217.        
  1218.         if x_end > buffer_width  + border_right  then x = buffer_width  + border_right  - text_length end
  1219.         if y_end > buffer_height + border_bottom then y = buffer_height + border_bottom - font_height end
  1220.     end
  1221.    
  1222.     return x, y, text_length
  1223. end
  1224.  
  1225.  
  1226. -- Complex function for drawing, that uses text_position
  1227. local function draw_text(x, y, text, ...)
  1228.     -- Reads external variables
  1229.     local font_name = Font or false
  1230.     local font_width  = SNES9X_FONT_WIDTH
  1231.     local font_height = SNES9X_FONT_HEIGHT
  1232.     local bg_default_color = font_name and COLOUR.outline or COLOUR.background
  1233.     local text_color, bg_color, always_on_client, always_on_game, ref_x, ref_y
  1234.     local arg1, arg2, arg3, arg4, arg5, arg6 = ...
  1235.    
  1236.     if not arg1 or arg1 == true then
  1237.        
  1238.         text_color = COLOUR.text
  1239.         bg_color = bg_default_color
  1240.         always_on_client, always_on_game, ref_x, ref_y = arg1, arg2, arg3, arg4
  1241.        
  1242.     elseif not arg2 or arg2 == true then
  1243.        
  1244.         text_color = arg1
  1245.         bg_color = bg_default_color
  1246.         always_on_client, always_on_game, ref_x, ref_y = arg2, arg3, arg4, arg5
  1247.        
  1248.     else
  1249.        
  1250.         text_color, bg_color = arg1, arg2
  1251.         always_on_client, always_on_game, ref_x, ref_y = arg3, arg4, arg5, arg6
  1252.        
  1253.     end
  1254.    
  1255.     local x_pos, y_pos, length = text_position(x, y, text, font_width, font_height,
  1256.                                     always_on_client, always_on_game, ref_x, ref_y)
  1257.     ;
  1258.     gui.opacity(Text_max_opacity * Text_opacity)
  1259.     gui.text(x_pos, y_pos, text, text_color, bg_color)
  1260.     gui.opacity(1.0) -- Snes9x
  1261.    
  1262.     return x_pos + length, y_pos + font_height, length
  1263. end
  1264.  
  1265.  
  1266. local function alert_text(x, y, text, text_color, bg_color, always_on_game, ref_x, ref_y)
  1267.     -- Reads external variables
  1268.     local font_width  = SNES9X_FONT_WIDTH
  1269.     local font_height = SNES9X_FONT_HEIGHT
  1270.    
  1271.     local x_pos, y_pos, text_length = text_position(x, y, text, font_width, font_height, false, always_on_game, ref_x, ref_y)
  1272.    
  1273.     gui.opacity(Background_max_opacity * Bg_opacity)
  1274.     draw_rectangle(x_pos, y_pos, text_length - 1, font_height - 1, bg_color, bg_color)  -- Snes9x
  1275.     gui.opacity(Text_max_opacity * Text_opacity)
  1276.     gui.text(x_pos, y_pos, text, text_color, 0)
  1277.     gui.opacity(1.0)
  1278. end
  1279.  
  1280.  
  1281. local function draw_over_text(x, y, value, base, color_base, color_value, color_bg, always_on_client, always_on_game, ref_x, ref_y)
  1282.     value = decode_bits(value, base)
  1283.     local x_end, y_end, length = draw_text(x, y, base,  color_base, color_bg, always_on_client, always_on_game, ref_x, ref_y)
  1284.     gui.opacity(Text_max_opacity * Text_opacity)
  1285.     gui.text(x_end - length, y_end - SNES9X_FONT_HEIGHT, value, color_value or COLOUR.text)
  1286.     gui.opacity(1.0)
  1287.    
  1288.     return x_end, y_end, length
  1289. end
  1290.  
  1291.  
  1292. -- Returns frames-time conversion
  1293. local function frame_time(frame)
  1294.     if not NTSC_FRAMERATE then error("NTSC_FRAMERATE undefined."); return end
  1295.    
  1296.     local total_seconds = frame/NTSC_FRAMERATE
  1297.     local hours = floor(total_seconds/3600)
  1298.     local tmp = total_seconds - 3600*hours
  1299.     local minutes = floor(tmp/60)
  1300.     tmp = tmp - 60*minutes
  1301.     local seconds = floor(tmp)
  1302.    
  1303.     local miliseconds = 1000* (total_seconds%1)
  1304.     if hours == 0 then hours = "" else hours = string.format("%d:", hours) end
  1305.     local str = string.format("%s%.2d:%.2d.%03.0f", hours, minutes, seconds, miliseconds)
  1306.     return str
  1307. end
  1308.  
  1309.  
  1310. -- Background opacity functions
  1311. local function increase_opacity()
  1312.     if Text_max_opacity <= 0.9 then Text_max_opacity = Text_max_opacity + 0.1
  1313.     else
  1314.         if Background_max_opacity <= 0.9 then Background_max_opacity = Background_max_opacity + 0.1 end
  1315.     end
  1316. end
  1317.  
  1318.  
  1319. local function decrease_opacity()
  1320.     if  Background_max_opacity >= 0.1 then Background_max_opacity = Background_max_opacity - 0.1
  1321.     else
  1322.         if Text_max_opacity >= 0.1 then Text_max_opacity = Text_max_opacity - 0.1 end
  1323.     end
  1324. end
  1325.  
  1326.  
  1327. -- displays a button everytime in (x,y)
  1328. -- object can be a text or a dbitmap
  1329. -- if user clicks onto it, fn is executed once
  1330. local Script_buttons = {}
  1331. local function create_button(x, y, object, fn, extra_options)
  1332.     local always_on_client, always_on_game, ref_x, ref_y, button_pressed
  1333.     if extra_options then
  1334.         always_on_client, always_on_game, ref_x, ref_y, button_pressed = extra_options.always_on_client, extra_options.always_on_game,
  1335.                                                                 extra_options.ref_x, extra_options.ref_y, extra_options.button_pressed
  1336.     end
  1337.    
  1338.     local width, height
  1339.     local object_type = type(object)
  1340.    
  1341.     if object_type == "string" then
  1342.         width, height = SNES9X_FONT_WIDTH, SNES9X_FONT_HEIGHT
  1343.         x, y, width = text_position(x, y, object, width, height, always_on_client, always_on_game, ref_x, ref_y)
  1344.     elseif object_type == "boolean" then
  1345.         width, height = SNES9X_FONT_WIDTH, SNES9X_FONT_HEIGHT
  1346.         x, y = text_position(x, y, nil, width, height, always_on_client, always_on_game, ref_x, ref_y)
  1347.     else error"Type of buttton not supported yet"
  1348.     end
  1349.    
  1350.     -- draw the button
  1351.     if button_pressed then
  1352.         draw_rectangle(x, y, width, height, "white", "#d8d8d8ff")  -- unlisted colours
  1353.     else
  1354.         draw_rectangle(x, y, width, height, "#606060ff", "#b0b0b0ff")
  1355.     end
  1356.     gui.line(x, y, x + width, y, button_pressed and "#606060ff" or "white")
  1357.     gui.line(x, y, x, y + height, button_pressed and "#606060ff" or "white")
  1358.    
  1359.     if object_type == "string" then
  1360.         gui.text(x + 1, y + 1, object, COLOUR.button_text, 0)
  1361.     elseif object_type == "boolean" then
  1362.         draw_rectangle(x + 1, y + 1, width - 2, height - 2, "#00ff0080", "#00ff00c0")
  1363.     end
  1364.    
  1365.     -- updates the table of buttons
  1366.     table.insert(Script_buttons, {x = x, y = y, width = width, height = height, object = object, action = fn})
  1367. end
  1368.  
  1369.  
  1370. function Options_menu.print_help()
  1371.     print("\n")
  1372.     print(" - - - TIPS - - - ")
  1373.     print("MOUSE:")
  1374.     print("Use the left click to draw blocks and to see the Map16 properties.")
  1375.     print("Use the right click to toogle the hitbox mode of Mario and sprites.")
  1376.     print("\n")
  1377.    
  1378.     print("CHEATS(better turn off while recording a movie):")
  1379.     print("L+R+up: stop gravity for Mario fly / L+R+down to cancel")
  1380.     print("Use the mouse to drag and drop sprites")
  1381.     print("While paused: B+select to get out of the level")
  1382.     print("              X+select to beat the level (main exit)")
  1383.     print("              A+select to get the secret exit (don't use it if there isn't one)")
  1384.    
  1385.     print("\n")
  1386.     print("OTHERS:")
  1387.     print(fmt("Press \"%s\" for more and \"%s\" for less opacity.", OPTIONS.hotkey_increase_opacity, OPTIONS.hotkey_decrease_opacity))
  1388.     print("It's better to play without the mouse over the game window.")
  1389.     print(" - - - end of tips - - - ")
  1390. end
  1391.  
  1392. local poked = false
  1393. local apply = false
  1394. function Options_menu.display()
  1395.     if not Options_menu.show_menu then return end
  1396.    
  1397.     -- Pauses emulator and draws the background
  1398.     Text_opacity = 1.0
  1399.     draw_rectangle(0, 0, Buffer_width, Buffer_height, COLOUR.mainmenu_outline, COLOUR.mainmenu_bg)
  1400.    
  1401.     -- Font stuff
  1402.     local delta_x = SNES9X_FONT_WIDTH
  1403.     local delta_y = SNES9X_FONT_HEIGHT + 4
  1404.     local x_pos, y_pos = 4, 4
  1405.     local tmp
  1406.    
  1407.     -- Exit menu button
  1408.     gui.box(0, 0, Buffer_width, delta_y, "#ffffff60", "#ffffff60") -- tab's shadow / unlisted color
  1409.     create_button(Buffer_width, 0, " X ", function() Options_menu.show_menu = false end, {always_on_client = true, always_on_game = true})
  1410.    
  1411.     -- Tabs
  1412.     create_button(x_pos, y_pos, "Show/hide", function() Options_menu.current_tab = "Show/hide options" end,
  1413.     {button_pressed = Options_menu.current_tab == "Show/hide options"})
  1414.     x_pos = x_pos + 9*delta_x + 2
  1415.     create_button(x_pos, y_pos, "Settings", function() Options_menu.current_tab = "Misc options" end,
  1416.     {button_pressed = Options_menu.current_tab == "Misc options"})
  1417.     x_pos = x_pos + 8*delta_x + 2
  1418.     create_button(x_pos, y_pos, "Cheats", function() Options_menu.current_tab = "Cheats" end,
  1419.     {button_pressed = Options_menu.current_tab == "Cheats"})
  1420.     x_pos = x_pos + 6*delta_x + 2
  1421.     create_button(x_pos, y_pos, "Debug info", function() Options_menu.current_tab = "Debug info" end,
  1422.     {button_pressed = Options_menu.current_tab == "Debug info"})
  1423.     x_pos = x_pos + 10*delta_x + 2
  1424.     create_button(x_pos, y_pos, "Misc tables", function() Options_menu.current_tab = "Sprite miscellaneous tables" end,
  1425.     {button_pressed = Options_menu.current_tab == "Sprite miscellaneous tables"})
  1426.     x_pos = x_pos + 11*delta_x + 2
  1427.     create_button(x_pos, y_pos, "Memory edit", function() Options_menu.current_tab = "Memory edit" end,
  1428.     {button_pressed = Options_menu.current_tab == "Memory edit"})
  1429.    
  1430.     x_pos, y_pos = 4, y_pos + delta_y + 4
  1431.     if Options_menu.current_tab == "Show/hide options" then
  1432.         local x_temp = 0
  1433.        
  1434.         -- Player
  1435.         tmp_str = "Player:"
  1436.         gui.text(x_pos, y_pos, tmp_str)
  1437.         x_temp = x_temp + 4*string.len(tmp_str) + 4
  1438.        
  1439.         tmp = OPTIONS.display_player_info and true or " "
  1440.         create_button(x_pos + x_temp, y_pos, tmp, function() OPTIONS.display_player_info = not OPTIONS.display_player_info end)
  1441.         tmp_str = "Info"
  1442.         gui.text(x_pos + x_temp + delta_x + 3, y_pos, tmp_str)
  1443.         x_temp = x_temp + 4*string.len(tmp_str) + 12
  1444.        
  1445.         tmp = OPTIONS.display_player_hitbox and true or " "
  1446.         create_button(x_pos + x_temp, y_pos, tmp, function() OPTIONS.display_player_hitbox = not OPTIONS.display_player_hitbox end)
  1447.         tmp_str = "Hitbox"
  1448.         gui.text(x_pos + x_temp + delta_x + 3, y_pos, tmp_str)
  1449.         x_temp = x_temp + 4*string.len(tmp_str) + 12
  1450.        
  1451.         tmp = OPTIONS.display_interaction_points and true or " "
  1452.         create_button(x_pos + x_temp, y_pos, tmp, function() OPTIONS.display_interaction_points = not OPTIONS.display_interaction_points end)
  1453.         tmp_str = "Interaction points"
  1454.         gui.text(x_pos + x_temp + delta_x + 3, y_pos, tmp_str)
  1455.         x_temp = x_temp + 4*string.len(tmp_str) + 12
  1456.        
  1457.         tmp = OPTIONS.display_tongue_hitbox and true or " "
  1458.         create_button(x_pos + x_temp, y_pos, tmp, function() OPTIONS.display_tongue_hitbox = not OPTIONS.display_tongue_hitbox end)
  1459.         tmp_str = "Tongue hitbox"
  1460.         gui.text(x_pos + x_temp + delta_x + 3, y_pos, tmp_str)
  1461.         x_temp = 0 + 4*string.len("Player:") + 4
  1462.         y_pos = y_pos + delta_y
  1463.        
  1464.         tmp = OPTIONS.display_throw_info and true or " "
  1465.         create_button(x_pos + x_temp, y_pos, tmp, function() OPTIONS.display_throw_info = not OPTIONS.display_throw_info end)
  1466.         tmp_str = "Throw info"
  1467.         gui.text(x_pos + x_temp + delta_x + 3, y_pos, tmp_str)
  1468.         x_temp = x_temp + 4*string.len(tmp_str) + 12
  1469.        
  1470.         tmp = OPTIONS.display_blocked_status and true or " "
  1471.         create_button(x_pos + x_temp, y_pos, tmp, function() OPTIONS.display_blocked_status = not OPTIONS.display_blocked_status end)
  1472.         tmp_str = "Blocked status"
  1473.         gui.text(x_pos + x_temp + delta_x + 3, y_pos, tmp_str)
  1474.         x_temp = x_temp + 4*string.len(tmp_str) + 12
  1475.        
  1476.         y_pos = y_pos + delta_y + 4
  1477.        
  1478.        
  1479.         -- Sprites
  1480.         x_temp = 0
  1481.         tmp_str = "Sprites:"
  1482.         gui.text(x_pos, y_pos, tmp_str)
  1483.        
  1484.         x_temp = x_temp + 4*string.len(tmp_str) + 4
  1485.         tmp = OPTIONS.display_sprite_info and true or " "
  1486.         create_button(x_pos + x_temp, y_pos, tmp, function() OPTIONS.display_sprite_info = not OPTIONS.display_sprite_info end)
  1487.         tmp_str = "Info"
  1488.         gui.text(x_pos + x_temp + delta_x + 3, y_pos, tmp_str)
  1489.        
  1490.         x_temp = x_temp + 4*string.len(tmp_str) + 12
  1491.         tmp = OPTIONS.display_sprite_hitbox and true or " "
  1492.         create_button(x_pos + x_temp, y_pos, tmp, function() OPTIONS.display_sprite_hitbox = not OPTIONS.display_sprite_hitbox end)
  1493.         tmp_str = "Hitboxes"
  1494.         gui.text(x_pos + x_temp + delta_x + 3, y_pos, tmp_str)
  1495.         y_pos = y_pos + delta_y + 4
  1496.        
  1497.        
  1498.         tmp = OPTIONS.display_debug_info and true or " "
  1499.         create_button(x_pos, y_pos, tmp, function() OPTIONS.display_debug_info = not OPTIONS.display_debug_info end)
  1500.         gui.text(x_pos + delta_x + 3, y_pos, "Show Some Debug Info?")
  1501.         y_pos = y_pos + delta_y
  1502.        
  1503.         tmp = OPTIONS.display_movie_info and true or " "
  1504.         create_button(x_pos, y_pos, tmp, function() OPTIONS.display_movie_info = not OPTIONS.display_movie_info end)
  1505.         gui.text(x_pos + delta_x + 3, y_pos, "Display Movie Info?")
  1506.         y_pos = y_pos + delta_y
  1507.        
  1508.         tmp = OPTIONS.display_misc_info and true or " "
  1509.         create_button(x_pos, y_pos, tmp, function() OPTIONS.display_misc_info = not OPTIONS.display_misc_info end)
  1510.         gui.text(x_pos + delta_x + 3, y_pos, "Display Misc Info?")
  1511.         y_pos = y_pos + delta_y
  1512.        
  1513.         tmp = OPTIONS.display_level_info and true or " "
  1514.         create_button(x_pos, y_pos, tmp, function() OPTIONS.display_level_info = not OPTIONS.display_level_info end)
  1515.         gui.text(x_pos + delta_x + 3, y_pos, "Show Level Info?")
  1516.         y_pos = y_pos + delta_y
  1517.        
  1518.         --[[tmp = OPTIONS.display_yoshi_info and true or " "
  1519.         create_button(x_pos, y_pos, tmp, function() OPTIONS.display_yoshi_info = not OPTIONS.display_yoshi_info end)
  1520.         gui.text(x_pos + delta_x + 3, y_pos, "Show Yoshi Info?")
  1521.         y_pos = y_pos + delta_y
  1522.        
  1523.         tmp = OPTIONS.display_extended_sprite_info and true or " "
  1524.         create_button(x_pos, y_pos, tmp, function() OPTIONS.display_extended_sprite_info = not OPTIONS.display_extended_sprite_info end)
  1525.         gui.text(x_pos + delta_x + 3, y_pos, "Show Extended Sprite Info?")
  1526.         y_pos = y_pos + delta_y
  1527.        
  1528.         tmp = OPTIONS.display_cluster_sprite_info and true or " "
  1529.         create_button(x_pos, y_pos, tmp, function() OPTIONS.display_cluster_sprite_info = not OPTIONS.display_cluster_sprite_info end)
  1530.         gui.text(x_pos + delta_x + 3, y_pos, "Show Cluster Sprite Info?")
  1531.         y_pos = y_pos + delta_y
  1532.        
  1533.         tmp = OPTIONS.display_minor_extended_sprite_info and true or " "
  1534.         create_button(x_pos, y_pos, tmp, function() OPTIONS.display_minor_extended_sprite_info = not OPTIONS.display_minor_extended_sprite_info end)
  1535.         gui.text(x_pos + delta_x + 3, y_pos, "Show Minor Ext. Spr. Info?")
  1536.         y_pos = y_pos + delta_y
  1537.        
  1538.         tmp = OPTIONS.display_bounce_sprite_info and true or " "
  1539.         create_button(x_pos, y_pos, tmp, function() OPTIONS.display_bounce_sprite_info = not OPTIONS.display_bounce_sprite_info end)
  1540.         gui.text(x_pos + delta_x + 3, y_pos, "Show Bounce Sprite Info?")
  1541.         y_pos = y_pos + delta_y
  1542.        
  1543.         tmp = OPTIONS.display_static_camera_region and true or " "
  1544.         create_button(x_pos, y_pos, tmp, function() OPTIONS.display_static_camera_region = not OPTIONS.display_static_camera_region end)
  1545.         gui.text(x_pos + delta_x + 3, y_pos, "Show Static Camera Region?")
  1546.         y_pos = y_pos + delta_y]]
  1547.        
  1548.     elseif Options_menu.current_tab == "Cheats" then
  1549.        
  1550.         tmp = Cheat.allow_cheats and true or " "
  1551.         create_button(x_pos, y_pos, tmp, function() Cheat.allow_cheats = not Cheat.allow_cheats end)
  1552.         gui.text(x_pos + delta_x + 3, y_pos, "Allow Cheats?", COLOUR.warning)
  1553.         y_pos = y_pos + 2*delta_y
  1554.        
  1555.         if Cheat.allow_cheats then
  1556.             local value, widget_pointer
  1557.            
  1558.             -- Powerup
  1559.             value = u8(WRAM.powerup)
  1560.             gui.text(x_pos, y_pos, fmt("Powerup:%3d", value))
  1561.             create_button(x_pos + 11*SNES9X_FONT_WIDTH + 2, y_pos, "-", function() Cheat.change_address(WRAM.powerup, -1) end)
  1562.             create_button(x_pos + 12*SNES9X_FONT_WIDTH + 4, y_pos, "+", function() Cheat.change_address(WRAM.powerup, 1) end)
  1563.             y_pos = y_pos + delta_y
  1564.            
  1565.             -- Score
  1566.             value = u24(WRAM.mario_score)
  1567.             gui.text(x_pos, y_pos, fmt("Score:%7d0", value))
  1568.             create_button(x_pos + 14*SNES9X_FONT_WIDTH + 2, y_pos, "-", function() Cheat.change_address(WRAM.mario_score, -1, 3) end)
  1569.             create_button(x_pos + 15*SNES9X_FONT_WIDTH + 4, y_pos, "+", function() Cheat.change_address(WRAM.mario_score, 1, 3) end)
  1570.             y_pos = y_pos + 2
  1571.             draw_line(x_pos, y_pos + SNES9X_FONT_HEIGHT, x_pos + 100, y_pos + SNES9X_FONT_HEIGHT, 1, COLOUR.weak)  -- Snes9x: basic widget hack
  1572.             widget_pointer = floor(100*math.sqrt((value)/1000000))
  1573.             if mouse_onregion(x_pos, y_pos + SNES9X_FONT_HEIGHT - 2, x_pos + 100, y_pos + SNES9X_FONT_HEIGHT + 2) and User_input.leftclick then
  1574.                 value = math.min(999999, 100*(User_input.xmouse - x_pos)^2)
  1575.                 w24(WRAM.mario_score, value)
  1576.             end
  1577.             draw_rectangle(x_pos + widget_pointer - 1, y_pos + SNES9X_FONT_HEIGHT - 2, 2, 4, "#ff0000a0", COLOUR.warning)  -- unlisted color
  1578.             y_pos = y_pos + delta_y
  1579.            
  1580.             -- Coins
  1581.             value = u8(WRAM.player_coin)
  1582.             gui.text(x_pos, y_pos, fmt("Coins:%3d", value))
  1583.             create_button(x_pos +  9*SNES9X_FONT_WIDTH + 2, y_pos, "-", function() Cheat.change_address(WRAM.player_coin, -1) end)
  1584.             create_button(x_pos + 10*SNES9X_FONT_WIDTH + 4, y_pos, "+", function() Cheat.change_address(WRAM.player_coin, 1) end)
  1585.             y_pos = y_pos + delta_y
  1586.         end
  1587.        
  1588.     elseif Options_menu.current_tab == "Misc options" then
  1589.        
  1590.         tmp = OPTIONS.draw_tiles_with_click and true or " "
  1591.         create_button(x_pos, y_pos, tmp, function() OPTIONS.draw_tiles_with_click = not OPTIONS.draw_tiles_with_click end)
  1592.         gui.text(x_pos + delta_x + 3, y_pos, "Draw tiles with left click?")
  1593.         y_pos = y_pos + delta_y
  1594.        
  1595.         create_button(x_pos, y_pos, "Erase Tiles", function() Tiletable = {}; Layer1_tiles = {}; Layer2_tiles = {} end)
  1596.         y_pos = y_pos + delta_y
  1597.        
  1598.         -- Manage opacity / filter
  1599.         y_pos = y_pos + delta_y
  1600.         gui.text(x_pos, y_pos, "Opacity:")
  1601.         y_pos = y_pos + delta_y
  1602.         create_button(x_pos, y_pos, "-", function() if Filter_opacity >= 1 then Filter_opacity = Filter_opacity - 1 end end)
  1603.         create_button(x_pos + delta_x + 2, y_pos, "+", function()
  1604.             if Filter_opacity <= 9 then Filter_opacity = Filter_opacity + 1 end
  1605.         end)
  1606.         gui.text(x_pos + 2*delta_x + 5, y_pos, "Change filter opacity (" .. 10*Filter_opacity .. "%)")
  1607.         y_pos = y_pos + delta_y
  1608.        
  1609.         create_button(x_pos, y_pos, "-", decrease_opacity)
  1610.         create_button(x_pos + delta_x + 2, y_pos, "+", increase_opacity)
  1611.         gui.text(x_pos + 2*delta_x + 5, y_pos, ("Text opacity: (%.0f%%, %.0f%%)"):
  1612.             format(100*Text_max_opacity, 100*Background_max_opacity))
  1613.         y_pos = y_pos + delta_y
  1614.         gui.text(x_pos, y_pos, ("'%s' and '%s' are hotkeys for this."):
  1615.             format(OPTIONS.hotkey_decrease_opacity, OPTIONS.hotkey_increase_opacity), COLOUR.weak)
  1616.         y_pos = y_pos + delta_y
  1617.        
  1618.         tmp = OPTIONS.display_mouse_coordinates and true or " "
  1619.         create_button(x_pos, y_pos, tmp, function() OPTIONS.display_mouse_coordinates = not OPTIONS.display_mouse_coordinates end)
  1620.         gui.text(x_pos + delta_x + 3, y_pos, "Display mouse coordinates?")
  1621.         y_pos = y_pos + delta_y
  1622.        
  1623.         -- Others
  1624.         y_pos = y_pos + delta_y
  1625.         gui.text(x_pos, y_pos, "Help:")
  1626.         y_pos = y_pos + delta_y
  1627.         create_button(x_pos, y_pos, "Show tips in Snes9x: Console", Options_menu.print_help)
  1628.        
  1629.     elseif Options_menu.current_tab == "Debug info" then
  1630.         tmp = OPTIONS.display_debug_info and true or " "
  1631.         create_button(x_pos, y_pos, tmp, function() OPTIONS.display_debug_info = not OPTIONS.display_debug_info end)
  1632.         gui.text(x_pos + delta_x + 3, y_pos, "Show Some Debug Info?", COLOUR.warning)
  1633.         y_pos = y_pos + 2*delta_y
  1634.        
  1635.         tmp = OPTIONS.display_debug_player_extra and true or " "
  1636.         create_button(x_pos, y_pos, tmp, function() OPTIONS.display_debug_player_extra = not OPTIONS.display_debug_player_extra end)
  1637.         gui.text(x_pos + delta_x + 3, y_pos, "Player extra info")
  1638.         y_pos = y_pos + delta_y
  1639.        
  1640.         tmp = OPTIONS.display_debug_sprite_extra and true or " "
  1641.         create_button(x_pos, y_pos, tmp, function() OPTIONS.display_debug_sprite_extra = not OPTIONS.display_debug_sprite_extra end)
  1642.         gui.text(x_pos + delta_x + 3, y_pos, "Sprite extra info")
  1643.         y_pos = y_pos + delta_y
  1644.        
  1645.         tmp = OPTIONS.display_debug_sprite_tweakers and true or " "
  1646.         create_button(x_pos, y_pos, tmp, function() OPTIONS.display_debug_sprite_tweakers = not OPTIONS.display_debug_sprite_tweakers end)
  1647.         gui.text(x_pos + delta_x + 3, y_pos, "Sprite tweakers")
  1648.         y_pos = y_pos + delta_y
  1649.        
  1650.         tmp = OPTIONS.display_debug_extended_sprite and true or " "
  1651.         create_button(x_pos, y_pos, tmp, function() OPTIONS.display_debug_extended_sprite = not OPTIONS.display_debug_extended_sprite end)
  1652.         gui.text(x_pos + delta_x + 3, y_pos, "Extended sprites")
  1653.         y_pos = y_pos + delta_y
  1654.        
  1655.         tmp = OPTIONS.display_debug_cluster_sprite and true or " "
  1656.         create_button(x_pos, y_pos, tmp, function() OPTIONS.display_debug_cluster_sprite = not OPTIONS.display_debug_cluster_sprite end)
  1657.         gui.text(x_pos + delta_x + 3, y_pos, "Cluster sprites")
  1658.         y_pos = y_pos + delta_y
  1659.        
  1660.         tmp = OPTIONS.display_debug_minor_extended_sprite and true or " "
  1661.         create_button(x_pos, y_pos, tmp, function() OPTIONS.display_debug_minor_extended_sprite = not OPTIONS.display_debug_minor end)
  1662.         gui.text(x_pos + delta_x + 3, y_pos, "Minor Ext. sprites")
  1663.         y_pos = y_pos + delta_y
  1664.        
  1665.         tmp = OPTIONS.display_debug_bounce_sprite and true or " "
  1666.         create_button(x_pos, y_pos, tmp, function() OPTIONS.display_debug_bounce_sprite = not OPTIONS.display_debug_bounce_sprite end)
  1667.         gui.text(x_pos + delta_x + 3, y_pos, "Bounce sprites")
  1668.         y_pos = y_pos + delta_y
  1669.        
  1670.         tmp = OPTIONS.display_debug_controller_data and true or " "
  1671.         create_button(x_pos, y_pos, tmp, function() OPTIONS.display_debug_controller_data = not OPTIONS.display_debug_controller_data end)
  1672.         gui.text(x_pos + delta_x + 3, y_pos, "Controller data (might cause desyncs!)", COLOUR.warning)
  1673.         y_pos = y_pos + delta_y
  1674.        
  1675.         local x_temp = 0
  1676.         -- Tile Map
  1677.         tmp_str = "Tile Map:"
  1678.         gui.text(x_pos, y_pos, tmp_str)
  1679.         x_temp = x_temp + 4*string.len(tmp_str) + 4
  1680.        
  1681.         tmp = OPTIONS.draw_tile_map_grid and true or " "
  1682.         create_button(x_pos + x_temp, y_pos, tmp, function() OPTIONS.draw_tile_map_grid = not OPTIONS.draw_tile_map_grid end)
  1683.         tmp_str = "Grid"
  1684.         gui.text(x_pos + x_temp + delta_x + 3, y_pos, tmp_str)
  1685.         x_temp = x_temp + 4*string.len(tmp_str) + 12
  1686.        
  1687.         tmp = OPTIONS.draw_tile_map_type and true or " "
  1688.         create_button(x_pos + x_temp, y_pos, tmp, function() OPTIONS.draw_tile_map_type = not OPTIONS.draw_tile_map_type end)
  1689.         tmp_str = "Tile type"
  1690.         gui.text(x_pos + x_temp + delta_x + 3, y_pos, tmp_str)
  1691.         x_temp = x_temp + 4*string.len(tmp_str) + 12
  1692.        
  1693.         --[[
  1694.         tmp = OPTIONS.draw_tile_map_gfx_type and true or " "
  1695.         create_button(x_pos + x_temp, y_pos, tmp, function() OPTIONS.draw_tile_map_gfx_type = not OPTIONS.draw_tile_map_gfx_type end)
  1696.         tmp_str = "Graphical type"
  1697.         gui.text(x_pos + x_temp + delta_x + 3, y_pos, tmp_str)
  1698.         x_temp = x_temp + 4*string.len(tmp_str) + 12
  1699.        
  1700.         tmp = OPTIONS.draw_tile_map_phy_type and true or " "
  1701.         create_button(x_pos + x_temp, y_pos, tmp, function() OPTIONS.draw_tile_map_phy_type = not OPTIONS.draw_tile_map_phy_type end)
  1702.         tmp_str = "Physical type"
  1703.         gui.text(x_pos + x_temp + delta_x + 3, y_pos, tmp_str)
  1704.         x_temp = x_temp + 4*string.len(tmp_str) + 12
  1705.         y_pos = y_pos + delta_y]]
  1706.        
  1707.     elseif Options_menu.current_tab == "Sprite miscellaneous tables" then
  1708.        
  1709.         tmp = OPTIONS.display_miscellaneous_sprite_table and true or " "
  1710.         create_button(x_pos, y_pos, tmp, function() OPTIONS.display_miscellaneous_sprite_table = not OPTIONS.display_miscellaneous_sprite_table end)
  1711.         gui.text(x_pos + delta_x + 3, y_pos, "Show Miscellaneous Sprite Table?", COLOUR.warning)
  1712.         y_pos = y_pos + 2*delta_y
  1713.        
  1714.         local opt = OPTIONS.miscellaneous_sprite_table_number
  1715.         for i = 1, 19 do
  1716.             create_button(x_pos, y_pos, opt[i] and true or " ", function() opt[i] = not opt[i] end)
  1717.             gui.text(x_pos + delta_x + 3, y_pos, "Table " .. i)
  1718.            
  1719.             y_pos = y_pos + delta_y
  1720.             if i%10 == 0 then
  1721.                 x_pos, y_pos = 4 + 20*SNES9X_FONT_WIDTH, 3*delta_y + 8
  1722.             end
  1723.         end
  1724.    
  1725.     elseif Options_menu.current_tab == "Memory edit" then
  1726.        
  1727.         tmp = Memory.allow_edit and true or " "
  1728.         create_button(x_pos, y_pos, tmp, function() Memory.allow_edit = not Memory.allow_edit apply = false end)
  1729.         gui.text(x_pos + delta_x + 3, y_pos, "Allow memory edit?", COLOUR.warning)
  1730.         y_pos = y_pos + 2*delta_y
  1731.        
  1732.         if Memory.allow_edit then
  1733.             local address = OPTIONS.address
  1734.             local value = OPTIONS.value
  1735.             local poke = true
  1736.             local freeze = false
  1737.             local size = OPTIONS.size
  1738.             local crescent = false
  1739.             Memory.edit_method = OPTIONS.edit_method
  1740.             local x_temp, y_temp
  1741.             local widget_pointer
  1742.            
  1743.             --- Address ---
  1744.            
  1745.             -- Address digits, from the right to the left
  1746.            
  1747.             local first_digit = read_digit(address, 6, 16) --floor((address-floor(address/16)*16)/1)
  1748.             local second_digit = read_digit(address, 5, 16) --floor((address-floor(address/(16^2))*(16^2))/16)
  1749.             local third_digit = read_digit(address, 4, 16) --floor((address-floor(address/(16^3))*(16^3))/(16^2))
  1750.             local fourth_digit = read_digit(address, 3, 16) --floor((address-floor(address/(16^4))*(16^4))/(16^3))
  1751.             local fifth_digit = read_digit(address, 2, 16) --floor((address-floor(address/(16^5))*(16^5))/(16^4))
  1752.            
  1753.             local address_shown = string.upper(fmt("%x", address))
  1754.             local width, height = 12, SNES9X_FONT_HEIGHT
  1755.            
  1756.             gui.text(x_pos + 1, y_pos + 13, "Address:", COLOUR.text)
  1757.            
  1758.             -- [ + ] buttons
  1759.            
  1760.             create_button(x_pos + 8*delta_x + 15, y_pos, " + ", function()
  1761.             if OPTIONS.address < 0x7F0000 then OPTIONS.address = OPTIONS.address + 0x10000 end INI.save_options() end)
  1762.             if OPTIONS.address >= 0x7f0000 then gui.text(x_pos + 8*delta_x + 16, y_pos + 1, " + ", COLOUR.weak2, 0) end -- "disabled" button
  1763.            
  1764.             create_button(x_pos + 8*delta_x + 28, y_pos, " + ", function()
  1765.             if OPTIONS.address + 0x1000 < 0x800000 then OPTIONS.address = OPTIONS.address + 0x1000 end INI.save_options() end)
  1766.             if OPTIONS.address + 0x1000 > 0x800000 then gui.text(x_pos + 8*delta_x + 29, y_pos + 1, " + ", COLOUR.weak2, 0) end -- "disabled" button
  1767.            
  1768.             create_button(x_pos + 8*delta_x + 41, y_pos, " + ", function()
  1769.             if OPTIONS.address + 0x100 < 0x800000 then OPTIONS.address = OPTIONS.address + 0x100 end INI.save_options() end)
  1770.             if OPTIONS.address + 0x100 > 0x800000 then gui.text(x_pos + 8*delta_x + 42, y_pos + 1, " + ", COLOUR.weak2, 0) end -- "disabled" button
  1771.            
  1772.             create_button(x_pos + 8*delta_x + 54, y_pos, " + ", function()
  1773.             if OPTIONS.address + 0x10 < 0x800000 then OPTIONS.address = OPTIONS.address + 0x10 end INI.save_options() end)
  1774.             if OPTIONS.address + 0x10 > 0x800000 then gui.text(x_pos + 8*delta_x + 55, y_pos + 1, " + ", COLOUR.weak2, 0) end -- "disabled" button
  1775.            
  1776.             create_button(x_pos + 8*delta_x + 67, y_pos, " + ", function()
  1777.             if OPTIONS.address + 0x1 < 0x800000 then OPTIONS.address = OPTIONS.address + 0x1 end INI.save_options() end)
  1778.             if OPTIONS.address + 0x1 >= 0x800000 then gui.text(x_pos + 8*delta_x + 68, y_pos + 1, " + ", COLOUR.weak2, 0) end -- "disabled" button
  1779.            
  1780.             y_pos = y_pos + delta_y
  1781.            
  1782.             -- Digits boxes
  1783.            
  1784.             draw_rectangle(x_pos + 8*delta_x + 2, y_pos, width, height, COLOUR.text, COLOUR.background)
  1785.             draw_rectangle(x_pos + 8*delta_x + 15, y_pos, width, height, COLOUR.text, COLOUR.background)
  1786.             draw_rectangle(x_pos + 8*delta_x + 28, y_pos, width, height, COLOUR.text, COLOUR.background)
  1787.             draw_rectangle(x_pos + 8*delta_x + 41, y_pos, width, height, COLOUR.text, COLOUR.background)
  1788.             draw_rectangle(x_pos + 8*delta_x + 54, y_pos, width, height, COLOUR.text, COLOUR.background)
  1789.             draw_rectangle(x_pos + 8*delta_x + 67, y_pos, width, height, COLOUR.text, COLOUR.background)
  1790.            
  1791.             -- Digits
  1792.            
  1793.             x_pos = 43
  1794.             y_pos = y_pos + 1
  1795.             local colour = COLOUR.memory
  1796.            
  1797.             gui.text(x_pos, y_pos, "7", colour) x_pos = x_pos + 13
  1798.             gui.text(x_pos, y_pos, string.upper(fmt("%x", fifth_digit)), colour)  x_pos = x_pos + 13
  1799.             gui.text(x_pos, y_pos, string.upper(fmt("%x", fourth_digit)), colour)  x_pos = x_pos + 13
  1800.             gui.text(x_pos, y_pos, string.upper(fmt("%x", third_digit)), colour)  x_pos = x_pos + 13
  1801.             gui.text(x_pos, y_pos, string.upper(fmt("%x", second_digit)), colour)  x_pos = x_pos + 13
  1802.             gui.text(x_pos, y_pos, string.upper(fmt("%x", first_digit)), colour)  x_pos = x_pos + 13
  1803.             y_pos = y_pos + delta_y - 1
  1804.            
  1805.             -- [ - ] buttons
  1806.            
  1807.             x_pos = 4
  1808.            
  1809.             create_button(x_pos + 8*delta_x + 15, y_pos, " - ", function()
  1810.             if OPTIONS.address >= 0x7F0000 then OPTIONS.address = OPTIONS.address - 0x10000 end INI.save_options() end)
  1811.             if OPTIONS.address < 0x7F0000 then gui.text(x_pos + 8*delta_x + 16, y_pos + 1, " - ", COLOUR.weak2, 0) end -- "disabled" button
  1812.            
  1813.             create_button(x_pos + 8*delta_x + 28, y_pos, " - ", function()
  1814.             if OPTIONS.address - 0x1000 > 0x7E0000 then OPTIONS.address = OPTIONS.address - 0x1000 end INI.save_options() end)
  1815.             if OPTIONS.address - 0x1000 < 0x7E0000 then gui.text(x_pos + 8*delta_x + 29, y_pos + 1, " - ", COLOUR.weak2, 0) end -- "disabled" button
  1816.            
  1817.             create_button(x_pos + 8*delta_x + 41, y_pos, " - ", function()
  1818.             if OPTIONS.address - 0x100 > 0x7E0000 then OPTIONS.address = OPTIONS.address - 0x100 end INI.save_options() end)
  1819.             if OPTIONS.address - 0x100 < 0x7E0000 then gui.text(x_pos + 8*delta_x + 42, y_pos + 1, " - ", COLOUR.weak2, 0) end -- "disabled" button
  1820.            
  1821.             create_button(x_pos + 8*delta_x + 54, y_pos, " - ", function()
  1822.             if OPTIONS.address - 0x10 > 0x7E0000 then OPTIONS.address = OPTIONS.address - 0x10 end INI.save_options() end)
  1823.             if OPTIONS.address - 0x10 < 0x7E0000 then gui.text(x_pos + 8*delta_x + 55, y_pos + 1, " - ", COLOUR.weak2, 0) end -- "disabled" button
  1824.            
  1825.             create_button(x_pos + 8*delta_x + 67, y_pos, " - ", function()
  1826.             if OPTIONS.address > 0x7E0000 then OPTIONS.address = OPTIONS.address - 0x1 end INI.save_options() end)
  1827.             if OPTIONS.address <= 0x7E0000 then gui.text(x_pos + 8*delta_x + 68, y_pos + 1, " - ", COLOUR.weak2, 0) end -- "disabled" button
  1828.            
  1829.             --- Size ---
  1830.            
  1831.             x_pos = 5
  1832.             y_pos = 90
  1833.            
  1834.             gui.text(x_pos, y_pos, "Size:", COLOUR.text)
  1835.            
  1836.             x_temp, y_temp = 0, delta_y
  1837.             create_button(x_pos + x_temp, y_pos + y_temp, "        ", function() OPTIONS.size = 1 INI.save_options() end)
  1838.             if size == 1 then draw_rectangle(x_pos + x_temp + 1, y_pos + y_temp + 1, 8*delta_x - 2, delta_y - 6, "#00ff0080", "#00ff00c0") end
  1839.             gui.text(x_pos + delta_x + x_temp + 1, y_pos + y_temp + 1, "1 byte", COLOUR.button_text, 0)
  1840.            
  1841.             x_temp = 33
  1842.             create_button(x_pos + x_temp, y_pos + y_temp, "         ", function() OPTIONS.size = 2 INI.save_options() end)
  1843.             if size == 2 then draw_rectangle(x_pos + x_temp + 1, y_pos + y_temp + 1, 9*delta_x - 2, delta_y - 6, "#00ff0080", "#00ff00c0") end
  1844.             gui.text(x_pos + delta_x + x_temp + 1, y_pos + y_temp + 1, "2 bytes", COLOUR.button_text, 0)
  1845.            
  1846.             --[[ REMOVE
  1847.             x_temp = 70
  1848.             create_button(x_pos + x_temp, y_pos + y_temp, "              ", function() OPTIONS.size = 58 INI.save_options() end)
  1849.             if size == 58 then draw_rectangle(x_pos + x_temp + 1, y_pos + y_temp + 1, 14*delta_x - 2, delta_y - 6, "#00ff0080", "#00ff00c0") end
  1850.             gui.text(x_pos + delta_x + x_temp + 1, y_pos + y_temp + 1, "Sprite table", COLOUR.button_text, 0)]]
  1851.            
  1852.             --- Value ---
  1853.            
  1854.             x_pos = 5
  1855.             y_pos = 135
  1856.             y_temp = 38
  1857.            
  1858.             gui.text(x_pos, y_pos, "Value:", COLOUR.text)
  1859.             gui.text(x_pos + delta_x, y_pos + delta_y, "in hex", COLOUR.text)
  1860.             gui.text(x_pos + delta_x, y_pos + y_temp, "in dec", COLOUR.text)
  1861.            
  1862.             if size == 1 or size == 58 then -- 2 digits
  1863.                 -- Correction, so the value loops when you overflow/underflow
  1864.                 if OPTIONS.value > 0xFF then OPTIONS.value = OPTIONS.value%256
  1865.                 elseif  OPTIONS.value < 0 then OPTIONS.value = OPTIONS.value + 0x100 end
  1866.                
  1867.                 -- Display in decimal
  1868.                 local value_dec_shown = fmt("%03d", value)
  1869.                 draw_rectangle(x_pos + 8*delta_x, y_pos + y_temp - 1, width + 4, height, COLOUR.text, COLOUR.background)
  1870.                 gui.text(x_pos + 8*delta_x + 3, y_pos + y_temp, value_dec_shown, colour)
  1871.                
  1872.                
  1873.                 -- Value digits, from the right to the left
  1874.                 first_digit = string.upper(fmt("%x", floor((value-floor(value/(16^2))*(16^2))/16)))
  1875.                 second_digit = string.upper(fmt("%x", floor((value-floor(value/16)*16)/1)))
  1876.                
  1877.                 -- [ + ] buttons
  1878.                 x_temp = 12
  1879.                
  1880.                 create_button(x_pos + 5*delta_x + x_temp, y_pos, " + ", function() OPTIONS.value = OPTIONS.value + 0x10 INI.save_options() end)
  1881.                 x_temp = x_temp + 13
  1882.                 create_button(x_pos + 5*delta_x + x_temp, y_pos, " + ", function() OPTIONS.value = OPTIONS.value + 0x1 INI.save_options() end)
  1883.                 x_temp = x_temp + 13
  1884.                
  1885.                 y_pos = y_pos + delta_y
  1886.                
  1887.                 -- Digits boxes
  1888.                 draw_rectangle(x_pos + 8*delta_x, y_pos, width, height, COLOUR.text, COLOUR.background)
  1889.                 draw_rectangle(x_pos + 8*delta_x + 13, y_pos, width, height, COLOUR.text, COLOUR.background)
  1890.                
  1891.                 -- Digits
  1892.                 x_temp = 21
  1893.                 y_pos = y_pos + 1
  1894.                 local colour = COLOUR.memory
  1895.                
  1896.                 gui.text(x_pos + 4*delta_x + x_temp, y_pos, first_digit, colour)  x_temp = x_temp + 13
  1897.                 gui.text(x_pos + 4*delta_x + x_temp, y_pos, second_digit, colour)  x_temp = x_temp + 13
  1898.                 y_pos = y_pos + delta_y - 1
  1899.                
  1900.                 -- [ - ] buttons
  1901.                 x_temp = 12
  1902.                
  1903.                 create_button(x_pos + 5*delta_x + x_temp, y_pos, " - ", function() OPTIONS.value = OPTIONS.value - 0x10 INI.save_options() end)
  1904.                 x_temp = x_temp + 13
  1905.                 create_button(x_pos + 5*delta_x + x_temp, y_pos, " - ", function() OPTIONS.value = OPTIONS.value - 0x1 INI.save_options() end)
  1906.                 x_temp = x_temp + 13
  1907.                
  1908.                 -- Slider button
  1909.                 y_temp = 26
  1910.                
  1911.                 draw_line(x_pos, y_pos + y_temp, x_pos + 128, y_pos + y_temp, 1, COLOUR.weak)  -- Snes9x: basic widget hack
  1912.                 widget_pointer = math.floor(128*((value)/255))
  1913.                 if mouse_onregion(x_pos, y_pos + y_temp - 2, x_pos + 128, y_pos + y_temp + 2) and User_input.leftclick then
  1914.                     OPTIONS.value = math.floor((User_input.xmouse - x_pos)*(255/128))
  1915.                 end
  1916.                 draw_rectangle(x_pos + widget_pointer - 1, y_pos + y_temp - 2, 2, 4, "#ff0000a0", COLOUR.warning)  -- unlisted color
  1917.                
  1918.             elseif size == 2 then -- 4 digits
  1919.                 -- Correction, so the value loops when you overflow/underflow
  1920.                 if OPTIONS.value > 0xFFFF then OPTIONS.value = OPTIONS.value - 0x10000
  1921.                 elseif  OPTIONS.value < 0 then OPTIONS.value = OPTIONS.value + 0x10000 end
  1922.                
  1923.                 -- Display in decimal
  1924.                 local value_dec_shown = fmt("%05d", value)
  1925.                 draw_rectangle(x_pos + 8*delta_x, y_pos + y_temp - 1, width + 12, height, COLOUR.text, COLOUR.background)
  1926.                 gui.text(x_pos + 8*delta_x + 3, y_pos + y_temp, value_dec_shown, colour)
  1927.                
  1928.                 -- Value digits, from the right to the left
  1929.                 first_digit = string.upper(fmt("%x", floor((value-floor(value/(16^4))*(16^4))/(16^3))))
  1930.                 second_digit = string.upper(fmt("%x", floor((value-floor(value/(16^3))*(16^3))/(16^2))))
  1931.                 third_digit = string.upper(fmt("%x", floor((value-floor(value/(16^2))*(16^2))/16)))
  1932.                 fourth_digit = string.upper(fmt("%x", floor((value-floor(value/16)*16)/1)))
  1933.                
  1934.                 -- [ + ] buttons
  1935.                 x_temp = 12
  1936.                
  1937.                 create_button(x_pos + 5*delta_x + x_temp, y_pos, " + ", function() OPTIONS.value = OPTIONS.value + 0x1000 INI.save_options() end)
  1938.                 x_temp = x_temp + 13
  1939.                 create_button(x_pos + 5*delta_x + x_temp, y_pos, " + ", function() OPTIONS.value = OPTIONS.value + 0x100 INI.save_options() end)
  1940.                 x_temp = x_temp + 13
  1941.                 create_button(x_pos + 5*delta_x + x_temp, y_pos, " + ", function() OPTIONS.value = OPTIONS.value + 0x10 INI.save_options() end)
  1942.                 x_temp = x_temp + 13
  1943.                 create_button(x_pos + 5*delta_x + x_temp, y_pos, " + ", function() OPTIONS.value = OPTIONS.value + 0x1 INI.save_options() end)
  1944.                 x_temp = x_temp + 13
  1945.                
  1946.                 y_pos = y_pos + delta_y
  1947.                
  1948.                 -- Digits boxes
  1949.                 x_temp = 13
  1950.                
  1951.                 draw_rectangle(x_pos + 8*delta_x, y_pos, width, height, COLOUR.text, COLOUR.background)
  1952.                 draw_rectangle(x_pos + 8*delta_x + x_temp, y_pos, width, height, COLOUR.text, COLOUR.background)
  1953.                 draw_rectangle(x_pos + 8*delta_x + 2*x_temp, y_pos, width, height, COLOUR.text, COLOUR.background)
  1954.                 draw_rectangle(x_pos + 8*delta_x + 3*x_temp, y_pos, width, height, COLOUR.text, COLOUR.background)
  1955.                
  1956.                 -- Digits
  1957.                 x_temp = 21
  1958.                 y_pos = y_pos + 1
  1959.                 local colour = COLOUR.memory
  1960.                
  1961.                 gui.text(x_pos + 4*delta_x + x_temp, y_pos, first_digit, colour)  x_temp = x_temp + 13
  1962.                 gui.text(x_pos + 4*delta_x + x_temp, y_pos, second_digit, colour)  x_temp = x_temp + 13
  1963.                 gui.text(x_pos + 4*delta_x + x_temp, y_pos, third_digit, colour)  x_temp = x_temp + 13
  1964.                 gui.text(x_pos + 4*delta_x + x_temp, y_pos, fourth_digit, colour)  x_temp = x_temp + 13
  1965.                 y_pos = y_pos + delta_y - 1
  1966.                
  1967.                 -- [ - ] buttons
  1968.                 x_temp = 12
  1969.                
  1970.                 create_button(x_pos + 5*delta_x + x_temp, y_pos, " - ", function() OPTIONS.value = OPTIONS.value - 0x1000 INI.save_options() end)
  1971.                 x_temp = x_temp + 13
  1972.                 create_button(x_pos + 5*delta_x + x_temp, y_pos, " - ", function() OPTIONS.value = OPTIONS.value - 0x100 INI.save_options() end)
  1973.                 x_temp = x_temp + 13
  1974.                 create_button(x_pos + 5*delta_x + x_temp, y_pos, " - ", function() OPTIONS.value = OPTIONS.value - 0x10 INI.save_options() end)
  1975.                 x_temp = x_temp + 13
  1976.                 create_button(x_pos + 5*delta_x + x_temp, y_pos, " - ", function() OPTIONS.value = OPTIONS.value - 0x1 INI.save_options() end)
  1977.                 x_temp = x_temp + 13
  1978.                
  1979.                 -- Slider button
  1980.                 y_temp = 26
  1981.                
  1982.                 draw_line(x_pos, y_pos + y_temp, x_pos + 128, y_pos + y_temp, 1, COLOUR.weak)  -- Snes9x: basic widget hack
  1983.                 widget_pointer = floor(128*((value)/(256*256-1)))
  1984.                 if mouse_onregion(x_pos, y_pos + y_temp - 2, x_pos + 128, y_pos + y_temp + 2) and User_input.leftclick then
  1985.                     OPTIONS.value = floor((User_input.xmouse - x_pos)*((256*256-1)/128))
  1986.                 end
  1987.                 draw_rectangle(x_pos + widget_pointer - 1, y_pos + y_temp - 2, 2, 4, "#ff0000a0", COLOUR.warning)  -- unlisted color   
  1988.            
  1989.             end
  1990.            
  1991.             --- Sprite table ---
  1992.            
  1993.             x_pos = 135
  1994.             y_pos = 56
  1995.             x_temp = 13*delta_x + 2
  1996.            
  1997.             gui.text(x_pos, y_pos, "Sprite table?")
  1998.            
  1999.             -- Yes/No buttons
  2000.             create_button(x_pos + x_temp, y_pos, "     ", function() OPTIONS.edit_sprite_table = true INI.save_options() end)
  2001.             if OPTIONS.edit_sprite_table then draw_rectangle(x_pos + x_temp + 1, y_pos + 1, 5*delta_x - 2, delta_y - 6, "#00ff0080", "#00ff00c0")
  2002.             freeze = false end
  2003.             gui.text(x_pos + x_temp + 1, y_pos + 1, " Yes ", COLOUR.button_text, 0)
  2004.            
  2005.             x_temp = 18*delta_x + 3
  2006.             create_button(x_pos + x_temp, y_pos, "    ", function() OPTIONS.edit_sprite_table = false INI.save_options() end)
  2007.             if not OPTIONS.edit_sprite_table then draw_rectangle(x_pos + x_temp + 1, y_pos + 1, 4*delta_x - 2, delta_y - 6, "#00ff0080", "#00ff00c0")
  2008.             freeze = false end
  2009.             gui.text(x_pos + x_temp + 1, y_pos + 1, " No ", COLOUR.button_text, 0)
  2010.            
  2011.             y_pos = y_pos + delta_y
  2012.             x_temp = 0
  2013.             if OPTIONS.edit_sprite_table then
  2014.                 local opt = OPTIONS.edit_sprite_table_number
  2015.                 for i = 1, SMW2.sprite_max do
  2016.                     create_button(x_pos + x_temp, y_pos, "   ", function() opt[i] = not opt[i] end)
  2017.                     if opt[i] then
  2018.                         gui.text(x_pos + x_temp + 3, y_pos + 1, fmt("%02d", i - 1), COLOUR.positive)
  2019.                     else
  2020.                         gui.text(x_pos + x_temp + 3, y_pos + 1, fmt("%02d", i - 1))                
  2021.                     end
  2022.                
  2023.                     x_temp = x_temp + 13
  2024.                     --y_pos = y_pos + delta_y
  2025.                     if x_pos + x_temp > 242 then
  2026.                         x_temp, y_pos = 0, y_pos + delta_y - 3
  2027.                     end
  2028.                 end
  2029.             end
  2030.            
  2031.             --- Mode ---
  2032.            
  2033.             x_pos = 150
  2034.             y_pos = 115
  2035.             x_temp = 25
  2036.            
  2037.             gui.text(x_pos, y_pos, "Mode:")
  2038.             y_pos = y_pos + delta_y
  2039.            
  2040.             create_button(x_pos, y_pos, "      ", function() OPTIONS.edit_method = "Poke" INI.save_options() end)
  2041.             if Memory.edit_method == "Poke" then draw_rectangle(x_pos + 1, y_pos + 1, 6*delta_x - 2, delta_y - 6, "#00ff0080", "#00ff00c0")
  2042.             freeze = false end
  2043.             gui.text(x_pos + delta_x + 1, y_pos + 1, "Poke", COLOUR.button_text, 0)
  2044.            
  2045.             create_button(x_pos + x_temp, y_pos, "        ", function() OPTIONS.edit_method = "Freeze" INI.save_options() end)
  2046.             if Memory.edit_method == "Freeze" then draw_rectangle(x_pos + x_temp + 1, y_pos + 1, 8*delta_x - 2, delta_y - 6, "#00ff0080", "#00ff00c0")
  2047.             freeze = true end
  2048.             gui.text(x_pos + x_temp + delta_x + 1, y_pos + 1, "Freeze", COLOUR.button_text, 0)
  2049.            
  2050.             --- Action ---
  2051.            
  2052.             x_pos = 150
  2053.             y_pos = 145
  2054.            
  2055.             gui.text(x_pos, y_pos, "Action:")
  2056.             y_pos = y_pos + delta_y
  2057.            
  2058.             create_button(x_pos, y_pos, "       ", function() poked = false apply = true end)
  2059.             if apply and OPTIONS.edit_method == "Freeze" then gui.text(x_pos + delta_x + 1, y_pos + 1, "APPLY", COLOUR.weak2, 0)
  2060.             else gui.text(x_pos + delta_x + 1, y_pos + 1, "APPLY", COLOUR.memory) end
  2061.            
  2062.             if OPTIONS.edit_method == "Freeze" then
  2063.                 create_button(x_pos, y_pos + delta_y, "       ", function() apply = false end)
  2064.                 if apply and OPTIONS.edit_method == "Freeze" then gui.text(x_pos + delta_x + 3, y_pos + delta_y + 1, "STOP", COLOUR.warning)
  2065.                 else gui.text(x_pos + delta_x + 3, y_pos + delta_y + 1, "STOP", COLOUR.weak2, 0) end
  2066.             end
  2067.            
  2068.             --- Result ---
  2069.            
  2070.             x_pos = 195
  2071.             y_pos = 145
  2072.             x_temp = 8*delta_x
  2073.            
  2074.             gui.text(x_pos, y_pos, "Result:")
  2075.             gui.text(x_pos, y_pos + 2*delta_y, "in hex", COLOUR.text)
  2076.             gui.text(x_pos, y_pos + 3*delta_y, "in dec", COLOUR.text)
  2077.            
  2078.             gui.text(x_pos, y_pos + delta_y, address_shown, colour)
  2079.             if OPTIONS.edit_sprite_table then
  2080.                 gui.text(x_pos + 7*delta_x, y_pos + delta_y, "(table)", colour)
  2081.             end
  2082.            
  2083.             if size == 1 then
  2084.                 -- In hex
  2085.                 draw_rectangle(x_pos + x_temp, y_pos + 2*delta_y - 1, width, height, COLOUR.text, COLOUR.background)
  2086.                 gui.text(x_pos + x_temp + 3, y_pos + 2*delta_y,  string.upper(fmt("%02x", u8(address))), colour)
  2087.                 -- In decimal
  2088.                 draw_rectangle(x_pos + x_temp, y_pos + 3*delta_y - 1, width + 4, height, COLOUR.text, COLOUR.background)
  2089.                 gui.text(x_pos + x_temp + 3, y_pos + 3*delta_y, fmt("%03d", u8(address)), colour)
  2090.             elseif size == 2 then
  2091.                 -- In hex
  2092.                 draw_rectangle(x_pos + x_temp, y_pos + 2*delta_y - 1, width + 8, height, COLOUR.text, COLOUR.background)
  2093.                 gui.text(x_pos + x_temp + 3, y_pos + 2*delta_y,  string.upper(fmt("%04x", u16(address))), colour)  
  2094.                 -- In decimal
  2095.                 draw_rectangle(x_pos + x_temp, y_pos + 3*delta_y - 1, width + 12, height, COLOUR.text, COLOUR.background)
  2096.                 gui.text(x_pos + x_temp + 3, y_pos + 3*delta_y, fmt("%05d", u16(address)), colour)             
  2097.             end
  2098.            
  2099.             if apply and poked then
  2100.                 alert_text(Buffer_middle_x - 12*delta_x, 190, " Appling address freeze ", COLOUR.warning, COLOUR.warning_bg)           
  2101.             end
  2102.         end
  2103.        
  2104.     end
  2105.    
  2106.     return true
  2107. end
  2108.  
  2109.  
  2110. -- Gets input of the 1st controller / Might be deprecated someday...
  2111. local Joypad = {}
  2112. local function get_joypad()
  2113.     Joypad = joypad.get(1)
  2114.     for button, status in pairs(Joypad) do
  2115.         Joypad[button] = status and 1 or 0
  2116.     end
  2117. end
  2118.  
  2119. -- ############################################################
  2120. -- From gocha's
  2121.  
  2122. local pad_max = 2
  2123. local pad_press, pad_down, pad_up, pad_prev, pad_send = {}, {}, {}, {}, {}
  2124. local pad_presstime = {}
  2125. for player = 1, pad_max do
  2126.     pad_press[player] = {}
  2127.     pad_presstime[player] = { start=0, select=0, up=0, down=0, left=0, right=0, A=0, B=0, X=0, Y=0, L=0, R=0 }
  2128. end
  2129.  
  2130. local dev_press, dev_down, dev_up, dev_prev = input.get(), {}, {}, {}
  2131. local dev_presstime = {
  2132.     xmouse=0, ymouse=0, leftclick=0, rightclick=0, middleclick=0,
  2133.     shift=0, control=0, alt=0, capslock=0, numlock=0, scrolllock=0,
  2134.     ["0"]=0, ["1"]=0, ["2"]=0, ["3"]=0, ["4"]=0, ["5"]=0, ["6"]=0, ["7"]=0, ["8"]=0, ["9"]=0,
  2135.     A=0, B=0, C=0, D=0, E=0, F=0, G=0, H=0, I=0, J=0, K=0, L=0, M=0, N=0, O=0, P=0, Q=0, R=0, S=0, T=0, U=0, V=0, W=0, X=0, Y=0, Z=0,
  2136.     F1=0, F2=0, F3=0, F4=0, F5=0, F6=0, F7=0, F8=0, F9=0, F10=0, F11=0, F12=0,
  2137.     F13=0, F14=0, F15=0, F16=0, F17=0, F18=0, F19=0, F20=0, F21=0, F22=0, F23=0, F24=0,
  2138.     backspace=0, tab=0, enter=0, pause=0, escape=0, space=0,
  2139.     pageup=0, pagedown=0, ["end"]=0, home=0, insert=0, delete=0,
  2140.     left=0, up=0, right=0, down=0,
  2141.     numpad0=0, numpad1=0, numpad2=0, numpad3=0, numpad4=0, numpad5=0, numpad6=0, numpad7=0, numpad8=0, numpad9=0,
  2142.     ["numpad*"]=0, ["numpad+"]=0, ["numpad-"]=0, ["numpad."]=0, ["numpad/"]=0,
  2143.     tilde=0, plus=0, minus=0, leftbracket=0, rightbracket=0,
  2144.     semicolon=0, quote=0, comma=0, period=0, slash=0, backslash=0
  2145. }
  2146.  
  2147. -- Scan button presses
  2148. function scanJoypad()
  2149.     for i = 1, pad_max do
  2150.         pad_prev[i] = copytable(pad_press[i])
  2151.         pad_press[i] = joypad.get(i)
  2152.         pad_send[i] = copytable(pad_press[i])
  2153.         -- scan keydowns, keyups
  2154.         pad_down[i] = {}
  2155.         pad_up[i] = {}
  2156.         for k in pairs(pad_press[i]) do
  2157.             pad_down[i][k] = (pad_press[i][k] and not pad_prev[i][k])
  2158.             pad_up[i][k] = (pad_prev[i][k] and not pad_press[i][k])
  2159.         end
  2160.         -- count press length
  2161.         for k in pairs(pad_press[i]) do
  2162.             if not pad_press[i][k] then
  2163.                 pad_presstime[i][k] = 0
  2164.             else
  2165.                 pad_presstime[i][k] = pad_presstime[i][k] + 1
  2166.             end
  2167.         end
  2168.     end
  2169. end
  2170. -- Scan keyboard/mouse input
  2171. local function scanInputDevs()
  2172.     dev_prev = copytable(dev_press)
  2173.     dev_press = input.get()
  2174.     -- scan keydowns, keyups
  2175.     dev_down = {}
  2176.     dev_up = {}
  2177.     for k in pairs(dev_presstime) do
  2178.         dev_down[k] = (dev_press[k] and not dev_prev[k])
  2179.         dev_up[k] = (dev_prev[k] and not dev_press[k])
  2180.     end
  2181.     -- count press length
  2182.     for k in pairs(dev_presstime) do
  2183.         if not dev_press[k] then
  2184.             dev_presstime[k] = 0
  2185.         else
  2186.             dev_presstime[k] = dev_presstime[k] + 1
  2187.         end
  2188.     end
  2189. end
  2190. -- Send button presses
  2191. function sendJoypad()
  2192.     for i = 1, pad_max do
  2193.         joypad.set(i, pad_send[i])
  2194.     end
  2195. end
  2196.  
  2197.  
  2198.  
  2199. --#############################################################################
  2200. -- SMW2 FUNCTIONS:
  2201.  
  2202.  
  2203. -- Returns the id of Yoshi; if more than one, the lowest sprite slot
  2204. local function get_yoshi_id()
  2205.     for i = 0, SMW2.sprite_max - 1 do
  2206.         local id = u8(WRAM.sprite_number + i)
  2207.         local status = u8(WRAM.sprite_status + i)
  2208.         if id == 0x35 and status ~= 0 then return i end
  2209.     end
  2210.    
  2211.     return nil
  2212. end
  2213.  
  2214.  
  2215. local Real_frame, Previous_real_frame, Effective_frame, Game_mode
  2216. local Level_index, Room_index, Level_flag, Current_level
  2217. local Is_paused, Lock_animation_flag, Player_powerup, Player_animation_trigger
  2218. local Camera_x, Camera_y
  2219. local function scan_smw2()
  2220.     --[[
  2221.     Previous_real_frame = Real_frame or u8(WRAM.real_frame)
  2222.     Real_frame = u8(WRAM.real_frame)
  2223.     Effective_frame = u8(WRAM.effective_frame)]]
  2224.     Game_mode = u16(WRAM.game_mode)
  2225.     Is_paused = u8(WRAM.is_paused) == 1
  2226.     Level_index = u16(WRAM.level_index)
  2227.     --[[Level_flag = u8(WRAM.level_flag_table + Level_index)
  2228.     Lock_animation_flag = u8(WRAM.lock_animation_flag)
  2229.     Room_index = u24(WRAM.room_index)
  2230.    
  2231.     -- In level frequently used info
  2232.     Player_animation_trigger = u8(WRAM.player_animation_trigger)
  2233.     Player_powerup = u8(WRAM.powerup)]]
  2234.     Camera_x = s16(WRAM.camera_x)
  2235.     Camera_y = s16(WRAM.camera_y)
  2236. end
  2237.  
  2238.  
  2239. -- Converts the in-game (x, y) to SNES-screen coordinates
  2240. local function screen_coordinates(x, y, camera_x, camera_y)
  2241.     -- Sane values
  2242.     camera_x = camera_x or Camera_x or u8(WRAM.camera_x)
  2243.     camera_y = camera_y or Camera_y or u8(WRAM.camera_y)
  2244.    
  2245.     local x_screen = (x - camera_x)
  2246.     local y_screen = (y - camera_y) - Y_CAMERA_OFF
  2247.    
  2248.     return x_screen, y_screen
  2249. end
  2250.  
  2251.  
  2252. -- Converts Snes9x-screen coordinates to in-game (x, y)
  2253. local function game_coordinates(x_snes9x, y_snes9x, camera_x, camera_y)
  2254.     -- Sane values
  2255.     camera_x = camera_x or Camera_x or u8(WRAM.camera_x)
  2256.     camera_y = camera_y or Camera_y or u8(WRAM.camera_y)
  2257.    
  2258.     local x_game = x_snes9x + camera_x
  2259.     local y_game = y_snes9x + Y_CAMERA_OFF + camera_y
  2260.    
  2261.     return x_game, y_game
  2262. end
  2263.  
  2264.  
  2265. -- Returns the extreme values that Mario needs to have in order to NOT touch a rectangular object
  2266. local function display_boundaries(x_game, y_game, width, height, camera_x, camera_y)
  2267.     -- Font
  2268.     Text_opacity = 0.8
  2269.     Bg_opacity = 0.4
  2270.    
  2271.     -- Coordinates around the rectangle
  2272.     local left = width*floor(x_game/width)
  2273.     local top = height*floor(y_game/height)
  2274.     left, top = screen_coordinates(left, top, camera_x, camera_y)
  2275.     local right = left + width - 1
  2276.     local bottom = top + height - 1
  2277.    
  2278.     -- Reads WRAM values of the player
  2279.     local is_ducking = u8(WRAM.is_ducking)
  2280.     local powerup = Player_powerup
  2281.     local is_small = is_ducking ~= 0 or powerup == 0
  2282.    
  2283.     -- Left
  2284.     local left_text = string.format("%4d.ff", width*floor(x_game/width) - 16)
  2285.     draw_text(AR_x*left, AR_y*(top+bottom)/2, left_text, false, false, 1.0, 0.5)
  2286.    
  2287.     -- Right
  2288.     local right_text = string.format("%d.01", width*floor(x_game/width) + 15)
  2289.     draw_text(AR_x*right + 2, AR_y*(top+bottom)/2, right_text, false, false, 0.0, 0.5)
  2290.    
  2291.     -- Top
  2292.     local value = (Yoshi_riding_flag and y_game - 16) or y_game
  2293.     local top_text = fmt("%d.ff", width*floor(value/width) - 32)
  2294.     draw_text(AR_x*(left+right)/2, AR_y*top, top_text, false, false, 0.5, 1.0)
  2295.    
  2296.     -- Bottom
  2297.     value = y_game + height - 4 --height*floor(y_game/height) - 3
  2298.     local bottom_text = fmt("%d.ff", value)
  2299.     draw_text(AR_x*(left+right)/2, AR_y*bottom + 1, bottom_text, false, false, 0.5, 0.0)
  2300.    
  2301.     return left, top
  2302. end
  2303.  
  2304.  
  2305. local function read_screens()
  2306.     local screens_number = u8(WRAM.screens_number)
  2307.     local vscreen_number = u8(WRAM.vscreen_number)
  2308.     local hscreen_number = u8(WRAM.hscreen_number) - 1
  2309.     local vscreen_current = s8(WRAM.y + 1)
  2310.     local hscreen_current = s8(WRAM.x + 1)
  2311.     --local level_mode_settings = u8(WRAM.level_mode_settings)
  2312.     --local b1, b2, b3, b4, b5, b6, b7, b8 = bit.multidiv(level_mode_settings, 128, 64, 32, 16, 8, 4, 2)
  2313.     --draw_text(Buffer_middle_x, Buffer_middle_y, {"%x: %x%x%x%x%x%x%x%x", level_mode_settings, b1, b2, b3, b4, b5, b6, b7, b8}, COLOUR.text, COLOUR.background)
  2314.    
  2315.     local level_type
  2316.     if (level_mode_settings ~= 0) and (level_mode_settings == 0x3 or level_mode_settings == 0x4 or level_mode_settings == 0x7
  2317.         or level_mode_settings == 0x8 or level_mode_settings == 0xa or level_mode_settings == 0xd) then
  2318.             level_type = "Vertical"
  2319.         ;
  2320.     else
  2321.         level_type = "Horizontal"
  2322.     end
  2323.    
  2324.     return level_type, screens_number, hscreen_current, hscreen_number, vscreen_current, vscreen_number
  2325. end
  2326.  
  2327.  
  2328. local function get_map16_value(x_game, y_game)
  2329.     local num_x = floor(x_game/16)
  2330.     local num_y = floor(y_game/16)
  2331.     if num_x < 0 or num_y < 0 then return end  -- 1st breakpoint
  2332.    
  2333.     local level_type, screens, _, hscreen_number, _, vscreen_number = read_screens()
  2334.     local max_x, max_y
  2335.     if level_type == "Horizontal" then
  2336.         max_x = 16*(hscreen_number + 1)
  2337.         max_y = 27
  2338.     else
  2339.         max_x = 32
  2340.         max_y = 16*(vscreen_number + 1)
  2341.     end
  2342.    
  2343.     if num_x > max_x or num_y > max_y then return end  -- 2nd breakpoint
  2344.    
  2345.     local num_id, kind
  2346.     if level_type == "Horizontal" then
  2347.         num_id = 16*27*floor(num_x/16) + 16*num_y + num_x%16
  2348.         kind = (num_id >= 0 and num_id <= 0x35ff) and 256*u8(0x1c800 + num_id) + u8(0xc800 + num_id)
  2349.     else
  2350.         local nx = floor(num_x/16)
  2351.         local ny = floor(num_y/16)
  2352.         local n = 2*ny + nx
  2353.         local num_id = 16*16*n + 16*(num_y%16) + num_x%16
  2354.         kind = (num_id >= 0 and num_id <= 0x37ff) and 256*u8(0x1c800 + num_id) + u8(0xc800 + num_id)
  2355.     end
  2356.    
  2357.     if kind then return  num_x, num_y, kind end
  2358. end
  2359.  
  2360.  
  2361. local function draw_layer1_tiles(camera_x, camera_y)
  2362.     local x_origin, y_origin = screen_coordinates(0, 0, camera_x, camera_y)
  2363.     local x_mouse, y_mouse = game_coordinates(User_input.xmouse, User_input.ymouse, camera_x, camera_y)
  2364.     x_mouse = 16*floor(x_mouse/16)
  2365.     y_mouse = 16*floor(y_mouse/16)
  2366.    
  2367.     for number, positions in ipairs(Layer1_tiles) do
  2368.         -- Calculate the Lsnes coordinates
  2369.         local left = positions[1] + x_origin
  2370.         local top = positions[2] + y_origin
  2371.         local right = left + 15
  2372.         local bottom = top + 15
  2373.         local x_game, y_game = game_coordinates(left, top, camera_x, camera_y)
  2374.        
  2375.         -- Returns if block is way too outside the screen
  2376.         if left > - Border_left - 32 and top  > - Border_top - 32 and -- Snes9x: w/ 2*
  2377.         right < Screen_width  + Border_right + 32 and bottom < Screen_height + Border_bottom + 32 then
  2378.            
  2379.             -- Drawings
  2380.             Text_opacity = 1.0 -- Snes9x
  2381.             --[[cal num_x, num_y, kind = get_map16_value(x_game, y_game)
  2382.             if kind then
  2383.                 if kind >= 0x111 and kind <= 0x16d or kind == 0x2b then
  2384.                     -- default solid blocks, don't know how to include custom blocks
  2385.                     draw_rectangle(left + push_direction, top, 8, 15, 0, COLOUR.block_bg)
  2386.                 end
  2387.                 draw_rectangle(left, top, 15, 15, kind == SMW2.blank_tile_map16 and COLOUR.blank_tile or COLOUR.block, 0)
  2388.                
  2389.                 if Layer1_tiles[number][3] then
  2390.                     display_boundaries(x_game, y_game, 16, 16, camera_x, camera_y)  -- the text around it
  2391.                 end
  2392.                
  2393.                 -- Draw Map16 id
  2394.                 Text_opacity = 1.0
  2395.                 if kind and x_mouse == positions[1] and y_mouse == positions[2] then
  2396.                     draw_text(AR_x*(left + 4), AR_y*top - SNES9X_FONT_HEIGHT, fmt("Map16 (%d, %d), %x", num_x, num_y, kind),
  2397.                     false, false, 0.5, 1.0)
  2398.                 end
  2399.             end]]
  2400.            
  2401.             draw_rectangle(left, top, 15, 15, COLOUR.blank_tile, 0) -- REMOVE
  2402.            
  2403.         end
  2404.        
  2405.     end
  2406.    
  2407. end
  2408.  
  2409.  
  2410. local function draw_layer2_tiles()
  2411.     local layer2x = s16(WRAM.layer2_x_nextframe)
  2412.     local layer2y = s16(WRAM.layer2_y_nextframe)
  2413.    
  2414.     for number, positions in ipairs(Layer2_tiles) do
  2415.         draw_rectangle(-layer2x + positions[1], -layer2y + positions[2], 15, 15, COLOUR.layer2_line, COLOUR.layer2_bg)
  2416.     end
  2417. end
  2418.  
  2419.  
  2420. local function draw_tilesets(camera_x, camera_y)
  2421.     if Game_mode ~= SMW2.game_mode_level then return end
  2422.    
  2423.     local x_origin, y_origin = screen_coordinates(0, 0, camera_x, camera_y)
  2424.    
  2425.     --##############################################
  2426.     -- Tile grid
  2427.    
  2428.     Text_opacity = 1.0
  2429.    
  2430.     local width = 256 --u16(WRAM.level_width) or LEVEL[Level_index].width
  2431.     local height = 128 --u16(WRAM.level_height) or LEVEL[Level_index].height
  2432.     local block_x, block_y
  2433.     local x_pos, y_pos
  2434.     local x_screen, y_screen
  2435.     local screen_number, screen_id
  2436.     local block_id
  2437.     local kind_low, kind_high
  2438.     for screen_region_y = 0, 7 do
  2439.         --y_pos = y_origin + 16*screen_region_y
  2440.        
  2441.         for screen_region_x = 0, 15 do
  2442.             --x_pos = x_origin + 16*screen_region_x
  2443.             --x_screen, y_screen = screen_coordinates(x_pos, y_pos, camera_x, camera_y)
  2444.             --x_screen = x_screen + camera_x
  2445.             --y_screen = y_screen + camera_y
  2446.            
  2447.             screen_number = screen_region_y*16 + screen_region_x
  2448.             screen_id = u8(SFXRAM.screen_number_to_id + screen_number)
  2449.            
  2450.             for block_y = 0, 15 do
  2451.                 y_pos = y_origin + 256*screen_region_y + 16*block_y
  2452.                
  2453.                
  2454.                 for block_x = 0, 15 do
  2455.                     x_pos = x_origin + 256*screen_region_x + 16*block_x
  2456.                     x_screen, y_screen = screen_coordinates(x_pos, y_pos, camera_x, camera_y)
  2457.                     x_screen = x_screen + camera_x
  2458.                     y_screen = y_screen + camera_y
  2459.                    
  2460.                     block_id = 256*screen_id + 16*block_y + block_x
  2461.                    
  2462.                     if x_screen >= -256 and x_screen <= 256+16 and y_screen >= -256 and y_screen <= 224+16 then -- to not print the whole level, it's too laggy
  2463.                        
  2464.                         --local num_x, num_y, kind_low, kind_high, address_low, address_high = get_map16_value(x_game, y_game)
  2465.            
  2466.                         kind_low = u8(0x7E0000 + WRAM.Map16_data + 2*block_id) --
  2467.                         kind_high = u8(0x7E0000 + WRAM.Map16_data + 2*block_id + 1) --
  2468.                        
  2469.                         -- Tile type
  2470.                         if OPTIONS.draw_tile_map_type then
  2471.                             draw_text(x_pos + 5, y_pos + 1, fmt("%02x\n%02x", kind_high, kind_low), COLOUR.blank_tile)
  2472.                         end
  2473.                        
  2474.                         -- Grid
  2475.                         if OPTIONS.draw_tile_map_grid then
  2476.                            
  2477.                             local block_is_solid = false
  2478.                             for i = 1, #SOLID_BLOCKS do
  2479.                                 if kind_high == SOLID_BLOCKS[i] then
  2480.                                     block_is_solid = true
  2481.                                     break
  2482.                                 end
  2483.                             end
  2484.                             if block_is_solid then
  2485.                                 draw_rectangle(x_pos, y_pos, 15, 15, COLOUR.block, 0)
  2486.                             else
  2487.                                 draw_rectangle(x_pos, y_pos, 15, 15, COLOUR.blank_tile, 0)
  2488.                             end
  2489.                            
  2490.                             --[[
  2491.                             if kind_high == 0x01 or kind_high == 0x02 or kind_high == 0x03 or kind_high == 0x05 or kind_high == 0x06 or kind_high == 0x08 or kind_high == 0x0A or kind_high == 0x0C or kind_high == 0x0D or kind_high == 0x0F
  2492.                             or kind_high == 0x10 or kind_high == 0x15 or kind_high == 0x1A or kind_high == 0x1B or kind_high == 0x1C
  2493.                             or kind_high == 0x29 or kind_high == 0x2C or kind_high == 0x2F
  2494.                             or kind_high == 0x38 or kind_high == 0x39 or kind_high == 0x3E or kind_high == 0x3F
  2495.                             or kind_high == 0x40 or kind_high == 0x41 or kind_high == 0x44 or kind_high == 0x45 or kind_high == 0x4E
  2496.                             or kind_high == 0x50 or kind_high == 0x53 or kind_high == 0x55 or kind_high == 0x57 or kind_high == 0x59 or kind_high == 0x5B or kind_high == 0x5D or kind_high == 0x5F
  2497.                             or kind_high == 0x66 or kind_high == 0x67 or kind_high == 0x6B or kind_high == 0x6E
  2498.                             or kind_high == 0x79 or kind_high == 0x7D
  2499.                             or kind_high == 0x90 or kind_high == 0x9D then
  2500.                                 draw_rectangle(x_pos, y_pos, 15, 15, COLOUR.block, 0)
  2501.                             else
  2502.                                 draw_rectangle(x_pos, y_pos, 15, 15, COLOUR.blank_tile, 0)                 
  2503.                             end]]
  2504.                             --draw_rectangle(x_pos, y_pos, 15, 15, COLOUR.blank_tile, 0) -- REMOVE
  2505.                             --draw_text(x_pos, y_pos + 1, fmt("%x", num_id), COLOUR.blank_tile) -- REMOVE
  2506.                            
  2507.                             if block_y == 0 and block_x == 0 then -- REMOVE
  2508.                                 --screen_number = floor(num_id/256) + (num_id/16)%256
  2509.                                 --screen_id = u8(0x700CAA + screen_number)
  2510.                                
  2511.                                 draw_rectangle(x_pos, y_pos, 22, 16, COLOUR.warning, COLOUR.warning)
  2512.                                 draw_text(x_pos + 2, y_pos + 1, fmt("#:%02x\nID:%02x", screen_number, screen_id), COLOUR.text)
  2513.                                
  2514.                                 draw_rectangle(x_pos, y_pos, 255, 255, COLOUR.warning, 0)
  2515.                             end
  2516.                         end
  2517.                        
  2518.                         --[[
  2519.                         -- Tile type graphicaly
  2520.                         if OPTIONS.draw_tile_map_gfx_type then
  2521.                             if OPTIONS.draw_tile_map_phy_type then
  2522.                                 draw_text(x_pos + 5, y_pos + 1, fmt("%02x", kind_low), COLOUR.blank_tile)
  2523.                             else
  2524.                                 draw_text(x_pos + 5, y_pos + 4, fmt("%02x", kind_low), COLOUR.blank_tile)                  
  2525.                             end
  2526.                         end
  2527.                        
  2528.                         -- Tile type physicaly
  2529.                         if OPTIONS.draw_tile_map_phy_type then
  2530.                             if OPTIONS.draw_tile_map_gfx_type then
  2531.                                 draw_text(x_pos + 5, y_pos + 8, fmt("%02x", kind_high), COLOUR.blank_tile)
  2532.                             else
  2533.                                 draw_text(x_pos + 5, y_pos + 4, fmt("%02x", kind_high), COLOUR.blank_tile)                 
  2534.                             end
  2535.                        
  2536.                         end]]
  2537.                     end
  2538.                
  2539.                 end
  2540.            
  2541.             end
  2542.         end
  2543.     end
  2544.    
  2545.     --##############################################
  2546.     -- Tiles from click
  2547.    
  2548.     local x_mouse, y_mouse = game_coordinates(User_input.xmouse, User_input.ymouse, camera_x, camera_y)
  2549.     x_mouse = 16*floor(x_mouse/16)
  2550.     y_mouse = 16*floor(y_mouse/16)
  2551.    
  2552.     for number, positions in ipairs(Tiletable) do
  2553.         -- Calculate the Snes9x coordinates
  2554.         local left = positions[1] + x_origin
  2555.         local top = positions[2] + y_origin
  2556.         local right = left + 15
  2557.         local bottom = top + 15
  2558.         local x_game, y_game = game_coordinates(left, top, camera_x, camera_y)
  2559.        
  2560.         -- Returns if block is way too outside the screen
  2561.         if left > - Border_left - 32 and top  > - Border_top - 32 and -- Snes9x: w/ 2*
  2562.         right < Screen_width  + Border_right + 32 and bottom < Screen_height + Border_bottom + 32 then
  2563.            
  2564.             --draw_rectangle(left, top, 15, 15, COLOUR.block, 0)
  2565.            
  2566.             -- Math
  2567.             local num_x, num_y, kind_low, kind_high, address_low, address_high = get_map16_value(x_game, y_game)
  2568.            
  2569.             screen_region_x = floor(x_game/256)
  2570.             screen_region_y = floor(y_game/256)
  2571.            
  2572.             screen_number = screen_region_y*16 + screen_region_x
  2573.             screen_id = u8(SFXRAM.screen_number_to_id + screen_number)
  2574.            
  2575.             block_x = (x_game%256)/16
  2576.             block_y = (y_game%256)/16
  2577.            
  2578.             block_id = 256*screen_id + 16*block_y + block_x
  2579.            
  2580.             kind_low = u8(0x7E0000 + WRAM.Map16_data + 2*block_id) --
  2581.             kind_high = u8(0x7E0000 + WRAM.Map16_data + 2*block_id + 1) --
  2582.            
  2583.             -- Drawings
  2584.             local block_is_solid = false
  2585.             for i = 1, #SOLID_BLOCKS do
  2586.                 if kind_high == SOLID_BLOCKS[i] then
  2587.                     block_is_solid = true
  2588.                     break
  2589.                 end
  2590.             end
  2591.             if OPTIONS.draw_tile_map_grid then -- to make it easier to see when grid is activated
  2592.                 draw_rectangle(left, top, 15, 15, COLOUR.warning_soft, 0) -- this color fits well
  2593.             elseif block_is_solid then
  2594.                 draw_rectangle(left, top, 15, 15, COLOUR.block, 0)
  2595.             else
  2596.                 draw_rectangle(left, top, 15, 15, COLOUR.blank_tile, 0)
  2597.             end
  2598.            
  2599.             if Tiletable[number][3] then
  2600.                 display_boundaries(x_game, y_game, 16, 16, camera_x, camera_y)  -- the text around it
  2601.             end
  2602.            
  2603.             -- Draw Map16 id
  2604.             if x_mouse == positions[1] and y_mouse == positions[2] then
  2605.                 Text_opacity = 0.8
  2606.                
  2607.                 local y_pos
  2608.                 --if num_y < 2 then y_pos = bottom + 2*SNES9X_FONT_HEIGHT + 1 else y_pos = top - SNES9X_FONT_HEIGHT end
  2609.                
  2610.                 draw_text(left + 6, top - 16, fmt("block %03x", block_id), false, true, 0.5, 1.0)
  2611.                 draw_text(left + 6, top - 8, fmt("type: %02x %02x", kind_low, kind_high), false, true, 0.5, 1.0)
  2612.                
  2613.                 --draw_text(left + 6, y_pos + SNES9X_FONT_HEIGHT, fmt("%04x (%04x)", address_low, address_high), false, true, 0.5, 1.0) -- REMOVE
  2614.             end
  2615.         end
  2616.     end
  2617. end
  2618.  
  2619.  
  2620. -- if the user clicks in a tile, it will be be drawn
  2621. -- if click is onto drawn region, it'll be erased
  2622. -- there's a max of possible tiles
  2623. -- layer_table[n] is an array {x, y, [draw info?]}
  2624. local function select_tile()
  2625.     if not OPTIONS.draw_tiles_with_click then return end
  2626.     if Game_mode ~= SMW2.game_mode_level then return end
  2627.    
  2628.     local x_mouse, y_mouse = game_coordinates(User_input.xmouse, User_input.ymouse, Camera_x, Camera_y)
  2629.     x_mouse = 16*floor(x_mouse/16)
  2630.     y_mouse = 16*floor(y_mouse/16)
  2631.    
  2632.     for number, positions in ipairs(Tiletable) do  -- if mouse points a drawn tile, erase it
  2633.         if x_mouse == positions[1] and y_mouse == positions[2] then
  2634.             if Tiletable[number][3] == false then
  2635.                 Tiletable[number][3] = true
  2636.             else
  2637.                 table.remove(Tiletable, number)
  2638.             end
  2639.            
  2640.             return
  2641.         end
  2642.     end
  2643.    
  2644.     -- otherwise, draw a new tile
  2645.     if #Tiletable == OPTIONS.max_tiles_drawn then
  2646.         table.remove(Tiletable, 1)
  2647.         Tiletable[OPTIONS.max_tiles_drawn] = {x_mouse, y_mouse, false}
  2648.     else
  2649.         table.insert(Tiletable, {x_mouse, y_mouse, false})
  2650.     end
  2651.    
  2652. end
  2653.  
  2654. --[[local function select_tile(x, y, layer_table)
  2655.     if not OPTIONS.draw_tiles_with_click then return end
  2656.     --if Game_mode ~= SMW2.game_mode_level then return end
  2657.    
  2658.     for number, positions in ipairs(layer_table) do  -- if mouse points a drawn tile, erase it
  2659.         if x == positions[1] and y == positions[2] then
  2660.             -- Layer 1
  2661.             if layer_table == Layer1_tiles then
  2662.                 if layer_table[number][3] == false then
  2663.                     layer_table[number][3] = true
  2664.                 else
  2665.                     table.remove(layer_table, number)
  2666.                 end
  2667.             -- Layer 2
  2668.             elseif layer_table == Layer2_tiles then
  2669.                 table.remove(layer_table, number)
  2670.             end
  2671.            
  2672.             return
  2673.         end
  2674.     end
  2675.    
  2676.     -- otherwise, draw a new tile
  2677.     if #layer_table == OPTIONS.max_tiles_drawn then
  2678.         table.remove(layer_table, 1)
  2679.         layer_table[OPTIONS.max_tiles_drawn] = {x, y, false}
  2680.     else
  2681.         table.insert(layer_table, {x, y, false})
  2682.     end
  2683.    
  2684. end]]
  2685.  
  2686.  
  2687. -- uses the mouse to select an object
  2688. local function select_object(mouse_x, mouse_y, camera_x, camera_y)
  2689.     -- Font
  2690.     Text_opacity = 1.0
  2691.     Bg_opacity = 0.5
  2692.    
  2693.     local x_game, y_game = game_coordinates(mouse_x, mouse_y, camera_x, camera_y)
  2694.     local obj_id
  2695.    
  2696.     -- Checks if the mouse is over Mario
  2697.     local x_player = s16(WRAM.x)
  2698.     local y_player = s16(WRAM.y)
  2699.     if x_player + 0xe >= x_game and x_player + 0x2 <= x_game and y_player + 0x30 >= y_game and y_player + 0x8 <= y_game then
  2700.         obj_id = "Mario"
  2701.     end
  2702.    
  2703.     if not obj_id and OPTIONS.display_sprite_info then
  2704.         for id = 0, SMW2.sprite_max - 1 do
  2705.             local sprite_status = u8(WRAM.sprite_status + id)
  2706.             if sprite_status ~= 0 and Sprites_info[id].x then  -- TODO: see why the script gets here without exporting Sprites_info
  2707.                 -- Import some values
  2708.                 local x_sprite, y_sprite = Sprites_info[id].x, Sprites_info[id].y
  2709.                 local x_screen, y_screen = Sprites_info[id].x_screen, Sprites_info[id].y_screen
  2710.                 local boxid = Sprites_info[id].boxid
  2711.                 local xoff, yoff = Sprites_info[id].xoff, Sprites_info[id].yoff
  2712.                 local width, height = Sprites_info[id].width, Sprites_info[id].height
  2713.                
  2714.                 if x_sprite + xoff + width >= x_game and x_sprite + xoff <= x_game and
  2715.                 y_sprite + yoff + height >= y_game and y_sprite + yoff <= y_game then
  2716.                     obj_id = id
  2717.                     break
  2718.                 end
  2719.             end
  2720.         end
  2721.     end
  2722.    
  2723.     if not obj_id then return end
  2724.    
  2725.     draw_text(User_input.xmouse, User_input.ymouse - 8, obj_id, true, false, 0.5, 1.0)
  2726.     return obj_id, x_game, y_game
  2727. end
  2728.  
  2729.  
  2730. -- This function sees if the mouse if over some object, to change its hitbox mode
  2731. -- The order is: 1) player, 2) sprite.
  2732. local function right_click()
  2733.     local id = select_object(User_input.xmouse, User_input.ymouse, Camera_x, Camera_y)
  2734.    
  2735.     if tostring(id) == "Yoshi" then
  2736.        
  2737.         if OPTIONS.display_player_hitbox and OPTIONS.display_interaction_points then
  2738.             OPTIONS.display_interaction_points = false
  2739.             OPTIONS.display_player_hitbox = false
  2740.         elseif OPTIONS.display_player_hitbox then
  2741.             OPTIONS.display_interaction_points = true
  2742.             OPTIONS.display_player_hitbox = false
  2743.         elseif OPTIONS.display_interaction_points then
  2744.             OPTIONS.display_player_hitbox = true
  2745.         else
  2746.             OPTIONS.display_player_hitbox = true
  2747.         end
  2748.        
  2749.     end
  2750.     if id then return end
  2751.    
  2752.     local spr_id = tonumber(id)
  2753.     if spr_id and spr_id >= 0 and spr_id <= SMW2.sprite_max - 1 then
  2754.        
  2755.         local number = Sprites_info[spr_id].number
  2756.         if Sprite_hitbox[spr_id][number].sprite and Sprite_hitbox[spr_id][number].block then
  2757.             Sprite_hitbox[spr_id][number].sprite = false
  2758.             Sprite_hitbox[spr_id][number].block = false
  2759.         elseif Sprite_hitbox[spr_id][number].sprite then
  2760.             Sprite_hitbox[spr_id][number].block = true
  2761.             Sprite_hitbox[spr_id][number].sprite = false
  2762.         elseif Sprite_hitbox[spr_id][number].block then
  2763.             Sprite_hitbox[spr_id][number].sprite = true
  2764.         else
  2765.             Sprite_hitbox[spr_id][number].sprite = true
  2766.         end
  2767.        
  2768.     end
  2769.     if id then return end
  2770.    
  2771.     -- Select layer 2 tiles -- TODO
  2772.     --[[local layer2x = s16(WRAM.layer2_x_nextframe)
  2773.     local layer2y = s16(WRAM.layer2_y_nextframe)
  2774.     local x_mouse, y_mouse = User_input.xmouse + layer2x, User_input.ymouse + layer2y
  2775.     select_tile(16*floor(x_mouse/16), 16*floor(y_mouse/16) - Y_CAMERA_OFF, Layer2_tiles)]]
  2776. end
  2777.  
  2778.  
  2779. local function show_movie_info()
  2780.     if not OPTIONS.display_movie_info then return end
  2781.    
  2782.     -- Font
  2783.     Text_opacity = 1.0
  2784.     Bg_opacity = 1.0
  2785.     local y_text = - Border_top
  2786.     local x_text = 0
  2787.     local width = SNES9X_FONT_WIDTH
  2788.    
  2789.     local rec_color = (Readonly or not Movie_active) and COLOUR.text or COLOUR.warning
  2790.     local recording_bg = (Readonly or not Movie_active) and COLOUR.background or COLOUR.warning_bg
  2791.    
  2792.     -- Read-only or read-write?
  2793.     local movie_type = (not Movie_active and "No movie ") or (Readonly and "Movie " or "REC ")
  2794.     alert_text(x_text, y_text, movie_type, rec_color, recording_bg)
  2795.    
  2796.     -- Frame count
  2797.     x_text = x_text + width*string.len(movie_type)
  2798.     local movie_info
  2799.     if Readonly then
  2800.         movie_info = string.format("%d/%d", Lastframe_emulated, Framecount)
  2801.     else
  2802.         movie_info = string.format("%d", Lastframe_emulated)
  2803.     end
  2804.     draw_text(x_text, y_text, movie_info)  -- Shows the latest frame emulated, not the frame being run now
  2805.     x_text = x_text + width*string.len(movie_info)
  2806.    
  2807.     -- Rerecord count
  2808.     local rr_info = string.format(" %d ", Rerecords)
  2809.     draw_text(x_text, y_text, rr_info, COLOUR.weak)
  2810.     x_text = x_text + width*string.len(rr_info)
  2811.    
  2812.     -- Lag count
  2813.     draw_text(x_text, y_text, Lagcount, COLOUR.warning)
  2814.    
  2815.     local str = frame_time(Lastframe_emulated)    -- Shows the latest frame emulated, not the frame being run now
  2816.     alert_text(Buffer_width, Buffer_height, str, COLOUR.text, recording_bg, false, 1.0, 1.0)
  2817.    
  2818.     if Is_lagged then
  2819.         alert_text(Buffer_middle_x - 3*SNES9X_FONT_WIDTH, 2*SNES9X_FONT_HEIGHT, " LAG ", COLOUR.warning, COLOUR.warning_bg)
  2820.         emu.message("Lag detected!") -- Snes9x
  2821.        
  2822.     end
  2823.    
  2824. end
  2825.  
  2826.  
  2827. local function show_misc_info()
  2828.     if not OPTIONS.display_misc_info then return end
  2829.    
  2830.     -- Font
  2831.     Text_opacity = 1.0
  2832.     Bg_opacity = 1.0
  2833.     local delta_y = SNES9X_FONT_HEIGHT
  2834.    
  2835.     -- Display
  2836.     local game_mode = string.upper(fmt("%04x", Game_mode))
  2837.     draw_text(Buffer_width + Border_right - 20, -Border_top, fmt("Mode:%s", game_mode), true, false)
  2838.    
  2839.     local camera_str = fmt("Camera (%d, %d)", Camera_x, Camera_y)
  2840.     draw_text(Buffer_middle_x - string.len(camera_str)*SNES9X_FONT_WIDTH/2, 208, camera_str)
  2841.    
  2842.     local RNG = u16(SFXRAM.RNG)
  2843.     RNG = string.upper(fmt("%04x", RNG))
  2844.     draw_text(180, 0, fmt("RNG:%s", RNG))
  2845.    
  2846.     local red_coin_counter = u8(WRAM.red_coin_counter)
  2847.     local star_counter = u16(WRAM.star_counter)
  2848.     local flower_counter = u8(WRAM.flower_counter)
  2849.     local coin_counter = u8(WRAM.coin_counter)
  2850.     local star_effective = math.floor(star_counter/10)
  2851.    
  2852.     local temp_str
  2853.     local x_temp = 0
  2854.    
  2855.     if Game_mode ~= SMW2.game_mode_level then return end
  2856.    
  2857.     temp_str = fmt("Stars:%d/30(%d)", star_effective, star_counter)
  2858.     draw_text(x_temp, delta_y, temp_str, COLOUR.weak, true)
  2859.     x_temp = x_temp + SNES9X_FONT_WIDTH*string.len(temp_str) + 8
  2860.    
  2861.     temp_str = fmt("Red coins:%d/20", red_coin_counter)
  2862.     draw_text(x_temp, delta_y, temp_str, COLOUR.weak, true)
  2863.     x_temp = x_temp + SNES9X_FONT_WIDTH*string.len(temp_str) + 8
  2864.    
  2865.     temp_str = fmt("Flowers:%d/5", flower_counter)
  2866.     draw_text(x_temp, delta_y, temp_str, COLOUR.weak, true)
  2867.     x_temp = x_temp + SNES9X_FONT_WIDTH*string.len(temp_str) + 8
  2868.    
  2869.     temp_str = fmt("Coins:%d", coin_counter)
  2870.     draw_text(x_temp, delta_y, temp_str, COLOUR.weak, true)
  2871. end
  2872.  
  2873.  
  2874. -- Display mouse coordinates right above it
  2875. local function show_mouse_info()
  2876.     if not OPTIONS.display_mouse_coordinates then return end
  2877.    
  2878.     -- Font
  2879.     Text_opacity = 1.0 -- Snes9x
  2880.     Bg_opacity = 1.0
  2881.    
  2882.     local x = User_input.xmouse
  2883.     local y = User_input.ymouse
  2884.     local x_level = x + Camera_x
  2885.     local y_level = y + Camera_y
  2886.    
  2887.     if User_input.xmouse >= 0 and User_input.xmouse <= 256 and User_input.ymouse >= 0 and User_input.ymouse <= 224 then
  2888.         alert_text(x, y - 8, fmt("(%d, %d)", x, y), COLOUR.text, COLOUR.background, 0.1, 0.5)
  2889.         alert_text(x, y + 8, fmt("(%d, %d)", x_level, y_level), COLOUR.text, COLOUR.background, 0.1, 0.5)
  2890.     end
  2891. end
  2892.  
  2893.  
  2894. -- Shows the controller input as the RAM and SNES registers store it
  2895. local function show_controller_data()
  2896.     if not (OPTIONS.display_debug_info and OPTIONS.display_debug_controller_data) then return end
  2897.    
  2898.     -- Font
  2899.     Text_opacity = 0.9
  2900.     local height = SNES9X_FONT_HEIGHT
  2901.     local x_pos, y_pos, x, y, _ = 0, 0, 0, SNES9X_FONT_HEIGHT
  2902.    
  2903.     local controller = memory.readword(0x1000000 + 0x4218) -- Snes9x / BUS area
  2904.     x = draw_over_text(x, y, controller, "BYsS^v<>AXLR0123", COLOUR.warning, false, true)
  2905.     _, y = draw_text(x, y, " (Registers)", COLOUR.warning, false, true)
  2906.    
  2907.     x = x_pos
  2908.     x = draw_over_text(x, y, 256*u8(WRAM.ctrl_1_1) + u8(WRAM.ctrl_1_2), "BYsS^v<>AXLR0123", COLOUR.weak)
  2909.     _, y = draw_text(x, y, " (RAM data)", COLOUR.weak, false, true)
  2910.    
  2911.     x = x_pos
  2912.     draw_over_text(x, y, 256*u8(WRAM.firstctrl_1_1) + u8(WRAM.firstctrl_1_2), "BYsS^v<>AXLR0123", 0, "#0xffff", 0) -- Snes9x
  2913. end
  2914.  
  2915.  
  2916. local function level_info()
  2917.     if not OPTIONS.display_level_info then return end
  2918.     if Game_mode ~= SMW2.game_mode_level then return end
  2919.    
  2920.     -- Font
  2921.     Text_opacity = 0.2 -- Snes9x
  2922.     Bg_opacity = 1.0
  2923.     local x_pos = 68
  2924.     local y_pos = 216
  2925.     local color = COLOUR.text
  2926.     Text_opacity = 1.0
  2927.     Bg_opacity = 1.0
  2928.    
  2929.    
  2930.     local level_index_str = string.upper(fmt("%02x", Level_index))
  2931.    
  2932.     -- converts the level index to the game level number
  2933.     local world_number = floor(Level_index/12) + 1
  2934.     local level_number = fmt("%d", Level_index%12 + 1)
  2935.     if level_number == "9" then level_number = "E" end -- Extra levels
  2936.    
  2937.     draw_text(x_pos, y_pos, fmt("Level:%s (%d - %s)", level_index_str, world_number, level_number), color)
  2938.     --[[
  2939.     -- Number of screens within the level
  2940.     local level_type, screens_number, hscreen_current, hscreen_number, vscreen_current, vscreen_number = read_screens()
  2941.    
  2942.     draw_text(x_pos, y_pos, fmt("%.1sLevel(%.2x)%s", level_type, level_number, sprite_buoyancy),
  2943.                     color, true, false)
  2944.     ;
  2945.    
  2946.     draw_text(x_pos, y_pos + SNES9X_FONT_HEIGHT, fmt("Screens(%d):", screens_number), true)
  2947.    
  2948.     draw_text(x_pos, y_pos + 2*SNES9X_FONT_HEIGHT, fmt("(%d/%d, %d/%d)", hscreen_current, hscreen_number,
  2949.                 vscreen_current, vscreen_number), true)
  2950.     ;]]
  2951. end
  2952.  
  2953.  
  2954. function draw_blocked_status(x_text, y_text, player_blocked_status, x_speed, y_speed)
  2955.     local bitmap_width  = 25 -- Snes9x
  2956.     local bitmap_height = 30 -- Snes9x
  2957.     local block_str = "Block:"
  2958.     local str_len = string.len(block_str)
  2959.     local xoffset = x_text + str_len*SNES9X_FONT_WIDTH
  2960.     local yoffset = y_text + 2
  2961.     local color_line = COLOUR.warning
  2962.    
  2963.     gui.gdoverlay(xoffset + 3, yoffset, IMAGES.player_blocked_status, Background_max_opacity * Bg_opacity * 0.5) -- Snes9x
  2964.    
  2965.     gui.opacity(Text_max_opacity*Text_opacity) -- Snes9x
  2966.     local blocked_status = {}
  2967.     local was_boosted = false
  2968.    
  2969.    
  2970.    
  2971.     -- Bottom right
  2972.     draw_rectangle(xoffset + 19, yoffset + bitmap_height, 8, 2, COLOUR.text)
  2973.     if bit.test(player_blocked_status, 0) then  
  2974.         draw_line(xoffset + 20, yoffset + bitmap_height + 1, xoffset + bitmap_width + 1, yoffset + bitmap_height + 1, 1, color_line)
  2975.     end
  2976.    
  2977.     -- Bottom middle
  2978.     draw_rectangle(xoffset + 11, yoffset + bitmap_height, 8, 2, COLOUR.text)
  2979.     if bit.test(player_blocked_status, 1) then
  2980.         draw_line(xoffset + 12, yoffset + bitmap_height + 1, xoffset + 18, yoffset + bitmap_height + 1, 1, color_line)
  2981.         --if x_speed > 0 then was_boosted = true end
  2982.     end
  2983.    
  2984.     -- Bottom left 
  2985.     draw_rectangle(xoffset + 3, yoffset + bitmap_height, 8, 2, COLOUR.text)
  2986.     if bit.test(player_blocked_status, 2) then
  2987.         draw_line(xoffset + 4, yoffset + bitmap_height + 1, xoffset + 10, yoffset + bitmap_height + 1, 1, color_line)
  2988.         --if x_speed < 0 then was_boosted = true end
  2989.     end
  2990.    
  2991.     -- Top right
  2992.     draw_rectangle(xoffset + 15, yoffset - 3, 12, 2, COLOUR.text)
  2993.     if bit.test(player_blocked_status, 3) then
  2994.         draw_line(xoffset + 16, yoffset - 2, xoffset + bitmap_width + 1, yoffset - 2, 1, color_line)
  2995.         --if y_speed > 6 then was_boosted = true end
  2996.     end
  2997.    
  2998.     -- Top left
  2999.     draw_rectangle(xoffset + 3, yoffset - 3, 12, 2, COLOUR.text)
  3000.     if bit.test(player_blocked_status, 4) then  
  3001.         draw_line(xoffset + 4, yoffset - 2, xoffset + 14, yoffset - 2, 1, color_line)
  3002.     end
  3003.    
  3004.     -- Right body
  3005.     draw_rectangle(xoffset + bitmap_width + 3, yoffset + 14, 2, 15, COLOUR.text)
  3006.     if bit.test(player_blocked_status, 5) then  
  3007.         draw_line(xoffset + bitmap_width + 4, yoffset + 15, xoffset + bitmap_width + 4, yoffset + bitmap_height - 2, 1, color_line)
  3008.     end
  3009.    
  3010.     -- Right head
  3011.     draw_rectangle(xoffset + bitmap_width + 3, yoffset, 2, 14, COLOUR.text)
  3012.     if bit.test(player_blocked_status, 6) then  
  3013.         draw_line(xoffset + bitmap_width + 4, yoffset + 1, xoffset + bitmap_width + 4, yoffset + 13, 1, color_line)
  3014.     end
  3015.    
  3016.     -- Left body
  3017.     draw_rectangle(xoffset, yoffset + 14, 2, 15, COLOUR.text)
  3018.     if bit.test(player_blocked_status, 7) then  
  3019.         draw_line(xoffset + 1, yoffset + 15, xoffset + 1, yoffset + bitmap_height - 2, 1, color_line)
  3020.     end
  3021.    
  3022.     -- Left head
  3023.     draw_rectangle(xoffset, yoffset, 2, 14, COLOUR.text)
  3024.     if bit.test(player_blocked_status, 8) then  
  3025.         draw_line(xoffset + 1, yoffset + 1, xoffset + 1, yoffset + 13, 1, color_line)
  3026.     end
  3027.    
  3028.     -- Fully inside the ground
  3029.     if player_blocked_status == 0x1ff then  
  3030.         draw_line(xoffset + 3, yoffset + floor(bitmap_height/2) - 1, xoffset + bitmap_width + 2, yoffset + floor(bitmap_height/2) - 1, 1, color_line)
  3031.         draw_line(xoffset + floor(bitmap_width/2) + 3, yoffset, xoffset + floor(bitmap_width/2) + 3, yoffset + bitmap_height - 1, 1, color_line)
  3032.     end
  3033.    
  3034.     draw_text(x_text, y_text, block_str, COLOUR.text, was_boosted and COLOUR.warning_bg or nil)
  3035. end
  3036.  
  3037.  
  3038. -- displays player's hitbox
  3039. local function player_hitbox(x, y, tongue_x_screen, tongue_y_screen) --player_hitbox(x, y, is_ducking, powerup, transparency_level)
  3040.     local x_screen, y_screen = screen_coordinates(x, y, Camera_x, Camera_y)
  3041.     local yoshi_hitbox = nil
  3042.     --local is_small = is_ducking ~= 0 or powerup == 0
  3043.    
  3044.     local x_points = X_INTERACTION_POINTS
  3045.     local y_points = Y_INTERACTION_POINTS[2]
  3046.     --[[if is_small and not Yoshi_riding_flag then
  3047.         y_points = Y_INTERACTION_POINTS[1]
  3048.     elseif not is_small and not Yoshi_riding_flag then
  3049.         y_points = Y_INTERACTION_POINTS[2]
  3050.     elseif is_small and Yoshi_riding_flag then
  3051.         y_points = Y_INTERACTION_POINTS[3]
  3052.     else
  3053.         y_points = Y_INTERACTION_POINTS[4]
  3054.     end]]
  3055.    
  3056.    
  3057.     --draw_box(x_screen + x_points.left_side, y_screen + y_points.head, x_screen + x_points.right_side, y_screen + y_points.foot,
  3058.             --COLOUR.interaction_bg, COLOUR.interaction_bg)
  3059.            
  3060.     ;
  3061.    
  3062.     if OPTIONS.display_player_hitbox then
  3063.        
  3064.         -- Collision with sprites
  3065.         local mario_bg = (not Yoshi_riding_flag and COLOUR.mario_bg) or COLOUR.mario_mounted_bg
  3066.        
  3067.         draw_box(x_screen + x_points.left_side  - 1, y_screen + y_points.sprite,
  3068.                  x_screen + x_points.right_side + 1, y_screen + y_points.foot + 1, COLOUR.mario, mario_bg)
  3069.         ;
  3070.        
  3071.     end
  3072.    
  3073.     -- Interaction points (collision with blocks)
  3074.     if OPTIONS.display_interaction_points then
  3075.        
  3076.         -- Background for block interaction
  3077.         draw_box(x_screen - 1, y_screen + 2, x_screen + 17, y_screen + 33, COLOUR.interaction_nohitbox, COLOUR.interaction_nohitbox_bg)
  3078.        
  3079.         local color = COLOUR.interaction
  3080.        
  3081.         if not SHOW_PLAYER_HITBOX then
  3082.             --draw_box(x_screen + x_points.left_side , y_screen + y_points.head,
  3083.                     -- x_screen + x_points.right_side, y_screen + y_points.foot, COLOUR.interaction_nohitbox, COLOUR.interaction_nohitbox_bg)
  3084.         end
  3085.        
  3086.         --- Horizontal lines
  3087.        
  3088.         -- Feet
  3089.         gui.line(x_screen + 3, y_screen + 31, x_screen + 13, y_screen + 31, color)
  3090.         --gui.line(x_screen + 10, y_screen + 31, x_screen + 13, y_screen + 31, color)
  3091.        
  3092.         -- Shoulders
  3093.         gui.line(x_screen + 1, y_screen + 9, x_screen + 3, y_screen + 9, color)
  3094.         gui.line(x_screen + 13, y_screen + 9, x_screen + 15, y_screen + 9, color)
  3095.        
  3096.         -- "Knees"
  3097.         gui.line(x_screen + 2, y_screen + 23, x_screen + 4, y_screen + 23, color)
  3098.         gui.line(x_screen + 12, y_screen + 23, x_screen + 14, y_screen + 23, color)
  3099.        
  3100.         -- Head
  3101.         gui.line(x_screen + 6, y_screen + 4, x_screen + 10, y_screen + 4, color)       
  3102.        
  3103.        
  3104.         --- Vertical lines
  3105.        
  3106.         -- Body
  3107.         gui.line(x_screen + 15, y_screen + 9, x_screen + 15, y_screen + 23, color)
  3108.         gui.line(x_screen + 1, y_screen + 9, x_screen + 1, y_screen + 23, color)
  3109.        
  3110.         -- Feet
  3111.         gui.line(x_screen + 3, y_screen + 31, x_screen + 3, y_screen + 29, color)
  3112.         gui.line(x_screen + 8, y_screen + 31, x_screen + 8, y_screen + 29, color)
  3113.         gui.line(x_screen + 13, y_screen + 31, x_screen + 13, y_screen + 29, color)
  3114.        
  3115.         -- Head (top)
  3116.         gui.line(x_screen + 6, y_screen + 4, x_screen + 6, y_screen + 6, color)
  3117.         gui.line(x_screen + 10, y_screen + 4, x_screen + 10, y_screen + 6, color)  
  3118.        
  3119.     end
  3120.    
  3121.     local x_test, y_test = s16(0x700156), s16(0x700158) -- REMOVE
  3122.     --gui.line(x_test, y_test, 100, 100, "blue") -- REMOVE
  3123.     gui.crosshair(x_test, y_test, 2, "blue") -- REMOVE
  3124.    
  3125.    
  3126.     -- Tongue hitbox
  3127.     if OPTIONS.display_tongue_hitbox then
  3128.         local tongue_state = u8(SFXRAM.tongue_state)
  3129.         local ammo_in_mouth = u8(SFXRAM.ammo_in_mouth)
  3130.         local sprite_in_mouth = false
  3131.         for i = 0, SMW2.sprite_max - 1 do
  3132.             if Sprites_info[i].sprite_status == 0x08 then sprite_in_mouth = true end
  3133.         end
  3134.        
  3135.         if tongue_state ~= 0 and tongue_state < 5 and ammo_in_mouth == 0 and not sprite_in_mouth then
  3136.             draw_box(tongue_x_screen - 14, tongue_y_screen - 10, tongue_x_screen + 13, tongue_y_screen + 9, COLOUR.positive)
  3137.         end
  3138.     end
  3139.    
  3140.     --[[
  3141.     -- That's the pixel that appears when Mario dies in the pit
  3142.     Show_player_point_position = Show_player_point_position or y_screen >= 200 or
  3143.         (OPTIONS.display_debug_info and OPTIONS.display_debug_player_extra)
  3144.     if Show_player_point_position then
  3145.         draw_rectangle(x_screen - 1, y_screen - 1, 2, 2, COLOUR.interaction_bg, COLOUR.text)
  3146.         Show_player_point_position = false
  3147.     end]]
  3148.    
  3149.     return x_points, y_points
  3150. end
  3151.  
  3152.  
  3153. local function egg_throw_info(egg_target_x, egg_target_y, direction, x_centered, y_centered, x_screen, y_screen)
  3154.     if Is_paused then return end
  3155.    
  3156.     --- Memory reading
  3157.     local egg_target_radial_pos = u8(SFXRAM.egg_target_radial_pos)
  3158.     local egg_target_radial_subpos = u8(SFXRAM.egg_target_radial_subpos)
  3159.     local egg_throw_state = u8(SFXRAM.egg_throw_state)
  3160.     local egg_throw_state_timer = u8(SFXRAM.egg_throw_state_timer)
  3161.    
  3162.     --- Transformations
  3163.     local egg_throw_origin_x, egg_throw_origin_y -- found with tests
  3164.     if direction == RIGHT_ARROW then
  3165.         egg_throw_origin_x = x_centered - 2
  3166.         egg_throw_origin_y = y_centered - 20
  3167.     else
  3168.         egg_throw_origin_x = x_centered - 14
  3169.         egg_throw_origin_y = y_centered - 20
  3170.     end
  3171.    
  3172.     local target_delta_x, target_delta_y = egg_target_x - egg_throw_origin_x, egg_target_y - egg_throw_origin_y
  3173.     local extended_target_x, extended_target_y =  egg_target_x + target_delta_x, egg_target_y - target_delta_y
  3174.    
  3175.     local egg_throw_effective_timer -- found with tests and math
  3176.     if egg_throw_state == 10 then egg_throw_effective_timer = 27
  3177.     elseif egg_throw_state == 9 then egg_throw_effective_timer = 26
  3178.     elseif egg_throw_state == 8 then egg_throw_effective_timer = 3*egg_throw_state + egg_throw_state_timer - 1
  3179.     elseif egg_throw_state == 7 then egg_throw_effective_timer = 23
  3180.     elseif egg_throw_state == 6 then egg_throw_effective_timer = 3*egg_throw_state + egg_throw_state_timer
  3181.     elseif egg_throw_state == 5 then egg_throw_effective_timer = 3*egg_throw_state + egg_throw_state_timer
  3182.     elseif egg_throw_state == 4 then egg_throw_effective_timer = 15
  3183.     elseif egg_throw_state == 3 then egg_throw_effective_timer = 14
  3184.     elseif egg_throw_state == 2 then egg_throw_effective_timer = 13
  3185.     elseif egg_throw_state == 1 then egg_throw_effective_timer = egg_throw_state_timer
  3186.     elseif egg_throw_state == 0 then egg_throw_effective_timer = egg_throw_state_timer -- or egg_throw_state
  3187.     end
  3188.  
  3189.     local egg_target_x_screen, egg_target_y_screen = screen_coordinates(egg_target_x, egg_target_y, Camera_x, Camera_y)
  3190.     local egg_throw_origin_x_screen, egg_throw_origin_y_screen = screen_coordinates(egg_throw_origin_x, egg_throw_origin_y, Camera_x, Camera_y)
  3191.  
  3192.     local radius = floor(sqrt(target_delta_x^2 + target_delta_y^2))
  3193.    
  3194.     --- Prints
  3195.    
  3196.     -- Target
  3197.     if egg_throw_effective_timer == 18 then
  3198.         draw_arrow(egg_throw_origin_x_screen, egg_throw_origin_y_screen, egg_target_x_screen, egg_target_y_screen, COLOUR.warning_soft)
  3199.         gui.crosshair(egg_target_x_screen, egg_target_y_screen, 2, "blue")
  3200.         draw_text(egg_target_x_screen, egg_target_y_screen + 16, fmt("%02d.%02x", egg_target_radial_pos, egg_target_radial_subpos), COLOUR.positive)
  3201.     end
  3202.    
  3203.     -- Radius
  3204.     if egg_throw_effective_timer == 18 then
  3205.         --draw_text(egg_target_x_screen + 8, egg_target_y_screen, fmt("%d", radius), COLOUR.positive) -- REMOVE
  3206.         if direction == RIGHT_ARROW then
  3207.             for i = -pi/2, 5*pi/18, pi/80 do
  3208.                 draw_pixel(egg_throw_origin_x_screen + cos(i)*(68) , egg_throw_origin_y_screen + sin(i)*(68), COLOUR.text)
  3209.             --draw_text(0, 150 + i*10*SNES9X_FONT_HEIGHT, fmt("sin:%f cos:%f", sin(i), cos(i)), COLOUR.text) -- REMOVE
  3210.             end
  3211.         else
  3212.             for i = 13*pi/18, 3*pi/2, pi/80 do
  3213.                 draw_pixel(egg_throw_origin_x_screen + cos(i)*(68) , egg_throw_origin_y_screen + sin(i)*(68), COLOUR.text)
  3214.             --draw_text(0, 150 + i*10*SNES9X_FONT_HEIGHT, fmt("sin:%f cos:%f", sin(i), cos(i)), COLOUR.text) -- REMOVE
  3215.             end    
  3216.         end
  3217.     end
  3218.    
  3219.     -- Extended target
  3220.     if egg_throw_effective_timer == 18 then
  3221.         draw_arrow(egg_target_x_screen, egg_target_y_screen,
  3222.                     egg_target_x_screen + 2*target_delta_x, egg_target_y_screen + 2*target_delta_y, COLOUR.blank_tile)
  3223.     end
  3224.    
  3225.     -- Timer
  3226.     if egg_throw_effective_timer ~= 0 then
  3227.         alert_text(x_screen + 4, y_screen - 16, fmt(" %d ", egg_throw_effective_timer), COLOUR.positive, COLOUR.warning_bg)
  3228.     end
  3229. end
  3230.  
  3231.  
  3232. local function player()
  3233.     if not OPTIONS.display_player_info then return end
  3234.     if Game_mode ~= SMW2.game_mode_level then return end
  3235.     if Is_paused then return end
  3236.    
  3237.     -- Font
  3238.     Text_opacity = 1.0
  3239.    
  3240.     -- Reads SFXRAM and maybe WRAM
  3241.     local x = s16(SFXRAM.x)
  3242.     local y = s16(SFXRAM.y)
  3243.     local x_sub = u8(SFXRAM.x_sub)
  3244.     local y_sub = u8(SFXRAM.y_sub)
  3245.     local x_speed = s8(SFXRAM.x_speed)
  3246.     local x_subspeed = u8(SFXRAM.x_subspeed)
  3247.     local y_speed = s8(SFXRAM.y_speed)
  3248.     local y_subspeed = u8(SFXRAM.y_subspeed)
  3249.     local direction = u8(SFXRAM.direction)
  3250.     local ground_pound_timer = u8(SFXRAM.ground_pound_timer)
  3251.     local ground_pound_state = u8(SFXRAM.ground_pound_state)
  3252.     local player_blocked_status = u16(SFXRAM.player_blocked_status)
  3253.     local on_sprite_platform = u16(SFXRAM.on_sprite_platform)
  3254.     local x_centered = u16(SFXRAM.x_centered)
  3255.     local y_centered = u16(SFXRAM.y_centered)
  3256.     local tongue_x = s16(SFXRAM.tongue_x)
  3257.     local tongue_y = s16(SFXRAM.tongue_y)
  3258.     local egg_target_x = s16(SFXRAM.egg_target_x)
  3259.     local egg_target_y = s16(SFXRAM.egg_target_y)
  3260.     --local diving_status = s8(SFXRAM.diving_status)
  3261.     --local player_item = u8(SFXRAM.player_item)
  3262.     --local is_ducking = u8(SFXRAM.is_ducking)
  3263.     --local on_ground = u8(SFXRAM.on_ground)
  3264.     --local can_jump_from_water = u8(SFXRAM.can_jump_from_water)
  3265.     --local carrying_item = u8(SFXRAM.carrying_item)
  3266.    
  3267.     -- Transformations
  3268.     if direction == 0 then direction = RIGHT_ARROW else direction = LEFT_ARROW end
  3269.     local x_screen, y_screen = screen_coordinates(x, y, Camera_x, Camera_y)
  3270.     local x_centered_screen, y_centered_screen = screen_coordinates(x_centered, y_centered, Camera_x, Camera_y)
  3271.     local tongue_x_screen, tongue_y_screen = screen_coordinates(tongue_x + x_centered, tongue_y + y_centered, Camera_x, Camera_y)
  3272.    
  3273.    
  3274.     --- Table
  3275.     local i = 0
  3276.     local delta_x = SNES9X_FONT_WIDTH
  3277.     local delta_y = SNES9X_FONT_HEIGHT
  3278.     local table_x = 0
  3279.     local table_y = AR_y*22
  3280.     local temp_colour
  3281.    
  3282.     draw_text(table_x, table_y + i*delta_y, fmt("Pos (%+d.%02x, %+d.%02x) %s", x, x_sub, y, y_sub, direction))
  3283.     i = i + 1
  3284.    
  3285.     draw_text(table_x, table_y + i*delta_y, fmt("Speed (%+d.%02x, %+d.%02x)", x_speed, x_subspeed, y_speed, y_subspeed))
  3286.     i = i + 1
  3287.    
  3288.     draw_text(table_x, table_y + i*delta_y, fmt("Tongue (%+d, %+d)", tongue_x, tongue_y))
  3289.     if OPTIONS.display_tongue_hitbox then
  3290.         gui.crosshair(tongue_x_screen, tongue_y_screen, 2, COLOUR.positive)
  3291.     end
  3292.     i = i + 1
  3293.    
  3294.     draw_text(table_x, table_y + i*delta_y, fmt("Target (%+d, %+d)", egg_target_x, egg_target_y))
  3295.     i = i + 1
  3296.    
  3297.     draw_text(table_x, table_y + i*delta_y, fmt("Center (%+d, %+d)", x_centered, y_centered)) -- REMOVE maybe
  3298.     i = i + 1
  3299.    
  3300.     local can_jump -- block or sprite
  3301.     if bit.test(player_blocked_status, 0) or bit.test(player_blocked_status, 1) or bit.test(player_blocked_status, 2) or on_sprite_platform == 1 then
  3302.         can_jump = "yes"
  3303.         temp_colour = COLOUR.positive
  3304.     else
  3305.         can_jump = "no"
  3306.         temp_colour = COLOUR.warning
  3307.     end
  3308.     draw_text(table_x, table_y + i*delta_y, fmt("Can jump:"))
  3309.     draw_text(table_x + 9*delta_x + 2, table_y + i*delta_y, fmt("%s", can_jump), temp_colour)
  3310.     i = i + 1
  3311.    
  3312.     if OPTIONS.display_blocked_status then
  3313.         draw_blocked_status(table_x, table_y + i*delta_y + 2, player_blocked_status, x_speed, y_speed)
  3314.         i = i + 1
  3315.     end
  3316.    
  3317.    
  3318.    
  3319.     --- Other info
  3320.    
  3321.     if ground_pound_timer ~= 0 and ground_pound_timer ~= 255 and ground_pound_state == 0 then
  3322.         alert_text(x_screen + 4, y_screen + 40, fmt(" %d ", ground_pound_timer), COLOUR.positive, COLOUR.warning_bg)
  3323.     end
  3324.    
  3325.     -- shows hitbox, interaction points, and tongue hitbox for player
  3326.     player_hitbox(x, y, tongue_x_screen, tongue_y_screen)
  3327.     --player_hitbox(x, y, is_ducking, powerup, 1.0) -- TODO
  3328.    
  3329.    
  3330.     --[[if OPTIONS.display_static_camera_region then -- TODO
  3331.         Show_player_point_position = true
  3332.         local left_cam, right_cam = u16(0x07142c), u16(0x07142e)  -- unlisted WRAM / Snes9x memory bank
  3333.         draw_box(left_cam, 0, right_cam, 224, COLOUR.static_camera_region, COLOUR.static_camera_region)
  3334.     end]]
  3335.    
  3336.     -- Egg throw info
  3337.     if OPTIONS.display_throw_info then
  3338.         egg_throw_info(egg_target_x, egg_target_y, direction, x_centered, y_centered, x_screen, y_screen)
  3339.     end
  3340.    
  3341.    
  3342.     if OPTIONS.display_debug_player_extra then
  3343.         gui.crosshair(x_screen, y_screen, 2, COLOUR.text)
  3344.         gui.crosshair(x_centered_screen, y_centered_screen, 2, COLOUR.text)
  3345.     end
  3346. end
  3347.  
  3348.  
  3349. local function extended_sprites()
  3350.     if not OPTIONS.display_extended_sprite_info then return end
  3351.     if Is_paused then return end
  3352.    
  3353.     -- Font
  3354.     Text_opacity = 1.0
  3355.     local height = SNES9X_FONT_HEIGHT
  3356.    
  3357.     local y_pos = AR_y*144
  3358.     local counter = 0
  3359.     for id = 0, SMW2.extended_sprite_max - 1 do
  3360.         local extspr_number = u8(WRAM.extspr_number + id)
  3361.        
  3362.         if extspr_number ~= 0 then
  3363.             -- Reads WRAM addresses
  3364.             local x = 256*u8(WRAM.extspr_x_high + id) + u8(WRAM.extspr_x_low + id)
  3365.             local y = 256*u8(WRAM.extspr_y_high + id) + u8(WRAM.extspr_y_low + id)
  3366.             local sub_x = bit.rshift(u8(WRAM.extspr_subx + id), 4)
  3367.             local sub_y = bit.rshift(u8(WRAM.extspr_suby + id), 4)
  3368.             local x_speed = s8(WRAM.extspr_x_speed + id)
  3369.             local y_speed = s8(WRAM.extspr_y_speed + id)
  3370.             local extspr_table = u8(WRAM.extspr_table + id)
  3371.             local extspr_table2 = u8(WRAM.extspr_table2 + id)
  3372.            
  3373.             -- Reduction of useless info
  3374.             local special_info = ""
  3375.             if OPTIONS.display_debug_info and OPTIONS.display_debug_extended_sprite and
  3376.             (extspr_table ~= 0 or extspr_table2 ~= 0) then
  3377.                 special_info = fmt("(%x, %x) ", extspr_table, extspr_table2)
  3378.             end
  3379.            
  3380.             -- x speed for Fireballs
  3381.             if extspr_number == 5 then x_speed = 16*x_speed end
  3382.            
  3383.             if OPTIONS.display_extended_sprite_info then
  3384.                 draw_text(Buffer_width + Border_right, y_pos + counter*height, fmt("#%.2d %.2x %s(%d.%x(%+.2d), %d.%x(%+.2d))",
  3385.                                                     id, extspr_number, special_info, x, sub_x, x_speed, y, sub_y, y_speed),
  3386.                                                     COLOUR.extended_sprites, true, false)
  3387.             end
  3388.            
  3389.             if (OPTIONS.display_debug_info and OPTIONS.display_debug_extended_sprite) or not UNINTERESTING_EXTENDED_SPRITES[extspr_number]
  3390.                 or (extspr_number == 1 and extspr_table2 == 0xf)
  3391.             then
  3392.                 local x_screen, y_screen = screen_coordinates(x, y, Camera_x, Camera_y)
  3393.                
  3394.                 local t = HITBOX_EXTENDED_SPRITE[extspr_number] or
  3395.                     {xoff = 0, yoff = 0, width = 16, height = 16, color_line = COLOUR.awkward_hitbox, color_bg = COLOUR.awkward_hitbox_bg}
  3396.                 local xoff = t.xoff
  3397.                 local yoff = t.yoff + Y_CAMERA_OFF
  3398.                 local xrad = t.width
  3399.                 local yrad = t.height
  3400.                
  3401.                 local color_line = t.color_line or COLOUR.extended_sprites
  3402.                 local color_bg = t.color_bg or COLOUR.extended_sprites_bg
  3403.                 if extspr_number == 0x5 or extspr_number == 0x11 then
  3404.                     color_bg = (Real_frame - id)%4 == 0 and COLOUR.special_extended_sprite_bg or 0
  3405.                 end
  3406.                 draw_rectangle(x_screen+xoff, y_screen+yoff, xrad, yrad, color_line, color_bg) -- regular hitbox
  3407.                
  3408.                 -- Experimental: attempt to show Mario's fireball vs sprites
  3409.                 -- this is likely wrong in some situation, but I can't solve this yet
  3410.                 if extspr_number == 5 or extspr_number == 1 then
  3411.                     local xoff_spr = x_speed >= 0 and -5 or  1
  3412.                     local yoff_spr = - floor(y_speed/16) - 4 + (y_speed >= -40 and 1 or 0)
  3413.                     local yrad_spr = y_speed >= -40 and 19 or 20
  3414.                     draw_rectangle(x_screen + xoff_spr, y_screen + yoff_spr, 12, yrad_spr, color_line, color_bg)
  3415.                 end
  3416.             end
  3417.            
  3418.             counter = counter + 1
  3419.         end
  3420.     end
  3421.    
  3422.     Text_opacity = 0.5
  3423.     local x_pos, y_pos, length = draw_text(Buffer_width + Border_right, y_pos, fmt("Ext. spr:%2d ", counter), COLOUR.weak, true, false, 0.0, 1.0)
  3424.    
  3425.     if u8(WRAM.spinjump_flag) ~= 0 and u8(WRAM.powerup) == 3 then
  3426.         local fireball_timer = u8(WRAM.spinjump_fireball_timer)
  3427.         draw_text(x_pos - length - SNES9X_FONT_WIDTH, y_pos, fmt("%d %s",
  3428.         fireball_timer%16, bit.test(fireball_timer, 4) and RIGHT_ARROW or LEFT_ARROW), COLOUR.extended_sprites, true, false, 1.0, 1.0)
  3429.     end
  3430.    
  3431. end
  3432.  
  3433.  
  3434. local function cluster_sprites()
  3435.     if not OPTIONS.display_cluster_sprite_info or u8(WRAM.cluspr_flag) == 0 then return end
  3436.    
  3437.     -- Font
  3438.     Text_opacity = 1.0
  3439.     local height = SNES9X_FONT_HEIGHT
  3440.     local x_pos, y_pos = AR_x*90, AR_y*57  -- Snes9x has no space to draw 20 lines
  3441.     local counter = 0
  3442.    
  3443.     if OPTIONS.display_debug_info and OPTIONS.display_debug_cluster_sprite then
  3444.         draw_text(x_pos, y_pos, "Cluster Spr.", COLOUR.weak)
  3445.         counter = counter + 1
  3446.     end
  3447.    
  3448.     local reappearing_boo_counter
  3449.    
  3450.     for id = 0, SMW2.cluster_sprite_max - 1 do
  3451.         local clusterspr_number = u8(WRAM.cluspr_number + id)
  3452.        
  3453.         if clusterspr_number ~= 0 then
  3454.             if not HITBOX_CLUSTER_SPRITE[clusterspr_number] then
  3455.                 print("Warning: wrong cluster sprite number:", clusterspr_number)  -- should not happen without cheats
  3456.                 return
  3457.             end
  3458.            
  3459.             -- Reads WRAM addresses
  3460.             local x = signed(256*u8(WRAM.cluspr_x_high + id) + u8(WRAM.cluspr_x_low + id), 16)
  3461.             local y = signed(256*u8(WRAM.cluspr_y_high + id) + u8(WRAM.cluspr_y_low + id), 16)
  3462.             local clusterspr_timer, special_info, table_1, table_2, table_3
  3463.            
  3464.             -- Reads cluster's table
  3465.             local x_screen, y_screen = screen_coordinates(x, y, Camera_x, Camera_y)
  3466.             local t = HITBOX_CLUSTER_SPRITE[clusterspr_number] or
  3467.                 {xoff = 0, yoff = 0, width = 16, height = 16, color_line = COLOUR.awkward_hitbox, color_bg = COLOUR.awkward_hitbox_bg, oscillation = 1}
  3468.             local xoff = t.xoff
  3469.             local yoff = t.yoff + Y_CAMERA_OFF
  3470.             local xrad = t.width
  3471.             local yrad = t.height
  3472.             local phase = t.phase or 0
  3473.             local oscillation = (Real_frame - id)%t.oscillation == phase
  3474.             local color = t.color or COLOUR.cluster_sprites
  3475.             local color_bg = t.bg or COLOUR.sprites_bg
  3476.             local invencibility_hitbox = nil
  3477.            
  3478.             if OPTIONS.display_debug_info and OPTIONS.display_debug_cluster_sprite then
  3479.                 table_1 = u8(WRAM.cluspr_table_1 + id)
  3480.                 table_2 = u8(WRAM.cluspr_table_2 + id)
  3481.                 table_3 = u8(WRAM.cluspr_table_3 + id)
  3482.                 draw_text(x_pos, y_pos + counter*height, ("#%d(%d): (%d, %d) %d, %d, %d")
  3483.                 :format(id, clusterspr_number, x, y, table_1, table_2, table_3), color)
  3484.                 counter = counter + 1
  3485.             end
  3486.            
  3487.             -- Case analysis
  3488.             if clusterspr_number == 3 or clusterspr_number == 8 then
  3489.                 clusterspr_timer = u8(WRAM.cluspr_timer + id)
  3490.                 if clusterspr_timer ~= 0 then special_info = " " .. clusterspr_timer end
  3491.             elseif clusterspr_number == 6 then
  3492.                 table_1 = table_1 or u8(WRAM.cluspr_table_1 + id)
  3493.                 if table_1 >= 111 or (table_1 < 31 and table_1 >= 16) then
  3494.                     yoff = yoff + 17
  3495.                 elseif table_1 >= 103 or table_1 < 16 then
  3496.                     invencibility_hitbox = true
  3497.                 elseif table_1 >= 95 or (table_1 < 47 and table_1 >= 31) then
  3498.                     yoff = yoff + 16
  3499.                 end
  3500.             elseif clusterspr_number == 7 then
  3501.                 reappearing_boo_counter = reappearing_boo_counter or u8(WRAM.reappearing_boo_counter)
  3502.                 invencibility_hitbox = (reappearing_boo_counter > 0xde) or (reappearing_boo_counter < 0x3f)
  3503.                 special_info = " " .. reappearing_boo_counter
  3504.             end
  3505.            
  3506.             -- Hitbox and sprite id
  3507.             color = invencibility_hitbox and COLOUR.weak or color
  3508.             color_bg = (invencibility_hitbox and 0) or (oscillation and color_bg) or 0
  3509.             draw_rectangle(x_screen + xoff, y_screen + yoff, xrad, yrad, color, color_bg)
  3510.             draw_text(AR_x*(x_screen + xoff) + xrad, AR_y*(y_screen + yoff), special_info and id .. special_info or id,
  3511.             color, false, false, 0.5, 1.0)
  3512.         end
  3513.     end
  3514. end
  3515.  
  3516.  
  3517. local function minor_extended_sprites()
  3518.     if not OPTIONS.display_minor_extended_sprite_info then return end
  3519.    
  3520.     -- Font
  3521.     gui.opacity(1.0)
  3522.     Text_opacity = 1.0
  3523.     local height = SNES9X_FONT_HEIGHT
  3524.     local x_pos, y_pos = 0, Buffer_height - height*SMW2.minor_extended_sprite_max
  3525.     local counter = 0
  3526.    
  3527.     for id = 0, SMW2.minor_extended_sprite_max - 1 do
  3528.         local minorspr_number = u8(WRAM.minorspr_number + id)
  3529.        
  3530.         if minorspr_number ~= 0 then
  3531.             -- Reads WRAM addresses
  3532.             local x = signed(256*u8(WRAM.minorspr_x_high + id) + u8(WRAM.minorspr_x_low + id), 16)
  3533.             local y = signed(256*u8(WRAM.minorspr_y_high + id) + u8(WRAM.minorspr_y_low + id), 16)
  3534.             local xspeed, yspeed = s8(WRAM.minorspr_xspeed + id), s8(WRAM.minorspr_yspeed + id)
  3535.             local x_sub, y_sub = u8(WRAM.minorspr_x_sub + id), u8(WRAM.minorspr_y_sub + id)
  3536.             local timer = u8(WRAM.minorspr_timer + id)
  3537.            
  3538.             -- Only sprites 1 and 10 use the higher byte
  3539.             local x_screen, y_screen = screen_coordinates(x, y, Camera_x, Camera_y)
  3540.             if minorspr_number ~= 1 and minorspr_number ~= 10 then  -- Boo stream and Piece of brick block
  3541.                 x_screen = x_screen%0x100
  3542.                 y_screen = y_screen%0x100
  3543.             end
  3544.            
  3545.             -- Draw next to the sprite
  3546.             local text = "#" .. id .. (timer ~= 0 and (" " .. timer) or "")
  3547.             draw_text(AR_x*(x_screen + 8), AR_y*(y_screen + 4), text, COLOUR.minor_extended_sprites, false, false, 0.5, 1.0)
  3548.             if minorspr_number == 10 then  -- Boo stream
  3549.                 draw_rectangle(x_screen + 4, y_screen + 4 + Y_CAMERA_OFF, 8, 8, COLOUR.minor_extended_sprites, COLOUR.sprites_bg)
  3550.             end
  3551.            
  3552.             -- Draw in the table
  3553.             if OPTIONS.display_debug_info and OPTIONS.display_debug_minor_extended_sprite then
  3554.                 draw_text(x_pos, y_pos + counter*height, ("#%d(%d): %d.%x(%d), %d.%x(%d)")
  3555.                 :format(id, minorspr_number, x, floor(x_sub/16), xspeed, y, floor(y_sub/16), yspeed), COLOUR.minor_extended_sprites)
  3556.             end
  3557.             counter = counter + 1
  3558.         end
  3559.     end
  3560.    
  3561.     if OPTIONS.display_debug_info and OPTIONS.display_debug_minor_extended_sprite then
  3562.         draw_text(x_pos, y_pos - height, "Minor Ext Spr:" .. counter, COLOUR.weak)
  3563.     end
  3564. end
  3565.  
  3566.  
  3567. local function bounce_sprite_info()
  3568.     if not OPTIONS.display_bounce_sprite_info then return end
  3569.    
  3570.     -- Debug info
  3571.     local x_txt, y_txt = AR_x*90, AR_y*37
  3572.     if OPTIONS.display_debug_info and OPTIONS.display_debug_bounce_sprite then
  3573.         Text_opacity = 0.5
  3574.         draw_text(x_txt, y_txt, "Bounce Spr.", COLOUR.weak)
  3575.     end
  3576.    
  3577.     -- Font
  3578.     Text_opacity = 0.6
  3579.     local height = SNES9X_FONT_HEIGHT
  3580.    
  3581.     local stop_id = (u8(WRAM.bouncespr_last_id) - 1)%SMW2.bounce_sprite_max
  3582.     for id = 0, SMW2.bounce_sprite_max - 1 do
  3583.         local bounce_sprite_number = u8(WRAM.bouncespr_number + id)
  3584.         if bounce_sprite_number ~= 0 then
  3585.             local x = 256*u8(WRAM.bouncespr_x_high + id) + u8(WRAM.bouncespr_x_low + id)
  3586.             local y = 256*u8(WRAM.bouncespr_y_high + id) + u8(WRAM.bouncespr_y_low + id)
  3587.             local bounce_timer = u8(WRAM.bouncespr_timer + id)
  3588.            
  3589.             if OPTIONS.display_debug_info and OPTIONS.display_debug_bounce_sprite then
  3590.                 draw_text(x_txt, y_txt + height*(id + 1), fmt("#%d:%d (%d, %d)", id, bounce_sprite_number, x, y))
  3591.             end
  3592.            
  3593.             local x_screen, y_screen = screen_coordinates(x, y, Camera_x, Camera_y)
  3594.             x_screen, y_screen = AR_x*(x_screen + 8), AR_y*y_screen
  3595.             local color = id == stop_id and COLOUR.warning or COLOUR.text
  3596.             draw_text(x_screen , y_screen, fmt("#%d:%d", id, bounce_timer), color, false, false, 0.5)  -- timer
  3597.            
  3598.             -- Turn blocks
  3599.             if bounce_sprite_number == 7 then
  3600.                 turn_block_timer = u8(WRAM.turn_block_timer + id)
  3601.                 draw_text(x_screen, y_screen + height, turn_block_timer, color, false, false, 0.5)
  3602.             end
  3603.         end
  3604.     end
  3605. end
  3606.  
  3607.  
  3608. local function sprite_info(id, counter, table_position)
  3609.     Text_opacity = 1.0
  3610.    
  3611.     -- id to read memory correctly
  3612.     local id_off = 4*id
  3613.    
  3614.     local sprite_status = u8(SFXRAM.sprite_status + id_off)
  3615.     if sprite_status == 0 then return 0 end  -- returns if the slot is empty
  3616.    
  3617.     local sprite_type = u16(SFXRAM.sprite_type + id_off)
  3618.     local x = s16(SFXRAM.sprite_x + id_off + 2)
  3619.     local y = s16(SFXRAM.sprite_y + id_off + 2)
  3620.     local x_speed = s8(SFXRAM.sprite_x_speed + id_off)
  3621.     local x_subspeed = u8(SFXRAM.sprite_x_subspeed + id_off)
  3622.     local y_speed = s8(SFXRAM.sprite_y_speed + id_off)
  3623.     local y_subspeed = u8(SFXRAM.sprite_y_subspeed + id_off)
  3624.     local x_centered = u16(SFXRAM.sprite_x_center + id_off)
  3625.     local y_centered = u16(SFXRAM.sprite_y_center + id_off)
  3626.     --local x_sub = u8(WRAM.sprite_x_sub + id_off)
  3627.     --local y_sub = u8(WRAM.sprite_y_sub + id_off)
  3628.     --local stun = u8(WRAM.sprite_miscellaneous7 + id_off)
  3629.     --local underwater = u8(WRAM.sprite_underwater + id_off)
  3630.     --local x_offscreen = s8(WRAM.sprite_x_offscreen + id_off)
  3631.     --local y_offscreen = s8(WRAM.sprite_y_offscreen + id_off)
  3632.    
  3633.     sprite_type = string.upper(fmt("%03x", sprite_type)) -- to make it easier to read
  3634.    
  3635.     local special = ""
  3636.     --[[if (OPTIONS.display_debug_info and OPTIONS.display_debug_sprite_extra) or
  3637.     ((sprite_status ~= 0x8 and sprite_status ~= 0x9 and sprite_status ~= 0xa and sprite_status ~= 0xb) or stun ~= 0) then
  3638.         special = string.format("(%d %d) ", sprite_status, stun)
  3639.     end]] -- TODO
  3640.    
  3641.     ---**********************************************
  3642.     -- Calculates the sprites dimensions and screen positions
  3643.    
  3644.     local x_screen, y_screen = screen_coordinates(x, y, Camera_x, Camera_y)
  3645.     local x_centered_screen, y_centered_screen = screen_coordinates(x_centered, y_centered, Camera_x, Camera_y)
  3646.    
  3647.     if Game_mode == 0x0007 then -- adjustment for the intro "glitched" sprite positions
  3648.         x_screen = x_screen + Camera_x
  3649.         if Camera_y ~= 0 then
  3650.             y_screen = y_screen + Camera_y
  3651.         end
  3652.     --elseif Game_mode == 0x002C then y_screen = y_screen - 256
  3653.     end
  3654.    
  3655.     -- Sprite clipping vs mario and sprites
  3656.     local boxid = bit.band(u8(WRAM.sprite_2_tweaker + id_off), 0x3f)  -- This is the type of box of the sprite
  3657.     local xoff = HITBOX_SPRITE[boxid].xoff
  3658.     local yoff = HITBOX_SPRITE[boxid].yoff + Y_CAMERA_OFF
  3659.     local sprite_half_width = u16(SFXRAM.sprite_hitbox_half_width + id_off)  --HITBOX_SPRITE[boxid].width
  3660.     local sprite_half_height = u16(SFXRAM.sprite_hitbox_half_height + id_off)   --HITBOX_SPRITE[boxid].height
  3661.    
  3662.     -- Sprite clipping vs objects
  3663.     local clip_obj = bit.band(u8(WRAM.sprite_1_tweaker + id_off), 0xf)  -- type of hitbox for blocks
  3664.     local xpt_right = OBJ_CLIPPING_SPRITE[clip_obj].xright
  3665.     local ypt_right = OBJ_CLIPPING_SPRITE[clip_obj].yright
  3666.     local xpt_left = OBJ_CLIPPING_SPRITE[clip_obj].xleft
  3667.     local ypt_left = OBJ_CLIPPING_SPRITE[clip_obj].yleft
  3668.     local xpt_down = OBJ_CLIPPING_SPRITE[clip_obj].xdown
  3669.     local ypt_down = OBJ_CLIPPING_SPRITE[clip_obj].ydown
  3670.     local xpt_up = OBJ_CLIPPING_SPRITE[clip_obj].xup
  3671.     local ypt_up = OBJ_CLIPPING_SPRITE[clip_obj].yup
  3672.    
  3673.     -- Process interaction with player every frame?
  3674.     -- Format: dpmksPiS. This 'm' bit seems odd, since it has false negatives
  3675.     local oscillation_flag = bit.test(u8(WRAM.sprite_4_tweaker + id_off), 5) or OSCILLATION_SPRITES[number]
  3676.    
  3677.     -- calculates the correct color to use, according to id
  3678.     local info_color = COLOUR.sprites[id%(#COLOUR.sprites) + 1]
  3679.     local color_background = COLOUR.sprites_bg
  3680.     --[[ sprite_type == 0x35 then -- TODO
  3681.         info_color = COLOUR.yoshi
  3682.         color_background = COLOUR.yoshi_bg
  3683.     else
  3684.         info_color = COLOUR.sprites[id%(#COLOUR.sprites) + 1]
  3685.         color_background = COLOUR.sprites_bg
  3686.     end]]
  3687.    
  3688.    
  3689.     --[[if (not oscillation_flag) and (Real_frame - id)%2 == 1 then color_background = 0 end     -- due to sprite oscillation every other frame
  3690.                                                                                     -- notice that some sprites interact with Mario every frame
  3691.     ;]] -- TODO
  3692.    
  3693.    
  3694.     ---**********************************************
  3695.     -- Displays sprites hitboxes -- TODO
  3696.     if OPTIONS.display_sprite_hitbox then
  3697.    
  3698.         gui.crosshair(x_centered_screen, y_centered_screen, 2, COLOUR.text)
  3699.        
  3700.         draw_box(x_centered_screen - sprite_half_width, y_centered_screen - sprite_half_height, x_centered_screen + sprite_half_width, y_centered_screen + sprite_half_height, info_color)
  3701.        
  3702.         --[[
  3703.         -- That's the pixel that appears when the sprite vanishes in the pit
  3704.         if y_screen >= 224 or (OPTIONS.display_debug_info and OPTIONS.display_debug_sprite_extra) then
  3705.             draw_pixel(x_screen, y_screen, info_color)
  3706.         end
  3707.        
  3708.         if Sprite_hitbox[id][sprite_type].block then
  3709.             draw_box(x_screen + xpt_left, y_screen + ypt_down, x_screen + xpt_right, y_screen + ypt_up,
  3710.                 COLOUR.sprites_clipping_bg, Sprite_hitbox[id][sprite_type].sprite and 0 or COLOUR.sprites_clipping_bg)
  3711.         end
  3712.        
  3713.         if Sprite_hitbox[id][sprite_type].sprite and not ABNORMAL_HITBOX_SPRITES[sprite_type] then  -- show sprite/sprite clipping
  3714.             draw_rectangle(x_screen + xoff, y_screen + yoff, sprite_width, sprite_height, info_color, color_background)
  3715.         end
  3716.        
  3717.         if Sprite_hitbox[id][sprite_type].block then  -- show sprite/object clipping
  3718.             local size, color = 1, COLOUR.sprites_interaction_pts
  3719.             draw_line(x_screen + xpt_right, y_screen + ypt_right, x_screen + xpt_right - size, y_screen + ypt_right, 1, color) -- right
  3720.             draw_line(x_screen + xpt_left, y_screen + ypt_left, x_screen + xpt_left + size, y_screen + ypt_left, 1, color)  -- left
  3721.             draw_line(x_screen + xpt_down, y_screen + ypt_down, x_screen + xpt_down, y_screen + ypt_down - size, 1, color) -- down
  3722.             draw_line(x_screen + xpt_up, y_screen + ypt_up, x_screen + xpt_up, y_screen + ypt_up + size, 1, color)  -- up
  3723.         end]]
  3724.     end
  3725.    
  3726.    
  3727.     ---**********************************************
  3728.     -- Special sprites analysis:
  3729.    
  3730.     -- Toadies
  3731.     if sprite_type == "091" then
  3732.         for id = 0, 3 do
  3733.             local toadies_x = s16(WRAM.toadies_relative_x + 4*id) + x
  3734.             local toadies_y = s16(WRAM.toadies_relative_y + 4*id) + y
  3735.            
  3736.             -- Position
  3737.             local toadies_x_screen, toadies_y_screen = screen_coordinates(toadies_x, toadies_y, Camera_x, Camera_y)
  3738.             gui.crosshair(toadies_x_screen, toadies_y_screen, 2, "blue")
  3739.            
  3740.             -- Table
  3741.             draw_text(Buffer_width + Border_right, 176, "Toadies:", "red", true)
  3742.             local toadies_str = fmt("{%02d} %d, %d", id, toadies_x, toadies_y)
  3743.             draw_text(Buffer_width + Border_right, 184 + id*SNES9X_FONT_HEIGHT, toadies_str, "red", true)
  3744.         end
  3745.     end
  3746.    
  3747.     ---**********************************************
  3748.     -- Prints those informations next to the sprite
  3749.     Text_opacity = 0.7  -- Snes9x
  3750.     Bg_opacity = 1.0
  3751.    
  3752.     if x_screen >= 0 and x_screen <= 256 and y_screen >= 0 and y_screen <= 224 then
  3753.         Text_opacity = 0.8
  3754.     else
  3755.         Text_opacity = 0.5
  3756.     end
  3757.    
  3758.     draw_text(x_screen + 8, y_screen - 5, fmt("<%02d>", id), info_color, COLOUR.background, COLOUR.halo, true)
  3759.    
  3760.     -- Sprite position pixel and cross
  3761.     draw_pixel(x_screen, y_screen, info_color, COLOUR.background)
  3762.     if OPTIONS.display_debug_sprite_extra then
  3763.         gui.crosshair(x_screen, y_screen, 2, info_color)
  3764.     end
  3765.    
  3766.     ---**********************************************
  3767.     -- The sprite table:
  3768.    
  3769.     --[[cal x_speed_water = "" -- TODO
  3770.     if underwater ~= 0 then  -- if sprite is underwater
  3771.         local correction = floor(3*floor(x_speed/2)/2)
  3772.         x_speed_water = string.format("%+.2d=%+.2d", correction - x_speed, correction)
  3773.     end]]
  3774.     --local sprite_str = fmt("#%02d %02x %s%d.%1x(%+.2d%s) %d.%1x(%+.2d)",
  3775.                     --id, sprite_type, special, x, floor(x_sub/16), x_speed, x_speed_water, y, floor(y_sub/16), y_speed)
  3776.    
  3777.     --special = string.upper(fmt("[%02x] ", sprite_status)) -- REMOVE
  3778.    
  3779.     local sprite_str = fmt("<%02d> %s %s%d(%+d.%02x), %d(%+d.%02x)", id, sprite_type, special, x, x_speed, x_subspeed, y, y_speed, y_subspeed)        
  3780.    
  3781.     --Text_opacity = 1.0
  3782.     Bg_opacity = 1.0
  3783.     if x_screen >= 0 and x_screen <= 256 and y_screen >= 0 and y_screen <= 224 then
  3784.         Text_opacity = 0.8
  3785.     else
  3786.         Text_opacity = 0.5
  3787.     end
  3788.    
  3789.     draw_text(Buffer_width + Border_right, table_position + counter*SNES9X_FONT_HEIGHT, sprite_str, info_color, true)
  3790.    
  3791.     -- Miscellaneous sprite table
  3792.     if OPTIONS.display_miscellaneous_sprite_table then
  3793.         -- Font
  3794.         Font = false
  3795.         local x_mis, y_mis = 0, AR_y*144 + counter*SNES9X_FONT_HEIGHT
  3796.        
  3797.         local t = OPTIONS.miscellaneous_sprite_table_number
  3798.         local misc, text = nil, fmt("#%.2d", id)
  3799.         for num = 1, 19 do
  3800.             misc = t[num] and u8(WRAM["sprite_miscellaneous" .. num] + id_off) or false
  3801.             text = misc and fmt("%s %3d", text, misc) or text
  3802.         end
  3803.        
  3804.         draw_text(x_mis, y_mis, text, info_color)
  3805.     end
  3806.    
  3807.     ---**********************************************
  3808.     -- Exporting some values
  3809.     Sprites_info[id].sprite_type = sprite_type
  3810.     Sprites_info[id].sprite_status = sprite_status
  3811.     Sprites_info[id].x, Sprites_info[id].y = x, y
  3812.     Sprites_info[id].x_screen, Sprites_info[id].y_screen = x_screen, y_screen
  3813.     Sprites_info[id].boxid = boxid
  3814.     Sprites_info[id].xoff, Sprites_info[id].yoff = xoff, yoff
  3815.     Sprites_info[id].width, Sprites_info[id].height = sprite_width, sprite_height
  3816.    
  3817.     return 1
  3818. end
  3819.  
  3820.  
  3821. local function sprites()
  3822.     if not OPTIONS.display_sprite_info then return end
  3823.     if Is_paused then return end
  3824.    
  3825.     local valid_game_mode = false
  3826.     if Game_mode == SMW2.game_mode_level then valid_game_mode = true
  3827.     elseif Game_mode == 0x0007 then valid_game_mode = true end -- Intro (0x0007) too
  3828.     if valid_game_mode == false then return end
  3829.    
  3830.     local counter = 0
  3831.     local table_position = AR_y*22
  3832.     for id = 0, SMW2.sprite_max - 1 do
  3833.         counter = counter + sprite_info(id, counter, table_position)
  3834.     end
  3835.    
  3836.     -- Font
  3837.     Text_opacity = 0.6 -- Snes9x
  3838.    
  3839.  
  3840.     draw_text(Buffer_width + Border_right, table_position - SNES9X_FONT_HEIGHT, fmt("spr:%.2d", counter), COLOUR.weak, true)
  3841.     --
  3842.     -- Miscellaneous sprite table: index
  3843.     if OPTIONS.display_miscellaneous_sprite_table then
  3844.         Font = false
  3845.        
  3846.         local t = OPTIONS.miscellaneous_sprite_table_number
  3847.         local text = "Tab"
  3848.         for num = 1, 19 do
  3849.             text = t[num] and fmt("%s %3d", text, num) or text
  3850.         end
  3851.        
  3852.         draw_text(0, AR_y*144 - SNES9X_FONT_HEIGHT, text, info_color)
  3853.     end
  3854. end
  3855.  
  3856.  
  3857. local function yoshi()
  3858.     if not OPTIONS.display_yoshi_info then return end
  3859.    
  3860.     -- Font
  3861.     Text_opacity = 1.0
  3862.     Bg_opacity = 1.0
  3863.     local x_text = 0
  3864.     local y_text = AR_y*88
  3865.    
  3866.     local yoshi_id = Yoshi_id
  3867.     if yoshi_id ~= nil then
  3868.         local eat_id = u8(WRAM.sprite_miscellaneous16 + yoshi_id)
  3869.         local eat_type = u8(WRAM.sprite_number + eat_id)
  3870.         local tongue_len = u8(WRAM.sprite_miscellaneous4 + yoshi_id)
  3871.         local tongue_timer = u8(WRAM.sprite_miscellaneous9 + yoshi_id)
  3872.         local tongue_wait = u8(WRAM.sprite_tongue_wait)
  3873.         local tongue_height = u8(WRAM.yoshi_tile_pos)
  3874.         local tongue_out = u8(WRAM.sprite_miscellaneous13 + yoshi_id)
  3875.        
  3876.         local eat_type_str = eat_id == SMW2.null_sprite_id and "-" or string.format("%02x", eat_type)
  3877.         local eat_id_str = eat_id == SMW2.null_sprite_id and "-" or string.format("#%02d", eat_id)
  3878.        
  3879.         -- Yoshi's direction and turn around
  3880.         local turn_around = u8(WRAM.sprite_miscellaneous14 + yoshi_id)
  3881.         local yoshi_direction = u8(WRAM.sprite_miscellaneous12 + yoshi_id)
  3882.         local direction_symbol
  3883.         if yoshi_direction == 0 then direction_symbol = RIGHT_ARROW else direction_symbol = LEFT_ARROW end
  3884.        
  3885.         draw_text(x_text, y_text, fmt("Yoshi %s %d", direction_symbol, turn_around), COLOUR.yoshi)
  3886.         local h = SNES9X_FONT_HEIGHT
  3887.        
  3888.         if eat_id == SMW2.null_sprite_id and tongue_len == 0 and tongue_timer == 0 and tongue_wait == 0 then
  3889.             Text_opacity = 0.2 -- Snes9x
  3890.         end
  3891.         draw_text(x_text, y_text + h, fmt("(%0s, %0s) %02d, %d, %d",
  3892.                             eat_id_str, eat_type_str, tongue_len, tongue_wait, tongue_timer), COLOUR.yoshi)
  3893.         ;
  3894.        
  3895.         -- more WRAM values
  3896.         local yoshi_x = 256*u8(WRAM.sprite_x_high + yoshi_id) + u8(WRAM.sprite_x_low + yoshi_id)
  3897.         local yoshi_y = 256*u8(WRAM.sprite_y_high + yoshi_id) + u8(WRAM.sprite_y_low + yoshi_id)
  3898.         local x_screen, y_screen = screen_coordinates(yoshi_x, yoshi_y, Camera_x, Camera_y)
  3899.        
  3900.         -- invisibility timer
  3901.         local mount_invisibility = u8(WRAM.sprite_miscellaneous18 + yoshi_id)
  3902.         if mount_invisibility ~= 0 then
  3903.             Text_opacity = 0.5 -- Snes9x
  3904.             draw_text(AR_x*(x_screen + 4), AR_y*(y_screen - 12), mount_invisibility, COLOUR.yoshi)
  3905.         end
  3906.        
  3907.         -- Tongue hitbox and timer
  3908.         if tongue_wait ~= 0 or tongue_out ~=0 or tongue_height == 0x89 then  -- if tongue is out or appearing
  3909.             -- the position of the hitbox pixel
  3910.             local tongue_direction = yoshi_direction == 0 and 1 or -1
  3911.             local tongue_high = tongue_height ~= 0x89
  3912.             local x_tongue = x_screen + 24 - 40*yoshi_direction + tongue_len*tongue_direction
  3913.             x_tongue = not tongue_high and x_tongue or x_tongue - 5*tongue_direction
  3914.             local y_tongue = y_screen + 10 + 11*(tongue_high and 0 or 1)
  3915.            
  3916.             -- the drawing
  3917.             local tongue_line
  3918.             if tongue_wait <= 9  then  -- hitbox point vs berry tile
  3919.                 draw_rectangle(x_tongue - 1, y_tongue - 1, 2, 2, COLOUR.tongue_bg, COLOUR.text)
  3920.                 tongue_line = COLOUR.tongue_line
  3921.             else tongue_line = COLOUR.tongue_bg
  3922.             end
  3923.            
  3924.             -- tongue out: time predictor
  3925.             local tinfo, tcolor
  3926.             if tongue_wait > 9 then tinfo = tongue_wait - 9; tcolor = COLOUR.tongue_line  -- not ready yet
  3927.            
  3928.             elseif tongue_out == 1 then tinfo = 17 + tongue_wait; tcolor = COLOUR.text  -- tongue going out
  3929.            
  3930.             elseif tongue_out == 2 then  -- at the max or tongue going back
  3931.                 tinfo = math.max(tongue_wait, tongue_timer) + floor((tongue_len + 7)/4) - (tongue_len ~= 0 and 1 or 0)
  3932.                 tcolor = eat_id == SMW2.null_sprite_id and COLOUR.text or COLOUR.warning
  3933.            
  3934.             elseif tongue_out == 0 then tinfo = 0; tcolor = COLOUR.text  -- tongue in
  3935.            
  3936.             else tinfo = tongue_timer + 1; tcolor = COLOUR.tongue_line -- item was just spat out
  3937.             end
  3938.            
  3939.             Text_opacity = 0.5 -- Snes9x
  3940.             draw_text(AR_x*(x_tongue + 4), AR_y*(y_tongue + 5), tinfo, tcolor, false, false, 0.5)
  3941.             Text_opacity = 1.0
  3942.             draw_rectangle(x_tongue, y_tongue + 1, 8, 4, tongue_line, COLOUR.tongue_bg)
  3943.         end
  3944.        
  3945.     end
  3946. end
  3947.  
  3948.  
  3949. local function show_counters()
  3950.     if not OPTIONS.display_counters then return end
  3951.    
  3952.     -- Font
  3953.     Text_opacity = 1.0
  3954.     Bg_opacity = 1.0
  3955.     local height = SNES9X_FONT_HEIGHT
  3956.     local text_counter = 0
  3957.    
  3958.     local invincibility_timer = u16(SFXRAM.invincibility_timer)
  3959.     local eat_timer = u16(SFXRAM.eat_timer)
  3960.     local transform_timer = u16(SFXRAM.transform_timer)
  3961.     local star_timer = u16(SFXRAM.star_timer)
  3962.     local switch_timer = u16(WRAM.switch_timer)
  3963.     --local end_level_timer = u8(SFXRAM.end_level_timer)
  3964.    
  3965.     local display_counter = function(label, value, default, mult, frame, color)
  3966.         if value == default then return end
  3967.         text_counter = text_counter + 1
  3968.         local color = color or COLOUR.text
  3969.        
  3970.         draw_text(0, AR_y*102 + (text_counter * height), fmt("%s: %d", label, (value * mult) - frame), color)
  3971.     end
  3972.    
  3973.     if Player_animation_trigger == 5 or Player_animation_trigger == 6 then
  3974.         display_counter("Pipe", pipe_entrance_timer, -1, 1, 0, COLOUR.counter_pipe)
  3975.     end
  3976.     display_counter("Invincibility", invincibility_timer, 0, 1, 0, COLOUR.counter_pballoon)
  3977.     display_counter("Swallow", eat_timer, 0, 1, 0, COLOUR.counter_multicoin)
  3978.     display_counter("Transform", transform_timer, 0, 1, 0, COLOUR.counter_gray_pow)
  3979.     display_counter("Star", star_timer, 0, 1, 0, COLOUR.counter_blue_pow)
  3980.     if Game_mode == SMW2.game_mode_level then
  3981.         display_counter("Switch", switch_timer, 0, 1, 0, COLOUR.counter_dircoin)
  3982.     end
  3983.     --display_counter("End Level", end_level_timer, 0, 2, (Real_frame - 1) % 2)
  3984.    
  3985.     --if Lock_animation_flag ~= 0 then display_counter("Animation", animation_timer, 0, 1, 0) end  -- shows when player is getting hurt or dying
  3986.    
  3987. end
  3988.  
  3989.  
  3990. -- Main function to run inside a level
  3991. local function level_mode()
  3992.     --if Game_mode == SMW2.game_mode_level then
  3993.        
  3994.         -- Draws/Erases the tiles if user clicked
  3995.         draw_tilesets(Camera_x, Camera_y)
  3996.        
  3997.         --draw_layer1_tiles(Camera_x, Camera_y)
  3998.        
  3999.         --draw_layer2_tiles()
  4000.        
  4001.         sprites()
  4002.        
  4003.         --extended_sprites()
  4004.        
  4005.         --cluster_sprites()
  4006.        
  4007.         --minor_extended_sprites()
  4008.        
  4009.         --bounce_sprite_info()
  4010.        
  4011.         level_info()
  4012.        
  4013.         player()
  4014.        
  4015.         --yoshi()
  4016.        
  4017.         show_counters()
  4018.        
  4019.         -- Draws/Erases the hitbox for objects
  4020.         if true or User_input.mouse_inwindow == 1 then
  4021.             select_object(User_input.xmouse, User_input.ymouse, Camera_x, Camera_y)
  4022.         end
  4023.        
  4024.     --end
  4025. end
  4026.  
  4027.  
  4028. local function overworld_mode() -- TODO
  4029.     --[[if Game_mode ~= SMW2.game_mode_overworld then return end
  4030.    
  4031.     -- Font
  4032.     Text_opacity = 1.0
  4033.     Bg_opacity = 1.0
  4034.    
  4035.     local height = SNES9X_FONT_HEIGHT
  4036.     local y_text = SNES9X_FONT_HEIGHT
  4037.    
  4038.     -- Real frame modulo 8
  4039.     local real_frame_8 = Real_frame%8
  4040.     draw_text(Buffer_width + Border_right, y_text, fmt("Real Frame = %3d = %d(mod 8)", Real_frame, real_frame_8), true)
  4041.    
  4042.     -- Star Road info
  4043.     local star_speed = u8(WRAM.star_road_speed)
  4044.     local star_timer = u8(WRAM.star_road_timer)
  4045.     y_text = y_text + height
  4046.     draw_text(Buffer_width + Border_right, y_text, fmt("Star Road(%x %x)", star_speed, star_timer), COLOUR.cape, true)]]
  4047. end
  4048.  
  4049.  
  4050. local function left_click()
  4051.     for _, field in pairs(Script_buttons) do
  4052.        
  4053.         -- if mouse is over the button
  4054.         if mouse_onregion(field.x, field.y, field.x + field.width, field.y + field.height) then
  4055.                 field.action()
  4056.                 return
  4057.         end
  4058.     end
  4059.    
  4060.     -- Drag and drop sprites
  4061.     if Cheat.allow_cheats then
  4062.         local id = select_object(User_input.xmouse, User_input.ymouse, Camera_x, Camera_y)
  4063.         if type(id) == "number" and id >= 0 and id < SMW2.sprite_max then
  4064.             Cheat.dragging_sprite_id = id
  4065.             Cheat.is_dragging_sprite = true
  4066.             return
  4067.         end
  4068.     end
  4069.    
  4070.     if not Options_menu.show_menu then
  4071.         select_tile()
  4072.     end    
  4073.    
  4074.     -- Layer 1 tiles
  4075.     --[[local x_mouse, y_mouse = game_coordinates(User_input.xmouse, User_input.ymouse, Camera_x, Camera_y)
  4076.     x_mouse = 16*floor(x_mouse/16)
  4077.     y_mouse = 16*floor(y_mouse/16)
  4078.     if not Options_menu.show_menu then
  4079.         select_tile(x_mouse, y_mouse, Layer1_tiles)
  4080.     end]]
  4081. end
  4082.  
  4083.  
  4084. -- This function runs at the end of paint callback
  4085. -- Specific for info that changes if the emulator is paused and idle callback is called
  4086. local function snes9x_buttons()
  4087.     -- Font
  4088.     Text_opacity = 1.0
  4089.    
  4090.     if not Options_menu.show_menu and User_input.mouse_inwindow == 1 then
  4091.         create_button(100, -Border_top, " Menu ", function() Options_menu.show_menu = true end) -- Snes9x
  4092.        
  4093.         create_button(-Border_left, Buffer_height - Border_bottom, Cheat.allow_cheats and "Cheats: allowed" or "Cheats: blocked",
  4094.             function() Cheat.allow_cheats = not Cheat.allow_cheats end, {always_on_client = true, ref_y = 1.0})
  4095.         ;
  4096.        
  4097.         create_button(Buffer_width + Border_right, Buffer_height + Border_bottom, "Erase Tiles",
  4098.             function() Tiletable = {} end, {always_on_client = true, ref_y = 1.0})
  4099.         ;
  4100.     else
  4101.         if Cheat.allow_cheats then  -- show cheat status anyway
  4102.             Text_opacity = 0.8
  4103.             draw_text(-Border_left, Buffer_height + Border_bottom, "Cheats: allowed", COLOUR.warning, true, false, 0, 1)
  4104.         end
  4105.     end
  4106.    
  4107.     -- Drag and drop sprites with the mouse
  4108.     if Cheat.is_dragging_sprite then
  4109.         Cheat.drag_sprite(Cheat.dragging_sprite_id)
  4110.         Cheat.is_cheating = true
  4111.     end
  4112.    
  4113.     Options_menu.display()
  4114. end
  4115.  
  4116.  
  4117.  
  4118. --#############################################################################
  4119. -- CHEATS
  4120.  
  4121. -- This signals that some cheat is activated, or was some short time ago
  4122. Cheat.allow_cheats = false
  4123. Cheat.is_cheating = false
  4124. function Cheat.is_cheat_active()
  4125.     if Cheat.is_cheating then
  4126.         alert_text(Buffer_middle_x - 3*SNES9X_FONT_WIDTH, 0, " Cheat ", COLOUR.warning,COLOUR.warning_bg)
  4127.         Previous.is_cheating = true
  4128.     else
  4129.         if Previous.is_cheating then
  4130.             emu.message("Script applied cheat")
  4131.             Previous.is_cheating = false
  4132.         end
  4133.     end
  4134. end
  4135.  
  4136.  
  4137. -- Called from Cheat.beat_level()
  4138. function Cheat.activate_next_level(secret_exit)
  4139.     if u8(WRAM.level_exit_type) == 0x80 and u8(WRAM.midway_point) == 1 then
  4140.         if secret_exit then
  4141.             w8(WRAM.level_exit_type, 0x2)
  4142.         else
  4143.             w8(WRAM.level_exit_type, 1)
  4144.         end
  4145.     end
  4146.    
  4147.     Cheat.is_cheating = true
  4148. end
  4149.  
  4150.  
  4151. -- allows start + select + X to activate the normal exit
  4152. --        start + select + A to activate the secret exit
  4153. --        start + select + B to exit the level without activating any exits
  4154. function Cheat.beat_level()
  4155.     if Is_paused and Joypad["select"] and (Joypad["X"] or Joypad["A"] or Joypad["B"]) then
  4156.         w8(WRAM.level_flag_table + Level_index, bit.bor(Level_flag, 0x80))
  4157.        
  4158.         local secret_exit = Joypad["A"]
  4159.         if not Joypad["B"] then
  4160.             w8(WRAM.midway_point, 1)
  4161.         else
  4162.             w8(WRAM.midway_point, 0)
  4163.         end
  4164.        
  4165.         Cheat.activate_next_level(secret_exit)
  4166.     end
  4167. end
  4168.  
  4169.  
  4170. -- This function makes Mario's position free
  4171. -- Press L+R+up to activate and L+R+down to turn it off.
  4172. -- While active, press directionals to fly free and Y or X to boost him up
  4173. Cheat.under_free_move = false
  4174. function Cheat.free_movement()
  4175.     if (Joypad["L"] and Joypad["R"] and Joypad["up"]) then Cheat.under_free_move = true end
  4176.     if (Joypad["L"] and Joypad["R"] and Joypad["down"]) then Cheat.under_free_move = false end
  4177.     if not Cheat.under_free_move then
  4178.         if Previous.under_free_move then return end -- w8(SFXRAM.is_frozen, 0) end
  4179.         return
  4180.     end
  4181.    
  4182.     local x_pos, y_pos = u16(SFXRAM.x), u16(SFXRAM.y)
  4183.     --local movement_mode = u8(WRAM.player_animation_trigger)
  4184.     local pixels = (Joypad["Y"] and 7) or (Joypad["X"] and 4) or 1  -- how many pixels per frame
  4185.    
  4186.     -- Math
  4187.     if Joypad["left"] then x_pos = x_pos - pixels end
  4188.     if Joypad["right"] then x_pos = x_pos + pixels end
  4189.     if Joypad["up"] then y_pos = y_pos - pixels end
  4190.     if Joypad["down"] then y_pos = y_pos + pixels end
  4191.    
  4192.     -- Disable normal button behavior
  4193.     if Joypad["down"] then pad_send[1].down = false end -- avoid ground pound
  4194.     --if Joypad["down"] then gui.text(100, 100, "down", COLOUR.text) end
  4195.     if Joypad["A"] then pad_send[1].A = false end -- avoid throwing egg
  4196.     --if Joypad["A"] then gui.text(100, 100, "A", COLOUR.text) end
  4197.     if Joypad["B"] then pad_send[1].B = false end -- avoid "jumping"
  4198.     --if Joypad["B"] then gui.text(100, 100, "B", COLOUR.text) end
  4199.     if Joypad["Y"] then pad_send[1].Y = false end -- avoid licking
  4200.     --if Joypad["Y"] then gui.text(100, 100, "Y", COLOUR.text) end
  4201.     joypad.set(1, pad_send[1]) -- set
  4202.    
  4203.    
  4204.     --[[ freeze player to avoid deaths
  4205.     if movement_mode == 0 then
  4206.         w8(WRAM.frozen, 1)
  4207.         w8(WRAM.x_speed, 0)
  4208.         w8(WRAM.y_speed, 0)
  4209.        
  4210.         -- animate sprites by incrementing the effective frame
  4211.         w8(WRAM.effective_frame, (u8(WRAM.effective_frame) + 1) % 256)
  4212.     else
  4213.         w8(WRAM.frozen, 0)
  4214.     end]]
  4215.    
  4216.     -- manipulate some values
  4217.     w16(SFXRAM.x, x_pos)
  4218.     w16(SFXRAM.y, y_pos)
  4219.     w8(SFXRAM.x_speed, 0)
  4220.     w8(SFXRAM.x_subspeed, 0)
  4221.     w8(SFXRAM.y_speed, -1)
  4222.     w8(SFXRAM.y_subspeed, 96)
  4223.     w8(SFXRAM.invincibility_timer, 120)
  4224.    
  4225.     --w8(WRAM.invincibility_timer, 127)
  4226.     --[[w8(WRAM.vertical_scroll_flag_header, 1)  -- free vertical scrolling
  4227.     w8(WRAM.vertical_scroll_enabled, 1)]]
  4228.    
  4229.     Cheat.is_cheating = true
  4230.     Previous.under_free_move = true
  4231. end
  4232.  
  4233.  
  4234. -- Drag and drop sprites with the mouse, if the cheats are activated and mouse is over the sprite
  4235. -- Right clicking and holding: drags the sprite
  4236. -- Releasing: drops it over the latest spot
  4237. function Cheat.drag_sprite(id)
  4238.     --if Game_mode ~= SMW2.game_mode_level then Cheat.is_dragging_sprite = false ; return end
  4239.    
  4240.     local xoff, yoff = Sprites_info[id].xoff, Sprites_info[id].yoff
  4241.     local xgame, ygame = game_coordinates(User_input.xmouse - xoff, User_input.ymouse - yoff, Camera_x, Camera_y)
  4242.    
  4243.     local sprite_xhigh = floor(xgame/256)
  4244.     local sprite_xlow = xgame - 256*sprite_xhigh
  4245.     local sprite_yhigh = floor(ygame/256)
  4246.     local sprite_ylow = ygame - 256*sprite_yhigh
  4247.    
  4248.     w8(WRAM.sprite_x_high + id, sprite_xhigh)
  4249.     w8(WRAM.sprite_x_low + id, sprite_xlow)
  4250.     w8(WRAM.sprite_y_high + id, sprite_yhigh)
  4251.     w8(WRAM.sprite_y_low + id, sprite_ylow)
  4252. end
  4253.  
  4254.  
  4255. -- Snes9x: modifies address <address> value from <current> to <current + modification>
  4256. -- [size] is the optional size in bytes of the address
  4257. -- TODO: [is_signed] is untrue if the value is unsigned, true otherwise
  4258. function Cheat.change_address(address, modification, size)
  4259.     size = size or 1
  4260.     local memoryf_read =  (size == 1 and u8) or (size == 2 and u16) or (size == 3 and u24) or error"size is too big"
  4261.     local memoryf_write = (size == 1 and w8) or (size == 2 and w16) or (size == 3 and w24) or error"size is too big"
  4262.     local max_value = 256^size - 1
  4263.     local current = memoryf_read(address)
  4264.     --if is_signed then max_value = signed(max_value, 8*size) end
  4265.    
  4266.     local new = (current + modification)%(max_value + 1)
  4267.     memoryf_write(address, new)
  4268.     Cheat.is_cheating = true
  4269. end
  4270.  
  4271.  
  4272. --#############################################################################
  4273. -- MEMORY EDIT --
  4274.  
  4275. function Memory.edit()
  4276.     if not Memory.allow_edit then return end
  4277.     if not apply then return end
  4278.  
  4279.     if OPTIONS.edit_method == "Freeze" then
  4280.         poked = false
  4281.     else
  4282.         apply = false
  4283.     end
  4284.    
  4285.     local slot = OPTIONS.edit_sprite_table_number
  4286.     if not poked then
  4287.         if OPTIONS.edit_sprite_table then
  4288.             for i = 1, SMW2.sprite_max do
  4289.                 if slot[i] then
  4290.                     if OPTIONS.size == 2 then
  4291.                         memory.writeword(OPTIONS.address + 2*(i - 1), OPTIONS.value)
  4292.                     else
  4293.                         memory.writebyte(OPTIONS.address + 2*(i - 1), OPTIONS.value)
  4294.                     end
  4295.            
  4296.                     if OPTIONS.edit_method == "Poke" then
  4297.                         emu.message("\n         Applied address poke")
  4298.                     else
  4299.                         alert_text(Buffer_middle_x - 12*SNES9X_FONT_WIDTH, 190, " Appling address freeze ", COLOUR.warning, COLOUR.warning_bg)
  4300.                     end
  4301.            
  4302.                     poked = true
  4303.                 end
  4304.             end
  4305.         else
  4306.             if OPTIONS.size == 2 then
  4307.                 memory.writeword(OPTIONS.address, OPTIONS.value)
  4308.             else
  4309.                 memory.writebyte(OPTIONS.address, OPTIONS.value)
  4310.             end
  4311.        
  4312.             if OPTIONS.edit_method == "Poke" then
  4313.                 emu.message("\n         Applied address poke")
  4314.             else
  4315.                 alert_text(Buffer_middle_x - 12*SNES9X_FONT_WIDTH, 190, " Appling address freeze ", COLOUR.warning, COLOUR.warning_bg)
  4316.             end
  4317.        
  4318.             poked = true
  4319.         end
  4320.     end
  4321. end
  4322.  
  4323.  
  4324. --#############################################################################
  4325. -- MAIN --
  4326.  
  4327.  
  4328. -- Key presses:
  4329. Keys.registerkeypress("rightclick", right_click)
  4330. Keys.registerkeypress("leftclick", left_click)
  4331. Keys.registerkeypress(OPTIONS.hotkey_increase_opacity, increase_opacity)
  4332. Keys.registerkeypress(OPTIONS.hotkey_decrease_opacity, decrease_opacity)
  4333.  
  4334. -- Key releases:
  4335. Keys.registerkeyrelease("mouse_inwindow", function() Cheat.is_dragging_sprite = false end)
  4336. Keys.registerkeyrelease("leftclick", function() Cheat.is_dragging_sprite = false end)
  4337.  
  4338.  
  4339. gui.register(function()
  4340.     -- Initial values, don't make drawings here
  4341.     snes9x_status()
  4342.     Script_buttons = {}  -- reset the buttons
  4343.    
  4344.     -- Dark filter to cover the game area
  4345.     if Filter_opacity ~= 0 then
  4346.         gui.opacity(Filter_opacity/10)
  4347.         gui.box(0, 0, Buffer_width, Buffer_height, Filter_color)
  4348.         gui.opacity(1.0)
  4349.     end
  4350.    
  4351.     -- Drawings are allowed now
  4352.     scan_smw2()
  4353.    
  4354.     level_mode()
  4355.     overworld_mode()
  4356.    
  4357.     show_movie_info()
  4358.     show_misc_info()
  4359.     show_controller_data()
  4360.    
  4361.     Cheat.is_cheat_active()
  4362.    
  4363.     snes9x_buttons()
  4364.    
  4365.     show_mouse_info()
  4366.    
  4367.     --memory.writebyte(0x7E03B4, 255)
  4368.    
  4369.     --
  4370.     if Options_menu.current_tab == "Memory edit" then -- REMOVE
  4371.         gui.text(180, 192, string.format("poked = %s", tostring(poked)), COLOUR.warning)
  4372.         gui.text(180, 200, string.format("apply = %s", tostring(apply)), COLOUR.warning)
  4373.         gui.text(170, 208, string.format(".edit_method = %s", tostring(OPTIONS.edit_method)), COLOUR.warning)
  4374.     end
  4375. end)
  4376.  
  4377.  
  4378. emu.registerbefore(function()
  4379.     Joypad = joypad.get(1)
  4380.     --get_joypad()
  4381.     scanInputDevs()
  4382.     scanJoypad()
  4383.     sendJoypad()
  4384.    
  4385.     if Cheat.allow_cheats then
  4386.         Cheat.is_cheating = false
  4387.        
  4388.         Cheat.free_movement()
  4389.         Cheat.beat_level()
  4390.     else
  4391.         -- Cancel any continuous cheat
  4392.         Cheat.under_free_move = false
  4393.        
  4394.         Cheat.is_cheating = false
  4395.     end
  4396.    
  4397.     Memory.edit()
  4398. end)
  4399.  
  4400.  
  4401. emu.registerexit(function()
  4402.     INI.save_options()
  4403.     print("Finishing Yoshi's Island script.")
  4404. end)
  4405.  
  4406.  
  4407. print("Lua script loaded successfully.")
  4408.  
  4409.  
  4410. while true do
  4411.     -- User input data
  4412.     Previous.User_input = copytable(User_input)
  4413.     local tmp = input.get()
  4414.     for entry, value in pairs(User_input) do
  4415.         User_input[entry] = tmp[entry] or false
  4416.     end
  4417.     User_input.mouse_inwindow = mouse_onregion(0, 0, Buffer_width - 1, Buffer_height - 1) and 1 or 0 -- Snes9x, custom field
  4418.    
  4419.     -- Detect if a key was just pressed or released
  4420.     for entry, value in pairs(User_input) do
  4421.         if (value ~= false) and (Previous.User_input[entry] == false) then Keys.pressed[entry] = true
  4422.             else Keys.pressed[entry] = false
  4423.         end
  4424.         if (value == false) and (Previous.User_input[entry] ~= false) then Keys.released[entry] = true
  4425.             else Keys.released[entry] = false
  4426.         end
  4427.     end
  4428.    
  4429.     -- Key presses/releases execution:
  4430.     for entry, value in pairs(Keys.press) do
  4431.         if Keys.pressed[entry] then
  4432.             value()
  4433.         end
  4434.     end
  4435.     for entry, value in pairs(Keys.release) do
  4436.         if Keys.released[entry] then
  4437.             value()
  4438.         end
  4439.     end
  4440.    
  4441.     -- Lag-flag is accounted correctly only inside this loop
  4442.     Is_lagged = emu.lagged()
  4443.    
  4444.     emu.frameadvance()
  4445. end
Add Comment
Please, Sign In to add comment