1
1
mirror of https://github.com/OpenDiablo2/OpenDiablo2 synced 2024-11-18 18:36:12 -05:00
OpenDiablo2/d2game/d2player/game_controls.go
nicholas-eden bdfdeda67b
Add support for missiles (#308)
* WIP: Add support for missiles

Break AnimatedEntity into two parts to support single and composite animations.  Summon misssiles on right click.

* Break animated entity down further

Move npc only logic to npc struct, reduce duplication in map entities

* Change a bunch of int32s to int
2020-02-22 20:44:30 -05:00

201 lines
5.0 KiB
Go

package d2player
import (
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2data/d2datadict"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2resource"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2asset"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2input"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2map"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2render"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2term"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2ui"
)
type Panel interface {
IsOpen() bool
Toggle()
Open()
Close()
}
// ID of missile to create when user right clicks.
var missileID = 59
type GameControls struct {
hero *d2map.Hero
mapEngine *d2map.MapEngine
inventory *Inventory
heroStats *HeroStats
// UI
globeSprite *d2ui.Sprite
mainPanel *d2ui.Sprite
menuButton *d2ui.Sprite
skillIcon *d2ui.Sprite
}
func NewGameControls(hero *d2map.Hero, mapEngine *d2map.MapEngine) *GameControls {
d2term.BindAction("setmissile", "set missile id to summon on right click", func(id int) {
missileID = id
})
return &GameControls{
hero: hero,
mapEngine: mapEngine,
inventory: NewInventory(),
heroStats: NewHeroStats(),
}
}
func (g *GameControls) OnKeyDown(event d2input.KeyEvent) bool {
if event.Key == d2input.KeyI {
g.inventory.Toggle()
return true
}
if event.Key == d2input.KeyC {
g.heroStats.Toggle()
return true
}
return false
}
func (g *GameControls) OnMouseButtonDown(event d2input.MouseEvent) bool {
px, py := g.mapEngine.ScreenToWorld(event.X, event.Y)
px = float64(int(px*10)) / 10.0
py = float64(int(py*10)) / 10.0
heroPosX := g.hero.AnimatedComposite.LocationX / 5.0
heroPosY := g.hero.AnimatedComposite.LocationY / 5.0
if event.Button == d2input.MouseButtonLeft {
path, _, found := g.mapEngine.PathFind(heroPosX, heroPosY, px, py)
if found {
g.hero.AnimatedComposite.SetPath(path, func() {
g.hero.AnimatedComposite.SetAnimationMode(
d2enum.AnimationModeObjectNeutral.String(),
)
})
}
return true
}
if event.Button == d2input.MouseButtonRight {
missile, err := d2map.CreateMissile(
int(g.hero.AnimatedComposite.LocationX),
int(g.hero.AnimatedComposite.LocationY),
d2datadict.Missiles[missileID],
)
if err != nil {
return false
}
missile.SetTarget(px*5, py*5, func() {
g.mapEngine.RemoveEntity(missile)
})
g.mapEngine.AddEntity(missile)
return true
}
return false
}
func (g *GameControls) Load() {
animation, _ := d2asset.LoadAnimation(d2resource.GameGlobeOverlap, d2resource.PaletteSky)
g.globeSprite, _ = d2ui.LoadSprite(animation)
animation, _ = d2asset.LoadAnimation(d2resource.GamePanels, d2resource.PaletteSky)
g.mainPanel, _ = d2ui.LoadSprite(animation)
animation, _ = d2asset.LoadAnimation(d2resource.MenuButton, d2resource.PaletteSky)
g.menuButton, _ = d2ui.LoadSprite(animation)
animation, _ = d2asset.LoadAnimation(d2resource.GenericSkills, d2resource.PaletteSky)
g.skillIcon, _ = d2ui.LoadSprite(animation)
g.inventory.Load()
g.heroStats.Load()
}
// TODO: consider caching the panels to single image that is reused.
func (g *GameControls) Render(target d2render.Surface) {
g.inventory.Render(target)
g.heroStats.Render(target)
width, height := target.GetSize()
offset := 0
// Left globe holder
g.mainPanel.SetCurrentFrame(0)
w, _ := g.mainPanel.GetCurrentFrameSize()
g.mainPanel.SetPosition(offset, height)
g.mainPanel.Render(target)
// Left globe
g.globeSprite.SetCurrentFrame(0)
g.globeSprite.SetPosition(offset+28, height-5)
g.globeSprite.Render(target)
offset += w
// Left skill
g.skillIcon.SetCurrentFrame(2)
w, _ = g.skillIcon.GetCurrentFrameSize()
g.skillIcon.SetPosition(offset, height)
g.skillIcon.Render(target)
offset += w
// Left skill selector
g.mainPanel.SetCurrentFrame(1)
w, _ = g.mainPanel.GetCurrentFrameSize()
g.mainPanel.SetPosition(offset, height)
g.mainPanel.Render(target)
offset += w
// Stamina
g.mainPanel.SetCurrentFrame(2)
w, _ = g.mainPanel.GetCurrentFrameSize()
g.mainPanel.SetPosition(offset, height)
g.mainPanel.Render(target)
offset += w
// Center menu button
g.menuButton.SetCurrentFrame(0)
w, _ = g.mainPanel.GetCurrentFrameSize()
g.menuButton.SetPosition((width/2)-8, height-16)
g.menuButton.Render(target)
// Potions
g.mainPanel.SetCurrentFrame(3)
w, _ = g.mainPanel.GetCurrentFrameSize()
g.mainPanel.SetPosition(offset, height)
g.mainPanel.Render(target)
offset += w
// Right skill selector
g.mainPanel.SetCurrentFrame(4)
w, _ = g.mainPanel.GetCurrentFrameSize()
g.mainPanel.SetPosition(offset, height)
g.mainPanel.Render(target)
offset += w
// Right skill
g.skillIcon.SetCurrentFrame(10)
w, _ = g.skillIcon.GetCurrentFrameSize()
g.skillIcon.SetPosition(offset, height)
g.skillIcon.Render(target)
offset += w
// Right globe holder
g.mainPanel.SetCurrentFrame(5)
w, _ = g.mainPanel.GetCurrentFrameSize()
g.mainPanel.SetPosition(offset, height)
g.mainPanel.Render(target)
// Right globe
g.globeSprite.SetCurrentFrame(1)
g.globeSprite.SetPosition(offset+8, height-8)
g.globeSprite.Render(target)
}