2019-12-16 11:04:39 -05:00
|
|
|
package d2player
|
|
|
|
|
|
|
|
import (
|
2020-08-24 15:50:33 -04:00
|
|
|
"fmt"
|
2020-09-08 15:58:35 -04:00
|
|
|
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2geom"
|
|
|
|
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2util"
|
2020-09-09 08:21:27 -04:00
|
|
|
"github.com/OpenDiablo2/OpenDiablo2/d2game/d2player/help"
|
2020-06-30 12:43:13 -04:00
|
|
|
"image"
|
2020-06-22 15:55:32 -04:00
|
|
|
"image/color"
|
2020-06-23 12:28:05 -04:00
|
|
|
"log"
|
2020-06-25 00:39:09 -04:00
|
|
|
"math"
|
2020-06-22 15:55:32 -04:00
|
|
|
"time"
|
|
|
|
|
2020-07-22 15:03:03 -04:00
|
|
|
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2data/d2datadict"
|
2020-08-25 09:10:26 -04:00
|
|
|
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
|
2020-07-22 15:03:03 -04:00
|
|
|
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2math/d2vector"
|
|
|
|
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2gui"
|
|
|
|
|
2020-06-28 21:40:52 -04:00
|
|
|
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
|
2020-01-26 00:39:13 -05:00
|
|
|
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2resource"
|
2020-02-01 18:55:56 -05:00
|
|
|
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2asset"
|
2020-06-21 18:40:37 -04:00
|
|
|
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2map/d2mapengine"
|
|
|
|
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2map/d2mapentity"
|
|
|
|
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2map/d2maprenderer"
|
2020-02-01 18:55:56 -05:00
|
|
|
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2ui"
|
2019-12-16 11:04:39 -05:00
|
|
|
)
|
|
|
|
|
2020-07-26 14:52:54 -04:00
|
|
|
// Panel represents the panel at the bottom of the game screen
|
2019-12-28 23:32:53 -05:00
|
|
|
type Panel interface {
|
|
|
|
IsOpen() bool
|
|
|
|
Toggle()
|
|
|
|
Open()
|
|
|
|
Close()
|
|
|
|
}
|
|
|
|
|
2020-07-22 15:03:03 -04:00
|
|
|
const (
|
2020-08-11 18:01:33 -04:00
|
|
|
initialMissileID = 59
|
|
|
|
expBarWidth = 120.0
|
|
|
|
staminaBarWidth = 102.0
|
|
|
|
globeHeight = 80
|
|
|
|
globeWidth = 80
|
|
|
|
hoverLabelOuterPad = 5
|
|
|
|
mouseBtnActionsTreshhold = 0.25
|
2020-07-22 15:03:03 -04:00
|
|
|
)
|
2020-02-22 20:44:30 -05:00
|
|
|
|
2020-07-26 14:52:54 -04:00
|
|
|
// GameControls represents the game's controls on the screen
|
2019-12-16 11:04:39 -05:00
|
|
|
type GameControls struct {
|
2020-08-11 18:01:33 -04:00
|
|
|
actionableRegions []ActionableRegion
|
|
|
|
renderer d2interface.Renderer // TODO: This shouldn't be a dependency
|
|
|
|
inputListener InputCallbackListener
|
|
|
|
hero *d2mapentity.Player
|
|
|
|
mapEngine *d2mapengine.MapEngine
|
|
|
|
mapRenderer *d2maprenderer.MapRenderer
|
|
|
|
uiManager *d2ui.UIManager
|
|
|
|
inventory *Inventory
|
|
|
|
heroStatsPanel *HeroStatsPanel
|
2020-09-09 08:21:27 -04:00
|
|
|
helpOverlay *help.Overlay
|
2020-08-25 09:10:26 -04:00
|
|
|
miniPanel *miniPanel
|
2020-08-11 18:01:33 -04:00
|
|
|
lastMouseX int
|
|
|
|
lastMouseY int
|
|
|
|
missileID int
|
|
|
|
globeSprite *d2ui.Sprite
|
|
|
|
hpManaStatusSprite *d2ui.Sprite
|
|
|
|
mainPanel *d2ui.Sprite
|
|
|
|
menuButton *d2ui.Sprite
|
|
|
|
skillIcon *d2ui.Sprite
|
|
|
|
zoneChangeText *d2ui.Label
|
|
|
|
nameLabel *d2ui.Label
|
2020-08-24 15:50:33 -04:00
|
|
|
hpManaStatsLabel *d2ui.Label
|
2020-08-11 18:01:33 -04:00
|
|
|
runButton *d2ui.Button
|
|
|
|
lastLeftBtnActionTime float64
|
|
|
|
lastRightBtnActionTime float64
|
|
|
|
FreeCam bool
|
|
|
|
isZoneTextShown bool
|
2020-08-24 15:50:33 -04:00
|
|
|
hpStatsIsVisible bool
|
|
|
|
manaStatsIsVisible bool
|
2020-08-25 09:10:26 -04:00
|
|
|
isSinglePlayer bool
|
2019-12-16 11:04:39 -05:00
|
|
|
}
|
|
|
|
|
2020-06-23 12:28:05 -04:00
|
|
|
type ActionableType int
|
2020-07-26 14:52:54 -04:00
|
|
|
|
2020-06-24 13:49:13 -04:00
|
|
|
type ActionableRegion struct {
|
|
|
|
ActionableTypeId ActionableType
|
2020-09-08 15:58:35 -04:00
|
|
|
Rect d2geom.Rectangle
|
2020-06-24 13:49:13 -04:00
|
|
|
}
|
2020-06-23 12:28:05 -04:00
|
|
|
|
|
|
|
const (
|
|
|
|
// Since they require special handling, not considering (1) globes, (2) content of the mini panel, (3) belt
|
2020-08-25 09:10:26 -04:00
|
|
|
leftSkill ActionableType = iota
|
|
|
|
leftSelect
|
|
|
|
xp
|
|
|
|
walkRun
|
|
|
|
stamina
|
|
|
|
miniPnl
|
|
|
|
rightSelect
|
|
|
|
rightSkill
|
|
|
|
hpGlobe
|
|
|
|
manaGlobe
|
|
|
|
miniPanelCharacter
|
|
|
|
miniPanelInventory
|
2020-06-23 12:28:05 -04:00
|
|
|
)
|
|
|
|
|
2020-08-11 18:01:33 -04:00
|
|
|
// NewGameControls creates a GameControls instance and returns a pointer to it
|
2020-08-06 10:30:23 -04:00
|
|
|
func NewGameControls(
|
|
|
|
renderer d2interface.Renderer,
|
|
|
|
hero *d2mapentity.Player,
|
|
|
|
mapEngine *d2mapengine.MapEngine,
|
|
|
|
mapRenderer *d2maprenderer.MapRenderer,
|
|
|
|
inputListener InputCallbackListener,
|
|
|
|
term d2interface.Terminal,
|
|
|
|
ui *d2ui.UIManager,
|
2020-08-25 09:10:26 -04:00
|
|
|
isSinglePlayer bool,
|
2020-08-06 10:30:23 -04:00
|
|
|
) (*GameControls, error) {
|
2020-07-22 15:03:03 -04:00
|
|
|
missileID := initialMissileID
|
2020-08-11 18:01:33 -04:00
|
|
|
|
|
|
|
err := term.BindAction("setmissile", "set missile id to summon on right click", func(id int) {
|
2020-02-22 20:44:30 -05:00
|
|
|
missileID = id
|
|
|
|
})
|
2020-08-11 18:01:33 -04:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2020-02-22 20:44:30 -05:00
|
|
|
|
2020-08-06 10:30:23 -04:00
|
|
|
zoneLabel := ui.NewLabel(d2resource.Font30, d2resource.PaletteUnits)
|
2020-07-07 20:16:22 -04:00
|
|
|
zoneLabel.Alignment = d2gui.HorizontalAlignCenter
|
2020-06-22 15:55:32 -04:00
|
|
|
|
2020-08-06 10:30:23 -04:00
|
|
|
nameLabel := ui.NewLabel(d2resource.FontFormal11, d2resource.PaletteStatic)
|
2020-07-07 20:16:22 -04:00
|
|
|
nameLabel.Alignment = d2gui.HorizontalAlignCenter
|
2020-08-02 21:26:07 -04:00
|
|
|
nameLabel.SetText(d2ui.ColorTokenize("", d2ui.ColorTokenServer))
|
2020-06-25 00:39:09 -04:00
|
|
|
|
2020-08-24 15:50:33 -04:00
|
|
|
hpManaStatsLabel := ui.NewLabel(d2resource.Font16, d2resource.PaletteUnits)
|
|
|
|
hpManaStatsLabel.Alignment = d2gui.HorizontalAlignLeft
|
|
|
|
|
2020-07-11 11:25:34 -04:00
|
|
|
// TODO make this depend on the hero type to respect inventory.txt
|
|
|
|
var inventoryRecordKey string
|
2020-07-26 14:52:54 -04:00
|
|
|
|
2020-07-11 11:25:34 -04:00
|
|
|
switch hero.Class {
|
|
|
|
case d2enum.HeroAssassin:
|
|
|
|
inventoryRecordKey = "Assassin"
|
|
|
|
case d2enum.HeroAmazon:
|
|
|
|
inventoryRecordKey = "Amazon2"
|
|
|
|
case d2enum.HeroBarbarian:
|
|
|
|
inventoryRecordKey = "Barbarian2"
|
|
|
|
case d2enum.HeroDruid:
|
|
|
|
inventoryRecordKey = "Druid"
|
|
|
|
case d2enum.HeroNecromancer:
|
|
|
|
inventoryRecordKey = "Necromancer2"
|
|
|
|
case d2enum.HeroPaladin:
|
|
|
|
inventoryRecordKey = "Paladin2"
|
|
|
|
case d2enum.HeroSorceress:
|
|
|
|
inventoryRecordKey = "Sorceress2"
|
|
|
|
default:
|
|
|
|
inventoryRecordKey = "Amazon2"
|
|
|
|
}
|
2020-07-22 15:03:03 -04:00
|
|
|
|
2020-07-11 11:25:34 -04:00
|
|
|
inventoryRecord := d2datadict.Inventory[inventoryRecordKey]
|
|
|
|
|
2020-08-06 10:30:23 -04:00
|
|
|
hoverLabel := nameLabel
|
|
|
|
hoverLabel.SetBackgroundColor(color.RGBA{0, 0, 0, uint8(128)})
|
2020-08-03 00:48:17 -04:00
|
|
|
|
2020-08-24 15:50:33 -04:00
|
|
|
globeStatsLabel := hpManaStatsLabel
|
|
|
|
|
2020-06-21 20:46:00 -04:00
|
|
|
gc := &GameControls{
|
2020-08-24 15:50:33 -04:00
|
|
|
uiManager: ui,
|
|
|
|
renderer: renderer,
|
|
|
|
hero: hero,
|
|
|
|
mapEngine: mapEngine,
|
|
|
|
inputListener: inputListener,
|
|
|
|
mapRenderer: mapRenderer,
|
|
|
|
inventory: NewInventory(ui, inventoryRecord),
|
|
|
|
heroStatsPanel: NewHeroStatsPanel(ui, hero.Name(), hero.Class, hero.Stats),
|
2020-09-09 08:21:27 -04:00
|
|
|
helpOverlay: help.NewHelpOverlay(renderer),
|
2020-08-25 09:10:26 -04:00
|
|
|
miniPanel: newMiniPanel(ui, isSinglePlayer),
|
2020-08-24 15:50:33 -04:00
|
|
|
missileID: missileID,
|
|
|
|
nameLabel: hoverLabel,
|
|
|
|
zoneChangeText: zoneLabel,
|
|
|
|
hpManaStatsLabel: globeStatsLabel,
|
2020-06-24 13:49:13 -04:00
|
|
|
actionableRegions: []ActionableRegion{
|
2020-09-08 15:58:35 -04:00
|
|
|
{leftSkill, d2geom.Rectangle{Left: 115, Top: 550, Width: 50, Height: 50}},
|
|
|
|
{leftSelect, d2geom.Rectangle{Left: 206, Top: 563, Width: 30, Height: 30}},
|
|
|
|
{xp, d2geom.Rectangle{Left: 253, Top: 560, Width: 125, Height: 5}},
|
|
|
|
{walkRun, d2geom.Rectangle{Left: 255, Top: 573, Width: 17, Height: 20}},
|
|
|
|
{stamina, d2geom.Rectangle{Left: 273, Top: 573, Width: 105, Height: 20}},
|
|
|
|
{miniPnl, d2geom.Rectangle{Left: 393, Top: 563, Width: 12, Height: 23}},
|
|
|
|
{rightSelect, d2geom.Rectangle{Left: 562, Top: 563, Width: 30, Height: 30}},
|
|
|
|
{rightSkill, d2geom.Rectangle{Left: 634, Top: 550, Width: 50, Height: 50}},
|
|
|
|
{hpGlobe, d2geom.Rectangle{Left: 30, Top: 525, Width: 65, Height: 50}},
|
|
|
|
{manaGlobe, d2geom.Rectangle{Left: 700, Top: 525, Width: 65, Height: 50}},
|
|
|
|
{miniPanelCharacter, d2geom.Rectangle{Left: 325, Top: 526, Width: 26, Height: 26}},
|
|
|
|
{miniPanelInventory, d2geom.Rectangle{Left: 351, Top: 526, Width: 26, Height: 26}},
|
2020-06-23 12:28:05 -04:00
|
|
|
},
|
2020-08-11 18:01:33 -04:00
|
|
|
lastLeftBtnActionTime: 0,
|
|
|
|
lastRightBtnActionTime: 0,
|
2020-08-25 09:10:26 -04:00
|
|
|
isSinglePlayer: isSinglePlayer,
|
2019-12-16 11:04:39 -05:00
|
|
|
}
|
2020-06-21 20:46:00 -04:00
|
|
|
|
2020-08-11 18:01:33 -04:00
|
|
|
err = term.BindAction("freecam", "toggle free camera movement", func() {
|
2020-06-21 20:46:00 -04:00
|
|
|
gc.FreeCam = !gc.FreeCam
|
|
|
|
})
|
|
|
|
|
2020-07-26 14:52:54 -04:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return gc, nil
|
2020-06-21 20:46:00 -04:00
|
|
|
}
|
|
|
|
|
2020-08-11 18:01:33 -04:00
|
|
|
// OnKeyRepeat is called to handle repeated key presses
|
2020-07-03 15:09:16 -04:00
|
|
|
func (g *GameControls) OnKeyRepeat(event d2interface.KeyEvent) bool {
|
2020-06-21 20:46:00 -04:00
|
|
|
if g.FreeCam {
|
|
|
|
var moveSpeed float64 = 8
|
2020-07-06 21:26:08 -04:00
|
|
|
if event.KeyMod() == d2enum.KeyModShift {
|
2020-06-21 20:46:00 -04:00
|
|
|
moveSpeed *= 2
|
|
|
|
}
|
|
|
|
|
2020-07-06 21:26:08 -04:00
|
|
|
if event.Key() == d2enum.KeyDown {
|
2020-07-18 23:37:35 -04:00
|
|
|
v := d2vector.NewVector(0, moveSpeed)
|
2020-07-25 09:36:54 -04:00
|
|
|
g.mapRenderer.MoveCameraTargetBy(v)
|
2020-07-18 23:37:35 -04:00
|
|
|
|
2020-06-21 20:46:00 -04:00
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
2020-07-06 21:26:08 -04:00
|
|
|
if event.Key() == d2enum.KeyUp {
|
2020-07-18 23:37:35 -04:00
|
|
|
v := d2vector.NewVector(0, -moveSpeed)
|
2020-07-25 09:36:54 -04:00
|
|
|
g.mapRenderer.MoveCameraTargetBy(v)
|
2020-07-18 23:37:35 -04:00
|
|
|
|
2020-06-21 20:46:00 -04:00
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
2020-07-06 21:26:08 -04:00
|
|
|
if event.Key() == d2enum.KeyRight {
|
2020-07-18 23:37:35 -04:00
|
|
|
v := d2vector.NewVector(moveSpeed, 0)
|
2020-07-25 09:36:54 -04:00
|
|
|
g.mapRenderer.MoveCameraTargetBy(v)
|
2020-07-18 23:37:35 -04:00
|
|
|
|
2020-06-21 20:46:00 -04:00
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
2020-07-06 21:26:08 -04:00
|
|
|
if event.Key() == d2enum.KeyLeft {
|
2020-07-18 23:37:35 -04:00
|
|
|
v := d2vector.NewVector(-moveSpeed, 0)
|
2020-07-25 09:36:54 -04:00
|
|
|
g.mapRenderer.MoveCameraTargetBy(v)
|
2020-07-18 23:37:35 -04:00
|
|
|
|
2020-06-21 20:46:00 -04:00
|
|
|
return true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false
|
2019-12-16 11:04:39 -05:00
|
|
|
}
|
|
|
|
|
2020-08-11 18:01:33 -04:00
|
|
|
// OnKeyDown handles key presses
|
2020-07-03 15:09:16 -04:00
|
|
|
func (g *GameControls) OnKeyDown(event d2interface.KeyEvent) bool {
|
|
|
|
switch event.Key() {
|
2020-07-06 21:26:08 -04:00
|
|
|
case d2enum.KeyEscape:
|
2020-06-25 14:56:49 -04:00
|
|
|
if g.inventory.IsOpen() || g.heroStatsPanel.IsOpen() {
|
2020-06-21 18:44:33 -04:00
|
|
|
g.inventory.Close()
|
2020-06-25 14:56:49 -04:00
|
|
|
g.heroStatsPanel.Close()
|
2020-06-22 09:23:56 -04:00
|
|
|
g.updateLayout()
|
2020-08-11 18:01:33 -04:00
|
|
|
|
2020-06-21 18:44:33 -04:00
|
|
|
break
|
|
|
|
}
|
2020-07-06 21:26:08 -04:00
|
|
|
case d2enum.KeyI:
|
2020-01-25 23:28:21 -05:00
|
|
|
g.inventory.Toggle()
|
2020-06-22 09:23:56 -04:00
|
|
|
g.updateLayout()
|
2020-07-06 21:26:08 -04:00
|
|
|
case d2enum.KeyC:
|
2020-06-25 14:56:49 -04:00
|
|
|
g.heroStatsPanel.Toggle()
|
2020-06-22 09:23:56 -04:00
|
|
|
g.updateLayout()
|
2020-07-06 21:26:08 -04:00
|
|
|
case d2enum.KeyR:
|
2020-06-24 15:23:38 -04:00
|
|
|
g.onToggleRunButton()
|
2020-09-09 08:21:27 -04:00
|
|
|
case d2enum.KeyH:
|
|
|
|
g.helpOverlay.Toggle()
|
|
|
|
g.updateLayout()
|
2020-06-21 18:44:33 -04:00
|
|
|
default:
|
|
|
|
return false
|
2020-02-08 10:51:11 -05:00
|
|
|
}
|
2020-08-11 18:01:33 -04:00
|
|
|
|
2020-06-22 15:55:32 -04:00
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
2020-08-11 18:01:33 -04:00
|
|
|
// OnMouseButtonRepeat handles repeated mouse clicks
|
2020-07-03 15:09:16 -04:00
|
|
|
func (g *GameControls) OnMouseButtonRepeat(event d2interface.MouseEvent) bool {
|
|
|
|
px, py := g.mapRenderer.ScreenToWorld(event.X(), event.Y())
|
2020-06-22 15:55:32 -04:00
|
|
|
px = float64(int(px*10)) / 10.0
|
|
|
|
py = float64(int(py*10)) / 10.0
|
|
|
|
|
2020-09-08 15:58:35 -04:00
|
|
|
now := d2util.Now()
|
2020-07-03 15:09:16 -04:00
|
|
|
button := event.Button()
|
2020-07-06 21:26:08 -04:00
|
|
|
isLeft := button == d2enum.MouseButtonLeft
|
|
|
|
isRight := button == d2enum.MouseButtonRight
|
2020-08-11 18:01:33 -04:00
|
|
|
lastLeft := now - g.lastLeftBtnActionTime
|
|
|
|
lastRight := now - g.lastRightBtnActionTime
|
2020-07-03 15:09:16 -04:00
|
|
|
inRect := !g.isInActiveMenusRect(event.X(), event.Y())
|
2020-07-22 15:03:03 -04:00
|
|
|
shouldDoLeft := lastLeft >= mouseBtnActionsTreshhold
|
|
|
|
shouldDoRight := lastRight >= mouseBtnActionsTreshhold
|
2020-07-03 15:09:16 -04:00
|
|
|
|
|
|
|
if isLeft && shouldDoLeft && inRect {
|
2020-08-11 18:01:33 -04:00
|
|
|
g.lastLeftBtnActionTime = now
|
2020-07-26 14:52:54 -04:00
|
|
|
|
2020-06-22 15:55:32 -04:00
|
|
|
g.inputListener.OnPlayerMove(px, py)
|
2020-07-18 23:37:35 -04:00
|
|
|
|
|
|
|
if g.FreeCam {
|
|
|
|
if event.Button() == d2enum.MouseButtonLeft {
|
|
|
|
camVect := g.mapRenderer.Camera.GetPosition().Vector
|
|
|
|
|
|
|
|
x, y := float64(g.lastMouseX-400)/5, float64(g.lastMouseY-300)/5
|
|
|
|
targetPosition := d2vector.NewPositionTile(x, y)
|
|
|
|
targetPosition.Add(&camVect)
|
|
|
|
|
|
|
|
g.mapRenderer.SetCameraTarget(&targetPosition)
|
|
|
|
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-06-22 15:55:32 -04:00
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
2020-07-03 15:09:16 -04:00
|
|
|
if isRight && shouldDoRight && inRect {
|
2020-08-11 18:01:33 -04:00
|
|
|
g.lastRightBtnActionTime = now
|
2020-07-26 14:52:54 -04:00
|
|
|
|
2020-07-22 15:03:03 -04:00
|
|
|
g.inputListener.OnPlayerCast(g.missileID, px, py)
|
2020-07-26 14:52:54 -04:00
|
|
|
|
2020-06-22 15:55:32 -04:00
|
|
|
return true
|
|
|
|
}
|
2019-12-16 11:04:39 -05:00
|
|
|
|
2020-06-21 18:44:33 -04:00
|
|
|
return true
|
2020-01-25 23:28:21 -05:00
|
|
|
}
|
2019-12-16 11:04:39 -05:00
|
|
|
|
2020-08-11 18:01:33 -04:00
|
|
|
// OnMouseMove handles mouse movement events
|
2020-07-03 15:09:16 -04:00
|
|
|
func (g *GameControls) OnMouseMove(event d2interface.MouseMoveEvent) bool {
|
|
|
|
mx, my := event.X(), event.Y()
|
2020-06-25 00:39:09 -04:00
|
|
|
g.lastMouseX = mx
|
|
|
|
g.lastMouseY = my
|
2020-08-03 13:44:00 -04:00
|
|
|
g.inventory.lastMouseX = mx
|
|
|
|
g.inventory.lastMouseY = my
|
2020-06-25 00:39:09 -04:00
|
|
|
|
2020-06-23 12:28:05 -04:00
|
|
|
for i := range g.actionableRegions {
|
|
|
|
// Mouse over a game control element
|
|
|
|
if g.actionableRegions[i].Rect.IsInRect(mx, my) {
|
|
|
|
g.onHoverActionable(g.actionableRegions[i].ActionableTypeId)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-06-21 16:06:52 -04:00
|
|
|
return false
|
2020-06-21 15:26:07 -04:00
|
|
|
}
|
|
|
|
|
2020-08-11 18:01:33 -04:00
|
|
|
// OnMouseButtonDown handles mouse button presses
|
2020-07-03 15:09:16 -04:00
|
|
|
func (g *GameControls) OnMouseButtonDown(event d2interface.MouseEvent) bool {
|
|
|
|
mx, my := event.X(), event.Y()
|
2020-07-26 14:52:54 -04:00
|
|
|
|
2020-06-23 12:28:05 -04:00
|
|
|
for i := range g.actionableRegions {
|
|
|
|
// If click is on a game control element
|
|
|
|
if g.actionableRegions[i].Rect.IsInRect(mx, my) {
|
|
|
|
g.onClickActionable(g.actionableRegions[i].ActionableTypeId)
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
px, py := g.mapRenderer.ScreenToWorld(mx, my)
|
2020-02-22 20:44:30 -05:00
|
|
|
px = float64(int(px*10)) / 10.0
|
|
|
|
py = float64(int(py*10)) / 10.0
|
|
|
|
|
2020-07-06 21:26:08 -04:00
|
|
|
if event.Button() == d2enum.MouseButtonLeft && !g.isInActiveMenusRect(mx, my) {
|
2020-09-08 15:58:35 -04:00
|
|
|
g.lastLeftBtnActionTime = d2util.Now()
|
2020-07-26 14:52:54 -04:00
|
|
|
|
2020-06-18 14:11:04 -04:00
|
|
|
g.inputListener.OnPlayerMove(px, py)
|
2020-07-26 14:52:54 -04:00
|
|
|
|
2020-02-22 20:44:30 -05:00
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
2020-07-06 21:26:08 -04:00
|
|
|
if event.Button() == d2enum.MouseButtonRight && !g.isInActiveMenusRect(mx, my) {
|
2020-09-08 15:58:35 -04:00
|
|
|
g.lastRightBtnActionTime = d2util.Now()
|
2020-07-26 14:52:54 -04:00
|
|
|
|
2020-07-22 15:03:03 -04:00
|
|
|
g.inputListener.OnPlayerCast(g.missileID, px, py)
|
2020-07-26 14:52:54 -04:00
|
|
|
|
2020-06-26 20:03:00 -04:00
|
|
|
return true
|
2019-12-28 23:32:53 -05:00
|
|
|
}
|
2020-02-22 20:44:30 -05:00
|
|
|
|
2020-01-25 23:28:21 -05:00
|
|
|
return false
|
2019-12-16 11:04:39 -05:00
|
|
|
}
|
|
|
|
|
2020-08-11 18:01:33 -04:00
|
|
|
// Load loads the resources required for the GameControls
|
2019-12-16 11:04:39 -05:00
|
|
|
func (g *GameControls) Load() {
|
2020-02-01 18:55:56 -05:00
|
|
|
animation, _ := d2asset.LoadAnimation(d2resource.GameGlobeOverlap, d2resource.PaletteSky)
|
2020-08-06 10:30:23 -04:00
|
|
|
g.globeSprite, _ = g.uiManager.NewSprite(animation)
|
2020-01-31 23:18:11 -05:00
|
|
|
|
2020-06-25 14:56:49 -04:00
|
|
|
animation, _ = d2asset.LoadAnimation(d2resource.HealthManaIndicator, d2resource.PaletteSky)
|
2020-08-06 10:30:23 -04:00
|
|
|
g.hpManaStatusSprite, _ = g.uiManager.NewSprite(animation)
|
2020-06-25 14:56:49 -04:00
|
|
|
|
2020-02-01 18:55:56 -05:00
|
|
|
animation, _ = d2asset.LoadAnimation(d2resource.GamePanels, d2resource.PaletteSky)
|
2020-08-06 10:30:23 -04:00
|
|
|
g.mainPanel, _ = g.uiManager.NewSprite(animation)
|
2020-01-31 23:18:11 -05:00
|
|
|
|
2020-02-01 18:55:56 -05:00
|
|
|
animation, _ = d2asset.LoadAnimation(d2resource.MenuButton, d2resource.PaletteSky)
|
2020-08-25 09:10:26 -04:00
|
|
|
_ = animation.SetCurrentFrame(2)
|
2020-08-06 10:30:23 -04:00
|
|
|
g.menuButton, _ = g.uiManager.NewSprite(animation)
|
2020-01-31 23:18:11 -05:00
|
|
|
|
2020-02-01 18:55:56 -05:00
|
|
|
animation, _ = d2asset.LoadAnimation(d2resource.GenericSkills, d2resource.PaletteSky)
|
2020-08-06 10:30:23 -04:00
|
|
|
g.skillIcon, _ = g.uiManager.NewSprite(animation)
|
2020-01-31 23:18:11 -05:00
|
|
|
|
2020-06-24 15:23:38 -04:00
|
|
|
g.loadUIButtons()
|
|
|
|
|
2019-12-28 23:32:53 -05:00
|
|
|
g.inventory.Load()
|
2020-06-25 14:56:49 -04:00
|
|
|
g.heroStatsPanel.Load()
|
2020-09-09 08:21:27 -04:00
|
|
|
g.helpOverlay.Load()
|
2020-06-21 16:06:52 -04:00
|
|
|
}
|
|
|
|
|
2020-06-24 15:23:38 -04:00
|
|
|
func (g *GameControls) loadUIButtons() {
|
|
|
|
// Run button
|
2020-08-06 10:30:23 -04:00
|
|
|
g.runButton = g.uiManager.NewButton(d2ui.ButtonTypeRun, "")
|
2020-07-26 14:52:54 -04:00
|
|
|
|
2020-06-24 15:23:38 -04:00
|
|
|
g.runButton.SetPosition(255, 570)
|
|
|
|
g.runButton.OnActivated(func() { g.onToggleRunButton() })
|
2020-07-26 14:52:54 -04:00
|
|
|
|
2020-06-24 15:23:38 -04:00
|
|
|
if g.hero.IsRunToggled() {
|
|
|
|
g.runButton.Toggle()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (g *GameControls) onToggleRunButton() {
|
|
|
|
g.runButton.Toggle()
|
|
|
|
g.hero.ToggleRunWalk()
|
|
|
|
// TODO: change the running menu icon
|
|
|
|
g.hero.SetIsRunning(g.hero.IsRunToggled())
|
|
|
|
}
|
|
|
|
|
2020-08-11 18:01:33 -04:00
|
|
|
// Advance advances the state of the GameControls
|
2020-06-21 16:06:52 -04:00
|
|
|
func (g *GameControls) Advance(elapsed float64) error {
|
2020-07-18 23:37:35 -04:00
|
|
|
g.mapRenderer.Advance(elapsed)
|
2020-06-21 16:06:52 -04:00
|
|
|
return nil
|
2019-12-16 11:04:39 -05:00
|
|
|
}
|
|
|
|
|
2020-06-22 09:23:56 -04:00
|
|
|
func (g *GameControls) updateLayout() {
|
2020-06-25 19:18:37 -04:00
|
|
|
isRightPanelOpen := g.isLeftPanelOpen()
|
|
|
|
isLeftPanelOpen := g.isRightPanelOpen()
|
2020-06-22 09:23:56 -04:00
|
|
|
|
2020-08-11 18:01:33 -04:00
|
|
|
switch {
|
|
|
|
case isRightPanelOpen == isLeftPanelOpen:
|
2020-06-22 09:23:56 -04:00
|
|
|
g.mapRenderer.ViewportDefault()
|
2020-08-11 18:01:33 -04:00
|
|
|
case isRightPanelOpen:
|
2020-06-22 09:23:56 -04:00
|
|
|
g.mapRenderer.ViewportToLeft()
|
2020-08-11 18:01:33 -04:00
|
|
|
default:
|
2020-06-22 09:23:56 -04:00
|
|
|
g.mapRenderer.ViewportToRight()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-06-25 19:18:37 -04:00
|
|
|
func (g *GameControls) isLeftPanelOpen() bool {
|
|
|
|
// TODO: add quest log panel
|
|
|
|
return g.heroStatsPanel.IsOpen()
|
|
|
|
}
|
|
|
|
|
|
|
|
func (g *GameControls) isRightPanelOpen() bool {
|
|
|
|
// TODO: add skills tree panel
|
|
|
|
return g.inventory.IsOpen()
|
|
|
|
}
|
|
|
|
|
2020-08-11 18:01:33 -04:00
|
|
|
func (g *GameControls) isInActiveMenusRect(px, py int) bool {
|
2020-09-08 15:58:35 -04:00
|
|
|
var bottomMenuRect = d2geom.Rectangle{Left: 0, Top: 550, Width: 800, Height: 50}
|
2020-07-26 14:52:54 -04:00
|
|
|
|
2020-09-08 15:58:35 -04:00
|
|
|
var leftMenuRect = d2geom.Rectangle{Left: 0, Top: 0, Width: 400, Height: 600}
|
2020-07-26 14:52:54 -04:00
|
|
|
|
2020-09-08 15:58:35 -04:00
|
|
|
var rightMenuRect = d2geom.Rectangle{Left: 400, Top: 0, Width: 400, Height: 600}
|
2020-07-26 14:52:54 -04:00
|
|
|
|
2020-06-25 19:18:37 -04:00
|
|
|
if bottomMenuRect.IsInRect(px, py) {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
|
|
|
if g.isLeftPanelOpen() && leftMenuRect.IsInRect(px, py) {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
|
|
|
if g.isRightPanelOpen() && rightMenuRect.IsInRect(px, py) {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
2020-08-25 09:10:26 -04:00
|
|
|
if g.miniPanel.IsOpen() && g.miniPanel.isInRect(px, py) {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
2020-06-25 19:18:37 -04:00
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
2019-12-16 11:04:39 -05:00
|
|
|
// TODO: consider caching the panels to single image that is reused.
|
2020-08-11 18:01:33 -04:00
|
|
|
// Render draws the GameControls onto the target
|
2020-07-26 14:52:54 -04:00
|
|
|
func (g *GameControls) Render(target d2interface.Surface) error {
|
2020-08-24 15:50:33 -04:00
|
|
|
|
|
|
|
mx, my := g.lastMouseX, g.lastMouseY
|
2020-08-05 21:27:45 -04:00
|
|
|
for entityIdx := range g.mapEngine.Entities() {
|
|
|
|
entity := (g.mapEngine.Entities())[entityIdx]
|
2020-06-27 18:58:41 -04:00
|
|
|
if !entity.Selectable() {
|
2020-06-25 00:39:09 -04:00
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
2020-08-01 19:03:09 -04:00
|
|
|
entPos := entity.GetPosition()
|
|
|
|
entOffset := entPos.RenderOffset()
|
2020-06-25 00:39:09 -04:00
|
|
|
entScreenXf, entScreenYf := g.mapRenderer.WorldToScreenF(entity.GetPositionF())
|
|
|
|
entScreenX := int(math.Floor(entScreenXf))
|
|
|
|
entScreenY := int(math.Floor(entScreenYf))
|
2020-08-01 19:03:09 -04:00
|
|
|
entityWidth, entityHeight := entity.GetSize()
|
|
|
|
halfWidth, halfHeight := entityWidth/2, entityHeight/2
|
|
|
|
l, r := entScreenX-halfWidth-hoverLabelOuterPad, entScreenX+halfWidth+hoverLabelOuterPad
|
|
|
|
t, b := entScreenY-halfHeight-hoverLabelOuterPad, entScreenY+halfHeight-hoverLabelOuterPad
|
|
|
|
xWithin := (l <= mx) && (r >= mx)
|
|
|
|
yWithin := (t <= my) && (b >= my)
|
|
|
|
within := xWithin && yWithin
|
|
|
|
|
|
|
|
if within {
|
|
|
|
xOff, yOff := int(entOffset.X()), int(entOffset.Y())
|
2020-08-03 00:48:17 -04:00
|
|
|
|
2020-08-02 21:26:07 -04:00
|
|
|
g.nameLabel.SetText(entity.Label())
|
|
|
|
|
2020-08-01 19:03:09 -04:00
|
|
|
xLabel, yLabel := entScreenX-xOff, entScreenY-yOff-entityHeight-hoverLabelOuterPad
|
|
|
|
g.nameLabel.SetPosition(xLabel, yLabel)
|
2020-08-03 00:48:17 -04:00
|
|
|
|
2020-06-25 00:39:09 -04:00
|
|
|
g.nameLabel.Render(target)
|
2020-06-27 18:58:41 -04:00
|
|
|
entity.Highlight()
|
2020-07-26 14:52:54 -04:00
|
|
|
|
2020-06-25 00:39:09 -04:00
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-08-11 18:01:33 -04:00
|
|
|
if err := g.heroStatsPanel.Render(target); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := g.inventory.Render(target); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2019-12-28 23:32:53 -05:00
|
|
|
|
2019-12-28 16:46:08 -05:00
|
|
|
width, height := target.GetSize()
|
2020-02-01 21:51:49 -05:00
|
|
|
offset := 0
|
2019-12-16 11:04:39 -05:00
|
|
|
|
|
|
|
// Left globe holder
|
2020-07-26 14:52:54 -04:00
|
|
|
if err := g.mainPanel.SetCurrentFrame(0); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2019-12-21 20:53:18 -05:00
|
|
|
w, _ := g.mainPanel.GetCurrentFrameSize()
|
2020-07-26 14:52:54 -04:00
|
|
|
|
2019-12-28 23:32:53 -05:00
|
|
|
g.mainPanel.SetPosition(offset, height)
|
2020-07-26 14:52:54 -04:00
|
|
|
|
|
|
|
if err := g.mainPanel.Render(target); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2019-12-16 11:04:39 -05:00
|
|
|
|
2020-06-25 14:56:49 -04:00
|
|
|
// Health status bar
|
|
|
|
healthPercent := float64(g.hero.Stats.Health) / float64(g.hero.Stats.MaxHealth)
|
|
|
|
hpBarHeight := int(healthPercent * float64(globeHeight))
|
2020-07-26 14:52:54 -04:00
|
|
|
|
|
|
|
if err := g.hpManaStatusSprite.SetCurrentFrame(0); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2020-06-30 12:43:13 -04:00
|
|
|
g.hpManaStatusSprite.SetPosition(offset+30, height-13)
|
2020-07-26 14:52:54 -04:00
|
|
|
|
|
|
|
if err := g.hpManaStatusSprite.RenderSection(target, image.Rect(0, globeHeight-hpBarHeight, globeWidth, globeHeight)); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2020-06-25 14:56:49 -04:00
|
|
|
|
2020-06-30 12:43:13 -04:00
|
|
|
// Left globe
|
2020-07-26 14:52:54 -04:00
|
|
|
if err := g.globeSprite.SetCurrentFrame(0); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2020-06-30 12:43:13 -04:00
|
|
|
g.globeSprite.SetPosition(offset+28, height-5)
|
2020-07-26 14:52:54 -04:00
|
|
|
|
|
|
|
if err := g.globeSprite.Render(target); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2020-06-25 14:56:49 -04:00
|
|
|
|
2019-12-16 11:04:39 -05:00
|
|
|
offset += w
|
|
|
|
|
|
|
|
// Left skill
|
2020-07-26 14:52:54 -04:00
|
|
|
if err := g.skillIcon.SetCurrentFrame(2); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2019-12-21 20:53:18 -05:00
|
|
|
w, _ = g.skillIcon.GetCurrentFrameSize()
|
2020-07-26 14:52:54 -04:00
|
|
|
|
2019-12-28 23:32:53 -05:00
|
|
|
g.skillIcon.SetPosition(offset, height)
|
2020-07-26 14:52:54 -04:00
|
|
|
|
|
|
|
if err := g.skillIcon.Render(target); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2019-12-16 11:04:39 -05:00
|
|
|
offset += w
|
|
|
|
|
|
|
|
// Left skill selector
|
2020-07-26 14:52:54 -04:00
|
|
|
if err := g.mainPanel.SetCurrentFrame(1); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2019-12-21 20:53:18 -05:00
|
|
|
w, _ = g.mainPanel.GetCurrentFrameSize()
|
2020-07-26 14:52:54 -04:00
|
|
|
|
2019-12-28 23:32:53 -05:00
|
|
|
g.mainPanel.SetPosition(offset, height)
|
2020-07-26 14:52:54 -04:00
|
|
|
|
|
|
|
if err := g.mainPanel.Render(target); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2019-12-16 11:04:39 -05:00
|
|
|
offset += w
|
|
|
|
|
|
|
|
// Stamina
|
2020-07-26 14:52:54 -04:00
|
|
|
if err := g.mainPanel.SetCurrentFrame(2); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2019-12-21 20:53:18 -05:00
|
|
|
w, _ = g.mainPanel.GetCurrentFrameSize()
|
2020-07-26 14:52:54 -04:00
|
|
|
|
2019-12-28 23:32:53 -05:00
|
|
|
g.mainPanel.SetPosition(offset, height)
|
2020-07-26 14:52:54 -04:00
|
|
|
|
|
|
|
if err := g.mainPanel.Render(target); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2019-12-16 11:04:39 -05:00
|
|
|
offset += w
|
|
|
|
|
2020-06-25 14:56:49 -04:00
|
|
|
// Stamina status bar
|
|
|
|
target.PushTranslation(273, 572)
|
2020-07-08 21:57:35 -04:00
|
|
|
target.PushEffect(d2enum.DrawEffectModulate)
|
2020-07-26 14:52:54 -04:00
|
|
|
|
2020-06-25 14:56:49 -04:00
|
|
|
staminaPercent := float64(g.hero.Stats.Stamina) / float64(g.hero.Stats.MaxStamina)
|
2020-07-26 14:52:54 -04:00
|
|
|
|
2020-06-25 14:56:49 -04:00
|
|
|
target.DrawRect(int(staminaPercent*staminaBarWidth), 19, color.RGBA{R: 175, G: 136, B: 72, A: 200})
|
|
|
|
target.PopN(2)
|
|
|
|
|
|
|
|
// Experience status bar
|
|
|
|
target.PushTranslation(256, 561)
|
2020-07-26 14:52:54 -04:00
|
|
|
|
2020-06-25 14:56:49 -04:00
|
|
|
expPercent := float64(g.hero.Stats.Experience) / float64(g.hero.Stats.NextLevelExp)
|
2020-07-26 14:52:54 -04:00
|
|
|
|
2020-06-25 14:56:49 -04:00
|
|
|
target.DrawRect(int(expPercent*expBarWidth), 2, color.RGBA{R: 255, G: 255, B: 255, A: 255})
|
|
|
|
target.Pop()
|
|
|
|
|
2019-12-16 11:04:39 -05:00
|
|
|
// Center menu button
|
2020-08-25 09:10:26 -04:00
|
|
|
menuButtonFrameIndex := 0
|
|
|
|
if g.miniPanel.isOpen {
|
|
|
|
menuButtonFrameIndex = 2
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := g.menuButton.SetCurrentFrame(menuButtonFrameIndex); err != nil {
|
2020-07-26 14:52:54 -04:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2019-12-21 20:53:18 -05:00
|
|
|
w, _ = g.mainPanel.GetCurrentFrameSize()
|
2020-07-26 14:52:54 -04:00
|
|
|
|
2019-12-21 20:53:18 -05:00
|
|
|
g.menuButton.SetPosition((width/2)-8, height-16)
|
2020-07-26 14:52:54 -04:00
|
|
|
|
|
|
|
if err := g.menuButton.Render(target); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2019-12-16 11:04:39 -05:00
|
|
|
|
2020-08-25 09:10:26 -04:00
|
|
|
if err := g.miniPanel.Render(target); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2019-12-16 11:04:39 -05:00
|
|
|
// Potions
|
2020-07-26 14:52:54 -04:00
|
|
|
if err := g.mainPanel.SetCurrentFrame(3); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2019-12-21 20:53:18 -05:00
|
|
|
w, _ = g.mainPanel.GetCurrentFrameSize()
|
2020-07-26 14:52:54 -04:00
|
|
|
|
2019-12-28 23:32:53 -05:00
|
|
|
g.mainPanel.SetPosition(offset, height)
|
2020-07-26 14:52:54 -04:00
|
|
|
|
|
|
|
if err := g.mainPanel.Render(target); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2019-12-16 11:04:39 -05:00
|
|
|
offset += w
|
|
|
|
|
|
|
|
// Right skill selector
|
2020-07-26 14:52:54 -04:00
|
|
|
if err := g.mainPanel.SetCurrentFrame(4); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2019-12-21 20:53:18 -05:00
|
|
|
w, _ = g.mainPanel.GetCurrentFrameSize()
|
2020-07-26 14:52:54 -04:00
|
|
|
|
2019-12-28 23:32:53 -05:00
|
|
|
g.mainPanel.SetPosition(offset, height)
|
2020-07-26 14:52:54 -04:00
|
|
|
|
|
|
|
if err := g.mainPanel.Render(target); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2019-12-16 11:04:39 -05:00
|
|
|
offset += w
|
|
|
|
|
|
|
|
// Right skill
|
2020-07-26 14:52:54 -04:00
|
|
|
if err := g.skillIcon.SetCurrentFrame(2); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2019-12-21 20:53:18 -05:00
|
|
|
w, _ = g.skillIcon.GetCurrentFrameSize()
|
2020-07-26 14:52:54 -04:00
|
|
|
|
2019-12-28 23:32:53 -05:00
|
|
|
g.skillIcon.SetPosition(offset, height)
|
2020-07-26 14:52:54 -04:00
|
|
|
|
|
|
|
if err := g.skillIcon.Render(target); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2019-12-16 11:04:39 -05:00
|
|
|
offset += w
|
|
|
|
|
|
|
|
// Right globe holder
|
2020-07-26 14:52:54 -04:00
|
|
|
if err := g.mainPanel.SetCurrentFrame(5); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2019-12-21 20:53:18 -05:00
|
|
|
w, _ = g.mainPanel.GetCurrentFrameSize()
|
2020-07-26 14:52:54 -04:00
|
|
|
|
2019-12-28 23:32:53 -05:00
|
|
|
g.mainPanel.SetPosition(offset, height)
|
2020-07-26 14:52:54 -04:00
|
|
|
|
|
|
|
if err := g.mainPanel.Render(target); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2019-12-16 11:04:39 -05:00
|
|
|
|
2020-06-30 12:43:13 -04:00
|
|
|
// Mana status bar
|
|
|
|
manaPercent := float64(g.hero.Stats.Mana) / float64(g.hero.Stats.MaxMana)
|
|
|
|
manaBarHeight := int(manaPercent * float64(globeHeight))
|
2020-07-26 14:52:54 -04:00
|
|
|
|
|
|
|
if err := g.hpManaStatusSprite.SetCurrentFrame(1); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2020-06-30 12:43:13 -04:00
|
|
|
g.hpManaStatusSprite.SetPosition(offset+7, height-12)
|
2020-07-26 14:52:54 -04:00
|
|
|
|
|
|
|
if err := g.hpManaStatusSprite.RenderSection(target, image.Rect(0, globeHeight-manaBarHeight, globeWidth, globeHeight)); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2020-06-30 12:43:13 -04:00
|
|
|
|
2019-12-16 11:04:39 -05:00
|
|
|
// Right globe
|
2020-07-26 14:52:54 -04:00
|
|
|
if err := g.globeSprite.SetCurrentFrame(1); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2019-12-28 23:32:53 -05:00
|
|
|
g.globeSprite.SetPosition(offset+8, height-8)
|
2020-07-26 14:52:54 -04:00
|
|
|
|
|
|
|
if err := g.globeSprite.Render(target); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := g.globeSprite.Render(target); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2020-06-25 14:56:49 -04:00
|
|
|
|
2020-06-22 15:55:32 -04:00
|
|
|
if g.isZoneTextShown {
|
|
|
|
g.zoneChangeText.SetPosition(width/2, height/4)
|
|
|
|
g.zoneChangeText.Render(target)
|
|
|
|
}
|
2020-06-25 14:56:49 -04:00
|
|
|
|
2020-08-24 15:50:33 -04:00
|
|
|
hpWithin := (95 >= mx) && (30 <= mx) && (575 >= my) && (525 <= my)
|
|
|
|
manaWithin := (765 >= mx) && (700 <= mx) && (575 >= my) && (525 <= my)
|
|
|
|
|
|
|
|
// Display current hp and mana stats hpGlobe or manaGlobe region is clicked
|
|
|
|
if hpWithin || g.hpStatsIsVisible {
|
|
|
|
g.hpManaStatsLabel.SetText(d2ui.ColorTokenize(fmt.Sprintf("LIFE: %v / %v", float64(g.hero.Stats.Health), float64(g.hero.Stats.MaxHealth)), d2ui.ColorTokenWhite))
|
|
|
|
g.hpManaStatsLabel.SetPosition(15, 485)
|
|
|
|
g.hpManaStatsLabel.Render(target)
|
|
|
|
}
|
|
|
|
|
|
|
|
if manaWithin || g.manaStatsIsVisible {
|
|
|
|
g.hpManaStatsLabel.SetText(fmt.Sprintf("MANA: %v / %v", float64(g.hero.Stats.Mana), float64(g.hero.Stats.MaxMana)))
|
|
|
|
widthManaLabel, _ := g.hpManaStatsLabel.GetSize()
|
|
|
|
xManaLabel := 785 - widthManaLabel
|
|
|
|
g.hpManaStatsLabel.SetPosition(xManaLabel, 485)
|
|
|
|
g.hpManaStatsLabel.Render(target)
|
|
|
|
}
|
|
|
|
|
2020-09-09 08:21:27 -04:00
|
|
|
if err := g.helpOverlay.Render(target); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2020-07-26 14:52:54 -04:00
|
|
|
return nil
|
2020-06-22 15:55:32 -04:00
|
|
|
}
|
|
|
|
|
2020-08-11 18:01:33 -04:00
|
|
|
// SetZoneChangeText sets the zoneChangeText
|
2020-06-22 15:55:32 -04:00
|
|
|
func (g *GameControls) SetZoneChangeText(text string) {
|
|
|
|
g.zoneChangeText.SetText(text)
|
|
|
|
}
|
|
|
|
|
2020-08-11 18:01:33 -04:00
|
|
|
// ShowZoneChangeText shows the zoneChangeText
|
2020-06-22 15:55:32 -04:00
|
|
|
func (g *GameControls) ShowZoneChangeText() {
|
|
|
|
g.isZoneTextShown = true
|
|
|
|
}
|
|
|
|
|
2020-08-11 18:01:33 -04:00
|
|
|
// HideZoneChangeTextAfter hides the zoneChangeText after the given amount of seconds
|
2020-06-22 15:55:32 -04:00
|
|
|
func (g *GameControls) HideZoneChangeTextAfter(delay float64) {
|
|
|
|
time.AfterFunc(time.Duration(delay)*time.Second, func() {
|
|
|
|
g.isZoneTextShown = false
|
|
|
|
})
|
2019-12-16 11:04:39 -05:00
|
|
|
}
|
2020-06-21 16:06:52 -04:00
|
|
|
|
2020-08-24 15:50:33 -04:00
|
|
|
// HpStatsIsVisible returns true if the hp and mana stats are visible to the player
|
|
|
|
func (g *GameControls) HpStatsIsVisible() bool {
|
|
|
|
return g.hpStatsIsVisible
|
|
|
|
}
|
|
|
|
|
|
|
|
// ManaStatsIsVisible returns true if the hp and mana stats are visible to the player
|
|
|
|
func (g *GameControls) ManaStatsIsVisible() bool {
|
|
|
|
return g.manaStatsIsVisible
|
|
|
|
}
|
|
|
|
|
|
|
|
// ToggleHpStats toggles the visibility of the hp and mana stats placed above their respective globe
|
|
|
|
func (g *GameControls) ToggleHpStats() {
|
|
|
|
g.hpStatsIsVisible = !g.hpStatsIsVisible
|
|
|
|
}
|
|
|
|
|
|
|
|
// ToggleManaStats toggles the visibility of the hp and mana stats placed above their respective globe
|
|
|
|
func (g *GameControls) ToggleManaStats() {
|
|
|
|
g.manaStatsIsVisible = !g.manaStatsIsVisible
|
|
|
|
}
|
|
|
|
|
2020-06-23 12:28:05 -04:00
|
|
|
// Handles what to do when an actionable is hovered
|
|
|
|
func (g *GameControls) onHoverActionable(item ActionableType) {
|
|
|
|
switch item {
|
|
|
|
case leftSkill:
|
|
|
|
return
|
2020-08-25 09:10:26 -04:00
|
|
|
case leftSelect:
|
2020-06-23 12:28:05 -04:00
|
|
|
return
|
|
|
|
case xp:
|
|
|
|
return
|
|
|
|
case walkRun:
|
|
|
|
return
|
|
|
|
case stamina:
|
|
|
|
return
|
2020-08-25 09:10:26 -04:00
|
|
|
case miniPnl:
|
2020-06-23 12:28:05 -04:00
|
|
|
return
|
2020-08-25 09:10:26 -04:00
|
|
|
case rightSelect:
|
2020-06-23 12:28:05 -04:00
|
|
|
return
|
|
|
|
case rightSkill:
|
|
|
|
return
|
2020-08-24 15:50:33 -04:00
|
|
|
case hpGlobe:
|
|
|
|
return
|
|
|
|
case manaGlobe:
|
|
|
|
return
|
2020-06-23 12:28:05 -04:00
|
|
|
default:
|
|
|
|
log.Printf("Unrecognized ActionableType(%d) being hovered\n", item)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Handles what to do when an actionable is clicked
|
|
|
|
func (g *GameControls) onClickActionable(item ActionableType) {
|
|
|
|
switch item {
|
2020-06-24 13:49:13 -04:00
|
|
|
case leftSkill:
|
|
|
|
log.Println("Left Skill Action Pressed")
|
2020-08-25 09:10:26 -04:00
|
|
|
case leftSelect:
|
2020-06-24 13:49:13 -04:00
|
|
|
log.Println("Left Skill Selector Action Pressed")
|
|
|
|
case xp:
|
|
|
|
log.Println("XP Action Pressed")
|
|
|
|
case walkRun:
|
|
|
|
log.Println("Walk/Run Action Pressed")
|
|
|
|
case stamina:
|
|
|
|
log.Println("Stamina Action Pressed")
|
2020-08-25 09:10:26 -04:00
|
|
|
case miniPnl:
|
2020-06-24 13:49:13 -04:00
|
|
|
log.Println("Mini Panel Action Pressed")
|
2020-08-25 09:10:26 -04:00
|
|
|
|
|
|
|
g.miniPanel.Toggle()
|
|
|
|
case rightSelect:
|
2020-06-24 13:49:13 -04:00
|
|
|
log.Println("Right Skill Selector Action Pressed")
|
|
|
|
case rightSkill:
|
|
|
|
log.Println("Right Skill Action Pressed")
|
2020-08-24 15:50:33 -04:00
|
|
|
case hpGlobe:
|
|
|
|
g.ToggleHpStats()
|
|
|
|
log.Println("HP Globe Pressed")
|
|
|
|
case manaGlobe:
|
|
|
|
g.ToggleManaStats()
|
|
|
|
log.Println("Mana Globe Pressed")
|
2020-08-25 09:10:26 -04:00
|
|
|
case miniPanelCharacter:
|
|
|
|
log.Println("Character button on mini panel is pressed")
|
|
|
|
|
|
|
|
g.heroStatsPanel.Toggle()
|
|
|
|
g.updateLayout()
|
|
|
|
case miniPanelInventory:
|
|
|
|
log.Println("Inventory button on mini panel is pressed")
|
|
|
|
|
|
|
|
g.inventory.Toggle()
|
|
|
|
g.updateLayout()
|
2020-06-23 12:28:05 -04:00
|
|
|
default:
|
|
|
|
log.Printf("Unrecognized ActionableType(%d) being clicked\n", item)
|
|
|
|
}
|
|
|
|
}
|