-- 320x200
-- Don't mind my variable names
local coolCounter = 0
local goRed = false
local speedometerEnabled = true
local iconSize = 10;
-- Width and Height
local width = 130;
local height = 10;
-- X and Y offsets
local ypos = 1
local xpos = 0
local targetxpos = 0
-- Text X and Y offsets
local txoffset = 2
local tyoffset = 0
local rtxoffset = 0
local rtyoffset = 0
local hudEnabled = true
local useOpposite = false
local customIntermission = false
local a = 0x00090000
-- Water/Space timer X offsets
local timerxoffset = 1;
local animspeed = 10
local started = false
local curspeed = animspeed
freeslot("SKINCOLOR_HUD")
addHook("MapLoad", function ()
curspeed = 0
started = false
xpos = -width - 48;
a = 0x00090000
end)
local function disableHudElements()
if hud.enabled("intermissiontally") and customIntermission then hud.disable("intermissiontally") end
if not hud.enabled("intermissiontally") and not customIntermission then hud.enable("intermissiontally") end
if hudEnabled then
if hud.enabled("score") then hud.disable("score") end
if hud.enabled("time") then hud.disable("time") end
if hud.enabled("rings") then hud.disable("rings") end
if hud.enabled("lives") then hud.disable("lives") end
else
if not hud.enabled("score") then hud.enable("score") end
if not hud.enabled("time") then hud.enable("time") end
if not hud.enabled("rings") then hud.enable("rings") end
if not hud.enabled("lives") then hud.enable("lives") end
end
end
addHook("PreThinkFrame", disableHudElements)
CV_RegisterVar({name="hudwidth", defaultValue="" + width, flags=CV_CALL, pv={MIN=100,MAX=320}, func=function (var)
width = var.value;
end})
CV_RegisterVar({name="hudxpos", defaultValue="" + xpos, flags=CV_CALL, pv={MIN=100,MAX=320}, func=function (var)
targetxpos = var.value
end})
CV_RegisterVar({name="hudypos", defaultValue="" + ypos, flags=CV_CALL, pv={MIN=100,MAX=320}, func=function (var)
ypos = var.value
end})
CV_RegisterVar({name="speedometer", defaultValue=1, flags=CV_CALL, pv=CV_OnOff, func=function (var)
local v = string.lower(var.string)
if v == "on" or v == "1" or v == "Yes" then
speedometerEnabled = true
else
speedometerEnabled = false
end
end})
CV_RegisterVar({name="hud", defaultValue=1, flags=CV_CALL, pv=CV_OnOff, func=function (var)
local v = string.lower(var.string)
if v == "on" or v == "1" or v == "Yes" then
hudEnabled = true
else
hudEnabled = false
end
print(var.value)
end})
CV_RegisterVar({name="hudopposite", defaultValue=0, flags=CV_CALL, pv=CV_OnOff, func=function (var)
local v = string.lower(var.string)
if v == "on" or v == "1" or v == "Yes" then
useOpposite = true
else
useOpposite = false
end
print(var.value)
end})
CV_RegisterVar({name="hudintermission", defaultValue=0, flags=CV_CALL, pv=CV_OnOff, func=function (var)
local v = string.lower(var.string)
if v == "on" or v == "1" or v == "Yes" then
customIntermission = true
else
customIntermission = false
end
print(var.value)
end})
local deccel = FRACUNIT
local accelAdd = -1
local minSpeed = 1
local color
local play = nil
local function hudHandler(v, p, cam)
if not hudEnabled then return end
if not (p.mo or p.mo.valid) then return end
play = p
color = p.mo.color
if p.mo.skin == "modernsonic" then return end
if v.renderer() == "none" then return end
if p.mo == nil or not p.valid then return end
if p.powers[pw_carry] == CR_NIGHTSMODE then return end
if G_IsSpecialStage() then return end
xpos = xpos + (max(min(targetxpos - xpos, curspeed), -curspeed))
if a > 0 and xpos == targetxpos then
a = a - 0x00010000
end
coolCounter = coolCounter + 1
local timer = 0
local timerMax = 0
if not started and p.speed > FRACUNIT/10 then
started = true
curspeed = animspeed
end
if p.powers[pw_underwater] then
timerMax = 1050
timer = min(p.powers[pw_underwater], timerMax)
elseif p.powers[pw_spacetime] then
timerMax = 405
timer = min(p.powers[pw_spacetime], timerMax)
end
local col = 29
if v.RandomChance(deccel) then
if curspeed > minSpeed then
curspeed = curspeed - accelAdd
end
end
if coolCounter > 7 then
coolCounter = 0
if not goRed then goRed = true else goRed = false end
end
if p.rings > 0 then goRed = false end
if goRed then col = 38 end
local txpos = 5;
local rpos = -5;
--Rings
v.drawFill(xpos, ypos, width, height, col|a|V_SNAPTOTOP|a|V_SNAPTOLEFT)
local ramp = 0
if p.skincolor then
if useOpposite then
ramp = skincolors[ColorOpposite(p.mo.color)].ramp
else
ramp = skincolors[p.mo.color].ramp
end
end
local i = 0
local step = width / 16
if not ramp then return end
v.drawFill(xpos, ypos + height, width, 1, ramp[15]|a|V_SNAPTOTOP|a|V_SNAPTOLEFT)
while i < 16 do
local c = ramp[i]
local x = 0
while x < step do
v.drawFill(xpos + (i * step) + x, ypos + height, 1, 1, c|a|V_SNAPTOTOP|a|V_SNAPTOLEFT)
x = x + 1
end
i = i + 1
end
v.drawString(xpos + txpos + rtxoffset, 1 + ypos, "Rings", V_YELLOWMAP|a|V_SNAPTOTOP|a|V_SNAPTOLEFT, "left")
local twidth = v.stringWidth("" + p.rings, V_SNAPTOTOP|a|V_SNAPTOLEFT)
v.drawString(xpos + width + txpos - twidth + rpos, 1 + ypos, "" + p.rings, V_YELLOWMAP|a|V_SNAPTOTOP|a|V_SNAPTOLEFT, "left")
--Time
v.drawString(xpos + txpos + txoffset, 4 + ypos + height, "Time", V_SNAPTOTOP|a|V_SNAPTOLEFT, "left")
local f = "%02d"
local str = string.format(f, G_TicsToMinutes(p.realtime, true)) + ":" + string.format(f, G_TicsToSeconds(p.realtime)) + "." + string.format(f, G_TicsToCentiseconds(p.realtime))
local twidth = v.stringWidth(str, V_SNAPTOTOP|a|V_SNAPTOLEFT)
v.drawString(xpos + width + txpos - twidth + rpos, 4 + ypos + height, str, V_YELLOWMAP|a|V_SNAPTOTOP|a|V_SNAPTOLEFT, "left")
--Score
v.drawString(xpos + txpos + txoffset, 4 + ypos + height + 10, "Score", V_SNAPTOTOP|a|V_SNAPTOLEFT, "left")
local str = "" + p.score
local twidth = v.stringWidth(str, V_SNAPTOTOP|a|V_SNAPTOLEFT)
v.drawString(xpos + width + txpos - twidth + rpos, 4 + ypos + height + 10, str, V_YELLOWMAP|a|V_SNAPTOTOP|a|V_SNAPTOLEFT, "left")
--Life counter
local xwidth = v.stringWidth("x", V_SNAPTOBOTTOM|a|V_SNAPTOLEFT, "small")
local s = v.getSprite2Patch(p.realmo.skin, SPR2_LIFE, false, 0)
local scaleMul = FRACUNIT;
local colormap = v.getColormap(p.mo.skin, p.mo.color);
if not s then
s = v.getSpritePatch("TV1U", A)
scaleMul = FRACUNIT/3
end
local off = 10;
local nyoff = -2;
local lyoff = -2;
if G_GametypeUsesLives() then
v.drawScaled(((320 - xpos) - iconSize)*FRACUNIT, (ypos+iconSize)*FRACUNIT, FixedMul(FRACUNIT + (2/FRACUNIT), scaleMul), s, V_SNAPTOTOP|a|V_SNAPTORIGHT, colormap)
v.drawString((320 - xpos) - (iconSize * 2) - 20, ypos + (iconSize/2) - 1, string.format("%02d", p.lives), V_YELLOWMAP|a|V_SNAPTOTOP|a|V_SNAPTORIGHT)
v.drawString((((320 - xpos) - (iconSize * 2) - 4)), ypos + (iconSize/2) + 2, "x", V_YELLOWMAP|a|V_SNAPTOTOP|a|V_SNAPTORIGHT, "small")
end
--Underwater/Space timer
if timerMax > 0 then
v.drawFill(xpos + timerxoffset, 4 + ypos + height + 20, width - timerxoffset - 1, 2, 159|a|V_SNAPTOTOP|a|V_SNAPTOLEFT)
v.drawFill(xpos + timerxoffset, 4 + ypos + height + 20, FixedInt(FixedMul(FixedDiv(timer*FRACUNIT, timerMax*FRACUNIT), width*FRACUNIT)) - timerxoffset - 1, 2, 131|a|V_SNAPTOTOP|a|V_SNAPTOLEFT)
end
local h = 3;
--Boss health
--if not (boss == nil) and boss.valid and bossHealthEnabled then
-- if P_CheckSight(p.mo, boss) then
-- local off = 32 + 4;
-- v.drawString(320 - xpos - width - xpos - off, ypos, "BOSS", V_REDMAP|a|V_SNAPTOTOP|a|V_SNAPTORIGHT)
-- v.drawFill(320 - xpos - width - xpos, ypos, width, height, 29|a|V_SNAPTOTOP|a|V_SNAPTORIGHT)
-- local w = width - (h * 2)
-- v.drawFill(320 - xpos - width - xpos + h, ypos + h, w, height - (h * 2), 40|a|V_SNAPTOTOP|a|V_SNAPTORIGHT)
-- v.drawFill(320 - xpos - width - xpos + h, ypos + h, min(FixedInt(FixedMul(FixedDiv((bossHealth*FRACUNIT),(bossMaxHealth*FRACUNIT)), w*FRACUNIT)), w), height - (h * 2), 35|a|V_SNAPTOTOP|a|V_SNAPTORIGHT)
-- end
--end
--Speedometer
if not speedometerEnabled then return end
local off = (8 * 5) + 4;
local px = 0;
v.drawString(px + xpos, 200 - height - 9, "SPEED", skincolors[p.mo.color].chatcolor|a|V_SNAPTOBOTTOM|a|V_SNAPTOLEFT)
v.drawFill(px + xpos, 200 - height, width, height, 29|a|V_SNAPTOBOTTOM|a|V_SNAPTOLEFT)
local w = width - (h * 2)
v.drawFill(px + xpos + h, 200 - height + h, w, height - (h * 2), ramp[15]|a|V_SNAPTOBOTTOM|a|V_SNAPTOLEFT)
v.drawFill(px + xpos + h, 200 - height + h, min(FixedInt(FixedMul(FixedDiv((p.speed),(skins[0].runspeed*2 + (skins[0].runspeed/2))), w*FRACUNIT)), w), height - (h * 2), ramp[4]|a|V_SNAPTOBOTTOM|a|V_SNAPTOLEFT)
if p.powers[pw_tailsfly] > 0 then
v.drawFill(px + xpos + h, 200 - height + h + (height - (h * 2)), w, 1, ramp[13]|a|V_SNAPTOBOTTOM|a|V_SNAPTOLEFT)
v.drawFill(px + xpos + h, 200 - height + h + (height - (h * 2)), min(FixedInt(FixedMul(FixedDiv((p.powers[pw_tailsfly]*FRACUNIT),280*FRACUNIT), w*FRACUNIT)), w), 1, ramp[0]|a|V_SNAPTOBOTTOM|a|V_SNAPTOLEFT)
end
local i = 0;
local sstep = width / 16;
v.drawFill(px + xpos, (200 - 1), width, 1, ramp[15]|a|V_SNAPTOBOTTOM|a|V_SNAPTOLEFT)
while i < 16 do
local c = ramp[i]
local x = 0
while x < sstep do
v.drawFill(px + xpos + (i * sstep) + x, (200 - 1), 1, 1, c|a|V_SNAPTOBOTTOM|a|V_SNAPTOLEFT)
x = x + 1
end
i = i + 1
end
end
local function intermissionScreen(v)
if v.renderer() == "none" then return end
if play == nil or not play.valid then return end
if not customIntermission then return end
local str = "test"
local tw = v.stringWidth(str)
local testScore = play.score
local testTime = play.realtime
local p = play
--Time
v.drawString(targetxpos + txoffset, 4 + ypos, "Time", V_SNAPTOTOP|V_SNAPTOLEFT, "left")
local f = "%02d"
local time = testTime
local str = string.format(f, G_TicsToMinutes(time, true)) + ":" + string.format(f, G_TicsToSeconds(time)) + "." + string.format(f, G_TicsToCentiseconds(time))
local twidth = v.stringWidth(str, V_SNAPTOTOP|V_SNAPTOLEFT)
v.drawString(targetxpos + width - twidth, 4 + ypos, str, V_YELLOWMAP|V_SNAPTOTOP|V_SNAPTOLEFT, "left")
--Score
v.drawString(targetxpos + txoffset, 4 + ypos + 10, "Score", V_SNAPTOTOP|V_SNAPTOLEFT, "left")
local str = "" + testScore
local twidth = v.stringWidth(str, V_SNAPTOTOP|V_SNAPTOLEFT)
v.drawString(targetxpos + width - twidth, 4 + ypos + 10, str, V_YELLOWMAP|V_SNAPTOTOP|V_SNAPTOLEFT, "left")
--Now i have to calculate the bonuses, pain
local ringBonus = p.rings * 100
local seconds = G_TicsToSeconds(play.realtime, true)
local timeBonus = 0
if seconds <= 600 then timeBonus = 0 end
if seconds <= 599 then timeBonus = 100 end
if seconds <= 539 then timeBonus = 200 end
if seconds <= 479 then timeBonus = 300 end
if seconds <= 419 then timeBonus = 400 end
if seconds <= 359 then timeBonus = 500 end
if seconds <= 299 then timeBonus = 1000 end
if seconds <= 239 then timeBonus = 2000 end
if seconds <= 179 then timeBonus = 3000 end
if seconds <= 119 then timeBonus = 4000 end
if seconds <= 89 then timeBonus = 5000 end
if seconds <= 59 then timeBonus = 10000 end
if seconds <= 29 then timeBonus = 50000 end
local y = 100 - 32
local h = 175
local w = 200
local name = skins[play.skin].realname
local col = skincolors[color]
local c = col.chatcolor
local ramp = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
if color then
if useOpposite then
ramp = skincolors[ColorOpposite(color)].ramp
else
ramp = skincolors[color].ramp
end
end
local tw = v.stringWidth(name + " ") + v.stringWidth("Got Through")
local pos = 160 + (tw / 2)
local ww = w + 8;
local step = w / 16;
v.drawString(pos - tw, y, name, c)
v.drawString(pos - (tw - v.stringWidth(name + " ")), y, "Got Through", V_YELLOWMAP)
y = y + 20
pos = 160 + (w / 2)
v.drawFill(pos - w, y + 8, w, 1, ramp[15])
local i = 0
while i < 16 do
local c = ramp[i]
local x = 0
while x < step do
v.drawFill((pos - w) + (i * step) + x, y + 8, 1, 1, c)
x = x + 1
end
i = i + 1
end
v.drawString(pos - w, y, "RING BONUS")
local s = ringBonus + ""
local wi = v.stringWidth(s)
v.drawString(pos - wi, y, s, V_YELLOWMAP)
y = y + 12
v.drawFill(pos - w, y + 8, w, 1, ramp[15])
local i = 0
while i < 16 do
local c = ramp[i]
local x = 0
while x < step do
v.drawFill((pos - w) + (i * step) + x, y + 8, 1, 1, c)
x = x + 1
end
i = i + 1
end
v.drawString(pos - w, y, "TIME BONUS")
local s = timeBonus + ""
local wi = v.stringWidth(s)
v.drawString(pos - wi, y, s, V_YELLOWMAP)
end
hud.add(hudHandler, "game")
hud.add(intermissionScreen, "intermission")