--*****************************************************************************
local Draw= {}
--*****************************************************************************
--Coordinates is the top-left pixel of the 3x5 digit.
--Used for drawing compact, colored numbers.
local Px,Li= gui.pixel, gui.line
Draw[0]= function(x,y,c) -- ###
Li(x ,y ,x ,y+4,c)-- # #
Li(x+2,y ,x+2,y+4,c)-- # #
Px(x+1,y ,c) -- # #
Px(x+1,y+4,c) -- ###
end
Draw[1]= function(x,y,c) -- #
Li(x ,y+4,x+2,y+4,c)-- ##
Li(x+1,y ,x+1,y+3,c)-- #
Px(x ,y+1,c) -- #
end -- ###
Draw[2]= function(x,y,c) -- ###
Li(x ,y ,x+2,y ,c)-- #
Li(x ,y+3,x+2,y+1,c)-- ###
Li(x ,y+4,x+2,y+4,c)-- #
Px(x ,y+2,c) -- ###
Px(x+2,y+2,c)
end
Draw[3]= function(x,y,c) -- ###
Li(x ,y ,x+1,y ,c)-- #
Li(x ,y+2,x+1,y+2,c)-- ###
Li(x ,y+4,x+1,y+4,c)-- #
Li(x+2,y ,x+2,y+4,c)-- ###
end
Draw[4]= function(x,y,c) -- # #
Li(x ,y ,x ,y+2,c)-- # #
Li(x+2,y ,x+2,y+4,c)-- ###
Px(x+1,y+2,c) -- #
end -- #
Draw[5]= function(x,y,c) -- ###
Li(x ,y ,x+2,y ,c)-- #
Li(x ,y+1,x+2,y+3,c)-- ###
Li(x ,y+4,x+2,y+4,c)-- #
Px(x ,y+2,c) -- ###
Px(x+2,y+2,c)
end
Draw[6]= function(x,y,c) -- ###
Li(x ,y ,x+2,y ,c)-- #
Li(x ,y+1,x ,y+4,c)-- ###
Li(x+2,y+2,x+2,y+4,c)-- # #
Px(x+1,y+2,c) -- ###
Px(x+1,y+4,c)
end
-- ###
Draw[7]= function(x,y,c) -- #
Li(x ,y ,x+1,y ,c)-- ##
Li(x+2,y ,x+1,y+4,c)-- #
end -- #
Draw[8]= function(x,y,c) -- ###
Li(x ,y ,x ,y+4,c)-- # #
Li(x+2,y ,x+2,y+4,c)-- ###
Px(x+1,y ,c) -- # #
Px(x+1,y+2,c) -- ###
Px(x+1,y+4,c)
end
Draw[9]= function(x,y,c) -- ###
Li(x ,y ,x ,y+2,c)-- # #
Li(x+2,y ,x+2,y+3,c)-- ###
Li(x ,y+4,x+2,y+4,c)-- #
Px(x+1,y ,c) -- ###
Px(x+1,y+2,c)
end
Draw[10]=function(x,y,c) -- #
Li(x ,y+1,x ,y+4,c)-- # #
Li(x+2,y+1,x+2,y+4,c)-- # #
Px(x+1,y ,c) -- ###
Px(x+1,y+3,c) -- # #
end
Draw[11]=function(x,y,c) -- ##
Li(x ,y ,x ,y+4,c)-- # #
Li(x+1,y ,x+2,y+1,c)-- ##
Li(x+1,y+4,x+2,y+3,c)-- # #
Px(x+1,y+2,c) -- ##
end
Draw[12]=function(x,y,c) -- #
Li(x ,y+1,x ,y+3,c)-- # #
Li(x+1,y ,x+2,y+1,c)-- #
Li(x+1,y+4,x+2,y+3,c)-- # #
end -- #
Draw[13]=function(x,y,c) -- ##
Li(x ,y ,x ,y+4,c)-- # #
Li(x+2,y+1,x+2,y+3,c)-- # #
Px(x+1,y ,c) -- # #
Px(x+1,y+4,c) -- ##
end
Draw[14]=function(x,y,c) -- ###
Li(x ,y ,x ,y+4,c)-- #
Li(x+1,y ,x+2,y ,c)-- ##
Li(x+1,y+4,x+2,y+4,c)-- #
Px(x+1,y+2,c) -- ###
end
Draw[15]=function(x,y,c) -- ###
Li(x ,y ,x ,y+4,c)-- #
Li(x+1,y ,x+2,y ,c)-- ##
Px(x+1,y+2,c) -- #
end -- #
--*****************************************************************************
local function __DN_AnyBase(right, y, Number, c, bkgnd, div)
--*****************************************************************************
-- Works with any base from 2 to 16. Paints the input number.
-- Returns the x position where it would paint another digit.
-- It only works with integers. Rounds fractions toward zero.
if div < 2 then return end -- Prevents the function from never returning.
local Digit= {}
local Negative= false
if Number < 0 then
Number= -Number
Negative= true
end
Number= math.floor(Number)
c= c or "white"
bkgnd= bkgnd or "clear"
local i= 0
if Number < 1 then
Digit[1]= 0
i= 1
end
while (Number >= 1) do
i= i+1
Digit[i]= Number % div
Number= math.floor(Number/div)
end
if Negative then i= i+1 end
local x= right - i*4
gui.box(x+1, y-1, right+1, y+5,bkgnd,bkgnd)
i= 1
while Draw[Digit[i]] do
Draw[Digit[i]](right-2,y,c)
right= right-4
i=i+1
end
if Negative then
gui.line(right, y+2,right-2,y+2,c)
right= right-4
end
return right
end
--*****************************************************************************
local function DrawNum(right, y, Number, c, bkgnd)
--*****************************************************************************
-- Paints the input number as right-aligned. Decimal version.
return __DN_AnyBase(right, y, Number, c, bkgnd, 10)
end
--*****************************************************************************
local function DrawNumx(right, y, Number, c, bkgnd)
--*****************************************************************************
-- Paints the input number as right-aligned. Hexadecimal version.
return __DN_AnyBase(right, y, Number, c, bkgnd, 16)
end
-------------------------------------------------------------------------------
local R1u,R1s= memory.readbyte, memory.readbytesigned
local R2u,R2s= memory.readword, memory.readwordsigned
--*****************************************************************************
local function Roll(r) -- Apparently, this is the RNG function
--*****************************************************************************
if r == 0 then return 1 end -- Can't tell what, really.
r= r*3
if r >= 384 then r= r+1 end -- High bit before r*3 probably determines +1
return r%256 -- Fit within one byte
end -- Address 0059 holds the RNG value
--I've pre-generated the table.
--local Init_RNG= {0,1,3,9,27,81,243,218,143,174,11,33,99,41,123,113,83}
local Loop_RNG= {249,236,197,80,240,209,116,92,20,60,180,29,87,5,15,45,
135,150,195,74,222,155,210,119,101, 47,141,168}
--*****************************************************************************
local function r_tbl()
--*****************************************************************************
--Well, get the RNG
local RNG= R1u(0x0059)
--Scan through our list of values to locate where in the loop it is.
--This scan is inefficient, though. I keep looking even after I found it.
--Also scanned every frame rather than whenever RNG changes.
local Found= false
for i= 1, #Loop_RNG do
if RNG == Loop_RNG[i] then
DrawNum(254,3+i*6,Loop_RNG[i],"white","black")
Found= true
else
DrawNum(254,3+i*6,Loop_RNG[i],"green","black")
end
end
if Found then return end
--Down here, I'm not inside the Loop_RNG. Predict other numbers, then
DrawNum(240,9,RNG,"white","black")
for i= 1, 28 do -- Place a limit, just in case.
RNG= Roll(RNG)
if RNG == Loop_RNG[1] then return end -- Ah, our Loop_RNG. Done!
DrawNum(240,9+6*i,RNG,"orange","black")
end
end
--*****************************************************************************
local function CarDisp() -- Dem CPU cars, man! Needs to see 'em, I say!
--*****************************************************************************
for i= 0, 2 do -- There are three lanes. Each lane uses separate memory.
local X= 61 + 51*i
local addr= 0x0520+i*16
local clr,tmr= "green","grey"
local dst= "grey"
local ID= R1s(addr)
if ID < 0 then clr,tmr= "grey","green"
else
dst= "green"
local distance= R1u(addr+2)
if distance >= 64 then dst= "cyan" end -- Lane change range
if distance == 102 then dst= "green" end -- Empty zone
if distance >= 103 then dst= "orange" end -- possible impact now.
if distance >= 112 then dst= "white" end -- Side.
if distance >= 124 then dst= "orange" end -- Front.
end
DrawNumx(X+10, 9,R1u(addr+ 0),clr,"black") -- ID
DrawNum( X+20, 9,R1u(addr+ 3),tmr,"black") -- Respawn timer
DrawNum( X+30, 9,R1u(addr+ 6),tmr,"black") -- Respawn timer init
DrawNum( X+12, 16,R1u(addr+ 1),clr,"black") -- Speed
DrawNum( X+12, 23,R1u(addr+ 4),tmr,"black") -- Respawn Speed (base)
DrawNum( X+12, 30,R1u(addr+ 5),tmr,"black") -- Respawn Speed (RNGplus)
DrawNum( X+25, 16,R1u(addr+ 2),dst,"black") -- Dist main
DrawNumx(X+34, 16,R1u(addr+ 7),clr,"black") -- Dist sub
DrawNum (X+25, 23,R1s(addr+ 8),clr,"black") -- X offset (lane shift)
DrawNumx(X+34, 23,R1u(addr+11),clr,"black") -- X sub
DrawNumx(X+24, 31,R1u(addr+ 9),tmr,"black") -- Lane change timer
DrawNumx(X+32, 31,R1u(addr+10),clr,"black") -- Related to impacts?
DrawNumx(X+24, 38,R1u(addr+12),clr,"black") -- Visible position
-- DrawNumx(X+32, 38,R1u(addr+13),clr,"black") -- 0xFF
-- DrawNumx(X+24, 45,R1u(addr+14),clr,"black") -- 0xFF
-- DrawNumx(X+32, 45,R1u(addr+15),clr,"black") -- 0xFF
--Predict the velocities of spawning cars: Three numbers in advance.
local r= R1u(0x0059)
for j= 0, 2 do
r= Roll(r)
DrawNum(X+12,37+6*j,
R1u(addr+4)+bit.band(r,R1u(addr+5)),
"white","black")
end -- RNG loop
end -- car loop
end -- function
--*****************************************************************************
local function SpeedCalcs()
--*****************************************************************************
--Paints the info into the HUD. Alas, I bury the position for the paint here.
--To figure out what your speed does, we need it!
local speed= R1u(0x0038)
--Curves have varying effect based on speed
--Alas, I'm finding it difficult to work out.
--Speed also has an effect on how well you move, X-wise.
local Xspd= speed -- 0~127
if speed >= 128 then Xspd= 127-math.floor((speed-128)/2) end --128~184
if speed >= 184 then Xspd= 99 end --184~222
if speed >= 222 then Xspd= 99-math.floor((speed-222)/2) end --222~240
if speed >= 240 then Xspd= 90 end --240~255
DrawNum( 126,188,math.floor(Xspd/32),"white","black")
DrawNumx(134,188, Xspd%32 ,"grey" ,"black")
end
local CourseDist= {
[0]=2084864, -- 509 * 16 * 256
2072576, -- 506 * 16 * 256
2084864, -- 509 * 16 * 256
2170880, -- 530 * 16 * 256
2093056, -- 511 * 16 * 256 Haven't figured out what internals to
1912832, -- 467 * 16 * 256 pick from to get these distances.
2048000, -- 500 * 16 * 256 Hate manufacturing numbers myself. Eyah...
2158592 -- 527 * 16 * 256
}
local BoingClr= {[0x00]= "grey",[0x01]="cyan",[0x80]="yellow"}
--*****************************************************************************
local function BasicHUD()
--*****************************************************************************
CarDisp()
r_tbl()
SpeedCalcs()
--Timer stuff, on the left side
DrawNum( 62,183,R2u(0x0029),"yellow","black") -- Frame timer (dec)
DrawNumx( 62,189,R2u(0x0029),"yellow","black") -- Frame timer (hex)
DrawNum( 62,204,R1u(0x0062),"white" ,"black") -- Game timer
--Left-right position crud
local HPos= R2s(0x0030,0x003F) -- Horizontal position
local clr= "green"
if HPos <= -138 then clr= "white" end --Slowdown
if HPos >= 136 then clr= "white" end
if HPos <= -147 then clr= "orange" end --Obstacles
if HPos >= 147 then clr= "orange" end --Going lazy using ifs.
DrawNum( 112,188,HPos ,clr ,"black") -- Position
DrawNumx(120,188,R1u(0x0039) ,"grey" ,"black") -- Sub-position
--Left of tachometer
DrawNum( 94,183,R1u(0x002B)-31,"grey" ,"black") -- Curve-to-be
DrawNum( 94,189,R1u(0x0448)-31,"white" ,"black") -- Curve-right-now
DrawNumx( 94,195,R1u(0x003C) ,"grey" ,"black") -- Curve sub-position
--Right of tachometer
clr= BoingClr[R1u(0x005A)] or "purple" -- BOING direction
DrawNumx(166,183,R1u(0x005C),clr ,"black") -- BOING speed
DrawNumx(166,189,R1u(0x005B),"grey" ,"black") -- BOING sub-position
--Speedometer mirror
DrawNum( 117,204,R1u(0x0038) ,"white" ,"black") -- Speed (main)
DrawNumx(125,204,R1u(0x0058) ,"grey" ,"black") -- Speed (sub)
--Miscellaneous
-- DrawNum( 137,188,R1s(0x03B0),"cyan" ,"black") -- Distant curve
DrawNum( 254,183,R1u(0x00E5),"white" ,"black") -- Stage
--Distance crud
local DM= R1u(0x00F9) -- Distance Multiplier
local Dist= R1u(0x008F)*DM*256 + R1u(0x0031)*256 + R1u(0x0068)
DrawNum( 116,218,Dist ,"White" ,"black") -- Distance traveled
local Lost= R2u(0x0029)*255 - Dist - 121975
DrawNum( 150,218,Lost ,"orange","black") -- Diff from theoretical
local CD= CourseDist[R1u(0x00E5)] or 1
local Remaining= CD-Dist
local Clr= "cyan"
if Remaining <= 0 then Clr= "orange"; Remaining= -Remaining end
DrawNum(116,225,Remaining,Clr,"black")
--There might be a good reason to separate the bytes more.
--However, combining it all to one decimal number is convenient record keeping.
--Lines of Motivation
Dist= Dist*256
local Modu= math.floor((Dist%CD) * 256/CD) - 1
Dist= math.floor(Dist/CD) - 1
if Dist >= 255 then gui.line(0,180,255 ,180,"orange")
elseif Dist >= 0 then gui.line(0,180,Dist,180,"green") end
if Modu >= 0 then gui.line(0,181,Modu,181,"orange") end
end
gui.register(BasicHUD)