User File #35183831238084413

Upload All User Files

#35183831238084413 - NES F-1 Race (J) HUD script

F1Race-info.lua
Game: F-1 Race ( NES, see all files )
2 comments, 751 downloads
Uploaded 11/23/2016 11:54 AM by TaoTao (see all 95)
Displays position, speed, etc.
function num_stou(n, size)
    if n < 0 then
        n = n + 2^(8*size)
    end
    return n
end

function num_utos(n, size)
    if n >= 2^(8*size-1) then
        n = n - 2^(8*size)
    end
    return n
end

function numdec_s_le(buf, size)
    local n = numdec_u_le(buf, size)
    return num_utos(n, size)
end

function numdec_u_le(buf, size)
    local n = 0
    for i = 1, size do
        n = n + 2^(8*(i-1)) * buf[i]
    end
    return n
end

function numdec_s_be(buf, size)
    local n = numdec_u_be(buf, size)
    return num_utos(n, size)
end

function numdec_u_be(buf, size)
    local n = 0
    for i = 1, size do
        n = n + 2^(8*(size-i)) * buf[i]
    end
    return n
end

function numdec_s32_le(buf)
    return numdec_s_le(buf, 4)
end

function numdec_u32_le(buf)
    return numdec_u_le(buf, 4)
end

function numdec_s24_le(buf)
    return numdec_s_le(buf, 3)
end

function numdec_u24_le(buf)
    return numdec_u_le(buf, 3)
end

function numdec_s16_le(buf)
    return numdec_s_le(buf, 2)
end

function numdec_u16_le(buf)
    return numdec_u_le(buf, 2)
end

function numdec_s32_be(buf)
    return numdec_s_be(buf, 4)
end

function numdec_u32_be(buf)
    return numdec_u_be(buf, 4)
end

function numdec_s24_be(buf)
    return numdec_s_be(buf, 3)
end

function numdec_u24_be(buf)
    return numdec_u_be(buf, 3)
end

function numdec_s16_be(buf)
    return numdec_s_be(buf, 2)
end

function numdec_u16_be(buf)
    return numdec_u_be(buf, 2)
end

function mem_read_bytes(addr, len)
    local buf = {}
    for i = 1, len do
        buf[i] = memory.readbyte(addr+(i-1))
    end
    return buf
end

function mem_read_s_le(addr, size)
    local buf = mem_read_bytes(addr, size)
    return numdec_s_le(buf, size)
end

function mem_read_u_le(addr, size)
    local buf = mem_read_bytes(addr, size)
    return numdec_u_le(buf, size)
end

function mem_read_s_be(addr, size)
    local buf = mem_read_bytes(addr, size)
    return numdec_s_be(buf, size)
end

function mem_read_u_be(addr, size)
    local buf = mem_read_bytes(addr, size)
    return numdec_u_be(buf, size)
end

function mem_read_s32_le(addr)
    return mem_read_s_le(addr, 4)
end

function mem_read_u32_le(addr)
    return mem_read_u_le(addr, 4)
end

function mem_read_s24_le(addr)
    return mem_read_s_le(addr, 3)
end

function mem_read_u24_le(addr)
    return mem_read_u_le(addr, 3)
end

function mem_read_s16_le(addr)
    return mem_read_s_le(addr, 2)
end

function mem_read_u16_le(addr)
    return mem_read_u_le(addr, 2)
end

function mem_read_s32_be(addr)
    return mem_read_s_be(addr, 4)
end

function mem_read_u32_be(addr)
    return mem_read_u_be(addr, 4)
end

function mem_read_s24_be(addr)
    return mem_read_s_be(addr, 3)
end

function mem_read_u24_be(addr)
    return mem_read_u_be(addr, 3)
end

function mem_read_s16_be(addr)
    return mem_read_s_be(addr, 2)
end

function mem_read_u16_be(addr)
    return mem_read_u_be(addr, 2)
end

function mem_read_s8(addr)
    return num_utos(mem_read_u8(addr), 1)
end

function mem_read_u8(addr)
    return memory.readbyte(addr)
end


local POS_CURB_LIMIT_MAX = 0x0061FF
local POS_CURB_LIMIT_MIN = 0xFFA200 - 0x1000000

local ENGINE_BRAKE = {
    --LOW
    {
        {
            0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100,
            0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
            0x0300, 0x0300, 0x0300, 0x0300, 0x0400, 0x0400, 0x0400, 0x0400,
            0x0500, 0x0500, 0x0600, 0x0600, 0x0700, 0x0700, 0x0800, 0x0800,
        },
        {
            0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100,
            0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
            0x0300, 0x0300, 0x0300, 0x0300, 0x0400, 0x0400, 0x0400, 0x0400,
            0x0500, 0x0500, 0x0600, 0x0600, 0x0700, 0x0700, 0x0800, 0x0800,
        },
    },
    --HI
    {
        {
            0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100,
            0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100,
            0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100,
            0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100,
        },
        {
            0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
            0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
            0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
            0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
        },
    },
}

