diff --git a/Assets/Lua/Genesis/Gargoyles.lua b/Assets/Lua/Genesis/Gargoyles.lua index cae3a84fbc..dcb4ca070f 100644 --- a/Assets/Lua/Genesis/Gargoyles.lua +++ b/Assets/Lua/Genesis/Gargoyles.lua @@ -1,448 +1,522 @@ --- Gargoyles, Genesis (BizHawk) --- feos, 2015-2016 - ---== Shortcuts ==-- -rb = memory.read_u8 -rw = memory.read_u16_be -rws = memory.read_s16_be -r24 = memory.read_u24_be -rl = memory.read_u32_be -box = gui.drawBox -text = gui.pixelText -line = gui.drawLine -AND = bit.band -SHIFT = bit.rshift - ---== RAM addresses ==-- -levnum = 0xff00ba -LevelFlr = 0xff00c0 -LevelCon = 0xff00c4 -mapline_tab = 0xff0244 -GlobalBase = 0xff1c76 -GolBase = 0xff2c76 -MapA_Buff = 0xff4af0 - ---== Camera Hack ==-- -camhack = false -div = 1 -- scale -size = 16/div -- block size - ---== Block cache ==-- -col = 0 -- block color -opout = 0x33000000 -- outer opacity -opin = 0x66000000 -- inner opacity -op = 0xff000000 -cache = {} - ---== Other stuff ==-- -XposLast = 0 -YposLast = 0 -room = 0 -workinglast = 0 -lagcount = emu.lagcount() -gui.defaultPixelFont("fceux") - -function main() - rnd1 = rl (0xff001c) - rnd2 = rw (0xff0020) - working = rb (0xff0073) - xblocks = rw (0xff00d4) - mapw = rw (0xff00d4)*8 - maph = rw (0xff00d6)*8 - Xpos = rws(0xff0106) - Ypos = rws(0xff0108) - camx = rws(0xff010c)+16 - camy = rws(0xff010e)+16 - run = rb (0xff1699) - inv = rw (0xff16d2) - health = rws(0xff2cc6) - backx = camx - backy = camy - Xspd = Xpos-XposLast - Yspd = Ypos-YposLast - facing = AND(rb(GolBase+0x48),2) -- object flag 1 - - Background() - CamhackHUD() - Objects() - PlayerBoxes() - HUD() - RoomTime() - Input() -end - -function RoomTime() - local start11 = 894--767 - local start12 = 2294 - local start13 = 4101 - local startl4 = 6000 - timer = emu.framecount() - - if timer < start11 then room = timer - elseif timer < start12 then room = timer - start11 - elseif timer < start13 then room = timer - start12 - elseif timer < startl4 then room = timer - start13 - end - text(160,214,"room cnt: "..room, "white") -end - -function HUD() - text(1, 0,emu.framecount(), framecol) - text(1,20,emu.lagcount(), "red") - text(1,30,movie.rerecordcount(),"orange") - - if working>0 then return end - if rndlast ~= rnd1 then rndcol = "red" else rndcol = "white" end - - text( 0,214,"rnd: ","yellow") - text( 26,214,string.format("%08X %04X",rnd1,rnd2),rndcol) - text(277, 0,string.format( - "x: %4d\ny: %4d\ndx: %3d\ndy: %3d\nhp: %3d\nrun:%3d\ninv:%3d", - Xpos,Ypos,Xspd,Yspd,health,run,inv) - ) -end - -function CamhackHUD() - if working==0 then - -- screen edge - box((backx-camx- 1)/div, - (backy-camy- 1)/div, - (backx-camx+320)/div, - (backy-camy+224)/div, - 0xff0000ff) - -- map edge - box( 0-camx/div+size, - 0-camy/div+size, - mapw/div-camx/div, - maph/div-camy/div, - 0xff0000ff) - end - - text(260,206,string.format("cHack: %s\nscale: %d",ch,div)) -end - -function Background() - if working>0 then - cache = {} - return - end - - if camhack then - camx = Xpos-320/2*div - camy = Ypos-224/2*div - box(0,0,320,240,0,0x66000000) - ch = "on" - else - ch = "off" - end - - local border = 0 - local offset = 32 - local basex = camx+border - local basey = camy+border - local basei = PosToIndex(basex-offset,basey-offset) - local boundx = 320*div-border - local boundy = 224*div-border - local xblockstockeck = ((camx+boundx+offset)-(basex-offset))/size/div - local yblockstockeck = ((camy+boundy+offset)-(basey-offset))/size/div - - for yblock = 0,yblockstockeck do - for xblock = 0,xblockstockeck do - local i = yblock*xblocks+xblock+basei - local x = basex+xblock*size*div - local y = basey+yblock*size*div - - if InBounds(x,basex-offset,camx+boundx+offset) then - local unit = cache[i] - - if unit == nil or workinglast>0 then - if InBounds(x,basex,camx+boundx) - and InBounds(y,basey,camy+boundy) - then cache[i] = GetBlock(x,y) - end - else - if not InBounds(x,basex,camx+boundx) - and not InBounds(y,basey,camy+boundy) - then cache[i] = nil - end - end - - if unit ~= nil then - DrawBG(unit,x,y) - end - elseif cache[i] ~= nil - then cache[i] = nil - end - end - end -end - -function DrawBG(unit, x, y) - local val= 0 - local x1 = x/div-camx/div-(camx%16)/div - local x2 = x1+size-1 - local y1 = y/div-camy/div-(camy%16)/div - local y2 = y1+size-1 - - if unit.contour ~= nil then - box(x1,y1,x2,y2,0x5500ff00,0x5500ff00) - - for pixel=0,15 do - val = unit.contour[pixel] - if val>0 then - gui.drawPixel( - x1+pixel/div, - y1+val/div-1/div, - 0xffffff00) - end - end - end - - if unit.block>0 then - local Fn = DrawBlock[unit.block] or DrawBlockDefault - Fn(x1,y1,x2,y2) - box(x1,y1,x2,y2,col+opin,col+opout) - end -end - -function GetBlock(x,y) - if working>0 then return nil end - - local final = { contour={}, block=0 } - - if x>0 and x0 and y0 or rb(a1+8)>0 then - for pixel=0,15 do - final.contour[pixel] = rb(a1+pixel) - end - else - final.contour = nil - end - else - return nil - end - - return final -end - -function PosToIndex(x,y) - return math.floor(x/16)+math.floor(y/16)*xblocks -end - -function IndexToPos(i) - return { x=(i%xblocks)*16, y=math.floor(i/xblocks)*16 } -end - -function InBounds(x,minimum,maximum) - if x>=minimum and x<=maximum - then return true - else return false - end -end - -DrawBlock = { - [0x80] = function(x1,y1,x2,y2) -- WALL - col = 0x00ffffff -- white - line(x1,y1,x1,y2,col+op) -- left - line(x2,y1,x2,y2,col+op) -- right - end, - [0x81] = function(x1,y1,x2,y2) -- CEILING - col = 0x00ffffff -- white - line(x1,y2,x2,y2,col+op) -- bottom - end, - [0x82] = function(x1,y1,x2,y2) -- CLIMB_U - col = 0x0000ffff -- cyan - line(x1,y2,x2,y2,col+op) -- bottom - end, - [0x83] = function(x1,y1,x2,y2) -- CLIMB_R - col = 0x0000ffff -- cyan - line(x1,y1,x1,y2,col+op) -- left - end, - [0x84] = function(x1,y1,x2,y2) -- CLIMB_L - col = 0x0000ffff -- cyan - line(x2,y1,x2,y2,col+op) -- right - end, - [0x85] = function(x1,y1,x2,y2) -- CLIMB_LR - col = 0x0000ffff -- cyan - line(x1,y1,x1,y2,col+op) -- left - line(x2,y1,x2,y2,col+op) -- right - end, - [0x86] = function(x1,y1,x2,y2) -- CLIMB_R_STAND_R - col = 0x00ffffff -- white - line(x1,y1,x2,y1,col+op) -- top - col = 0x0000ffff -- cyan - line(x1,y1,x1,y2,col+op) -- left - end, - [0x87] = function(x1,y1,x2,y2) -- CLIMB_L_STAND_L - col = 0x00ffffff -- white - line(x1,y1,x2,y1,col+op) -- top - col = 0x0000ffff -- cyan - line(x2,y1,x2,y2,col+op) -- right - end, - [0x88] = function(x1,y1,x2,y2) -- CLIMB_LR_STAND_LR - col = 0x00ffffff -- white - line(x1,y1,x2,y1,col+op) -- top - col = 0x00ff00ff -- cyan - line(x1,y1,x1,y2,col+op) -- left - col = 0x0000ffff -- cyan - line(x2,y1,x2,y2,col+op) -- right - end, - [0x70] = function(x1,y1,x2,y2) -- GRAB_SWING - col = 0x0000ff00 -- green - box(x1,y1,x2,y2,col,col+opout) - end, - [0x7f] = function(x1,y1,x2,y2) -- EXIT - col = 0x00ffff00 -- yellow - end, - [0xd0] = function(x1,y1,x2,y2) -- SPIKES - col = 0x00ff0000 -- red - box(x1,y1,x2,y2,col,col+opout) - end, - [0xd1] = function(x1,y1,x2,y2) -- SPIKES - col = 0x00ff0000 -- red - box(x1,y1,x2,y2,col,col+opout) - end -} - -function DrawBlockDefault(x1,y1,x2,y2)-- LEVEL_SPECIFIC - col = 0x00ff8800 -- orange - box(x1,y1,x2,y2,col+opin,col+opout) -end - -function Objects() - if working>0 then return end - - for i=0,63 do - local base = GlobalBase+i*128 - local flag2 = AND(rb(base+0x49),0x10) -- active - - if flag2==0x10 then - local xpos = rw (base+0x00) - local ypos = rw (base+0x02) - local dmg = rb (base+0x10) - local type = rw (base+0x40) - local hp = rw (base+0x50) - local cRAM = r24(base+0x75) -- pointer to 4 collision boxes per object - local col = 0 -- collision color - local xscr = (xpos-camx)/div - local yscr = (ypos-camy)/div - - for boxx=0,4 do - local x1 = (rws(cRAM+boxx*8+0)-camx)/div - local y1 = (rws(cRAM+boxx*8+2)-camy)/div - local x2 = (rws(cRAM+boxx*8+4)-camx)/div - local y2 = (rws(cRAM+boxx*8+6)-camy)/div - - if boxx==0 then - col = 0xff00ff00 -- body - if type==282 or type==258 then hp = 1 end -- archer hp doesn't matter - if hp>0 and type>0 then - text(x1+2,y1+1,string.format("%d",hp),col,0x88000000,"gens") - end - elseif boxx==1 then - col = 0xffffff00 -- floor - elseif boxx==2 then - if dmg>0 - then col = 0xffff0000 -- projectile - else col = 0xff8800ff -- item - end - if dmg>0 then - text(x1+2,y2+1,string.format("%d",dmg),col,0x88000000,"gens") - end - else - col = 0xffffffff -- other - end - - if x1~=0x8888 and x2<320 and x1>0 and y2<224 and y1>0 then - box(x1,y1,x2,y2,col) - end - end - end - end -end - -function PlayerBoxes() - if working>0 then return end - - local xx = (Xpos-camx)/div - local yy = (Ypos-camy)/div - local col = 0xff00ffff - local swcol = col -- usual detection - - if Yspd>0 then -- gimme swings to grab! - swcol = 0xff00ff00 - elseif Yspd==0 then -- can tell that too - swcol = 0xffffffff - end - - if facing==2 then - box(xx-0xf /div-2,yy-0x2c/div-1,xx-0xf /div+0,yy-0x2c/div+1,swcol) -- lefttop - else - box(xx+0xf /div-1,yy-0x2c/div-1,xx+0xf /div+1,yy-0x2c/div+1,swcol) -- rightttop - end - - box(xx -1,yy-0x2c/div-1,xx +1,yy-0x2c/div+1,col) -- top - box(xx-0xf /div-2,yy-0x1f/div-1,xx-0xf /div+0,yy-0x1f/div+1,col) -- left - box(xx+0x10/div-1,yy-0x1f/div-1,xx+0x10/div+1,yy-0x1f/div+1,col) -- right --- box(xx -1,yy-0x1f/div-1,xx +1,yy-0x1f/div+1,col) -- center - box(xx -1,yy-0x0f/div-1,xx +1,yy-0x0f/div+1,col) -- bottom - box(xx -1,yy -1,xx +1,yy +1,0xffffff00) -- feet --- box(xx -1,yy+0x10/div-1,xx +1,yy+0x10/div+1,col) -- ground -end - -function Input() - local i,u,d,l,r,a,b,c,s - - if movie.isloaded() then - i = movie.getinput(emu.framecount()-1) - else - i = joypad.getimmediate() - end - - if i["P1 Up" ] then u = "U" else u = " " end - if i["P1 Down" ] then d = "D" else d = " " end - if i["P1 Left" ] then l = "L" else l = " " end - if i["P1 Right"] then r = "R" else r = " " end - if i["P1 A" ] then a = "A" else a = " " end - if i["P1 B" ] then b = "B" else b = " " end - if i["P1 C" ] then c = "C" else c = " " end - if i["P1 Start"] then s = "S" else s = " " end - - text(1,10,u..d..l..r..a..b..c..s,"yellow") -end - -event.onframeend(function() - emu.setislagged(rb(0xfff6d4)==0) - - if rb(0xfff6d4)==0 then - lagcount = lagcount+1 - framecol = "red" - else - framecol = "white" - end - - emu.setlagcount(lagcount) - - rndlast = rnd1 - workinglast = working - XposLast = Xpos - YposLast = Ypos -end) - -while true do - main() - emu.frameadvance() +-- Gargoyles, Genesis (BizHawk) +-- feos, 2015-2017 + +--== Shortcuts ==-- +local rb = memory.read_u8 +local rw = memory.read_u16_be +local rws = memory.read_s16_be +local r24 = memory.read_u24_be +local rl = memory.read_u32_be +local box = gui.drawBox +local text = gui.text +local ptext = gui.pixelText +local line = gui.drawLine +local AND = bit.band +local SHIFT = bit.rshift + +--== RAM addresses ==-- +local levnum = 0xff00ba +local LevelFlr = 0xff00c0 +local LevelCon = 0xff00c4 +local mapline_tab = 0xff0244 +local GlobalBase = 0xff1c76 +local GolBase = 0xff2c76 +local MapA_Buff = 0xff4af0 + +--== Camera Hack ==-- +local camhack = false +local div = 1 -- scale +local size = 16/div -- block size + +--== Block cache ==-- +local col = 0 -- block color +local opout = 0x33000000 -- outer opacity +local opin = 0x66000000 -- inner opacity +local op = 0xff000000 +local cache = {} + +--== Other stuff ==-- +local MsgCutoff = 20 +local MsgTime = 1 +local MsgStep = 14 +local MsgOffs = 2 +local MsgTable = {} +local XposLast = 0 +local YposLast = 0 +local room = 0 +local workinglast = 0 +local wSize = client.getwindowsize() +local lagcount = emu.lagcount() +gui.defaultTextBackground(0xff000000) + +--== Object types ==-- +local types = { + "Goliath","Orb","Health1PLR","Health2PLR","Health1NME","Health2NME","Numeral", + "BigExplode","SmallExplode","GlassDebris","MetalDebris","WoodDebris", + "WallDebris","SignPiece","SteamVent","BreakWall","SkyLight","BreakLight", + "ThrowCrate","BreakEdgeLeft","BreakEdgeRight","Spark","Spark2","Sparks", + "Sparks2","Fireball","HomingProj1","HorzProj1","VertProj1","DirProj1", + "DirProj2","DropMine","Scratch","Icon","RaptorBot","SniperBot","SpiderBot", + "WaspBot","Xanatos","PlasmaBot","RabidHH","MorningStar","Archer","Arrow", + "Valkyrie","Axe","WeaponExp","Couldron","SpittingCouldron","FireballHead", + "FireballTrail","BigFireballHead","BigFireballTrail","Oil","OilGenerator", + "Claw","Stump","StumpBubble","StumpFire","ClawStump","StumpFireGen","Vent", + "VentSparks","Chain","FlameLick","Floor","MutVikBody","MutVikHead", + "MutVikHammer","EyeOfOdin","EyeOfOdinTrail","L1BreakWall","Catapult", + "L1BreakFloor","Gate","GateCrusher","Weight","WeightCrusher","WallFire", + "Balista","BalistaLog","PasteWall","FlameBoulder","CastlePiece", + "MutantSpiderBot","MutSpiLegs","MutSpiHead","MutSpiHeadFlame","MutSpiProj", + "MutSpiElecV","MutSpiElecH","PlasmaBall","PlasmaBallTail","PlasmaDeadHead", + "VertFlame","WallFlame","FloorFlame","OPPlatform","OPLink","OPOrb", + "Furnace","RobotGenerator","RockGenerator","BigRock","MediumRock", + "SmallRock","BigCouldronGen","BigCouldron","Trough","TroughGen","Energizer", + "Demona","TrajectoryProj","WallPaste","EdgePaste","Tentacle","Infuser", + "BigGuns","BigGunsProj","HighSignPole","HighSign","LowLight","L5Skylight", + "L5Wall","ElecGenerator","Electricity","WaspGenerator","TunnelEdge", + "ForegroundPost","Sorcerer","LightningTop","LightningBot","MDemonaWallFire", + "MDemonaFloorFire","EyeRooftopUp","EyeRooftopDn","EyeRaptor" +} + +local function RoomTime() + local start11 = 894--767 + local start12 = 2294 + local start13 = 5468 -- 4254 -- 4101 + local startl4 = 5506 + local startl5 = 7117 + local startl6 = 8412 + local startl7 = 17117 + local timer = emu.framecount() + if timer < start11 then room = timer + elseif timer < start12 then room = timer - start11 + elseif timer < start13 then room = timer - start12 + elseif timer < startl4 then room = timer - start13 + elseif timer < startl5 then room = timer - startl4 + elseif timer < startl6 then room = timer - startl5 + elseif timer < startl7 then room = timer - startl6 + end + text(2, 2, string.format("cx:%5d\ncy:%5d\nroom:%d", camx, camy, room), "white", "bottomright") +end + +local function HUD() + --if working > 0 then return end + local rndcol = "white" + if rndlast ~= rnd1 then rndcol = "red" end + text(0, 2, string.format("RNG:%08X %04X", rnd1, rnd2), rndcol, "bottomleft") + text(2, 0, string.format( + "x: %4d\ny: %4d\ndx: %3d\ndy: %3d\nhp: %3d\nrun:%3d\ninv:%3d", + Xpos, Ypos, Xspd, Yspd, health, run, inv), + "white", "topright") +end + +local function CamhackHUD() + if working == 0 then + -- screen edge + box((backx-camx- 1)/div, + (backy-camy- 1)/div, + (backx-camx+320)/div, + (backy-camy+224)/div, + 0xff0000ff, 0) + -- map edge + box( 0-camx/div+size, + 0-camy/div+size, + mapw/div-camx/div, + maph/div-camy/div, + 0xff0000ff, 0) + end + if camhack or div > 1 then + text(0, 0, string.format("div:%d", div), "white", "topleft") + end +end + +local function PosToIndex(x, y) + return math.floor(x/16)+math.floor(y/16)*xblocks +end + +local function IndexToPos(i) + return { x=(i%xblocks)*16, y=math.floor(i/xblocks)*16 } +end + +local function InBounds(x, minimum, maximum) + if x >= minimum and x <= maximum + then return true + else return false + end +end + +local function GetBlock(x, y) + if working > 0 then return nil end + local final = { contour={}, block=0 } + if x > 0 and x < mapw + and y > 0 and y < maph then + local pixels = 0 + local x1 = x/div-camx/div + local x2 = x1+size-1 + local y1 = y/div-camy/div + local y2 = y1+size-1 + local d4 = rw(mapline_tab+SHIFT(y, 4)*2) + local a1 = r24(LevelFlr+1) + local d1 = SHIFT(rw(MapA_Buff+d4+SHIFT(x, 4)*2), 1) + final.block = rb(a1+d1+2) + d1 = rw(a1+d1) + a1 = r24(LevelCon+1)+d1 + if rb(a1) > 0 or rb(a1+8) > 0 then + for pixel=0, 15 do + final.contour[pixel] = rb(a1+pixel) + end + else + final.contour = nil + end + else + return nil + end + return final +end + +local DrawBlock = { + [0x80] = function(x1, y1, x2, y2) -- WALL + col = 0x00ffffff -- white + line(x1, y1, x1, y2, col+op) -- left + line(x2, y1, x2, y2, col+op) -- right + end, + [0x81] = function(x1, y1, x2, y2) -- CEILING + col = 0x00ffffff -- white + line(x1, y2, x2, y2, col+op) -- bottom + end, + [0x82] = function(x1, y1, x2, y2) -- CLIMB_U + col = 0x0000ffff -- cyan + line(x1, y2, x2, y2, col+op) -- bottom + end, + [0x83] = function(x1, y1, x2, y2) -- CLIMB_R + col = 0x0000ffff -- cyan + line(x1, y1, x1, y2, col+op) -- left + end, + [0x84] = function(x1, y1, x2, y2) -- CLIMB_L + col = 0x0000ffff -- cyan + line(x2, y1, x2, y2, col+op) -- right + end, + [0x85] = function(x1, y1, x2, y2) -- CLIMB_LR + col = 0x0000ffff -- cyan + line(x1, y1, x1, y2, col+op) -- left + line(x2, y1, x2, y2, col+op) -- right + end, + [0x86] = function(x1, y1, x2, y2) -- CLIMB_R_STAND_R + col = 0x00ffffff -- white + line(x1, y1, x2, y1, col+op) -- top + col = 0x0000ffff -- cyan + line(x1, y1, x1, y2, col+op) -- left + end, + [0x87] = function(x1, y1, x2, y2) -- CLIMB_L_STAND_L + col = 0x00ffffff -- white + line(x1, y1, x2, y1, col+op) -- top + col = 0x0000ffff -- cyan + line(x2, y1, x2, y2, col+op) -- right + end, + [0x88] = function(x1, y1, x2, y2) -- CLIMB_LR_STAND_LR + col = 0x00ffffff -- white + line(x1, y1, x2, y1, col+op) -- top + col = 0x00ff00ff -- cyan + line(x1, y1, x1, y2, col+op) -- left + col = 0x0000ffff -- cyan + line(x2, y1, x2, y2, col+op) -- right + end, + [0x70] = function(x1, y1, x2, y2) -- GRAB_SWING + col = 0x0000ff00 -- green + box(x1, y1, x2, y2, col, col+opout) + end, + [0x7f] = function(x1, y1, x2, y2) -- EXIT + col = 0x00ffff00 -- yellow + end, + [0xd0] = function(x1, y1, x2, y2) -- SPIKES + col = 0x00ff0000 -- red + box(x1, y1, x2, y2, col, col+opout) + end, + [0xd1] = function(x1, y1, x2, y2) -- SPIKES + col = 0x00ff0000 -- red + box(x1, y1, x2, y2, col, col+opout) + end +} + +local function DrawBlockDefault(x1, y1, x2, y2) -- LEVEL_SPECIFIC + col = 0x00ff8800 -- orange + box(x1, y1, x2, y2, col+opin, col+opout) +end + +local function DrawBG(unit, x, y) + local val= 0 + local x1 = x/div-camx/div-(camx%16)/div + local x2 = x1+size-1 + local y1 = y/div-camy/div-(camy%16)/div + local y2 = y1+size-1 + if unit.contour ~= nil then + box(x1, y1, x2, y2, 0x5500ff00, 0x5500ff00) + for pixel=0, 15 do + val = unit.contour[pixel] + --[ [-- + if val > 0 then + gui.drawPixel( + x1+pixel/div, + y1+val/div-1/div, + 0xffffff00) + end + --]]-- + end + end + if unit.block > 0 then + local Fn = DrawBlock[unit.block] or DrawBlockDefault + Fn(x1, y1, x2, y2) + box(x1, y1, x2, y2, col+opin, col+opout) + end +end + +local function Background() + if working > 0 then + cache = {} + return + end + if camhack then + camx = Xpos-320/2*div + camy = Ypos-224/2*div + box(0, 0, 320, 240, 0, 0x66000000) + end + local border = 0 + local offset = 32 + local basex = camx+border + local basey = camy+border + local basei = PosToIndex(basex-offset, basey-offset) + local boundx = 320*div-border + local boundy = 224*div-border + local xblockstockeck = ((camx+boundx+offset)-(basex-offset))/size/div + local yblockstockeck = ((camy+boundy+offset)-(basey-offset))/size/div + for yblock = 0, yblockstockeck do + for xblock = 0, xblockstockeck do + local i = yblock*xblocks+xblock+basei + local x = basex+xblock*size*div + local y = basey+yblock*size*div + if InBounds(x, basex-offset, camx+boundx+offset) then + local unit = cache[i] + if unit == nil or workinglast > 0 then + if InBounds(x, basex, camx+boundx) + and InBounds(y, basey, camy+boundy) + then cache[i] = GetBlock(x, y) + end + else + if not InBounds(x, basex, camx+boundx) + and not InBounds(y, basey, camy+boundy) + then cache[i] = nil + end + end + if unit ~= nil then + DrawBG(unit, x, y) + end + elseif cache[i] ~= nil + then cache[i] = nil + end + end + end + CamhackHUD() +end + +local function Clamp(v, vmin, vmax) + if v < vmin then v = vmin end + if v > vmax then v = vmax end + return v +end + +local function Objects() + if working > 0 then return end + for i=0, 63 do + local base = GlobalBase+i*128 + local flag2 = AND(rb(base+0x49), 0x10) -- active + if flag2 == 0x10 then + local xpos = rw (base+0x00) + local ypos = rw (base+0x02) + local state = rw (base+0x0c) + local dmg = rb (base+0x10) + local id = rw (base+0x40) + local hp = rw (base+0x50) + local cRAM = r24(base+0x75) -- pointer to 4 collision boxes per object + local xscr = (xpos-camx)/div + local yscr = (ypos-camy)/div + local num = id/6 + local name = types[num] + local col = 0 -- collision color + for boxx=0, 4 do + local x0 = rw (cRAM+boxx*8) + local x1 = (rws(cRAM+boxx*8+0)-camx)/div + local y1 = (rws(cRAM+boxx*8+2)-camy)/div + local x2 = (rws(cRAM+boxx*8+4)-camx)/div + local y2 = (rws(cRAM+boxx*8+6)-camy)/div + if boxx == 0 then + col = 0xff00ff00 -- body + -- archer hp doesn't matter + if id == 282 or id == 258 then hp = 1 end + if hp > 0 and id > 0 and x0 ~= 0x8888 then + local xx = Clamp(xscr, 0, 318-string.len(name)*4) + local yy = Clamp(yscr, 0, 214) + ptext(xx, yy+2, string.format("%d", hp), col) + end + elseif boxx == 1 then + col = 0xffffff00 -- floor + elseif boxx == 2 then + if dmg > 0 + then col = 0xffff0000 -- projectile + else col = 0xff8800ff -- item + end + if dmg > 0 then + text(x1*wSize+2, y2*wSize+1, + string.format("%d", dmg), col, 0x88000000) + end + else + col = 0xffffffff -- other + end + if x1 ~= 0x8888 + and x1 <= 320 and x2 >= 0 + and y1 <= 224 and y2 >= 0 then + box(x1, y1, x2, y2, col, 0) + end + end + end + end +end + +local function PostRndRoll() + for i = 1,#MsgTable do + if MsgTable[i] and MsgTable[i].index == i then + local base = MsgTable[i].base + local xpos = rw(base+0x00) + local ypos = rw(base+0x02) + local id = rw(base+0x40) + local x = (xpos-camx)/div + local y = (ypos-camy)/div + local num = id/6 + local ymsg = 0 + local yoffs = math.floor((i-1)/MsgCutoff)*14 + local name = types[num] + local color = 0xffffff00 + + if base == GolBase then + name = "Goliath" + elseif not name then + name = string.format("%X", base) + color = 0xff00ffff + end + if y < 224/2 then + yoffs = -yoffs + ymsg = 210 + end + + x = Clamp(x, 2, 320-string.len(name)*4) + y = Clamp(y, 20, 214) + + line ((i-1)%MsgCutoff*MsgStep+3 +MsgOffs, ymsg+yoffs+4, x, y, color-0x88000000) + ptext((i-1)%MsgCutoff*MsgStep*wSize+MsgOffs, ymsg+yoffs, i, color) + + MsgTable[i].timer = MsgTable[i].timer-1 + if MsgTable[i].timer <= 0 then + MsgTable[i] = nil + end + end + end +end + +local function PlayerBoxes() + if working > 0 then return end + local xx = (Xpos-camx)/div + local yy = (Ypos-camy)/div + local col = 0xff00ffff + local swcol = col -- usual detection + if Yspd > 0 then -- gimme swings to grab! + swcol = 0xff00ff00 + elseif Yspd == 0 then -- can tell that too + swcol = 0xffffffff + end + if facing == 2 + then box(xx-0xf /div-2, yy-0x2c/div-1, xx-0xf/div+0, yy-0x2c/div+1, swcol, 0) -- lefttop + else box(xx+0xf /div , yy-0x2c/div-1, xx+0xf/div+2, yy-0x2c/div+1, swcol, 0) -- rightttop + end + box(xx -1, yy-0x2c/div-1, xx +1, yy-0x2c/div+1, col, 0) -- top + box(xx-0xf /div-2, yy-0x1f/div-1, xx-0xf /div+0, yy-0x1f/div+1, col, 0) -- left + box(xx+0x10/div-1, yy-0x1f/div-1, xx+0x10/div+1, yy-0x1f/div+1, col, 0) -- right +-- box(xx -1, yy-0x1f/div-1, xx +1, yy-0x1f/div+1, col, 0) -- center + box(xx -1, yy-0x0f/div-1, xx +1, yy-0x0f/div+1, col, 0) -- bottom + box(xx -1, yy -1, xx +1, yy +1,0xffffff00, 0) -- feet +-- box(xx -1, yy+0x10/div-1, xx +1, yy+0x10/div+1, col, 0) -- ground +end + +local function Input() + local i, u, d, l, r, a, b, c, s + if movie.isloaded() + then i = movie.getinput(emu.framecount()-1) + else i = joypad.getimmediate() + end + if i["P1 Up" ] then u = "U" else u = " " end + if i["P1 Down" ] then d = "D" else d = " " end + if i["P1 Left" ] then l = "L" else l = " " end + if i["P1 Right"] then r = "R" else r = " " end + if i["P1 A" ] then a = "A" else a = " " end + if i["P1 B" ] then b = "B" else b = " " end + if i["P1 C" ] then c = "C" else c = " " end + if i["P1 Start"] then s = "S" else s = " " end + text(1, 10, u..d..l..r..a..b..c..s, "yellow") +end + +event.onframeend(function() + emu.setislagged(rb(0xfff6d4) == 0) + if rb(0xfff6d4) == 0 then + lagcount = lagcount+1 + framecol = "red" + else + framecol = "white" + end + emu.setlagcount(lagcount) + wSize = client.getwindowsize() + rndlast = rnd1 + workinglast = working + XposLast = Xpos + YposLast = Ypos +end) + +event.onmemoryexecute(function() + local a0 = AND(emu.getregister("M68K A0"), 0xffffff) + if a0 ~= 0xff4044 then + for i = 1, 200 do + if MsgTable[i] == nil then + MsgTable[i] = { index = i, timer = MsgTime, base = a0 } + break + end + end + end +end, 0x257A, "RNGseed") + +local function main() + rnd1 = rl (0xff001c) + rnd2 = rw (0xff0020) + working = rb (0xff0073) + xblocks = rw (0xff00d4) + mapw = rw (0xff00d4)*8 + maph = rw (0xff00d6)*8 + Xpos = rws(0xff0106) + Ypos = rws(0xff0108) + camx = rws(0xff010c)+16 + camy = rws(0xff010e)+16 + run = rb (0xff1699) + inv = rw (0xff16d2) + health = rws(0xff2cc6) + backx = camx + backy = camy + Xspd = Xpos-XposLast + Yspd = Ypos-YposLast + facing = AND(rb(GolBase+0x48), 2) -- object flag 1 + if working > 0 then MsgTable = {} end + Background() + PlayerBoxes() + Objects() + PostRndRoll() + HUD() + RoomTime() +end + +while true do + main() + emu.frameadvance() end \ No newline at end of file