2019-12-16 11:04:39 -05:00
|
|
|
package d2player
|
|
|
|
|
|
|
|
import (
|
2020-08-24 15:50:33 -04:00
|
|
|
"fmt"
|
2020-12-21 15:46:58 -05:00
|
|
|
"strconv"
|
2020-09-24 19:28:14 -04:00
|
|
|
"strings"
|
2020-06-22 15:55:32 -04:00
|
|
|
"time"
|
|
|
|
|
2020-09-12 16:25:09 -04:00
|
|
|
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2geom"
|
|
|
|
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2util"
|
|
|
|
|
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"
|
2020-09-20 11:55:44 -04:00
|
|
|
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2hero"
|
2020-07-22 15:03:03 -04:00
|
|
|
|
2020-06-28 21:40:52 -04:00
|
|
|
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
|
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-11-18 16:02:49 -05:00
|
|
|
const (
|
|
|
|
logPrefix = "Player"
|
|
|
|
)
|
|
|
|
|
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
|
|
|
|
Open()
|
|
|
|
Close()
|
|
|
|
}
|
|
|
|
|
2020-11-05 14:55:09 -05:00
|
|
|
const mouseBtnActionsThreshold = 0.25
|
2020-02-22 20:44:30 -05:00
|
|
|
|
2020-10-24 22:52:26 -04:00
|
|
|
const (
|
|
|
|
// Since they require special handling, not considering (1) globes, (2) content of the mini panel, (3) belt
|
|
|
|
leftSkill actionableType = iota
|
|
|
|
xp
|
|
|
|
stamina
|
|
|
|
rightSkill
|
|
|
|
hpGlobe
|
|
|
|
manaGlobe
|
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
|
|
|
leftSkillX,
|
|
|
|
leftSkillY,
|
|
|
|
leftSkillWidth,
|
2020-11-13 15:08:43 -05:00
|
|
|
leftSkillHeight = 117, 550, 50, 50
|
2020-10-24 22:52:26 -04:00
|
|
|
|
|
|
|
xpX,
|
|
|
|
xpY,
|
|
|
|
xpWidth,
|
|
|
|
xpHeight = 253, 560, 125, 5
|
|
|
|
|
|
|
|
staminaX,
|
|
|
|
staminaY,
|
|
|
|
staminaWidth,
|
|
|
|
staminaHeight = 273, 573, 105, 20
|
|
|
|
|
|
|
|
rightSkillX,
|
|
|
|
rightSkillY,
|
|
|
|
rightSkillWidth,
|
2020-11-13 15:08:43 -05:00
|
|
|
rightSkillHeight = 635, 550, 50, 50
|
2020-10-24 22:52:26 -04:00
|
|
|
|
|
|
|
hpGlobeX,
|
|
|
|
hpGlobeY,
|
|
|
|
hpGlobeWidth,
|
|
|
|
hpGlobeHeight = 30, 525, 80, 60
|
|
|
|
|
|
|
|
manaGlobeX,
|
|
|
|
manaGlobeY,
|
|
|
|
manaGlobeWidth,
|
|
|
|
manaGlobeHeight = 695, 525, 80, 60
|
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
|
|
|
menuBottomRectX,
|
|
|
|
menuBottomRectY,
|
|
|
|
menuBottomRectW,
|
|
|
|
menuBottomRectH = 0, 550, 800, 50
|
|
|
|
|
|
|
|
menuLeftRectX,
|
|
|
|
menuLeftRectY,
|
|
|
|
menuLeftRectW,
|
2020-10-25 10:54:39 -04:00
|
|
|
menuLeftRectH = 0, 0, 400, 600
|
2020-10-24 22:52:26 -04:00
|
|
|
|
|
|
|
menuRightRectX,
|
|
|
|
menuRightRectY,
|
|
|
|
menuRightRectW,
|
2020-10-25 10:54:39 -04:00
|
|
|
menuRightRectH = 400, 0, 400, 600
|
2020-10-24 22:52:26 -04:00
|
|
|
)
|
|
|
|
|
2020-08-11 18:01:33 -04:00
|
|
|
// NewGameControls creates a GameControls instance and returns a pointer to it
|
2020-10-24 22:52:26 -04:00
|
|
|
// nolint:funlen // doesn't make sense to split this up
|
2020-08-06 10:30:23 -04:00
|
|
|
func NewGameControls(
|
2020-09-12 16:51:30 -04:00
|
|
|
asset *d2asset.AssetManager,
|
2020-08-06 10:30:23 -04:00
|
|
|
renderer d2interface.Renderer,
|
|
|
|
hero *d2mapentity.Player,
|
|
|
|
mapEngine *d2mapengine.MapEngine,
|
2020-10-07 21:20:05 -04:00
|
|
|
escapeMenu *EscapeMenu,
|
2020-08-06 10:30:23 -04:00
|
|
|
mapRenderer *d2maprenderer.MapRenderer,
|
2020-10-22 02:41:21 -04:00
|
|
|
inputListener inputCallbackListener,
|
2020-08-06 10:30:23 -04:00
|
|
|
term d2interface.Terminal,
|
|
|
|
ui *d2ui.UIManager,
|
2020-11-13 15:03:30 -05:00
|
|
|
keyMap *KeyMap,
|
2020-12-16 09:08:39 -05:00
|
|
|
audioProvider d2interface.AudioProvider,
|
2020-11-18 16:02:49 -05:00
|
|
|
l d2util.LogLevel,
|
2020-08-25 09:10:26 -04:00
|
|
|
isSinglePlayer bool,
|
2021-01-18 15:11:50 -05:00
|
|
|
players map[string]*d2mapentity.Player,
|
2020-08-06 10:30:23 -04:00
|
|
|
) (*GameControls, error) {
|
2020-07-11 11:25:34 -04:00
|
|
|
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:
|
2020-10-22 12:54:45 -04:00
|
|
|
inventoryRecordKey = "Assassin2"
|
2020-07-11 11:25:34 -04:00
|
|
|
case d2enum.HeroAmazon:
|
|
|
|
inventoryRecordKey = "Amazon2"
|
|
|
|
case d2enum.HeroBarbarian:
|
|
|
|
inventoryRecordKey = "Barbarian2"
|
|
|
|
case d2enum.HeroDruid:
|
2020-10-22 12:54:45 -04:00
|
|
|
inventoryRecordKey = "Druid2"
|
2020-07-11 11:25:34 -04:00
|
|
|
case d2enum.HeroNecromancer:
|
|
|
|
inventoryRecordKey = "Necromancer2"
|
|
|
|
case d2enum.HeroPaladin:
|
|
|
|
inventoryRecordKey = "Paladin2"
|
|
|
|
case d2enum.HeroSorceress:
|
|
|
|
inventoryRecordKey = "Sorceress2"
|
|
|
|
default:
|
2020-09-12 16:25:09 -04:00
|
|
|
return nil, fmt.Errorf("unknown hero class: %d", hero.Class)
|
2020-07-11 11:25:34 -04:00
|
|
|
}
|
2020-07-22 15:03:03 -04:00
|
|
|
|
2020-11-05 14:55:09 -05:00
|
|
|
actionableRegions := []actionableRegion{
|
|
|
|
{leftSkill, d2geom.Rectangle{
|
|
|
|
Left: leftSkillX,
|
|
|
|
Top: leftSkillY,
|
|
|
|
Width: leftSkillWidth,
|
|
|
|
Height: leftSkillHeight,
|
|
|
|
}},
|
|
|
|
{xp, d2geom.Rectangle{
|
|
|
|
Left: xpX,
|
|
|
|
Top: xpY,
|
|
|
|
Width: xpWidth,
|
|
|
|
Height: xpHeight,
|
|
|
|
}},
|
|
|
|
{stamina, d2geom.Rectangle{
|
|
|
|
Left: staminaX,
|
|
|
|
Top: staminaY,
|
|
|
|
Width: staminaWidth,
|
|
|
|
Height: staminaHeight,
|
|
|
|
}},
|
|
|
|
{rightSkill, d2geom.Rectangle{
|
|
|
|
Left: rightSkillX,
|
|
|
|
Top: rightSkillY,
|
|
|
|
Width: rightSkillWidth,
|
|
|
|
Height: rightSkillHeight,
|
|
|
|
}},
|
|
|
|
{hpGlobe, d2geom.Rectangle{
|
|
|
|
Left: hpGlobeX,
|
|
|
|
Top: hpGlobeY,
|
|
|
|
Width: hpGlobeWidth,
|
|
|
|
Height: hpGlobeHeight,
|
|
|
|
}},
|
|
|
|
{manaGlobe, d2geom.Rectangle{
|
|
|
|
Left: manaGlobeX,
|
|
|
|
Top: manaGlobeY,
|
|
|
|
Width: manaGlobeWidth,
|
|
|
|
Height: manaGlobeHeight,
|
|
|
|
}},
|
|
|
|
}
|
|
|
|
inventoryRecord := asset.Records.Layout.Inventory[inventoryRecordKey]
|
2020-08-24 15:50:33 -04:00
|
|
|
|
2020-11-18 16:02:49 -05:00
|
|
|
heroStatsPanel := NewHeroStatsPanel(asset, ui, hero.Name(), hero.Class, l, hero.Stats)
|
2021-01-13 11:34:33 -05:00
|
|
|
|
2021-01-18 15:11:50 -05:00
|
|
|
PartyPanel := NewPartyPanel(asset, ui, hero.Name(), l, hero, hero.Stats, players)
|
2021-01-13 11:34:33 -05:00
|
|
|
|
2020-12-16 09:08:39 -05:00
|
|
|
questLog := NewQuestLog(asset, ui, l, audioProvider, hero.Act)
|
2020-12-10 07:15:18 -05:00
|
|
|
|
|
|
|
inventory, err := NewInventory(asset, ui, l, hero.Gold, inventoryRecord)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2020-12-15 14:03:24 -05:00
|
|
|
skilltree := newSkillTree(hero.Skills, hero.Class, hero.Stats, asset, l, ui)
|
2020-11-16 04:41:01 -05:00
|
|
|
|
2020-11-18 16:02:49 -05:00
|
|
|
miniPanel := newMiniPanel(asset, ui, l, isSinglePlayer)
|
2020-11-16 04:41:01 -05:00
|
|
|
|
2020-09-20 17:52:01 -04:00
|
|
|
heroState, err := d2hero.NewHeroStateFactory(asset)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2020-11-21 05:35:32 -05:00
|
|
|
helpOverlay := NewHelpOverlay(asset, ui, l, keyMap)
|
2020-11-05 14:55:09 -05:00
|
|
|
|
|
|
|
const blackAlpha50percent = 0x0000007f
|
|
|
|
|
2020-06-21 20:46:00 -04:00
|
|
|
gc := &GameControls{
|
2020-11-05 14:55:09 -05:00
|
|
|
asset: asset,
|
|
|
|
ui: ui,
|
|
|
|
renderer: renderer,
|
|
|
|
hero: hero,
|
|
|
|
heroState: heroState,
|
|
|
|
escapeMenu: escapeMenu,
|
|
|
|
inputListener: inputListener,
|
|
|
|
mapRenderer: mapRenderer,
|
2020-11-16 04:41:01 -05:00
|
|
|
inventory: inventory,
|
|
|
|
skilltree: skilltree,
|
|
|
|
heroStatsPanel: heroStatsPanel,
|
2021-01-18 15:11:50 -05:00
|
|
|
PartyPanel: PartyPanel,
|
2020-12-02 02:19:15 -05:00
|
|
|
questLog: questLog,
|
2020-11-05 14:55:09 -05:00
|
|
|
HelpOverlay: helpOverlay,
|
2020-11-13 15:03:30 -05:00
|
|
|
keyMap: keyMap,
|
2020-10-24 22:52:26 -04:00
|
|
|
bottomMenuRect: &d2geom.Rectangle{
|
|
|
|
Left: menuBottomRectX,
|
|
|
|
Top: menuBottomRectY,
|
|
|
|
Width: menuBottomRectW,
|
|
|
|
Height: menuBottomRectH,
|
|
|
|
},
|
|
|
|
leftMenuRect: &d2geom.Rectangle{
|
|
|
|
Left: menuLeftRectX,
|
|
|
|
Top: menuLeftRectY,
|
|
|
|
Width: menuLeftRectW,
|
|
|
|
Height: menuLeftRectH,
|
|
|
|
},
|
|
|
|
rightMenuRect: &d2geom.Rectangle{
|
|
|
|
Left: menuRightRectX,
|
|
|
|
Top: menuRightRectY,
|
|
|
|
Width: menuRightRectW,
|
|
|
|
Height: menuRightRectH,
|
|
|
|
},
|
2020-11-05 14:55:09 -05:00
|
|
|
actionableRegions: actionableRegions,
|
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-12-15 06:37:35 -05:00
|
|
|
hud := NewHUD(asset, ui, hero, miniPanel, actionableRegions, mapEngine, l, gc, mapRenderer)
|
|
|
|
gc.hud = hud
|
|
|
|
|
|
|
|
hoverLabel := hud.nameLabel
|
|
|
|
hoverLabel.SetBackgroundColor(d2util.Color(blackAlpha50percent))
|
|
|
|
|
2020-11-16 04:41:01 -05:00
|
|
|
gc.heroStatsPanel.SetOnCloseCb(gc.onCloseHeroStatsPanel)
|
2020-12-22 08:28:29 -05:00
|
|
|
gc.questLog.SetOnCloseCb(gc.onCloseQuestLog)
|
2020-11-16 04:41:01 -05:00
|
|
|
gc.inventory.SetOnCloseCb(gc.onCloseInventory)
|
|
|
|
gc.skilltree.SetOnCloseCb(gc.onCloseSkilltree)
|
|
|
|
|
2020-11-21 05:35:32 -05:00
|
|
|
gc.escapeMenu.SetOnCloseCb(gc.hud.miniPanel.restoreDisabled)
|
|
|
|
gc.HelpOverlay.SetOnCloseCb(gc.hud.miniPanel.restoreDisabled)
|
2020-10-25 10:54:39 -04:00
|
|
|
|
2020-10-24 22:52:26 -04:00
|
|
|
err = gc.bindTerminalCommands(term)
|
2020-09-20 11:55:44 -04:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2020-11-22 00:36:59 -05:00
|
|
|
gc.Logger = d2util.NewLogger()
|
|
|
|
gc.Logger.SetLevel(l)
|
|
|
|
gc.Logger.SetPrefix(logPrefix)
|
2020-11-18 16:02:49 -05:00
|
|
|
|
2020-07-26 14:52:54 -04:00
|
|
|
return gc, nil
|
2020-06-21 20:46:00 -04:00
|
|
|
}
|
|
|
|
|
2020-11-18 16:02:49 -05:00
|
|
|
// GameControls represents the game's controls on the screen
|
|
|
|
type GameControls struct {
|
|
|
|
keyMap *KeyMap
|
|
|
|
actionableRegions []actionableRegion
|
|
|
|
asset *d2asset.AssetManager
|
|
|
|
renderer d2interface.Renderer // https://github.com/OpenDiablo2/OpenDiablo2/issues/798
|
|
|
|
inputListener inputCallbackListener
|
|
|
|
hero *d2mapentity.Player
|
|
|
|
heroState *d2hero.HeroStateFactory
|
|
|
|
mapRenderer *d2maprenderer.MapRenderer
|
|
|
|
escapeMenu *EscapeMenu
|
|
|
|
ui *d2ui.UIManager
|
|
|
|
inventory *Inventory
|
|
|
|
hud *HUD
|
|
|
|
skilltree *skillTree
|
|
|
|
heroStatsPanel *HeroStatsPanel
|
2021-01-18 15:11:50 -05:00
|
|
|
PartyPanel *PartyPanel
|
2020-12-02 02:19:15 -05:00
|
|
|
questLog *QuestLog
|
2020-11-18 16:02:49 -05:00
|
|
|
HelpOverlay *HelpOverlay
|
|
|
|
bottomMenuRect *d2geom.Rectangle
|
|
|
|
leftMenuRect *d2geom.Rectangle
|
|
|
|
rightMenuRect *d2geom.Rectangle
|
|
|
|
lastMouseX int
|
|
|
|
lastMouseY int
|
|
|
|
lastLeftBtnActionTime float64
|
|
|
|
lastRightBtnActionTime float64
|
|
|
|
FreeCam bool
|
|
|
|
isSinglePlayer bool
|
|
|
|
|
2020-11-22 00:36:59 -05:00
|
|
|
*d2util.Logger
|
2020-11-18 16:02:49 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
type actionableType int
|
|
|
|
|
|
|
|
type actionableRegion struct {
|
|
|
|
actionableTypeID actionableType
|
|
|
|
rect d2geom.Rectangle
|
|
|
|
}
|
|
|
|
|
|
|
|
// SkillResource represents a Skill with its corresponding icon sprite, path to DC6 file and icon number.
|
|
|
|
// SkillResourcePath points to a DC6 resource which contains the icons of multiple skills as frames.
|
|
|
|
// The IconNumber is the frame at which we can find our skill sprite in the DC6 file.
|
|
|
|
type SkillResource struct {
|
|
|
|
SkillResourcePath string // path to a skills DC6 file(see getSkillResourceByClass)
|
|
|
|
IconNumber int // the index of the frame in the DC6 file
|
|
|
|
SkillIcon *d2ui.Sprite
|
|
|
|
}
|
|
|
|
|
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 {
|
2020-11-01 22:43:23 -05:00
|
|
|
if event.Key() == d2enum.KeyEscape {
|
2020-10-07 21:20:05 -04:00
|
|
|
g.onEscKey()
|
2020-11-01 22:43:23 -05:00
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
|
|
|
gameEvent := g.keyMap.getGameEvent(event.Key())
|
|
|
|
|
|
|
|
switch gameEvent {
|
|
|
|
case d2enum.ClearScreen:
|
2020-12-22 08:21:34 -05:00
|
|
|
g.clearScreen()
|
2020-11-01 22:43:23 -05:00
|
|
|
g.updateLayout()
|
|
|
|
case d2enum.ToggleInventoryPanel:
|
2020-11-16 04:41:01 -05:00
|
|
|
g.toggleInventoryPanel()
|
2021-01-14 10:54:23 -05:00
|
|
|
case d2enum.TogglePartyPanel:
|
|
|
|
if !g.isSinglePlayer {
|
2021-01-14 13:24:18 -05:00
|
|
|
g.togglePartyPanel()
|
2021-01-14 10:54:23 -05:00
|
|
|
}
|
2020-11-01 22:43:23 -05:00
|
|
|
case d2enum.ToggleSkillTreePanel:
|
2020-12-02 06:32:16 -05:00
|
|
|
g.toggleSkilltreePanel()
|
2020-11-01 22:43:23 -05:00
|
|
|
case d2enum.ToggleCharacterPanel:
|
2020-11-16 04:41:01 -05:00
|
|
|
g.toggleHeroStatsPanel()
|
2020-12-02 02:19:15 -05:00
|
|
|
case d2enum.ToggleQuestLog:
|
|
|
|
g.toggleQuestLog()
|
2020-11-01 22:43:23 -05:00
|
|
|
case d2enum.ToggleRunWalk:
|
2020-11-05 14:55:09 -05:00
|
|
|
g.hud.onToggleRunButton(false)
|
2020-11-01 22:43:23 -05:00
|
|
|
case d2enum.HoldRun:
|
2020-11-05 14:55:09 -05:00
|
|
|
g.hud.onToggleRunButton(true)
|
2020-11-01 22:43:23 -05:00
|
|
|
case d2enum.ToggleHelpScreen:
|
2020-12-08 03:18:27 -05:00
|
|
|
g.toggleHelpOverlay()
|
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-10-07 16:12:56 -04:00
|
|
|
// OnKeyUp handles key release
|
|
|
|
func (g *GameControls) OnKeyUp(event d2interface.KeyEvent) bool {
|
2020-11-01 22:43:23 -05:00
|
|
|
gameEvent := g.keyMap.getGameEvent(event.Key())
|
|
|
|
|
2020-12-22 08:59:15 -05:00
|
|
|
if gameEvent == d2enum.HoldRun {
|
2020-11-05 14:55:09 -05:00
|
|
|
g.hud.onToggleRunButton(true)
|
2020-10-07 16:12:56 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
2020-10-22 01:12:06 -04:00
|
|
|
// When escape is pressed:
|
|
|
|
// 1. If there was some overlay or panel open, close it
|
|
|
|
// 2. Otherwise, if the Escape Menu was open, let the Escape Menu handle it
|
|
|
|
// 3. If nothing was open, open the Escape Menu
|
2020-10-07 21:20:05 -04:00
|
|
|
func (g *GameControls) onEscKey() {
|
|
|
|
escHandled := false
|
2020-10-22 01:12:06 -04:00
|
|
|
|
2020-12-22 08:21:34 -05:00
|
|
|
escHandled = g.hasOpenPanels() || g.HelpOverlay.IsOpen() || g.hud.skillSelectMenu.IsOpen()
|
|
|
|
g.clearScreen()
|
2020-10-07 21:20:05 -04:00
|
|
|
|
2020-12-22 08:59:15 -05:00
|
|
|
if escHandled {
|
2020-10-07 21:20:05 -04:00
|
|
|
g.updateLayout()
|
2020-12-22 08:59:15 -05:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
if g.escapeMenu.IsOpen() {
|
|
|
|
g.escapeMenu.OnEscKey()
|
|
|
|
} else {
|
|
|
|
g.openEscMenu()
|
2020-10-07 21:20:05 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-10-24 22:52:26 -04:00
|
|
|
func truncateFloat64(n float64) float64 {
|
|
|
|
const ten = 10.0
|
|
|
|
return float64(int(n*ten)) / ten
|
|
|
|
}
|
|
|
|
|
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 {
|
2020-10-24 22:52:26 -04:00
|
|
|
const (
|
|
|
|
screenWidth, screenHeight = 800, 600
|
|
|
|
halfScreenWidth, halfScreenHeight = screenWidth / 2, screenHeight / 2
|
|
|
|
subtilesPerTile = 5
|
|
|
|
)
|
|
|
|
|
2020-07-03 15:09:16 -04:00
|
|
|
px, py := g.mapRenderer.ScreenToWorld(event.X(), event.Y())
|
2020-10-24 22:52:26 -04:00
|
|
|
px = truncateFloat64(px)
|
|
|
|
py = truncateFloat64(py)
|
2020-06-22 15:55:32 -04:00
|
|
|
|
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-10-25 13:15:28 -04:00
|
|
|
shouldDoLeft := lastLeft >= mouseBtnActionsThreshold
|
|
|
|
shouldDoRight := lastRight >= mouseBtnActionsThreshold
|
2020-07-03 15:09:16 -04:00
|
|
|
|
2020-09-14 14:49:31 -04:00
|
|
|
if isLeft && shouldDoLeft && inRect && !g.hero.IsCasting() {
|
2020-08-11 18:01:33 -04:00
|
|
|
g.lastLeftBtnActionTime = now
|
2020-07-26 14:52:54 -04:00
|
|
|
|
2020-09-20 11:55:44 -04:00
|
|
|
if event.KeyMod() == d2enum.KeyModShift {
|
|
|
|
g.inputListener.OnPlayerCast(g.hero.LeftSkill.ID, px, py)
|
|
|
|
} else {
|
|
|
|
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
|
|
|
|
|
2020-10-24 22:52:26 -04:00
|
|
|
x := float64(halfScreenWidth) / subtilesPerTile
|
|
|
|
y := float64(halfScreenHeight) / subtilesPerTile
|
|
|
|
|
2020-07-18 23:37:35 -04:00
|
|
|
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-09-14 14:49:31 -04:00
|
|
|
if isRight && shouldDoRight && inRect && !g.hero.IsCasting() {
|
2020-08-11 18:01:33 -04:00
|
|
|
g.lastRightBtnActionTime = now
|
2020-07-26 14:52:54 -04:00
|
|
|
|
2020-09-20 11:55:44 -04:00
|
|
|
g.inputListener.OnPlayerCast(g.hero.RightSkill.ID, 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
|
2020-10-22 02:41:21 -04:00
|
|
|
if g.actionableRegions[i].rect.IsInRect(mx, my) {
|
|
|
|
g.onHoverActionable(g.actionableRegions[i].actionableTypeID)
|
2020-06-23 12:28:05 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-11-05 14:55:09 -05:00
|
|
|
g.hud.OnMouseMove(event)
|
2021-01-19 08:09:22 -05:00
|
|
|
g.PartyPanel.OnMouseMove(event)
|
2020-10-22 16:53:18 -04:00
|
|
|
|
2020-06-21 16:06:52 -04:00
|
|
|
return false
|
2020-06-21 15:26:07 -04:00
|
|
|
}
|
|
|
|
|
2020-11-13 15:03:30 -05:00
|
|
|
// OnMouseButtonUp handles mouse button presses
|
|
|
|
func (g *GameControls) OnMouseButtonUp(event d2interface.MouseEvent) bool {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
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
|
2020-10-22 02:41:21 -04:00
|
|
|
if g.actionableRegions[i].rect.IsInRect(mx, my) {
|
|
|
|
g.onClickActionable(g.actionableRegions[i].actionableTypeID)
|
2020-06-23 12:28:05 -04:00
|
|
|
return false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-11-05 14:55:09 -05:00
|
|
|
if g.hud.skillSelectMenu.IsOpen() && event.Button() == d2enum.MouseButtonLeft {
|
2020-10-22 16:53:18 -04:00
|
|
|
g.lastLeftBtnActionTime = d2util.Now()
|
2020-11-05 14:55:09 -05:00
|
|
|
g.hud.skillSelectMenu.HandleClick(mx, my)
|
|
|
|
g.hud.skillSelectMenu.ClosePanels()
|
2020-10-24 22:52:26 -04:00
|
|
|
|
2020-10-22 16:53:18 -04:00
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
2020-06-23 12:28:05 -04:00
|
|
|
px, py := g.mapRenderer.ScreenToWorld(mx, my)
|
2020-10-24 22:52:26 -04:00
|
|
|
px = truncateFloat64(px)
|
|
|
|
py = truncateFloat64(py)
|
2020-02-22 20:44:30 -05:00
|
|
|
|
2020-09-14 14:49:31 -04:00
|
|
|
if event.Button() == d2enum.MouseButtonLeft && !g.isInActiveMenusRect(mx, my) && !g.hero.IsCasting() {
|
2020-09-08 15:58:35 -04:00
|
|
|
g.lastLeftBtnActionTime = d2util.Now()
|
2020-07-26 14:52:54 -04:00
|
|
|
|
2020-09-20 11:55:44 -04:00
|
|
|
if event.KeyMod() == d2enum.KeyModShift {
|
|
|
|
g.inputListener.OnPlayerCast(g.hero.LeftSkill.ID, px, py)
|
|
|
|
} else {
|
|
|
|
g.inputListener.OnPlayerMove(px, py)
|
|
|
|
}
|
2020-07-26 14:52:54 -04:00
|
|
|
|
2020-02-22 20:44:30 -05:00
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
2020-09-14 14:49:31 -04:00
|
|
|
if event.Button() == d2enum.MouseButtonRight && !g.isInActiveMenusRect(mx, my) && !g.hero.IsCasting() {
|
2020-09-08 15:58:35 -04:00
|
|
|
g.lastRightBtnActionTime = d2util.Now()
|
2020-07-26 14:52:54 -04:00
|
|
|
|
2020-09-20 11:55:44 -04:00
|
|
|
g.inputListener.OnPlayerCast(g.hero.RightSkill.ID, 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-12-22 08:21:34 -05:00
|
|
|
func (g *GameControls) clearLeftScreenSide() {
|
|
|
|
g.heroStatsPanel.Close()
|
2021-01-18 15:11:50 -05:00
|
|
|
g.PartyPanel.Close()
|
2020-12-22 08:21:34 -05:00
|
|
|
g.questLog.Close()
|
|
|
|
g.hud.skillSelectMenu.ClosePanels()
|
|
|
|
g.hud.miniPanel.SetMovedRight(false)
|
|
|
|
g.updateLayout()
|
|
|
|
}
|
|
|
|
|
|
|
|
func (g *GameControls) clearRightScreenSide() {
|
|
|
|
g.inventory.Close()
|
|
|
|
g.skilltree.Close()
|
|
|
|
g.hud.skillSelectMenu.ClosePanels()
|
|
|
|
g.hud.miniPanel.SetMovedLeft(false)
|
|
|
|
g.updateLayout()
|
|
|
|
}
|
|
|
|
|
|
|
|
func (g *GameControls) clearScreen() {
|
|
|
|
g.clearRightScreenSide()
|
|
|
|
g.clearLeftScreenSide()
|
|
|
|
g.hud.skillSelectMenu.ClosePanels()
|
|
|
|
g.HelpOverlay.Close()
|
|
|
|
}
|
|
|
|
|
|
|
|
func (g *GameControls) openLeftPanel(panel Panel) {
|
2021-01-13 07:24:28 -05:00
|
|
|
if !g.HelpOverlay.IsOpen() && !g.escapeMenu.IsOpen() {
|
2020-12-22 08:21:34 -05:00
|
|
|
isOpen := panel.IsOpen()
|
2020-12-22 08:28:29 -05:00
|
|
|
|
2020-12-22 08:21:34 -05:00
|
|
|
g.clearLeftScreenSide()
|
2020-12-22 08:28:29 -05:00
|
|
|
|
2020-12-22 08:21:34 -05:00
|
|
|
if !isOpen {
|
|
|
|
panel.Open()
|
|
|
|
g.hud.miniPanel.SetMovedRight(true)
|
|
|
|
g.updateLayout()
|
|
|
|
}
|
2020-12-08 03:18:27 -05:00
|
|
|
}
|
2020-11-16 04:41:01 -05:00
|
|
|
}
|
|
|
|
|
2020-12-22 08:21:34 -05:00
|
|
|
func (g *GameControls) openRightPanel(panel Panel) {
|
2021-01-13 07:24:28 -05:00
|
|
|
if !g.HelpOverlay.IsOpen() && !g.escapeMenu.IsOpen() {
|
2020-12-22 08:21:34 -05:00
|
|
|
isOpen := panel.IsOpen()
|
2020-12-22 08:28:29 -05:00
|
|
|
|
2020-12-22 08:21:34 -05:00
|
|
|
g.clearRightScreenSide()
|
2020-12-22 08:28:29 -05:00
|
|
|
|
2020-12-22 08:21:34 -05:00
|
|
|
if !isOpen {
|
|
|
|
panel.Open()
|
|
|
|
g.hud.miniPanel.SetMovedLeft(true)
|
|
|
|
g.updateLayout()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (g *GameControls) toggleHeroStatsPanel() {
|
|
|
|
g.openLeftPanel(g.heroStatsPanel)
|
|
|
|
}
|
|
|
|
|
2021-01-14 13:24:18 -05:00
|
|
|
func (g *GameControls) togglePartyPanel() {
|
2021-01-18 15:11:50 -05:00
|
|
|
g.openLeftPanel(g.PartyPanel)
|
2021-01-13 11:34:33 -05:00
|
|
|
}
|
|
|
|
|
2020-11-16 04:41:01 -05:00
|
|
|
func (g *GameControls) onCloseHeroStatsPanel() {
|
|
|
|
}
|
|
|
|
|
2020-12-21 11:37:59 -05:00
|
|
|
func (g *GameControls) toggleLeftSkillPanel() {
|
|
|
|
if !g.HelpOverlay.IsOpen() {
|
2020-12-22 08:21:34 -05:00
|
|
|
g.clearScreen()
|
2020-12-21 11:37:59 -05:00
|
|
|
g.hud.skillSelectMenu.ToggleLeftPanel()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (g *GameControls) toggleRightSkillPanel() {
|
|
|
|
if !g.HelpOverlay.IsOpen() {
|
2020-12-22 08:21:34 -05:00
|
|
|
g.clearScreen()
|
2020-12-21 11:37:59 -05:00
|
|
|
g.hud.skillSelectMenu.ToggleRightPanel()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-12-02 02:19:15 -05:00
|
|
|
func (g *GameControls) toggleQuestLog() {
|
2020-12-22 08:21:34 -05:00
|
|
|
g.openLeftPanel(g.questLog)
|
2020-12-02 02:19:15 -05:00
|
|
|
}
|
|
|
|
|
2020-12-22 08:28:29 -05:00
|
|
|
func (g *GameControls) onCloseQuestLog() {
|
|
|
|
}
|
|
|
|
|
2020-12-08 03:18:27 -05:00
|
|
|
func (g *GameControls) toggleHelpOverlay() {
|
2020-12-22 08:21:34 -05:00
|
|
|
if !g.isRightPanelOpen() || g.isLeftPanelOpen() {
|
2020-12-14 12:29:54 -05:00
|
|
|
g.HelpOverlay.updateKeyMap(g.keyMap)
|
2020-12-22 08:21:34 -05:00
|
|
|
g.hud.skillSelectMenu.ClosePanels()
|
2020-12-08 03:18:27 -05:00
|
|
|
g.hud.miniPanel.openDisabled()
|
|
|
|
g.HelpOverlay.Toggle()
|
|
|
|
g.updateLayout()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-11-16 04:41:01 -05:00
|
|
|
func (g *GameControls) toggleInventoryPanel() {
|
2020-12-22 08:21:34 -05:00
|
|
|
g.openRightPanel(g.inventory)
|
2020-11-16 04:41:01 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
func (g *GameControls) onCloseInventory() {
|
|
|
|
}
|
|
|
|
|
|
|
|
func (g *GameControls) toggleSkilltreePanel() {
|
2020-12-22 08:21:34 -05:00
|
|
|
g.openRightPanel(g.skilltree)
|
2020-11-16 04:41:01 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
func (g *GameControls) onCloseSkilltree() {
|
|
|
|
}
|
|
|
|
|
|
|
|
func (g *GameControls) openEscMenu() {
|
2020-12-22 08:21:34 -05:00
|
|
|
g.clearScreen()
|
2020-11-21 05:35:32 -05:00
|
|
|
g.hud.miniPanel.closeDisabled()
|
2020-11-16 04:41:01 -05:00
|
|
|
g.escapeMenu.open()
|
|
|
|
g.updateLayout()
|
|
|
|
}
|
|
|
|
|
2020-09-14 14:47:11 -04:00
|
|
|
// Load the resources required for the GameControls
|
2019-12-16 11:04:39 -05:00
|
|
|
func (g *GameControls) Load() {
|
2020-11-05 14:55:09 -05:00
|
|
|
g.hud.Load()
|
2019-12-28 23:32:53 -05:00
|
|
|
g.inventory.Load()
|
2020-10-25 03:42:31 -04:00
|
|
|
g.skilltree.load()
|
2020-06-25 14:56:49 -04:00
|
|
|
g.heroStatsPanel.Load()
|
2021-01-18 15:11:50 -05:00
|
|
|
g.PartyPanel.Load()
|
2020-12-02 02:19:15 -05:00
|
|
|
g.questLog.Load()
|
2020-09-26 11:14:34 -04:00
|
|
|
g.HelpOverlay.Load()
|
2020-11-16 04:41:01 -05:00
|
|
|
|
2020-12-15 06:37:35 -05:00
|
|
|
g.loadAddButtons()
|
2020-12-15 12:02:52 -05:00
|
|
|
g.setAddButtons()
|
2020-12-15 06:37:35 -05:00
|
|
|
|
2020-11-16 04:41:01 -05:00
|
|
|
miniPanelActions := &miniPanelActions{
|
|
|
|
characterToggle: g.toggleHeroStatsPanel,
|
2021-01-14 13:24:18 -05:00
|
|
|
partyToggle: g.togglePartyPanel,
|
2020-11-16 04:41:01 -05:00
|
|
|
inventoryToggle: g.toggleInventoryPanel,
|
|
|
|
skilltreeToggle: g.toggleSkilltreePanel,
|
|
|
|
menuToggle: g.openEscMenu,
|
2020-12-02 02:19:15 -05:00
|
|
|
questToggle: g.toggleQuestLog,
|
2020-11-16 04:41:01 -05:00
|
|
|
}
|
|
|
|
g.hud.miniPanel.load(miniPanelActions)
|
2020-06-21 16:06:52 -04:00
|
|
|
}
|
|
|
|
|
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-11-21 05:35:32 -05:00
|
|
|
g.hud.Advance(elapsed)
|
2020-12-12 04:39:26 -05:00
|
|
|
g.inventory.Advance(elapsed)
|
2020-12-16 09:08:39 -05:00
|
|
|
g.questLog.Advance(elapsed)
|
2021-01-18 15:11:50 -05:00
|
|
|
g.PartyPanel.Advance(elapsed)
|
2020-11-13 15:03:30 -05:00
|
|
|
|
|
|
|
if err := g.escapeMenu.Advance(elapsed); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2020-12-15 12:02:52 -05:00
|
|
|
if g.heroStatsPanel.IsOpen() || g.skilltree.IsOpen() {
|
|
|
|
g.setAddButtons()
|
|
|
|
}
|
|
|
|
|
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-12-22 08:59:15 -05:00
|
|
|
case isLeftPanelOpen:
|
2020-06-22 09:23:56 -04:00
|
|
|
g.mapRenderer.ViewportToRight()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-06-25 19:18:37 -04:00
|
|
|
func (g *GameControls) isLeftPanelOpen() bool {
|
2021-01-18 15:11:50 -05:00
|
|
|
return g.heroStatsPanel.IsOpen() || g.PartyPanel.IsOpen() || g.questLog.IsOpen() || g.inventory.moveGoldPanel.IsOpen()
|
2020-06-25 19:18:37 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
func (g *GameControls) isRightPanelOpen() bool {
|
2020-10-22 12:54:45 -04:00
|
|
|
return g.inventory.IsOpen() || g.skilltree.IsOpen()
|
2020-06-25 19:18:37 -04:00
|
|
|
}
|
|
|
|
|
2020-12-22 08:28:29 -05:00
|
|
|
func (g *GameControls) hasOpenPanels() bool {
|
|
|
|
return g.isRightPanelOpen() || g.isLeftPanelOpen() || g.hud.skillSelectMenu.IsOpen()
|
|
|
|
}
|
|
|
|
|
2020-08-11 18:01:33 -04:00
|
|
|
func (g *GameControls) isInActiveMenusRect(px, py int) bool {
|
2020-10-24 22:52:26 -04:00
|
|
|
if g.bottomMenuRect.IsInRect(px, py) {
|
2020-06-25 19:18:37 -04:00
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
2020-10-24 22:52:26 -04:00
|
|
|
if g.isLeftPanelOpen() && g.leftMenuRect.IsInRect(px, py) {
|
2020-06-25 19:18:37 -04:00
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
2020-10-24 22:52:26 -04:00
|
|
|
if g.isRightPanelOpen() && g.rightMenuRect.IsInRect(px, py) {
|
2020-06-25 19:18:37 -04:00
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
2020-11-16 04:41:01 -05:00
|
|
|
if g.hud.miniPanel.IsOpen() && g.hud.miniPanel.IsInRect(px, py) {
|
2020-08-25 09:10:26 -04:00
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
2020-10-07 21:20:05 -04:00
|
|
|
if g.escapeMenu.IsOpen() {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
2020-09-26 11:14:34 -04:00
|
|
|
if g.HelpOverlay.IsOpen() && g.HelpOverlay.IsInRect(px, py) {
|
2020-09-15 23:37:08 -04:00
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
2020-11-05 14:55:09 -05:00
|
|
|
if g.hud.skillSelectMenu.IsOpen() {
|
2020-10-22 16:53:18 -04:00
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
2020-06-25 19:18:37 -04:00
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
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 {
|
2021-01-01 14:49:49 -05:00
|
|
|
if err := g.hud.Render(target); err != nil {
|
2020-10-24 22:52:26 -04:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2021-01-01 14:49:49 -05:00
|
|
|
if err := g.renderPanels(target); err != nil {
|
2020-10-24 22:52:26 -04:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2020-11-13 15:03:30 -05:00
|
|
|
if err := g.escapeMenu.Render(target); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2020-10-24 22:52:26 -04:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (g *GameControls) renderPanels(target d2interface.Surface) error {
|
2020-10-28 14:17:42 -04:00
|
|
|
g.inventory.Render(target)
|
2019-12-28 23:32:53 -05:00
|
|
|
|
2020-10-24 22:52:26 -04:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
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) {
|
2020-11-05 14:55:09 -05:00
|
|
|
g.hud.zoneChangeText.SetText(text)
|
2020-06-22 15:55:32 -04:00
|
|
|
}
|
|
|
|
|
2020-08-11 18:01:33 -04:00
|
|
|
// ShowZoneChangeText shows the zoneChangeText
|
2020-06-22 15:55:32 -04:00
|
|
|
func (g *GameControls) ShowZoneChangeText() {
|
2020-11-05 14:55:09 -05:00
|
|
|
g.hud.isZoneTextShown = true
|
2020-06-22 15:55:32 -04:00
|
|
|
}
|
|
|
|
|
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() {
|
2020-11-05 14:55:09 -05:00
|
|
|
g.hud.isZoneTextShown = false
|
2020-06-22 15:55:32 -04:00
|
|
|
})
|
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 {
|
2020-11-05 14:55:09 -05:00
|
|
|
return g.hud.hpStatsIsVisible
|
2020-08-24 15:50:33 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
// ManaStatsIsVisible returns true if the hp and mana stats are visible to the player
|
|
|
|
func (g *GameControls) ManaStatsIsVisible() bool {
|
2020-11-05 14:55:09 -05:00
|
|
|
return g.hud.manaStatsIsVisible
|
2020-08-24 15:50:33 -04:00
|
|
|
}
|
|
|
|
|
2020-09-20 11:55:44 -04:00
|
|
|
// ToggleHpStats toggles the visibility of the hp and mana stats placed above their respective globe and load only if they do not match
|
2020-08-24 15:50:33 -04:00
|
|
|
func (g *GameControls) ToggleHpStats() {
|
2020-11-05 14:55:09 -05:00
|
|
|
g.hud.hpStatsIsVisible = !g.hud.hpStatsIsVisible
|
2020-08-24 15:50:33 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
// ToggleManaStats toggles the visibility of the hp and mana stats placed above their respective globe
|
|
|
|
func (g *GameControls) ToggleManaStats() {
|
2020-11-05 14:55:09 -05:00
|
|
|
g.hud.manaStatsIsVisible = !g.hud.manaStatsIsVisible
|
2020-08-24 15:50:33 -04:00
|
|
|
}
|
|
|
|
|
2020-06-23 12:28:05 -04:00
|
|
|
// Handles what to do when an actionable is hovered
|
2020-10-22 02:41:21 -04:00
|
|
|
func (g *GameControls) onHoverActionable(item actionableType) {
|
2020-10-24 22:52:26 -04:00
|
|
|
hoverMap := map[actionableType]func(){
|
2020-11-16 04:41:01 -05:00
|
|
|
leftSkill: func() {},
|
|
|
|
xp: func() {},
|
|
|
|
stamina: func() {},
|
|
|
|
rightSkill: func() {},
|
|
|
|
hpGlobe: func() {},
|
|
|
|
manaGlobe: func() {},
|
2020-10-24 22:52:26 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
onHover, found := hoverMap[item]
|
|
|
|
if !found {
|
2020-11-22 00:36:59 -05:00
|
|
|
g.Errorf("Unrecognized actionableType(%d) being hovered", item)
|
2020-10-24 22:52:26 -04:00
|
|
|
return
|
2020-06-23 12:28:05 -04:00
|
|
|
}
|
2020-10-24 22:52:26 -04:00
|
|
|
|
|
|
|
onHover()
|
2020-06-23 12:28:05 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
// Handles what to do when an actionable is clicked
|
2020-10-22 02:41:21 -04:00
|
|
|
func (g *GameControls) onClickActionable(item actionableType) {
|
2020-10-24 22:52:26 -04:00
|
|
|
actionMap := map[actionableType]func(){
|
|
|
|
leftSkill: func() {
|
2020-12-21 11:37:59 -05:00
|
|
|
g.toggleLeftSkillPanel()
|
2020-10-24 22:52:26 -04:00
|
|
|
},
|
2020-08-25 09:10:26 -04:00
|
|
|
|
2020-10-24 22:52:26 -04:00
|
|
|
xp: func() {
|
2020-11-22 00:36:59 -05:00
|
|
|
g.Info("XP Action Pressed")
|
2020-10-24 22:52:26 -04:00
|
|
|
},
|
2020-10-22 12:54:45 -04:00
|
|
|
|
2020-10-24 22:52:26 -04:00
|
|
|
stamina: func() {
|
2020-11-22 00:36:59 -05:00
|
|
|
g.Info("Stamina Action Pressed")
|
2020-10-24 22:52:26 -04:00
|
|
|
},
|
|
|
|
|
|
|
|
rightSkill: func() {
|
2020-12-21 11:37:59 -05:00
|
|
|
g.toggleRightSkillPanel()
|
2020-10-24 22:52:26 -04:00
|
|
|
},
|
|
|
|
|
|
|
|
hpGlobe: func() {
|
|
|
|
g.ToggleHpStats()
|
2020-11-22 00:36:59 -05:00
|
|
|
g.Info("HP Globe Pressed")
|
2020-10-24 22:52:26 -04:00
|
|
|
},
|
|
|
|
|
|
|
|
manaGlobe: func() {
|
|
|
|
g.ToggleManaStats()
|
2020-11-22 00:36:59 -05:00
|
|
|
g.Info("Mana Globe Pressed")
|
2020-10-24 22:52:26 -04:00
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
action, found := actionMap[item]
|
|
|
|
if !found {
|
2020-11-18 16:02:49 -05:00
|
|
|
// Warning, because some action types are still todo, and could return this error
|
2020-11-22 00:36:59 -05:00
|
|
|
g.Warningf("Unrecognized actionableType(%d) being clicked", item)
|
2020-10-24 22:52:26 -04:00
|
|
|
return
|
2020-06-23 12:28:05 -04:00
|
|
|
}
|
2020-10-24 22:52:26 -04:00
|
|
|
|
|
|
|
action()
|
2020-06-23 12:28:05 -04:00
|
|
|
}
|
2020-09-20 11:55:44 -04:00
|
|
|
|
2020-12-21 15:46:58 -05:00
|
|
|
func (g *GameControls) bindTerminalCommands(term d2interface.Terminal) error {
|
|
|
|
if err := term.Bind("freecam", "toggle free camera movement", nil, g.commandFreeCam); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := term.Bind("setleftskill", "set skill to fire on left click", []string{"id"}, g.commandSetLeftSkill(term)); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := term.Bind("setrightskill", "set skill to fire on right click", []string{"id"}, g.commandSetRightSkill(term)); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := term.Bind("learnskills", "learn all skills for the a given class", []string{"token"}, g.commandLearnSkills(term)); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := term.Bind("learnskillid", "learn a skill by a given ID", []string{"id"}, g.commandLearnSkillID(term)); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// UnbindTerminalCommands unbinds commands from the terminal
|
|
|
|
func (g *GameControls) UnbindTerminalCommands(term d2interface.Terminal) error {
|
|
|
|
return term.Unbind("freecam", "setleftskill", "setrightskill", "learnskills", "learnskillid")
|
2020-10-24 22:52:26 -04:00
|
|
|
}
|
2020-10-22 16:53:18 -04:00
|
|
|
|
2020-12-21 15:46:58 -05:00
|
|
|
func (g *GameControls) setAddButtons() {
|
|
|
|
g.hud.addStatsButton.SetEnabled(g.hero.Stats.StatsPoints > 0)
|
|
|
|
g.hud.addSkillButton.SetEnabled(g.hero.Stats.SkillPoints > 0)
|
2020-10-24 22:52:26 -04:00
|
|
|
}
|
2020-10-22 16:53:18 -04:00
|
|
|
|
2020-12-21 15:46:58 -05:00
|
|
|
func (g *GameControls) loadAddButtons() {
|
|
|
|
g.hud.addStatsButton.OnActivated(func() { g.toggleHeroStatsPanel() })
|
|
|
|
g.hud.addSkillButton.OnActivated(func() { g.toggleSkilltreePanel() })
|
|
|
|
}
|
2020-10-24 22:52:26 -04:00
|
|
|
|
2020-12-21 15:46:58 -05:00
|
|
|
func (g *GameControls) commandFreeCam([]string) error {
|
|
|
|
g.FreeCam = !g.FreeCam
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (g *GameControls) commandSetLeftSkill(term d2interface.Terminal) func(args []string) error {
|
|
|
|
return func(args []string) error {
|
|
|
|
id, err := strconv.Atoi(args[0])
|
2020-10-22 16:53:18 -04:00
|
|
|
if err != nil {
|
2020-12-21 15:46:58 -05:00
|
|
|
term.Errorf("invalid argument")
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2020-12-21 16:22:27 -05:00
|
|
|
skill, err := g.heroSkillByID(id)
|
2020-10-22 16:53:18 -04:00
|
|
|
if err != nil {
|
2020-12-21 16:22:27 -05:00
|
|
|
term.Errorf(err.Error())
|
2020-12-21 15:46:58 -05:00
|
|
|
return nil
|
2020-10-22 16:53:18 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
g.hero.LeftSkill = skill
|
2020-10-24 22:52:26 -04:00
|
|
|
|
2020-12-21 15:46:58 -05:00
|
|
|
return nil
|
|
|
|
}
|
2020-10-24 22:52:26 -04:00
|
|
|
}
|
|
|
|
|
2020-12-21 15:46:58 -05:00
|
|
|
func (g *GameControls) commandSetRightSkill(term d2interface.Terminal) func(args []string) error {
|
|
|
|
return func(args []string) error {
|
|
|
|
id, err := strconv.Atoi(args[0])
|
|
|
|
if err != nil {
|
|
|
|
term.Errorf("invalid argument")
|
|
|
|
return nil
|
|
|
|
}
|
2020-10-24 22:52:26 -04:00
|
|
|
|
2020-12-21 16:22:27 -05:00
|
|
|
skill, err := g.heroSkillByID(id)
|
2020-10-24 22:52:26 -04:00
|
|
|
if err != nil {
|
2020-12-21 16:22:27 -05:00
|
|
|
term.Errorf(err.Error())
|
2020-12-21 15:46:58 -05:00
|
|
|
return nil
|
2020-10-24 22:52:26 -04:00
|
|
|
}
|
2020-10-22 16:53:18 -04:00
|
|
|
|
2020-10-24 22:52:26 -04:00
|
|
|
g.hero.RightSkill = skill
|
2020-12-21 15:46:58 -05:00
|
|
|
|
|
|
|
return nil
|
2020-10-24 22:52:26 -04:00
|
|
|
}
|
2020-12-21 15:46:58 -05:00
|
|
|
}
|
2020-10-24 22:52:26 -04:00
|
|
|
|
2020-12-21 15:46:58 -05:00
|
|
|
func (g *GameControls) commandLearnSkillID(term d2interface.Terminal) func(args []string) error {
|
|
|
|
return func(args []string) error {
|
|
|
|
id, err := strconv.Atoi(args[0])
|
|
|
|
if err != nil {
|
|
|
|
term.Errorf("invalid argument")
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2020-12-21 16:22:27 -05:00
|
|
|
skill, err := g.heroSkillByID(id)
|
2020-12-21 15:46:58 -05:00
|
|
|
if err != nil {
|
2020-12-21 16:22:27 -05:00
|
|
|
term.Errorf(err.Error())
|
2020-12-21 15:46:58 -05:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2020-12-21 16:22:27 -05:00
|
|
|
g.hero.Skills[skill.ID] = skill
|
2020-12-21 15:46:58 -05:00
|
|
|
g.hud.skillSelectMenu.RegenerateImageCache()
|
|
|
|
g.Infof("Learned skill: " + skill.Skill)
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
2020-10-24 22:52:26 -04:00
|
|
|
}
|
|
|
|
|
2020-12-21 16:22:27 -05:00
|
|
|
func (g *GameControls) heroSkillByID(id int) (*d2hero.HeroSkill, error) {
|
|
|
|
skillRecord := g.asset.Records.Skill.Details[id]
|
|
|
|
if skillRecord == nil {
|
|
|
|
return nil, fmt.Errorf("cannot find a skill record for ID: %d", id)
|
|
|
|
}
|
|
|
|
|
|
|
|
skill, err := g.heroState.CreateHeroSkill(1, skillRecord.Skill)
|
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("cannot create skill with ID of %d", id)
|
|
|
|
}
|
|
|
|
|
|
|
|
return skill, nil
|
2020-10-24 22:52:26 -04:00
|
|
|
}
|
|
|
|
|
2020-12-21 15:46:58 -05:00
|
|
|
func (g *GameControls) commandLearnSkills(term d2interface.Terminal) func(args []string) error {
|
|
|
|
const classTokenLength = 3
|
2020-10-24 22:52:26 -04:00
|
|
|
|
2020-12-21 15:46:58 -05:00
|
|
|
return func(args []string) error {
|
|
|
|
token := args[0]
|
2020-10-24 22:52:26 -04:00
|
|
|
if len(token) < classTokenLength {
|
2020-12-21 15:46:58 -05:00
|
|
|
term.Errorf("The given class token should be at least 3 characters")
|
|
|
|
return nil
|
2020-10-22 16:53:18 -04:00
|
|
|
}
|
2020-10-24 22:52:26 -04:00
|
|
|
|
2020-10-22 16:53:18 -04:00
|
|
|
validPrefixes := []string{"ama", "ass", "nec", "bar", "sor", "dru", "pal"}
|
|
|
|
classToken := strings.ToLower(token)
|
|
|
|
tokenPrefix := classToken[0:3]
|
|
|
|
isValidToken := false
|
|
|
|
|
|
|
|
for idx := range validPrefixes {
|
|
|
|
if strings.Compare(tokenPrefix, validPrefixes[idx]) == 0 {
|
|
|
|
isValidToken = true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if !isValidToken {
|
2020-10-24 22:52:26 -04:00
|
|
|
fmtInvalid := "Invalid class, must be a value starting with(case insensitive): %s"
|
2020-12-21 15:46:58 -05:00
|
|
|
term.Errorf(fmtInvalid, strings.Join(validPrefixes, ", "))
|
2020-10-24 22:52:26 -04:00
|
|
|
|
2020-12-21 15:46:58 -05:00
|
|
|
return nil
|
2020-10-22 16:53:18 -04:00
|
|
|
}
|
|
|
|
|
2020-10-24 22:52:26 -04:00
|
|
|
var err error
|
|
|
|
|
2020-10-22 16:53:18 -04:00
|
|
|
learnedSkillsCount := 0
|
2020-10-24 22:52:26 -04:00
|
|
|
|
2020-10-22 16:53:18 -04:00
|
|
|
for _, skillDetailRecord := range g.asset.Records.Skill.Details {
|
2020-10-29 09:50:15 -04:00
|
|
|
if skillDetailRecord.Charclass != classToken {
|
2020-10-24 22:52:26 -04:00
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
2020-11-09 09:03:00 -05:00
|
|
|
if skill, ok := g.hero.Skills[skillDetailRecord.ID]; ok {
|
2020-11-09 12:09:46 -05:00
|
|
|
skill.SkillPoints++
|
2020-11-09 09:03:00 -05:00
|
|
|
learnedSkillsCount++
|
|
|
|
} else {
|
|
|
|
skill, skillErr := g.heroState.CreateHeroSkill(1, skillDetailRecord.Skill)
|
|
|
|
if skill == nil {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
learnedSkillsCount++
|
|
|
|
|
|
|
|
g.hero.Skills[skill.ID] = skill
|
|
|
|
|
|
|
|
if skillErr != nil {
|
|
|
|
err = skillErr
|
|
|
|
break
|
|
|
|
}
|
2020-10-22 16:53:18 -04:00
|
|
|
}
|
|
|
|
}
|
2020-10-24 22:52:26 -04:00
|
|
|
|
2020-11-05 14:55:09 -05:00
|
|
|
g.hud.skillSelectMenu.RegenerateImageCache()
|
2020-11-22 00:36:59 -05:00
|
|
|
g.Infof("Learned %d skills", learnedSkillsCount)
|
2020-10-22 16:53:18 -04:00
|
|
|
|
|
|
|
if err != nil {
|
2020-12-21 15:46:58 -05:00
|
|
|
term.Errorf("cannot learn skill for class, error: %s", err)
|
|
|
|
return nil
|
2020-10-22 16:53:18 -04:00
|
|
|
}
|
|
|
|
|
2020-12-21 15:46:58 -05:00
|
|
|
return nil
|
2020-10-24 22:52:26 -04:00
|
|
|
}
|
2020-12-15 06:37:35 -05:00
|
|
|
}
|