2022-01-11 04:05:30 +00:00
|
|
|
package system
|
|
|
|
|
|
|
|
import (
|
|
|
|
"image"
|
|
|
|
"image/color"
|
2022-01-19 23:32:02 +00:00
|
|
|
"strings"
|
2022-01-11 04:05:30 +00:00
|
|
|
|
2022-01-14 05:30:52 +00:00
|
|
|
"github.com/hajimehoshi/ebiten/v2/ebitenutil"
|
|
|
|
|
2022-01-11 04:05:30 +00:00
|
|
|
"code.rocketnine.space/tslocum/citylimits/component"
|
|
|
|
"code.rocketnine.space/tslocum/citylimits/world"
|
|
|
|
"code.rocketnine.space/tslocum/gohan"
|
|
|
|
"github.com/hajimehoshi/ebiten/v2"
|
|
|
|
)
|
|
|
|
|
|
|
|
type RenderHudSystem struct {
|
2022-01-14 05:30:52 +00:00
|
|
|
op *ebiten.DrawImageOptions
|
|
|
|
hudImg *ebiten.Image
|
|
|
|
tmpImg *ebiten.Image
|
2022-01-15 00:58:44 +00:00
|
|
|
tmpImg2 *ebiten.Image
|
2022-01-14 05:30:52 +00:00
|
|
|
sidebarColor color.RGBA
|
2022-01-11 04:05:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func NewRenderHudSystem() *RenderHudSystem {
|
|
|
|
s := &RenderHudSystem{
|
2022-01-15 00:58:44 +00:00
|
|
|
op: &ebiten.DrawImageOptions{},
|
|
|
|
hudImg: ebiten.NewImage(1, 1),
|
|
|
|
tmpImg: ebiten.NewImage(1, 1),
|
|
|
|
tmpImg2: ebiten.NewImage(1, 1),
|
2022-01-11 04:05:30 +00:00
|
|
|
}
|
|
|
|
|
2022-01-14 05:30:52 +00:00
|
|
|
sidebarShade := uint8(111)
|
|
|
|
s.sidebarColor = color.RGBA{sidebarShade, sidebarShade, sidebarShade, 255}
|
|
|
|
|
2022-01-11 04:05:30 +00:00
|
|
|
return s
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *RenderHudSystem) Needs() []gohan.ComponentID {
|
|
|
|
return []gohan.ComponentID{
|
|
|
|
component.PositionComponentID,
|
|
|
|
component.VelocityComponentID,
|
|
|
|
component.WeaponComponentID,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *RenderHudSystem) Uses() []gohan.ComponentID {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *RenderHudSystem) Update(_ *gohan.Context) error {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *RenderHudSystem) Draw(_ *gohan.Context, screen *ebiten.Image) error {
|
|
|
|
// Draw HUD.
|
|
|
|
if world.World.HUDUpdated {
|
2022-01-14 07:14:22 +00:00
|
|
|
s.hudImg.Clear()
|
|
|
|
s.drawSidebar()
|
2022-01-21 02:25:09 +00:00
|
|
|
s.drawMessages()
|
2022-01-14 07:14:22 +00:00
|
|
|
s.drawTooltip()
|
2022-01-11 04:05:30 +00:00
|
|
|
world.World.HUDUpdated = false
|
|
|
|
}
|
|
|
|
screen.DrawImage(s.hudImg, nil)
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2022-01-14 07:14:22 +00:00
|
|
|
func (s *RenderHudSystem) drawSidebar() {
|
2022-01-11 04:05:30 +00:00
|
|
|
bounds := s.hudImg.Bounds()
|
|
|
|
if bounds.Dx() != world.World.ScreenW || bounds.Dy() != world.World.ScreenH {
|
|
|
|
s.hudImg = ebiten.NewImage(world.World.ScreenW, world.World.ScreenH)
|
2022-01-21 02:25:09 +00:00
|
|
|
s.tmpImg = ebiten.NewImage(world.World.ScreenW, world.World.ScreenH)
|
2022-01-15 00:58:44 +00:00
|
|
|
s.tmpImg2 = ebiten.NewImage(world.SidebarWidth, world.World.ScreenH)
|
2022-01-11 04:05:30 +00:00
|
|
|
} else {
|
|
|
|
s.hudImg.Clear()
|
|
|
|
s.tmpImg.Clear()
|
2022-01-15 00:58:44 +00:00
|
|
|
s.tmpImg2.Clear()
|
2022-01-11 04:05:30 +00:00
|
|
|
}
|
|
|
|
w := world.SidebarWidth
|
|
|
|
if bounds.Dx() < w {
|
|
|
|
w = bounds.Dx()
|
|
|
|
}
|
|
|
|
|
2022-01-14 05:30:52 +00:00
|
|
|
// Fill background.
|
2022-01-15 00:58:44 +00:00
|
|
|
s.hudImg.SubImage(image.Rect(0, 0, world.SidebarWidth, world.World.ScreenH)).(*ebiten.Image).Fill(s.sidebarColor)
|
2022-01-14 05:30:52 +00:00
|
|
|
|
|
|
|
// Draw buttons.
|
2022-01-11 04:05:30 +00:00
|
|
|
|
2022-01-15 00:58:44 +00:00
|
|
|
const paddingSize = 1
|
|
|
|
const columns = 3
|
2022-01-11 04:05:30 +00:00
|
|
|
|
2022-01-15 00:58:44 +00:00
|
|
|
const buttonWidth = world.SidebarWidth / columns
|
|
|
|
const buttonHeight = buttonWidth
|
2022-01-11 04:05:30 +00:00
|
|
|
world.World.HUDButtonRects = make([]image.Rectangle, len(world.HUDButtons))
|
2022-01-14 05:30:52 +00:00
|
|
|
var lastButtonY int
|
2022-01-11 04:05:30 +00:00
|
|
|
for i, button := range world.HUDButtons {
|
|
|
|
row := i / columns
|
2022-01-14 05:30:52 +00:00
|
|
|
x, y := (i%columns)*buttonWidth, row*buttonHeight
|
|
|
|
r := image.Rect(x+paddingSize, y+paddingSize, x+buttonWidth-paddingSize, y+buttonHeight-paddingSize)
|
|
|
|
|
2022-01-19 23:32:02 +00:00
|
|
|
if button != nil {
|
|
|
|
selected := world.World.HoverStructure == button.StructureType
|
|
|
|
if button.StructureType == world.StructureToggleTransparentStructures {
|
|
|
|
selected = world.World.TransparentStructures
|
|
|
|
}
|
2022-01-11 04:05:30 +00:00
|
|
|
|
2022-01-19 23:32:02 +00:00
|
|
|
// Draw background.
|
|
|
|
s.drawButtonBackground(s.tmpImg, r, selected)
|
2022-01-11 04:05:30 +00:00
|
|
|
|
2022-01-19 23:32:02 +00:00
|
|
|
// Draw sprite.
|
|
|
|
op := &ebiten.DrawImageOptions{}
|
|
|
|
op.GeoM.Translate(float64(x+paddingSize)+button.SpriteOffsetX, float64(y+paddingSize)+button.SpriteOffsetY)
|
|
|
|
s.tmpImg.SubImage(image.Rect(r.Min.X, r.Min.Y, r.Max.X, r.Max.Y)).(*ebiten.Image).DrawImage(button.Sprite, op)
|
2022-01-11 22:22:40 +00:00
|
|
|
|
2022-01-19 23:32:02 +00:00
|
|
|
s.drawButtonBorder(s.tmpImg, r, selected)
|
|
|
|
}
|
2022-01-11 22:22:40 +00:00
|
|
|
|
|
|
|
world.World.HUDButtonRects[i] = r
|
2022-01-14 05:30:52 +00:00
|
|
|
lastButtonY = y
|
|
|
|
}
|
|
|
|
|
2022-01-19 23:32:02 +00:00
|
|
|
s.drawDate(lastButtonY + buttonHeight + 10)
|
|
|
|
s.drawFunds(lastButtonY + buttonHeight + 55)
|
2022-01-15 00:58:44 +00:00
|
|
|
|
2022-01-14 05:30:52 +00:00
|
|
|
// Draw RCI indicator.
|
2022-01-15 00:58:44 +00:00
|
|
|
rciPadding := buttonWidth - 14
|
2022-01-14 05:30:52 +00:00
|
|
|
const rciSize = 100
|
|
|
|
rciX := buttonWidth
|
2022-01-19 23:32:02 +00:00
|
|
|
rciY := lastButtonY + buttonHeight + 55 + rciPadding
|
2022-01-14 05:30:52 +00:00
|
|
|
|
2022-01-21 02:25:09 +00:00
|
|
|
const rciButtonHeight = 20
|
|
|
|
|
2022-01-14 05:30:52 +00:00
|
|
|
// Draw RCI bars.
|
|
|
|
colorR := color.RGBA{0, 255, 0, 255}
|
|
|
|
colorC := color.RGBA{0, 0, 255, 255}
|
|
|
|
colorI := color.RGBA{231, 231, 72, 255}
|
|
|
|
demandR, demandC, demandI := world.Demand()
|
|
|
|
drawDemandBar := func(demand float64, clr color.RGBA, i int) {
|
|
|
|
barOffsetSize := 12
|
|
|
|
barOffset := -barOffsetSize + (i * barOffsetSize)
|
|
|
|
barWidth := 7
|
|
|
|
barX := rciX + buttonWidth/2 - barWidth/2 + barOffset
|
2022-01-21 02:25:09 +00:00
|
|
|
barY := rciY + (rciSize / 2)
|
|
|
|
if demand < 0 {
|
|
|
|
barY += rciButtonHeight / 2
|
|
|
|
} else {
|
|
|
|
barY -= rciButtonHeight / 2
|
|
|
|
}
|
2022-01-14 05:30:52 +00:00
|
|
|
barHeight := int((float64(rciSize) / 2) * demand)
|
2022-01-21 02:25:09 +00:00
|
|
|
s.tmpImg.SubImage(image.Rect(barX, barY, barX+barWidth, barY-barHeight)).(*ebiten.Image).Fill(clr)
|
2022-01-11 04:05:30 +00:00
|
|
|
}
|
2022-01-14 05:30:52 +00:00
|
|
|
drawDemandBar(demandR, colorR, 0)
|
|
|
|
drawDemandBar(demandC, colorC, 1)
|
|
|
|
drawDemandBar(demandI, colorI, 2)
|
|
|
|
|
|
|
|
// Draw RCI button.
|
|
|
|
const rciButtonPadding = 12
|
|
|
|
const rciButtonLabelPaddingX = 6
|
|
|
|
const rciButtonLabelPaddingY = 1
|
|
|
|
rciButtonY := rciY + (rciSize / 2) - (rciButtonHeight / 2)
|
|
|
|
rciButtonRect := image.Rect(rciX+rciButtonPadding, rciButtonY, rciX+buttonWidth-rciButtonPadding, rciButtonY+rciButtonHeight)
|
|
|
|
|
|
|
|
s.drawButtonBackground(s.tmpImg, rciButtonRect, false) // TODO
|
|
|
|
|
|
|
|
// Draw RCI label.
|
|
|
|
ebitenutil.DebugPrintAt(s.tmpImg, "R C I", rciX+rciButtonPadding+rciButtonLabelPaddingX, rciButtonY+rciButtonLabelPaddingY)
|
|
|
|
|
|
|
|
s.drawButtonBorder(s.tmpImg, rciButtonRect, false) // TODO
|
2022-01-11 04:05:30 +00:00
|
|
|
|
|
|
|
s.hudImg.DrawImage(s.tmpImg, nil)
|
|
|
|
}
|
2022-01-14 05:30:52 +00:00
|
|
|
|
|
|
|
func (s *RenderHudSystem) drawButtonBackground(img *ebiten.Image, r image.Rectangle, selected bool) {
|
|
|
|
buttonShade := uint8(142)
|
|
|
|
colorButton := color.RGBA{buttonShade, buttonShade, buttonShade, 255}
|
|
|
|
|
|
|
|
bgColor := colorButton
|
|
|
|
if selected {
|
|
|
|
bgColor = s.sidebarColor
|
|
|
|
}
|
|
|
|
|
|
|
|
img.SubImage(r).(*ebiten.Image).Fill(bgColor)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *RenderHudSystem) drawButtonBorder(img *ebiten.Image, r image.Rectangle, selected bool) {
|
|
|
|
borderSize := 2
|
|
|
|
|
|
|
|
lightBorderShade := uint8(216)
|
|
|
|
colorLightBorder := color.RGBA{lightBorderShade, lightBorderShade, lightBorderShade, 255}
|
|
|
|
|
|
|
|
mediumBorderShade := uint8(56)
|
|
|
|
colorMediumBorder := color.RGBA{mediumBorderShade, mediumBorderShade, mediumBorderShade, 255}
|
|
|
|
|
|
|
|
darkBorderShade := uint8(42)
|
|
|
|
colorDarkBorder := color.RGBA{darkBorderShade, darkBorderShade, darkBorderShade, 255}
|
|
|
|
|
|
|
|
topLeftBorder := colorLightBorder
|
|
|
|
bottomRightBorder := colorMediumBorder
|
|
|
|
if selected {
|
|
|
|
topLeftBorder = colorDarkBorder
|
|
|
|
bottomRightBorder = colorLightBorder
|
|
|
|
}
|
|
|
|
|
|
|
|
// Draw top and left border.
|
|
|
|
img.SubImage(image.Rect(r.Min.X, r.Min.Y, r.Max.X, r.Min.Y+borderSize)).(*ebiten.Image).Fill(topLeftBorder)
|
|
|
|
img.SubImage(image.Rect(r.Min.X, r.Min.Y, r.Min.X+borderSize, r.Max.Y)).(*ebiten.Image).Fill(topLeftBorder)
|
|
|
|
|
|
|
|
// Draw bottom and right border.
|
|
|
|
img.SubImage(image.Rect(r.Min.X, r.Max.Y-borderSize, r.Max.X, r.Max.Y)).(*ebiten.Image).Fill(bottomRightBorder)
|
|
|
|
img.SubImage(image.Rect(r.Max.X-borderSize, r.Min.Y, r.Max.X, r.Max.Y)).(*ebiten.Image).Fill(bottomRightBorder)
|
|
|
|
}
|
2022-01-14 07:14:22 +00:00
|
|
|
|
|
|
|
func (s *RenderHudSystem) drawTooltip() {
|
|
|
|
label := world.Tooltip()
|
|
|
|
if label == "" {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2022-01-19 23:32:02 +00:00
|
|
|
lines := 1 + strings.Count(label, "\n")
|
2022-01-21 02:25:09 +00:00
|
|
|
max := maxLen(strings.Split(label, "\n"))
|
2022-01-19 23:32:02 +00:00
|
|
|
|
2022-01-14 07:14:22 +00:00
|
|
|
scale := 3.0
|
|
|
|
x, y := world.SidebarWidth, 0
|
2022-01-21 02:25:09 +00:00
|
|
|
w, h := (max*6+10)*int(scale), 16*(int(scale))*lines+10
|
|
|
|
r := image.Rect(x, y, x+w, y+h)
|
|
|
|
s.hudImg.SubImage(r).(*ebiten.Image).Fill(color.RGBA{0, 0, 0, 120})
|
|
|
|
|
|
|
|
s.tmpImg.Clear()
|
|
|
|
ebitenutil.DebugPrint(s.tmpImg, label)
|
|
|
|
op := &ebiten.DrawImageOptions{}
|
|
|
|
op.GeoM.Scale(scale, scale)
|
|
|
|
op.GeoM.Translate(world.SidebarWidth+(4*scale), 2)
|
|
|
|
s.hudImg.DrawImage(s.tmpImg, op)
|
|
|
|
}
|
|
|
|
|
|
|
|
func maxLen(v []string) int {
|
|
|
|
max := 0
|
|
|
|
for _, line := range v {
|
|
|
|
l := len(line)
|
|
|
|
if l > max {
|
|
|
|
max = l
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return max
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *RenderHudSystem) drawMessages() {
|
|
|
|
lines := len(world.World.Messages)
|
|
|
|
if lines == 0 {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
/*var label string
|
|
|
|
max := maxLen(world.World.Messages)
|
|
|
|
for i := lines - 1; i >= 0; i-- {
|
|
|
|
if i != lines-1 {
|
|
|
|
label += "\n"
|
|
|
|
}
|
|
|
|
for j := max - len(world.World.Messages[i]); j > 0; j-- {
|
|
|
|
label += " "
|
|
|
|
}
|
|
|
|
label += world.World.Messages[i]
|
|
|
|
}*/
|
|
|
|
|
|
|
|
label := world.World.Messages[len(world.World.Messages)-1]
|
|
|
|
max := len(label)
|
|
|
|
lines = 1
|
|
|
|
|
|
|
|
const padding = 12
|
|
|
|
|
|
|
|
scale := 2.0
|
|
|
|
w, h := (max*6+10)*int(scale), 16*(int(scale))*lines+6
|
|
|
|
x, y := world.World.ScreenW-w, 0
|
2022-01-14 07:14:22 +00:00
|
|
|
r := image.Rect(x, y, x+w, y+h)
|
2022-01-15 00:58:44 +00:00
|
|
|
s.hudImg.SubImage(r).(*ebiten.Image).Fill(color.RGBA{0, 0, 0, 120})
|
2022-01-14 07:14:22 +00:00
|
|
|
|
|
|
|
s.tmpImg.Clear()
|
|
|
|
ebitenutil.DebugPrint(s.tmpImg, label)
|
|
|
|
op := &ebiten.DrawImageOptions{}
|
|
|
|
op.GeoM.Scale(scale, scale)
|
2022-01-21 02:25:09 +00:00
|
|
|
op.GeoM.Translate(float64(x)+padding, 0)
|
2022-01-14 07:14:22 +00:00
|
|
|
s.hudImg.DrawImage(s.tmpImg, op)
|
|
|
|
}
|
2022-01-15 00:58:44 +00:00
|
|
|
|
|
|
|
func (s *RenderHudSystem) drawDate(y int) {
|
|
|
|
const datePadding = 10
|
|
|
|
month, year := world.Date()
|
|
|
|
label := month
|
|
|
|
|
|
|
|
scale := 2.0
|
|
|
|
x, y := datePadding, y
|
|
|
|
|
|
|
|
s.tmpImg2.Clear()
|
|
|
|
ebitenutil.DebugPrint(s.tmpImg2, label)
|
|
|
|
op := &ebiten.DrawImageOptions{}
|
|
|
|
op.GeoM.Scale(scale, scale)
|
|
|
|
op.GeoM.Translate(float64(x), float64(y))
|
|
|
|
s.hudImg.DrawImage(s.tmpImg2, op)
|
|
|
|
|
|
|
|
label = year
|
|
|
|
|
|
|
|
x = world.SidebarWidth - 1 - datePadding - (len(label) * 6 * int(scale))
|
|
|
|
|
|
|
|
s.tmpImg2.Clear()
|
|
|
|
ebitenutil.DebugPrint(s.tmpImg2, label)
|
|
|
|
op.GeoM.Reset()
|
|
|
|
op.GeoM.Scale(scale, scale)
|
|
|
|
op.GeoM.Translate(float64(x), float64(y))
|
|
|
|
s.hudImg.DrawImage(s.tmpImg2, op)
|
|
|
|
}
|
2022-01-19 23:32:02 +00:00
|
|
|
|
|
|
|
func (s *RenderHudSystem) drawFunds(y int) {
|
|
|
|
label := world.World.Printer.Sprintf("$%d", world.World.Funds)
|
|
|
|
|
|
|
|
scale := 2.0
|
|
|
|
x, y := world.SidebarWidth/2-(len(label)*12)/2, y
|
|
|
|
|
|
|
|
s.tmpImg2.Clear()
|
|
|
|
ebitenutil.DebugPrint(s.tmpImg2, label)
|
|
|
|
op := &ebiten.DrawImageOptions{}
|
|
|
|
op.GeoM.Scale(scale, scale)
|
|
|
|
op.GeoM.Translate(float64(x), float64(y))
|
|
|
|
s.hudImg.DrawImage(s.tmpImg2, op)
|
|
|
|
}
|