Add RCI window
This commit is contained in:
parent
c16dec2e65
commit
cabff986f4
|
@ -51,7 +51,7 @@ func LoadSounds(ctx *audio.Context) {
|
|||
SoundSelect.SetVolume(0.6)
|
||||
|
||||
SoundBulldoze = LoadOGG(ctx, "sound/bulldozer/bulldozer.ogg", true)
|
||||
SoundBulldoze.SetVolume(0.4)
|
||||
SoundBulldoze.SetVolume(0.6)
|
||||
|
||||
const popVolume = 0.15
|
||||
SoundPop1 = LoadWAV(ctx, "sound/pop/pop1.wav")
|
||||
|
|
|
@ -135,13 +135,14 @@ func (g *game) Update() error {
|
|||
Sprite: world.DrawMap(world.StructureBulldozer),
|
||||
SpriteOffsetX: 12,
|
||||
SpriteOffsetY: -48,
|
||||
}, {
|
||||
},
|
||||
nil,
|
||||
{
|
||||
StructureType: world.StructureRoad,
|
||||
Sprite: world.DrawMap(world.StructureRoad),
|
||||
SpriteOffsetX: -12,
|
||||
SpriteOffsetY: -28,
|
||||
},
|
||||
nil,
|
||||
{
|
||||
StructureType: world.StructureResidentialZone,
|
||||
Sprite: world.DrawMap(world.StructureResidentialLow),
|
||||
|
|
|
@ -58,7 +58,7 @@ func (s *playerMoveSystem) buildStructure(structureType int, tileX int, tileY in
|
|||
}
|
||||
|
||||
structure, err := world.BuildStructure(world.World.HoverStructure, false, tileX, tileY)
|
||||
if err == nil {
|
||||
if err == nil || world.World.HoverStructure == world.StructureBulldozer {
|
||||
world.World.LastBuildX, world.World.LastBuildY = tileX, tileY
|
||||
|
||||
if world.IsPowerPlant(world.World.HoverStructure) {
|
||||
|
@ -89,8 +89,9 @@ func (s *playerMoveSystem) buildStructure(structureType int, tileX int, tileY in
|
|||
sound.Play()
|
||||
}
|
||||
|
||||
cost := world.StructureCosts[structureType]
|
||||
world.World.Funds -= cost
|
||||
if err == nil {
|
||||
world.World.Funds -= cost
|
||||
}
|
||||
|
||||
world.World.HUDUpdated = true
|
||||
} else {
|
||||
|
@ -297,11 +298,19 @@ func (s *playerMoveSystem) Update(ctx *gohan.Context) error {
|
|||
asset.SoundSelect.Rewind()
|
||||
asset.SoundSelect.Play()
|
||||
}
|
||||
} else if world.AltButtonAt(x, y) == 0 {
|
||||
world.World.ShowRCIWindow = !world.World.ShowRCIWindow
|
||||
world.World.HUDUpdated = true
|
||||
|
||||
asset.SoundSelect.Rewind()
|
||||
asset.SoundSelect.Play()
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
world.HandleRCIWindowClick(x, y)
|
||||
|
||||
if x >= world.World.ScreenW-helpW && y >= world.World.ScreenH-helpH {
|
||||
if inpututil.IsMouseButtonJustPressed(ebiten.MouseButtonLeft) {
|
||||
const (
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
package system
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"image"
|
||||
"image/color"
|
||||
"math"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/hajimehoshi/ebiten/v2/ebitenutil"
|
||||
|
@ -16,7 +18,7 @@ import (
|
|||
|
||||
const (
|
||||
helpW = 480
|
||||
helpH = 225
|
||||
helpH = 220
|
||||
)
|
||||
|
||||
type RenderHudSystem struct {
|
||||
|
@ -37,7 +39,7 @@ func NewRenderHudSystem() *RenderHudSystem {
|
|||
helpImg: ebiten.NewImage(helpW, helpH),
|
||||
}
|
||||
|
||||
sidebarShade := uint8(111)
|
||||
sidebarShade := uint8(108)
|
||||
s.sidebarColor = color.RGBA{sidebarShade, sidebarShade, sidebarShade, 255}
|
||||
|
||||
return s
|
||||
|
@ -66,6 +68,7 @@ func (s *RenderHudSystem) Draw(_ *gohan.Context, screen *ebiten.Image) error {
|
|||
s.drawSidebar()
|
||||
s.drawMessages()
|
||||
s.drawTooltip()
|
||||
s.drawRCIWindow()
|
||||
s.drawHelp()
|
||||
world.World.HUDUpdated = false
|
||||
}
|
||||
|
@ -261,12 +264,14 @@ func (s *RenderHudSystem) drawDemand(x, y int) {
|
|||
rciButtonY := rciY + (rciSize / 2) - (rciButtonHeight / 2)
|
||||
rciButtonRect := image.Rect(rciX+rciButtonPadding, rciButtonY, rciX+buttonWidth-rciButtonPadding, rciButtonY+rciButtonHeight)
|
||||
|
||||
s.drawButtonBackground(s.tmpImg, rciButtonRect, false) // TODO
|
||||
s.drawButtonBackground(s.tmpImg, rciButtonRect, world.World.ShowRCIWindow)
|
||||
|
||||
// Draw label.
|
||||
ebitenutil.DebugPrintAt(s.tmpImg, "R C I", rciX+rciButtonPadding+rciButtonLabelPaddingX, rciButtonY+rciButtonLabelPaddingY)
|
||||
|
||||
s.drawButtonBorder(s.tmpImg, rciButtonRect, false) // TODO
|
||||
s.drawButtonBorder(s.tmpImg, rciButtonRect, world.World.ShowRCIWindow)
|
||||
|
||||
world.World.RCIButtonRect = rciButtonRect
|
||||
}
|
||||
|
||||
func (s *RenderHudSystem) drawPower(x, y int) {
|
||||
|
@ -468,3 +473,52 @@ func (s *RenderHudSystem) drawHelp() {
|
|||
op.GeoM.Translate(float64(world.World.ScreenW)-helpW, float64(world.World.ScreenH)-helpH)
|
||||
s.hudImg.DrawImage(s.helpImg, op)
|
||||
}
|
||||
|
||||
func (s *RenderHudSystem) drawRCIWindow() {
|
||||
if !world.World.ShowRCIWindow {
|
||||
return
|
||||
}
|
||||
|
||||
const paddingX = 8
|
||||
|
||||
const (
|
||||
rciWindowW = 425
|
||||
rciWindowH = 100
|
||||
)
|
||||
|
||||
rciWindowRect := image.Rect(world.World.ScreenW/2-rciWindowW/2, world.World.ScreenH/2-rciWindowH/2, world.World.ScreenW/2+rciWindowW, world.World.ScreenH/2+rciWindowH)
|
||||
s.hudImg.SubImage(rciWindowRect).(*ebiten.Image).Fill(s.sidebarColor)
|
||||
|
||||
percentBar := func(tax float64) string {
|
||||
if tax >= 1.0 {
|
||||
tax = .99
|
||||
}
|
||||
bar := "----------"
|
||||
bar = bar[:int(tax*10)] + "%" + bar[int(tax*10)+1:]
|
||||
return bar
|
||||
}
|
||||
|
||||
label := fmt.Sprintf(`
|
||||
Residential %3s%% - |%s| +
|
||||
Commercial %3s%% - |%s| +
|
||||
Industrial %3s%% - |%s| +
|
||||
`,
|
||||
strconv.Itoa(int(world.World.TaxR*100)), percentBar(world.World.TaxR),
|
||||
strconv.Itoa(int(world.World.TaxC*100)), percentBar(world.World.TaxC),
|
||||
strconv.Itoa(int(world.World.TaxI*100)), percentBar(world.World.TaxI))
|
||||
|
||||
s.tmpImg.Clear()
|
||||
ebitenutil.DebugPrint(s.tmpImg, strings.TrimSpace(label))
|
||||
|
||||
op := &ebiten.DrawImageOptions{}
|
||||
op.GeoM.Scale(3, 3)
|
||||
op.GeoM.Translate(float64(rciWindowRect.Min.X)+paddingX, float64(rciWindowRect.Min.Y))
|
||||
s.hudImg.DrawImage(s.tmpImg, op)
|
||||
|
||||
s.hudImg.SubImage(image.Rect(rciWindowRect.Min.X, rciWindowRect.Min.Y, rciWindowRect.Max.X, rciWindowRect.Min.Y+1)).(*ebiten.Image).Fill(color.Black)
|
||||
s.hudImg.SubImage(image.Rect(rciWindowRect.Min.X, rciWindowRect.Max.Y-1, rciWindowRect.Max.X, rciWindowRect.Max.Y)).(*ebiten.Image).Fill(color.Black)
|
||||
s.hudImg.SubImage(image.Rect(rciWindowRect.Min.X, rciWindowRect.Min.Y, rciWindowRect.Min.X+1, rciWindowRect.Max.Y)).(*ebiten.Image).Fill(color.Black)
|
||||
s.hudImg.SubImage(image.Rect(rciWindowRect.Max.X-1, rciWindowRect.Min.Y, rciWindowRect.Max.X, rciWindowRect.Max.Y)).(*ebiten.Image).Fill(color.Black)
|
||||
|
||||
world.World.RCIWindowRect = rciWindowRect
|
||||
}
|
||||
|
|
|
@ -37,15 +37,24 @@ func (s *TaxSystem) Update(_ *gohan.Context) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
taxCollectionAmount := 777.77
|
||||
for _, zone := range world.World.Zones {
|
||||
if !zone.Powered {
|
||||
if zone.Population == 0 {
|
||||
continue
|
||||
}
|
||||
_ = zone
|
||||
|
||||
taxRate := world.World.TaxR
|
||||
if zone.Type == world.StructureCommercialZone {
|
||||
taxRate = world.World.TaxC
|
||||
} else if zone.Type == world.StructureIndustrialZone {
|
||||
taxRate = world.World.TaxI
|
||||
}
|
||||
|
||||
world.World.Funds += int(taxCollectionAmount * taxRate)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *TaxSystem) Draw(ctx *gohan.Context, screen *ebiten.Image) error {
|
||||
func (s *TaxSystem) Draw(_ *gohan.Context, _ *ebiten.Image) error {
|
||||
return gohan.ErrSystemWithoutDraw
|
||||
}
|
||||
|
|
|
@ -8,55 +8,55 @@ things YOUR way. For better or worse...
|
|||
Will you lead the clean energy front,
|
||||
or will you put profits before people?
|
||||
`, `
|
||||
Moving via mouse (2/10)
|
||||
Moving Via Mouse (2/10)
|
||||
To move around, place your cursor at
|
||||
the edge of the screen, or press and
|
||||
hold your middle mouse button while
|
||||
moving your cursor.
|
||||
`, `
|
||||
Moving via keyboard (3/10)
|
||||
Moving Via Keyboard (3/10)
|
||||
You can also use your keyboard to move
|
||||
by pressing any of the arrow keys or
|
||||
W/A/S/D. Try using your mouse and/or
|
||||
keyboard to move the camera around now.
|
||||
`, `
|
||||
Zoning areas (4/10)
|
||||
Structures are built according to the
|
||||
zoning category of an area. Demand for
|
||||
each category (Residential, Commercial,
|
||||
Zoning Areas (4/10)
|
||||
Structures are built according to how
|
||||
you zone areas of land. Demand for each
|
||||
category (Residential, Commercial,
|
||||
Industrial) is shown in the sidebar.
|
||||
`, `
|
||||
Did you know? (5/10)
|
||||
Did You Know? (5/10)
|
||||
Powering an area requires more input
|
||||
energy than the resulting electricity.
|
||||
In in fact, only a third of the energy
|
||||
is transmitted as usable electricity.
|
||||
In fact, only a third of the energy is
|
||||
transmitted as usable electricity.
|
||||
`, `
|
||||
Building blocks of a city (6/10)
|
||||
Building Blocks of a City (6/10)
|
||||
Structures require power, sewer and
|
||||
transportation in order to function.
|
||||
This is all facilitated via roads and
|
||||
underground wiring and piping.
|
||||
`, `
|
||||
Did you know? (7/10)
|
||||
Did You Know? (7/10)
|
||||
Meat-based diets require much more
|
||||
energy, land and water resources than
|
||||
vegetarian and especially vegan diets.
|
||||
Animal farms are a source of pollution.
|
||||
`, `
|
||||
Power to the people (8/10)
|
||||
Power to the People (8/10)
|
||||
Build a power plant, then zone a few
|
||||
areas for residential development.
|
||||
Connect the power plant to the newly
|
||||
zoned areas with a road.
|
||||
`, `
|
||||
Did you know? (9/10)
|
||||
Did You Know? (9/10)
|
||||
It takes large amounts of water to
|
||||
convert fossil fuels into electricity.
|
||||
Converting solar and wind energy uses
|
||||
negligible amounts of water.
|
||||
`, `
|
||||
Collecting taxes (10/10)
|
||||
Collecting Taxes (10/10)
|
||||
Each year, taxes are collected from the
|
||||
residents of the city. The tax rate you
|
||||
set determines how appealing your city
|
||||
|
|
114
world/world.go
114
world/world.go
|
@ -13,6 +13,8 @@ import (
|
|||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/hajimehoshi/ebiten/v2/inpututil"
|
||||
|
||||
"github.com/hajimehoshi/ebiten/v2/audio"
|
||||
|
||||
"golang.org/x/text/language"
|
||||
|
@ -31,7 +33,7 @@ const startingYear = 1950
|
|||
const maxPopulation = 100000
|
||||
|
||||
const (
|
||||
MonthTicks = 144 * 7
|
||||
MonthTicks = 144 * 5
|
||||
YearTicks = MonthTicks * 12
|
||||
)
|
||||
|
||||
|
@ -63,28 +65,33 @@ var HUDButtons []*HUDButton
|
|||
var CameraMinZoom = 0.1
|
||||
var CameraMaxZoom = 1.0
|
||||
|
||||
const (
|
||||
startingTaxR = 0.12
|
||||
startingTaxC = 0.12
|
||||
startingTaxI = 0.12
|
||||
)
|
||||
const startingTax = 0.12
|
||||
|
||||
var World = &GameWorld{
|
||||
CamScale: startingZoom,
|
||||
CamScaleTarget: startingZoom,
|
||||
CamMoving: true,
|
||||
PlayerWidth: 8,
|
||||
PlayerHeight: 32,
|
||||
TileImages: make(map[uint32]*ebiten.Image),
|
||||
ResetGame: true,
|
||||
Level: NewLevel(256),
|
||||
Printer: message.NewPrinter(language.English),
|
||||
Power: newPowerMap(),
|
||||
PowerOuts: newPowerOuts(),
|
||||
BuildDragX: -1,
|
||||
BuildDragY: -1,
|
||||
LastBuildX: -1,
|
||||
LastBuildY: -1,
|
||||
|
||||
PlayerWidth: 8,
|
||||
PlayerHeight: 32,
|
||||
|
||||
TileImages: make(map[uint32]*ebiten.Image),
|
||||
ResetGame: true,
|
||||
Level: NewLevel(256),
|
||||
|
||||
Power: newPowerMap(),
|
||||
PowerOuts: newPowerOuts(),
|
||||
|
||||
TaxR: startingTax,
|
||||
TaxC: startingTax,
|
||||
TaxI: startingTax,
|
||||
|
||||
BuildDragX: -1,
|
||||
BuildDragY: -1,
|
||||
LastBuildX: -1,
|
||||
LastBuildY: -1,
|
||||
|
||||
Printer: message.NewPrinter(language.English),
|
||||
}
|
||||
|
||||
type Zone struct {
|
||||
|
@ -162,6 +169,10 @@ type GameWorld struct {
|
|||
HUDUpdated bool
|
||||
HUDButtonRects []image.Rectangle
|
||||
|
||||
RCIButtonRect image.Rectangle
|
||||
RCIWindowRect image.Rectangle
|
||||
ShowRCIWindow bool
|
||||
|
||||
HelpUpdated bool
|
||||
HelpPage int
|
||||
HelpButtonRects []image.Rectangle
|
||||
|
@ -608,6 +619,72 @@ func HelpButtonAt(x, y int) int {
|
|||
return -1
|
||||
}
|
||||
|
||||
func AltButtonAt(x, y int) int {
|
||||
point := image.Point{x, y}
|
||||
if point.In(World.RCIButtonRect) {
|
||||
return 0
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
func HandleRCIWindowClick(x, y int) {
|
||||
if !World.ShowRCIWindow {
|
||||
return
|
||||
}
|
||||
|
||||
if !ebiten.IsMouseButtonPressed(ebiten.MouseButtonLeft) {
|
||||
return
|
||||
}
|
||||
|
||||
point := image.Point{x, y}
|
||||
if !point.In(World.RCIWindowRect) {
|
||||
return
|
||||
}
|
||||
|
||||
var updated bool
|
||||
barRectR := image.Rect(World.RCIWindowRect.Min.X+381, World.RCIWindowRect.Min.Y, World.RCIWindowRect.Min.X+575, World.RCIWindowRect.Min.Y+50)
|
||||
barRectC := image.Rect(World.RCIWindowRect.Min.X+381, World.RCIWindowRect.Min.Y+50, World.RCIWindowRect.Min.X+575, World.RCIWindowRect.Min.Y+100)
|
||||
barRectI := image.Rect(World.RCIWindowRect.Min.X+381, World.RCIWindowRect.Min.Y+100, World.RCIWindowRect.Min.X+575, World.RCIWindowRect.Max.Y)
|
||||
if point.In(barRectR) {
|
||||
World.TaxR = float64(x-barRectR.Min.X) / float64(barRectR.Dx())
|
||||
if World.TaxR >= .99 {
|
||||
World.TaxR = 1.0
|
||||
}
|
||||
World.HUDUpdated = true
|
||||
updated = true
|
||||
} else if point.In(barRectC) {
|
||||
World.TaxC = float64(x-barRectC.Min.X) / float64(barRectC.Dx())
|
||||
if World.TaxC >= .99 {
|
||||
World.TaxC = 1.0
|
||||
}
|
||||
World.HUDUpdated = true
|
||||
updated = true
|
||||
} else if point.In(barRectI) {
|
||||
World.TaxI = float64(x-barRectI.Min.X) / float64(barRectI.Dx())
|
||||
if World.TaxI >= .99 {
|
||||
World.TaxI = 1.0
|
||||
}
|
||||
World.HUDUpdated = true
|
||||
updated = true
|
||||
}
|
||||
if !updated {
|
||||
return
|
||||
}
|
||||
|
||||
if inpututil.IsMouseButtonJustPressed(ebiten.MouseButtonLeft) || World.Ticks%16 == 0 {
|
||||
sounds := []*audio.Player{
|
||||
asset.SoundPop1,
|
||||
asset.SoundPop2,
|
||||
asset.SoundPop3,
|
||||
asset.SoundPop4,
|
||||
asset.SoundPop5,
|
||||
}
|
||||
sound := sounds[rand.Intn(len(sounds))]
|
||||
sound.Rewind()
|
||||
sound.Play()
|
||||
}
|
||||
}
|
||||
|
||||
func SetHoverStructure(structureType int) {
|
||||
World.HoverStructure = structureType
|
||||
World.HUDUpdated = true
|
||||
|
@ -643,6 +720,7 @@ func Demand() (r, c, i float64) {
|
|||
}
|
||||
barPeak := 100.0
|
||||
r, c, i = r/barPeak, c/barPeak, i/barPeak
|
||||
r, c, i = r*(1-World.TaxR), c*(1-World.TaxC), i*(1-World.TaxI)
|
||||
clamp := func(v float64) float64 {
|
||||
if math.IsNaN(v) {
|
||||
return 0
|
||||
|
|
Loading…
Reference in New Issue