Skip to content

Instantly share code, notes, and snippets.

@realmonster
Last active December 18, 2018 09:39
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save realmonster/93090d4ef0b40c1b88d62f8840fad675 to your computer and use it in GitHub Desktop.
Save realmonster/93090d4ef0b40c1b88d62f8840fad675 to your computer and use it in GitHub Desktop.
Demolition Man script for TAS
-- Demolition Man script for gens/bizhawk for TAS
-- by r57shell
local scrollx = 0
local scrolly = 0
local level = 0
local level_prev = -1
local wblocks = 0
local hblocks = 0
local blocks = nil
local indexes = nil
local cdata = nil
local objs = {}
local ru8,ru16,ru32,rs8,rs16,rs32
local colors = {
[0x40] = 0xFFFFFF99, -- left wall
[0x41] = 0x00FFFF99, -- ground
[0x42] = 0xFFFFFF99, -- right wall
[0x43] = 0x00FF0099, -- wire ground
[0x44] = 0x00990099, -- zip line to the right
[0x45] = 0x00999999, -- right close to climb
[0x46] = 0x0000FF99, -- ladder left
[0x47] = 0x0000FF99, -- ladder right
[0x48] = 0xCCCCCC99, -- climb left
[0x49] = 0xCCCCCC99, -- climb right
[0x4A] = 0x00990099, -- horizontal zip line
[0x4B] = 0x00990099, -- zip line to the left
[0x4C] = 0x00999999, -- left close to climb
[0x4D] = 0x99990099,
[0x4E] = 0xCC00CC99, -- obstacle
[0x4F] = 0x9900FF99, -- ??
[0x50] = 0xFF400099,
[0x52] = 0xFF400099,
[0x56] = 0xFF400099,
[0x58] = 0xFF400099,
[0x5F] = 0xFF400099,
}
local gui_text, gui_box, gui_line, gui_pixel
if gens then
ru8 = memory.readbyteunsigned
ru16 = memory.readwordunsigned
ru32 = memory.readlongunsigned
rs8 = memory.readbytesigned
rs16 = memory.readwordsigned
rs32 = memory.readlongsigned
gui_text, gui_line, gui_pixel = gui.text, gui.line, gui.setpixel
local gb = gui.box
function gui_box(x1, y1, x2, y2, c, o)
gb(x1, y1, x2, y2, o, c)
end
else
ru8 = memory.read_u8
ru16 = memory.read_u16_be
ru32 = memory.read_u32_be
rs8 = memory.read_s8
rs16 = memory.read_s16_be
rs32 = memory.read_s32_be
gui_text = gui.pixelText
gui_box = gui.drawBox
gui_line = gui.drawLine
gui_pixel = gui.drawPixel
for i = 0, 0xFF do
if colors[i] then
colors[i] = bit.band(colors[i],0xFFFFFF00)/0x100+bit.band(colors[i],0xFF)*0x1000000
end
end
end
local max,min,floor = math.max, math.min, math.floor
gui_pixel_, gui_box_, gui_line_ = gui_pixel, gui_box, gui_line
local func_chunk =
[[local gui_box, gui_line, gui_pixel = gui_box_, gui_line_, gui_pixel_
return function (x,y)
]]
function loadlevel()
level_prev = level
local offs = 0x1AF924+level*0x52
wblocks, hblocks = ru16(ru32(offs+3*4)), ru16(ru32(offs+3*4)+2)
local blocks_offs, indexes_offs, ctiles, cdata_offs
= ru32(offs+3*4)+4, ru32(offs+2*4), ru32(offs+5*4), ru32(offs+6*4)
blocks = {}
indexes = {}
cdata = {}
for y = 0, hblocks-1 do
blocks[y] = {}
for x = 0, wblocks-1 do
local bs = blocks_offs+(y*wblocks+x)*2
local idx = ru16(bs)
blocks[y][x] = idx
if indexes[idx] == nil then
local t = {}
local idx1 = indexes_offs+idx*1024
for yy = 0, 15 do
t[yy] = {}
for xx = 0, 31 do
local idx2 = idx1 + (xx+yy*32)*2
local idx3 = ru16(idx2)
local idx4 = ru8(ctiles+2+idx3)
t[yy][xx] = idx4
if cdata[idx4] == nil then
local cd = cdata_offs + 4 + idx4*256
local arr = {}
for xxx = 0, 15 do
local c = nil
local p = nil
for yyy = 0, 15 do
local v = ru8(cd+yyy*16+xxx)
if colors[v] then
local t,x1,y1,x2,y2,z = unpack(arr[#arr] or {})
if z == colors[v]
and t < 2
and x2 == xxx
and y2 == yyy-1 then
arr[#arr][1] = 1
arr[#arr][5] = yyy
local tt,xx1,yy1,xx2,yy2,zz = unpack(arr[#arr-1] or {})
if (tt == 1 or tt == 2)
and zz == z
and yy1 == y1
and yy2 == yyy
and xx2 == xxx-1 then
arr[#arr] = nil
arr[#arr][1] = 2
arr[#arr][4] = xxx
end
else
arr[#arr+1] = {0,xxx,yyy,xxx,yyy,colors[v]}
end
end
if colors[v] ~= c then
c = colors[v]
p = yyy
end
end
end
local f = ""
for i = 1, #arr do
local t,x1,y1,x2,y2,z = unpack(arr[i])
if t == 0 then
f = f.."gui_pixel(x+"..x2..",y+"..y2..","..z..")\n"
elseif t == 1 then
f = f.."gui_line(x+"..x1..",y+"..y1..
",x+"..x2..",y+"..y2..","..z..")\n"
elseif t == 2 then
f = f.."gui_box(x+"..x1..",y+"..y1..
",x+"..x2..",y+"..y2..","..z..","..z..")\n"
end
end
f = func_chunk..f.."end"
cdata[idx4] = loadstring(f)()
end -- if
end -- for xx
end -- for yy
indexes[idx] = t
end -- if
end
end
local obj = ru32(ru32(offs+11*4))
local objs_count = ru32(ru32(offs+13*4))
objs = {}
for i = 0, objs_count-1 do
local x = ru16(obj+i*6)
local y = ru16(obj+i*6+2)
local t = ru16(obj+i*6+4)
local f = ru32(0x1FFBAA+t*4)
c = 0x00FF00FF
cc = 0x00FF0000
if f == 0x1AEDAE then
c = 0x0000FFFF
cc = 0x0000FF00
end
if f == 0x1BC85E then
c = 0x00FFFFFF
cc = 0x00FFFF00
end
if f == 0 then
c = 0xFFFFFFFF
cc = 0xFFFFFF00
end
if not gens then
c = bit.band(c,0xFFFFFF00)/0x100+bit.band(c,0xFF)*0x1000000
cc = bit.band(cc,0xFFFFFF00)/0x100+bit.band(cc,0xFF)*0x1000000
end
objs[i+1] = {x,y,string.format("%X",t),c,cc}
end
end
function drawcollision()
if level > 9 then return end
if level_prev ~= level then
loadlevel()
end
local left,right,top,bottom = scrollx,scrollx+320,scrolly,scrolly+224
for y = max(0,floor(top/256)), min(hblocks-1,floor((bottom-1)/256)) do
for x = max(0,floor(left/512)), min(wblocks-1,floor((right-1)/512)) do
local idx = blocks[y][x]
for yy = max(0,floor((top-y*256)/16)), min(15,floor((bottom-1-y*256)/16)) do
for xx = max(0,floor((left-x*512)/16)), min(31,floor((right-1-x*512)/16)) do
local idx1 = indexes[idx][yy][xx]
cdata[idx1](x*512+xx*16-scrollx,y*256+yy*16-scrolly)
end
end
end
end
end
function drawobjs()
local struct = 0x1AF924+0x52*level
for i = 1, #objs do
local x,y,t,c,cc = unpack(objs[i])
if x+16 >= scrollx and x < scrollx+320
and y+16 >= scrolly and y < scrolly+224 then
gui_box(x-scrollx,y-scrolly,x+15-scrollx,y+15-scrolly,c)
gui_text(x+2-scrollx,y+1-scrolly,t,c)
end
end
end
function render()
level = ru16(0xFF0538)
if level > 9 then return end
local player = ru32(0xFF055A)
local xpos = ru32(player+0x26)
local ypos = ru32(player+0x2A)
local hp = rs16(player+0x3C)
local granades = ru8(player+0xDE)
local granades_count = ru8(player+0xDF)
local w = ru8(player+0xE0)
local ammo = ru8(player+0xE1)
local state = ru16(player+0x4A)
local mapa = ru32(player+0x72)
local mapb = ru32(player+0x76)
if ru32(0x1AF924+level*0x52+5*4) ~= mapa
or ru32(0x1AF924+level*0x52+6*4) ~= mapb then
return
end
local text = string.format("%8X %8X %X %d",xpos,ypos,state,hp)
text = text..string.format("\n%d %d %d %d",granades,granades_count,w,ammo)
gui.text(125,0,text)
scrollx = rs16(0xFF04CC)
scrolly = rs16(0xFF04CE)
drawcollision()
drawobjs()
end
if gens then
gui.register(render)
else
event.onframeend(render)
end
@pygy
Copy link

pygy commented Dec 17, 2018

Further tips:

  • #arr is a O(log(#arr)) operation (it does a binary search for a non-nil value followed by a nil), you'll most probably get better perf by tracking the length manually (not sure how much this matters, I suppose that the cdata[idx1]() calls dominate here anyways).
  • You can define func_chunk as
local func_chunk =
[[local gui_box, gui_line, gui_pixel = ...
return function (x,y)
]]

then pass the functions as argument at call time cdata[idx4] = loadstring(f)(gui_box, gui_line, gui_pixel). No need for globals.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment