User File #38528305500717915

Upload All User Files

#38528305500717915 - Donkey Kong Country - hitboxes 1.0 (lsnes version)

DKC-hitboxes-lsnes-v1.0.lua
1052 downloads
Uploaded 4/23/2017 2:46 AM by Amaraticando (see all 21)
This game has different kinds of collisions, some of them are not featured yet. For instance, when you throw a barrel, the effective hitbox can be much bigger than the default. Other things like DK's hand smashing the ground, the animals attacks, etc are to be done yet.
-- Configuration
local config = {
  display_sprite_hitbox = true,
  display_sprite_info = false,
}

local colors = {
  "red",    -- Donkey Kong
  "magenta" -- Diddy
}

-- Some utility functions

local u8 = function(address) return memory.readbyte("WRAM", address) end
local s8 = function(address) return memory.readsbyte("WRAM", address) end
local u16 = function(address) return memory.readword("WRAM", address) end
local s16 = function(address) return memory.readsword("WRAM", address) end

local function rectangle(x, y, w, h, ...)
    -- Draw from top-left to bottom-right
    if w < 0 then
        x, w = x + w, -w
    end
    if h < 0 then
        y, h = y + h, -h
    end

    x, y, w, h = 2*x, 2*y, 2*w + 2, 2*h + 2
    gui.rectangle(x, y, w, h, 2, ...)
end

-- Definitions

local WRAM = {
  game_mode_ptr = 0x1c,
  camera_vertical_offset = 0x4a,
  -- 0xbe --> camera distance from level origin
  -- 0xc0 --> camera y mirror
  xcam_effective = 0x1a62,
  sprite_type = 0x0d45,
  xspeed = 0xe8b,
  xpos_camera = 0x88b,
  ypos_camera = 0x895,
  left_border_pos = 0x1b23,
  xpos_offset = 0x0b19,
  ypos_offset = 0x0bc1,
}

-- This table'll be used differently in the future
-- some sprites have completely different hitboxes depending on context
local odd_hitbox = {
  -- [sprite type] = offset,
  [0x15] = 0x08,
  [0x16] = 0x08,
  [0x23] = false, -- 0x0d,
}

local game = {}
local sprite = {}

-- Game functions

local function load_game_info()
  game.game_mode_ptr = u16(WRAM.game_mode_ptr)
  game.is_level_mode = game.game_mode_ptr == 0x80a9 or game.game_mode_ptr == 0xa98e
  game.camera_vertical_offset = u16(WRAM.camera_vertical_offset)
  game.xpos_camera = u16(WRAM.xpos_camera)
  game.ypos_camera = u16(WRAM.ypos_camera)
end

-- Debugging...
--[==[
-- get clipping
local function regexec(address, fn) memory.registerexec("BUS", address, fn) end

---[[
memory.registerexec("BUS", 0xbba533, function()
  print(string.format("Clipping(%d) x: %d -> %d / y: %d -> %d",
    memory.getregister("x")//2, u16(0xa6), u16(0xaa), u16(0xa8), u16(0xac)  ))
end)
--]]

regexec(0xbfcf14, function() print"bfcf14" end)
regexec(0xbba4d5, function() print"bba4d5" end)
regexec(0xbba4c8, function() print"bba4c8" end)

---[[
memory.registerexec("BUS", 0xbba600, function()
  print(string.format("%d: left: %d %d / right: %d %d / top: %d %d / down: %d %d",
    u16(0xb6), u16(0xb2), u16(0xa6), u16(0xaa), u16(0xae), u16(0xb0), u16(0xac), u16(0xa8), u16(0xb4) ))
end)
--]]
--]==]
-- end of debugging

local function draw_hitbox(xscreen, yscreen, slot, hitbox_offset, color)
  -- flip
  local do_flip = u16(0x0c69 + 2*slot)
  local xflip = bit.test(do_flip, 14) and -1 or 1
  local yflip = bit.test(do_flip, 15) and -1 or 1  -- not sure about that

  local xoff = xflip * memory.readsword("BUS", hitbox_offset + 0)
  local yoff = yflip * memory.readsword("BUS", hitbox_offset + 2)
  local width = xflip * memory.readsword("BUS", hitbox_offset + 4)
  local height = yflip * memory.readsword("BUS", hitbox_offset + 6)

  -- draw
  rectangle(xscreen + xoff, yscreen + yoff, width, height, color)
end

-- bba4d5 , bba4c8: get sprite clipping values (normal / special)
-- bba594: check for collision
--         b2 a6/ aa ae / b0 ac / a8 b4
local function sprite_hitbox(slot)
  local spr_type = u16(WRAM.sprite_type + 2*slot)
  local index = math.floor(u16(0xd11 + 2*slot)/2)

  -- position
  local xpos = u16(WRAM.xpos_offset + 2*slot)
  local ypos = u16(WRAM.ypos_offset + 2*slot)
  local xscreen = xpos - game.xpos_camera
  local yscreen = game.camera_vertical_offset - ypos - game.ypos_camera

  local color
  if slot <= 2 then
    color = colors[slot]
  elseif odd_hitbox[spr_type] then
    color = 0xff00
  else
    color = "yellow"
  end

  local hitbox_offset
  if odd_hitbox[spr_type] then
    hitbox_offset = 8*odd_hitbox[spr_type] + 0xa428
  else
    hitbox_offset = memory.readword("BUS", 0xbb8000 + index)
  end

  hitbox_offset = hitbox_offset + 0xbb0000
  draw_hitbox(xscreen, yscreen, slot, hitbox_offset, color)
end

local function draw_sprite_info()
  local xpos_camera = game.xpos_camera
  local ypos_camera = game.ypos_camera
  local camera_vertical_offset = game.camera_vertical_offset
  -- gui.text(0, 0, string.format("Cam: %d, %d", xpos_camera, ypos_camera))

  for slot = 1, 25 do
    local spr_type = u16(WRAM.sprite_type + 2*slot)
    local is_normal_sprite = slot <= 14

    if spr_type ~= 0 then
      local xpos = u16(WRAM.xpos_offset + 2*slot)
      local ypos = u16(WRAM.ypos_offset + 2*slot)
      local xscreen = xpos - xpos_camera
      local yscreen = camera_vertical_offset - ypos - ypos_camera

      local xspeed = s8(WRAM.xspeed + slot)  -- todo

      -- draw position pixel
      if config.display_sprite_info then
        gui.solidrectangle(2*xscreen, 2*yscreen, 2, 2, 0x40ffffff)
        gui.text(2*xscreen, 2*yscreen, "#" .. slot, 0x80ffffff, -1, 0x80000000)

        local mytext = string.format("#%d[%.2x] (%d, %d)", slot, spr_type, xpos, ypos)
        gui.text(512 - 8 * #mytext, 16*slot, mytext, is_normal_sprite and 0xffffff or 0x808080, -1, 0)
      end

      -- draw hitbox
      if is_normal_sprite then
        sprite_hitbox(slot)
      end
    end

  end
end

-- Callbacks and startup

function on_paint()
  load_game_info()

  if game.is_level_mode then
    draw_sprite_info()
  else
    gui.text(0, 0, "Outside level", 0xffffff, -1, 0)
  end
end

gui.repaint()
print("DKC Lua script has started.")