local ACCEL = {
    -- LOW
    {
        {
            0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
            0x0300, 0x0300, 0x0300, 0x0280, 0x0240, 0x0220, 0, 0,
            0, 0, 0, 0, 0, 0, 0, 0,
            0, 0, 0, 0, 0, 0, 0, 0,
        },
        {
            0x0220, 0x0240, 0x0280, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300,
            0x0400, 0x0400, 0x0400, 0x0400, 0x0300, 0x0280, 0x0240, 0,
            0, 0, 0, 0, 0, 0, 0, 0,
            0, 0, 0, 0, 0, 0, 0, 0,
        },
    },
    -- HI
    {
        {
            0x0120, 0x0130, 0x0140, 0x0150, 0x0160, 0x0170, 0x0180, 0x0198,
            0x01B0, 0x01C8, 0x01E0, 0x01F8, 0x0210, 0x0230, 0x0250, 0x0270,
            0x0240, 0x0220, 0x02F0, 0x01C0, 0x0190, 0x0168, 0x0140, 0x0120,
            0x0118, 0x0110, 0x0140, 0x0180, 0x0180, 0x0180, 0x0140, 0x00FF,
        },
        {
            0x0240, 0x0260, 0x0280, 0x02A0, 0x02C0, 0x02E0, 0x0300, 0x0320,
            0x0340, 0x0360, 0x0380, 0x03A0, 0x03B0, 0x03C0, 0x03D0, 0x03E0,
            0x03C0, 0x03A0, 0x0380, 0x0360, 0x0340, 0x0320, 0x0300, 0x02E0,
            0x0300, 0x0320, 0x0340, 0x0340, 0x0340, 0x0340, 0x0320, 0x00FF,
        },
    },
}

local CURVE_THRESHOLD = { 8, 24, 40 }
local CURVE_SPEED_LIMIT = {
    -- LV1
    {
        { 369, 339, 309 },
        { 509, 479, 449 },
    },
    -- LV2
    {
        { 349, 319, 289 },
        { 489, 459, 429 },
    },
    -- LV3
    {
        { 329, 299, 269 },
        { 469, 439, 409 },
    },
}

local MOVE_MASK = { 0x80, 0x40, 0x40 }
local MOVE_STR = { "R", "L" }

local RAND_PERIOD = 0xFFFE

local rand_idx = {}

local function get_engine_brake(speed, gear, turbo)
    local speed_idx = math.floor((speed/0x0100)/16) + 1
    local gear_idx = gear+1
    local turbo_idx = 1
    if turbo then turbo_idx = turbo_idx+1; end

    return ENGINE_BRAKE[gear_idx][turbo_idx][speed_idx]
end

local function get_accel(speed, gear, turbo)
    local speed_idx = math.floor((speed/0x0100)/16) + 1
    local gear_idx = gear+1
    local turbo_idx = 1
    if turbo then turbo_idx = turbo_idx+1; end

    return ACCEL[gear_idx][turbo_idx][speed_idx]
end

local function get_speed_limit(level, curve, turbo)
    local curve_abs = math.abs(curve)
    local curve_idx = 0
    for i = 1, #CURVE_THRESHOLD do
        if curve_abs >= CURVE_THRESHOLD[i] then
            curve_idx = curve_idx+1
        end
    end
    if curve_idx == 0 then return nil; end

    local level_idx = level+1

    local turbo_idx = 1
    if turbo then turbo_idx = turbo_idx+1; end

    return CURVE_SPEED_LIMIT[level_idx][turbo_idx][curve_idx]
end

local function get_move_dir(move, level)
    local mask = MOVE_MASK[level+1]
    if bit.band(move, mask) == 0 then
        return 1 -- R
    else
        return 2 -- L
    end
end

local function chk_enemy_pop(rand1, speed)
    if speed >= 0xC800 then
        return bit.band(rand1, 0x1F) == 0
    else
        return bit.band(rand1, 0x01FF) == 0
    end
end

local function rand_shift(r)
    local bit_new = bit.band(bit.bnot(bit.bxor(bit.rshift(r,15), bit.rshift(r,1), r)), 0x0001)
    return bit.band(bit.bor(bit.lshift(r,1), bit_new), 0xFFFF)
end

local function init_rand_idx()
    local r = 0x0000
    for i = 1, RAND_PERIOD do
        rand_idx[r] = i
        r = rand_shift(r)
    end
end

