User File #38528317092688522

Upload All User Files

#38528317092688522 - Donkey Kong Country - hitboxes 1.0 (BizHawk version)

DKC-hitboxes-bizhawk-v1.0.lua
1002 downloads
Uploaded 4/23/2017 2:47 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 = true,
}

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

-- Some utility functions

local u8 =  mainmemory.read_u8
local s8 =  mainmemory.read_s8
local u16 = mainmemory.read_u16_le
local s16 = mainmemory.read_s16_le

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

  gui.drawRectangle(x, y, w, h, ...)
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

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

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

  -- 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 = 0xff00ff00
  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.read_u16_le(0xbb8000 + index, "System Bus")
  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.drawPixel(xscreen, yscreen, 0xc0ffffff)
        gui.drawText(xscreen, yscreen, "#" .. slot, 0x80ffffff)

        local mytext = string.format("#%d[%.2x] (%d, %d)", slot, spr_type, xpos, ypos)
        gui.text(client.screenwidth()  - 10 * #mytext, 15*slot, mytext, is_normal_sprite and 0xffffffff or 0xff808080)
      end

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

  end
end

-- Callbacks and startup

print("DKC Lua script has started.")

while true do
  load_game_info()

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

  emu.frameadvance()
end