From 32a58fd5d3d4ad82919ac159fea36f3fe236f3b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=BCrkan=20Kaymak?= Date: Tue, 25 Aug 2020 16:10:26 +0300 Subject: [PATCH] Added mini panel (#711) * resolves #685, added mini panel * formatting --- d2common/d2resource/resource_paths.go | 5 +- d2game/d2gamescreen/game.go | 5 +- d2game/d2player/game_controls.go | 78 +++++++++++++++------ d2game/d2player/mini_panel.go | 98 +++++++++++++++++++++++++++ d2networking/d2client/game_client.go | 7 +- 5 files changed, 166 insertions(+), 27 deletions(-) create mode 100644 d2game/d2player/mini_panel.go diff --git a/d2common/d2resource/resource_paths.go b/d2common/d2resource/resource_paths.go index 56d2f4e4..a77d809d 100644 --- a/d2common/d2resource/resource_paths.go +++ b/d2common/d2resource/resource_paths.go @@ -134,6 +134,7 @@ const ( // --- GAME UI --- PentSpin = "/data/global/ui/CURSOR/pentspin.DC6" + Minipanel = "/data/global/ui/PANEL/minipanel.DC6" MinipanelSmall = "/data/global/ui/PANEL/minipanel_s.dc6" MinipanelButton = "/data/global/ui/PANEL/minipanelbtn.DC6" @@ -241,8 +242,8 @@ const ( MagicPrefix = "/data/global/excel/MagicPrefix.txt" MagicSuffix = "/data/global/excel/MagicSuffix.txt" - RarePrefix = "/data/global/excel/RarePrefix.txt" // these are for item names - RareSuffix = "/data/global/excel/RareSuffix.txt" + RarePrefix = "/data/global/excel/RarePrefix.txt" // these are for item names + RareSuffix = "/data/global/excel/RareSuffix.txt" // --- Monster Prefix/Suffixes (?) --- UniquePrefix = "/data/global/excel/UniquePrefix.txt" diff --git a/d2game/d2gamescreen/game.go b/d2game/d2gamescreen/game.go index c4193941..09000fe8 100644 --- a/d2game/d2gamescreen/game.go +++ b/d2game/d2gamescreen/game.go @@ -2,9 +2,10 @@ package d2gamescreen import ( "fmt" + "image/color" + "github.com/OpenDiablo2/OpenDiablo2/d2common/d2math/d2vector" "github.com/OpenDiablo2/OpenDiablo2/d2core/d2ui" - "image/color" "github.com/OpenDiablo2/OpenDiablo2/d2common/d2data/d2datadict" "github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum" @@ -248,7 +249,7 @@ func (v *Game) bindGameControls() error { var err error v.gameControls, err = d2player.NewGameControls(v.renderer, player, - v.gameClient.MapEngine, v.mapRenderer, v, v.terminal, v.uiManager) + v.gameClient.MapEngine, v.mapRenderer, v, v.terminal, v.uiManager, v.gameClient.IsSinglePlayer()) if err != nil { return err diff --git a/d2game/d2player/game_controls.go b/d2game/d2player/game_controls.go index bff3bccb..3ae31070 100644 --- a/d2game/d2player/game_controls.go +++ b/d2game/d2player/game_controls.go @@ -9,11 +9,10 @@ import ( "time" "github.com/OpenDiablo2/OpenDiablo2/d2common/d2data/d2datadict" + "github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum" "github.com/OpenDiablo2/OpenDiablo2/d2common/d2math/d2vector" "github.com/OpenDiablo2/OpenDiablo2/d2core/d2gui" - "github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum" - "github.com/OpenDiablo2/OpenDiablo2/d2common" "github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface" "github.com/OpenDiablo2/OpenDiablo2/d2common/d2resource" @@ -53,6 +52,7 @@ type GameControls struct { uiManager *d2ui.UIManager inventory *Inventory heroStatsPanel *HeroStatsPanel + miniPanel *miniPanel lastMouseX int lastMouseY int missileID int @@ -71,6 +71,7 @@ type GameControls struct { isZoneTextShown bool hpStatsIsVisible bool manaStatsIsVisible bool + isSinglePlayer bool } type ActionableType int @@ -82,16 +83,18 @@ type ActionableRegion struct { const ( // Since they require special handling, not considering (1) globes, (2) content of the mini panel, (3) belt - leftSkill = ActionableType(iota) - leftSelec = ActionableType(iota) - xp = ActionableType(iota) - walkRun = ActionableType(iota) - stamina = ActionableType(iota) - miniPanel = ActionableType(iota) - rightSelec = ActionableType(iota) - rightSkill = ActionableType(iota) - hpGlobe = ActionableType(iota) - manaGlobe = ActionableType(iota) + leftSkill ActionableType = iota + leftSelect + xp + walkRun + stamina + miniPnl + rightSelect + rightSkill + hpGlobe + manaGlobe + miniPanelCharacter + miniPanelInventory ) // NewGameControls creates a GameControls instance and returns a pointer to it @@ -103,6 +106,7 @@ func NewGameControls( inputListener InputCallbackListener, term d2interface.Terminal, ui *d2ui.UIManager, + isSinglePlayer bool, ) (*GameControls, error) { missileID := initialMissileID @@ -161,24 +165,28 @@ func NewGameControls( mapRenderer: mapRenderer, inventory: NewInventory(ui, inventoryRecord), heroStatsPanel: NewHeroStatsPanel(ui, hero.Name(), hero.Class, hero.Stats), + miniPanel: newMiniPanel(ui, isSinglePlayer), missileID: missileID, nameLabel: hoverLabel, zoneChangeText: zoneLabel, hpManaStatsLabel: globeStatsLabel, actionableRegions: []ActionableRegion{ {leftSkill, d2common.Rectangle{Left: 115, Top: 550, Width: 50, Height: 50}}, - {leftSelec, d2common.Rectangle{Left: 206, Top: 563, Width: 30, Height: 30}}, + {leftSelect, d2common.Rectangle{Left: 206, Top: 563, Width: 30, Height: 30}}, {xp, d2common.Rectangle{Left: 253, Top: 560, Width: 125, Height: 5}}, {walkRun, d2common.Rectangle{Left: 255, Top: 573, Width: 17, Height: 20}}, {stamina, d2common.Rectangle{Left: 273, Top: 573, Width: 105, Height: 20}}, - {miniPanel, d2common.Rectangle{Left: 393, Top: 563, Width: 12, Height: 23}}, - {rightSelec, d2common.Rectangle{Left: 562, Top: 563, Width: 30, Height: 30}}, + {miniPnl, d2common.Rectangle{Left: 393, Top: 563, Width: 12, Height: 23}}, + {rightSelect, d2common.Rectangle{Left: 562, Top: 563, Width: 30, Height: 30}}, {rightSkill, d2common.Rectangle{Left: 634, Top: 550, Width: 50, Height: 50}}, {hpGlobe, d2common.Rectangle{Left: 30, Top: 525, Width: 65, Height: 50}}, {manaGlobe, d2common.Rectangle{Left: 700, Top: 525, Width: 65, Height: 50}}, + {miniPanelCharacter, d2common.Rectangle{Left: 325, Top: 526, Width: 26, Height: 26}}, + {miniPanelInventory, d2common.Rectangle{Left: 351, Top: 526, Width: 26, Height: 26}}, }, lastLeftBtnActionTime: 0, lastRightBtnActionTime: 0, + isSinglePlayer: isSinglePlayer, } err = term.BindAction("freecam", "toggle free camera movement", func() { @@ -372,6 +380,7 @@ func (g *GameControls) Load() { g.mainPanel, _ = g.uiManager.NewSprite(animation) animation, _ = d2asset.LoadAnimation(d2resource.MenuButton, d2resource.PaletteSky) + _ = animation.SetCurrentFrame(2) g.menuButton, _ = g.uiManager.NewSprite(animation) animation, _ = d2asset.LoadAnimation(d2resource.GenericSkills, d2resource.PaletteSky) @@ -451,6 +460,10 @@ func (g *GameControls) isInActiveMenusRect(px, py int) bool { return true } + if g.miniPanel.IsOpen() && g.miniPanel.isInRect(px, py) { + return true + } + return false } @@ -607,7 +620,12 @@ func (g *GameControls) Render(target d2interface.Surface) error { target.Pop() // Center menu button - if err := g.menuButton.SetCurrentFrame(0); err != nil { + menuButtonFrameIndex := 0 + if g.miniPanel.isOpen { + menuButtonFrameIndex = 2 + } + + if err := g.menuButton.SetCurrentFrame(menuButtonFrameIndex); err != nil { return err } @@ -619,6 +637,10 @@ func (g *GameControls) Render(target d2interface.Surface) error { return err } + if err := g.miniPanel.Render(target); err != nil { + return err + } + // Potions if err := g.mainPanel.SetCurrentFrame(3); err != nil { return err @@ -774,7 +796,7 @@ func (g *GameControls) onHoverActionable(item ActionableType) { switch item { case leftSkill: return - case leftSelec: + case leftSelect: return case xp: return @@ -782,9 +804,9 @@ func (g *GameControls) onHoverActionable(item ActionableType) { return case stamina: return - case miniPanel: + case miniPnl: return - case rightSelec: + case rightSelect: return case rightSkill: return @@ -802,7 +824,7 @@ func (g *GameControls) onClickActionable(item ActionableType) { switch item { case leftSkill: log.Println("Left Skill Action Pressed") - case leftSelec: + case leftSelect: log.Println("Left Skill Selector Action Pressed") case xp: log.Println("XP Action Pressed") @@ -810,9 +832,11 @@ func (g *GameControls) onClickActionable(item ActionableType) { log.Println("Walk/Run Action Pressed") case stamina: log.Println("Stamina Action Pressed") - case miniPanel: + case miniPnl: log.Println("Mini Panel Action Pressed") - case rightSelec: + + g.miniPanel.Toggle() + case rightSelect: log.Println("Right Skill Selector Action Pressed") case rightSkill: log.Println("Right Skill Action Pressed") @@ -822,6 +846,16 @@ func (g *GameControls) onClickActionable(item ActionableType) { case manaGlobe: g.ToggleManaStats() log.Println("Mana Globe Pressed") + 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() default: log.Printf("Unrecognized ActionableType(%d) being clicked\n", item) } diff --git a/d2game/d2player/mini_panel.go b/d2game/d2player/mini_panel.go new file mode 100644 index 00000000..acc839f2 --- /dev/null +++ b/d2game/d2player/mini_panel.go @@ -0,0 +1,98 @@ +package d2player + +import ( + "github.com/OpenDiablo2/OpenDiablo2/d2common" + "github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface" + "github.com/OpenDiablo2/OpenDiablo2/d2common/d2resource" + "github.com/OpenDiablo2/OpenDiablo2/d2core/d2asset" + "github.com/OpenDiablo2/OpenDiablo2/d2core/d2ui" +) + +type miniPanel struct { + container *d2ui.Sprite + button *d2ui.Sprite + isOpen bool + isSinglePlayer bool + rectangle d2common.Rectangle +} + +func newMiniPanel(uiManager *d2ui.UIManager, isSinglePlayer bool) *miniPanel { + miniPanelContainerPath := d2resource.Minipanel + if isSinglePlayer { + miniPanelContainerPath = d2resource.MinipanelSmall + } + animation, _ := d2asset.LoadAnimation(miniPanelContainerPath, d2resource.PaletteSky) + containerSprite, _ := uiManager.NewSprite(animation) + + animation, _ = d2asset.LoadAnimation(d2resource.MinipanelButton, d2resource.PaletteSky) + buttonSprite, _ := uiManager.NewSprite(animation) + + rectangle := d2common.Rectangle{Left: 325, Top: 526, Width: 156, Height: 26} + + if !isSinglePlayer { + rectangle.Width = 182 + } + + return &miniPanel{container: containerSprite, button: buttonSprite, isOpen: true, isSinglePlayer: isSinglePlayer, rectangle: rectangle} +} + +func (m *miniPanel) IsOpen() bool { + return m.isOpen +} + +func (m *miniPanel) Toggle() { + m.isOpen = !m.isOpen +} + +func (m *miniPanel) Open() { + m.isOpen = true +} + +func (m *miniPanel) Close() { + m.isOpen = false +} + +func (m *miniPanel) Render(target d2interface.Surface) error { + if !m.isOpen { + return nil + } + + if err := m.container.SetCurrentFrame(0); err != nil { + return err + } + + width, height := target.GetSize() + + m.container.SetPosition((width/2)-75, height-48) + + if err := m.container.Render(target); err != nil { + return err + } + + buttonWidth, _ := m.button.GetCurrentFrameSize() + buttonWidth++ + + for i, j := 0, 0; j < 16; i++ { + if m.isSinglePlayer && j == 6 { // skip Party Screen button if the game is single player + j += 2 + } + + if err := m.button.SetCurrentFrame(j); err != nil { + return err + } + + m.button.SetPosition((width/2)-72+(buttonWidth*i), height-51) + + if err := m.button.Render(target); err != nil { + return err + } + + j += 2 + } + + return nil +} + +func (m *miniPanel) isInRect(x, y int) bool { + return m.rectangle.IsInRect(x, y) +} diff --git a/d2networking/d2client/game_client.go b/d2networking/d2client/game_client.go index 0f0b9782..f7eb5ee4 100644 --- a/d2networking/d2client/game_client.go +++ b/d2networking/d2client/game_client.go @@ -2,10 +2,11 @@ package d2client import ( "fmt" - "github.com/OpenDiablo2/OpenDiablo2/d2common/d2math" "log" "os" + "github.com/OpenDiablo2/OpenDiablo2/d2common/d2math" + "github.com/OpenDiablo2/OpenDiablo2/d2common/d2data/d2datadict" "github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum" "github.com/OpenDiablo2/OpenDiablo2/d2common/d2math/d2vector" @@ -290,3 +291,7 @@ func (g *GameClient) handlePingPacket() error { return nil } + +func (g *GameClient) IsSinglePlayer() bool { + return g.connectionType == d2clientconnectiontype.Local +}