local function get_info()
    local info = {}

    info.level = mem_read_u8(0x33)
    info.frame = mem_read_u8(0x4F)
    info.gear = mem_read_u8(0x47)
    info.turbo = mem_read_u8(0x75) ~= 0
    local pos_buf = { mem_read_u8(0x4D), mem_read_u8(0x4C), mem_read_u8(0x4E) }
    info.pos = numdec_s24_be(pos_buf)
    info.speed = mem_read_u24_be(0x50)
    info.rpm = mem_read_u8(0x53)
    info.distance = mem_read_u16_le(0x41)
    info.distance_way = mem_read_u8(0x43)

    local way_ptr = mem_read_u16_le(0x3C)
    info.way_curve = mem_read_s8(way_ptr)
    info.way_len = mem_read_u8(way_ptr+1)

    info.enemy = {}
    for i = 1, 3 do
        local e = {}
        e.x = mem_read_u8(0x8C+i-1)
        e.z = 256*mem_read_u8(0x8F+i-1) + mem_read_u8(0x92+i-1)
        e.move = mem_read_u8(0x98+i-1)
        info.enemy[i] = e
    end

    info.rand0 = mem_read_u16_le(0x2E)
    info.rand1 = mem_read_u16_le(0x30)

    return info
end

local function color_curb(frame)
    return frame % 2 == 1 and "red" or "gray"
end

local function color_speed(frame)
    return frame % 2 == 1 and "gray" or "white"
end

local function draw_info(info)
    local str_pos = string.format("%.3f", info.pos/256.0, num_stou(info.pos, 3))
    local curb_hit = info.pos < POS_CURB_LIMIT_MIN or info.pos > POS_CURB_LIMIT_MAX

    local engine_brake = get_engine_brake(info.speed, info.gear, info.turbo)
    local accel = get_accel(info.speed, info.gear, info.turbo)
    local str_speed = string.format("%.3f", info.speed/256.0)
    local str_dspeed = string.format("%.3f-%.3f=%.3f",
                                     accel/256.0, engine_brake/256.0, (accel-engine_brake)/256.0)

    local speed_limit = get_speed_limit(info.level, info.way_curve, info.turbo)
    local str_way = string.format("WAY: %d, %u/%u", info.way_curve, info.distance_way, info.way_len)
    if speed_limit then
        str_way = str_way .. string.format(", lim:%03u", speed_limit)
    end

    local str_enemy = "ENM: "
    for i = 1, 3 do
        local e = info.enemy[i]
        local x_str, z_str = "----", "------"
        if e.z < 0xF000 then
            x_str = string.format("0x%02X", e.x)
            z_str = string.format("0x%04X", e.z)
        end
        str_enemy = str_enemy .. string.format("(%s,%s)", x_str, z_str)
        if i ~= 3 then str_enemy = str_enemy .. " "; end
    end

    local str_enemy_act = "ACT: "
    for i = 1, 3 do
        local e = info.enemy[i]
        local move_str = string.format("0x%02X(%s)", e.move, MOVE_STR[get_move_dir(e.move, info.level)])
        str_enemy_act = str_enemy_act .. move_str
        if i ~= 3 then str_enemy_act = str_enemy_act .. " "; end
    end
    local rand1_str = string.format("rand1:%d", rand_idx[info.rand1])
    if chk_enemy_pop(info.rand1, info.speed) then
        rand1_str = rand1_str .. "(!)"
    end
    str_enemy_act = str_enemy_act .. "  " .. rand1_str

    gui.text(0, 48, "POS:")
    gui.text(23, 48, str_pos)

    if curb_hit then
        gui.text(80, 48, "curb!", color_curb(info.frame))
    end

    gui.text(0, 56, "SPD:")
    gui.text(22, 56, str_speed, color_speed(info.frame))
    gui.text(80, 56, str_dspeed)

    gui.text(0, 64, string.format("RPM: %u", info.rpm))
    gui.text(0, 80, string.format("DIS: %.3f", info.distance/256.0, info.distance))
    gui.text(0, 88, str_way)

    gui.text(0, 104, str_enemy)
    gui.text(0, 112, str_enemy_act)

    gui.text(0, 8, string.format("%03u", info.frame))
end

local function draw()
    local info = get_info()

    -- �n�[�h���Z�b�g����̓�����������������ĂȂ��̂ŏ��\�����Ȃ�
    if mem_read_u8(0x0600) == 0xA5 then
        draw_info(info)
    end
end

local function main()
    init_rand_idx()

    emu.registerafter(draw)
end

main()

Dimon12321
on 11/23/2016 12:37 PM
TaoTao
on 4/13/2017 11:17 PM
Quoting Dimon12321
Are you seriously going to work on this game?
Wow, sorry for the late reply. I am not working for now, but long ago I had worked for level 3. Movie file is here.