retro/data/stable/SonicAndKnuckles3-Genesis/script.lua (110 lines of code) (raw):
level_max_x = {
-- Angel Island Zone
["zone=0,act=0"] = 0x3080 + 0x1049,
["zone=0,act=1"] = 0x4870,
-- Hydrocity Zone
["zone=1,act=0"] = 0x3630,
["zone=1,act=1"] = 0x3F80,
-- Marble Garden Zone
["zone=2,act=0"] = 0x2D16,
["zone=2,act=1"] = 0x3B62,
-- Carnival Night Zone
["zone=3,act=0"] = 0x3163,
["zone=3,act=1"] = 0x4786,
-- Icecap Zone
["zone=5,act=0"] = 0x68A7, -- changes act before boss
["zone=5,act=1"] = 0x4342,
-- Launch Base Zone
["zone=6,act=0"] = 0x3D4A,
["zone=6,act=1"] = 0x39A3,
-- Mushroom Hill Zone
["zone=7,act=0"] = 0x420B,
["zone=7,act=1"] = 0x3D41,
-- Flying Battery Zone
["zone=4,act=0"] = 0x2DDD,
["zone=4,act=1"] = 0x33AD,
-- Sandopolis Zone
["zone=8,act=0"] = 0x40FB,
["zone=8,act=1"] = 0x5109,
-- Lava Reef Zone
["zone=9,act=0"] = 0x2BE4,
["zone=9,act=1"] = 0x38B0,
-- Hidden Palace Zone
["zone=22,act=1"] = 0x0FC8,
-- Death Egg Zone
["zone=11,act=0"] = 0x35EE,
["zone=11,act=1"] = 0x359F,
}
function level_key()
return string.format("zone=%d,act=%d", data.zone, data.act)
end
function clip(v, min, max)
if v < min then
return min
elseif v > max then
return max
else
return v
end
end
data.prev_lives = 3
function contest_done()
if data.special_stage ~= 0 then
return true
end
if data.lives < data.prev_lives then
return true
end
data.prev_lives = data.lives
if calc_progress(data) >= 1 then
return true
end
return false
end
data.offset_x = nil
end_x = nil
data.prev_screen_x = nil
data.prev_act = nil
function calc_progress(data)
if data.offset_x == nil then
data.offset_x = -data.x
data.prev_act = data.act
data.prev_screen_x = data.screen_x
end_x = level_max_x[level_key()] - data.x
end
-- when the act changes in the middle of a level, adjust offset_x to compensate
if data.act ~= data.prev_act then
data.offset_x = data.offset_x - (data.screen_x - data.prev_screen_x)
end
local cur_x = clip(data.x + data.offset_x, 0, end_x)
data.prev_act = data.act
data.prev_screen_x = data.screen_x
return cur_x / end_x
end
data.prev_progress = 0
frame_limit = 18000
function contest_reward()
local progress = calc_progress(data)
local reward = (progress - data.prev_progress) * 9000
data.prev_progress = progress
-- bonus for beating level quickly
if progress >= 1 then
reward = reward + (1 - clip(scenario.frame / frame_limit, 0, 1)) * 1000
end
return reward
end
data.xpos_last_x = nil
function xpos_done()
-- Some levels change act mid-way through.
-- This should not be allowed by the max x, but we
-- still have a fallback.
level_max_x["zone=0,act=0"] = 0x2f20
if data.prev_act == nil then
data.prev_act = data.act
end
if data.act ~= data.prev_act then
return true
end
if data.special_stage ~= 0 then
return true
end
if data.lives < data.prev_lives then
return true
end
data.prev_lives = data.lives
if scenario.frame >= frame_limit then
return true
end
return data.x > level_max_x[level_key()]
end
function xpos_rew()
if data.xpos_last_x == nil then
data.xpos_last_x = data.x
end
local result = data.x - data.xpos_last_x
data.xpos_last_x = data.x
return result
end