local World = require("game.world") local Palette = require("rendering.palette") local Fonts = require("rendering.fonts") local HUD = {} -- Tiny top-down tank icon (like the original lives display) local function drawTankIcon(cx, cy, s) -- Hull outline love.graphics.line(cx - s*1.2, cy - s*0.5, cx + s*0.6, cy - s*0.5) love.graphics.line(cx + s*0.6, cy - s*0.5, cx + s*0.8, cy) love.graphics.line(cx + s*0.8, cy, cx + s*0.6, cy + s*0.5) love.graphics.line(cx + s*0.6, cy + s*0.5, cx - s*1.2, cy + s*0.5) love.graphics.line(cx - s*1.2, cy + s*0.5, cx - s*1.2, cy - s*0.5) -- Barrel love.graphics.line(cx + s*0.4, cy - s*0.15, cx + s*1.8, cy - s*0.15) love.graphics.line(cx + s*0.4, cy + s*0.15, cx + s*1.8, cy + s*0.15) end local function bearingLabel(player, enemy) -- Returns an arcade-style directional message: "ENEMY IN RANGE", -- "ENEMY TO LEFT", "ENEMY TO RIGHT", or "ENEMY TO REAR". Returns nil -- when there is no targetable enemy (e.g. only a saucer present). if not (enemy and enemy.alive) then return nil end local dx, dz = World.wrappedDist(player.x, player.z, enemy.x, enemy.z) local cosA = math.cos(player.angle) local sinA = math.sin(player.angle) local rx = dx * cosA - dz * sinA -- rightward local rz = dx * sinA + dz * cosA -- forward local dist = math.sqrt(rx * rx + rz * rz) local bearing = math.atan2(rx, rz) if rz > 0 and math.abs(bearing) < 0.25 and dist < 800 then return "ENEMY IN RANGE" end if math.abs(bearing) > 3 * math.pi / 4 then return "ENEMY TO REAR" end if bearing > 0 then return "ENEMY TO RIGHT" end return "ENEMY TO LEFT" end function HUD.draw(player, enemy) local p = Palette.get() local sw = World.screenW local sh = World.screenH local rh = World.radarH local sc = sw / 1024 -- === LIVES (top-left) as tank icons === love.graphics.setColor(p.bright) love.graphics.setLineWidth(1.3 * sc) local iconSize = 7 * sc local iconSpacing = 26 * sc local livesStartX = 30 * sc local livesY = rh * 0.25 for i = 1, math.min(World.lives, 6) do drawTankIcon(livesStartX + (i - 1) * iconSpacing, livesY, iconSize) end -- === STATUS MESSAGES (authentic arcade: top-left of display) === -- "MOTION BLOCKED BY OBJECT" takes priority while active, then falls back to -- the directional enemy text ("ENEMY IN RANGE" / "ENEMY TO LEFT/RIGHT/REAR"). if player and player.alive then love.graphics.setFont(Fonts.small) if (player.blockedMessageTimer or 0) > 0 then local alpha = math.min(1, player.blockedMessageTimer / 0.3) love.graphics.setColor(p.bright[1], p.bright[2], p.bright[3], alpha) love.graphics.print("MOTION BLOCKED BY OBJECT", livesStartX, rh * 0.55) else local label = bearingLabel(player, enemy) if label then love.graphics.setColor(p.bright) love.graphics.print(label, livesStartX, rh * 0.55) end end end -- === SCORE (top-right, right-aligned) === love.graphics.setFont(Fonts.medium) love.graphics.setColor(p.bright) local scoreStr = string.format("%09d", World.score) local rightEdge = sw - 30 * sc local valW = Fonts.medium:getWidth(scoreStr) local scoreY = rh * 0.35 love.graphics.print(scoreStr, rightEdge - valW, scoreY) -- === HIGH SCORE (below score) === love.graphics.setFont(Fonts.small) love.graphics.setColor(p.bright[1], p.bright[2], p.bright[3], 0.7) local hsY = scoreY + Fonts.medium:getHeight() + 2 * sc local hsStr = string.format("%09d", World.highScore) local hsW = Fonts.small:getWidth(hsStr) love.graphics.print(hsStr, rightEdge - hsW, hsY) -- === SEPARATOR LINE === love.graphics.setColor(p.dim[1], p.dim[2], p.dim[3], 0.5) love.graphics.setLineWidth(1) love.graphics.line(0, rh, sw, rh) end return HUD