-- Gravity Force: who won a DOGFIGHT, read from RAM, for the bot arena.
--
-- A results plugin (od-unix/netplay_bot.cpp). Measured on the AROS
-- dogfight state (arena/gf-dogfight-aros.uss) with two bots playing:
--   lives      0x357c2 (port 1, top view), 0x3ace4 (port 0), a byte: the
--              ships left after this one, 5 at the start (six icons in the
--              status strip); 255 while the last ship flies
--   ship x, y  player records 0x37f30 (port 1) / 0x37fd6 (port 0), +0x14
--              and +0x18, longs in thousandths of a pixel; +0x1c / +0x20
--              the ship's pad
-- The last ship's crash is not counted anywhere we found: the record
-- just stops, where it crashed, and about 160 frames later the game shows
-- "PILOT N WINS" (drawn as pictures, no text in RAM). So a port is out
-- when its lives are 255 and its ship has not moved at all for STILL
-- frames away from its pad (a ship parked on its pad also stands still).

local LIVES = { [1] = 0x357c2, [0] = 0x3ace4 }
local REC = { [1] = 0x37f30, [0] = 0x37fd6 }
local STILL = 120
local PAD = 12000                  -- within 12 px of the pad is parked

local last, still, out = {}, { [0] = 0, [1] = 0 }, {}
local winner = nil

-- The spare ships, as the status strip shows them: 5 at the start is six
-- icons, 255 (the last ship flying) none.
local function spare(port)
  local v = ram.u8(LIVES[port])
  if v == nil then return nil end
  return (v + 1) % 256
end

-- Called once a frame by the seats, so the stillness count is in frames.
function results()
  for port, rec in pairs(REC) do
    local x, y = ram.u32(rec + 0x14), ram.u32(rec + 0x18)
    if x == nil then return nil end
    local key = x .. "," .. y
    if key == last[port] then still[port] = still[port] + 1 else still[port] = 0 end
    last[port] = key
    local px, py = ram.u32(rec + 0x1c), ram.u32(rec + 0x20)
    local parked = math.abs(x - px) < PAD and math.abs(y - py) < PAD
    if ram.u8(LIVES[port]) == 255 and still[port] >= STILL and not parked then out[port] = true end
  end
  if not winner then
    if out[0] and not out[1] then winner = 1 elseif out[1] and not out[0] then winner = 0 end
  end
  return {
    spare = { [1] = spare(1), [0] = spare(0) },
    out = { [1] = out[1] == true, [0] = out[0] == true },
    wins = { [1] = winner == 1 and 1 or 0, [0] = winner == 0 and 1 or 0 },
    over = winner ~= nil,
  }
end
