mirror of
https://github.com/OpenDiablo2/OpenDiablo2
synced 2024-09-06 11:34:15 -04:00
Fixed inventory display bugs - Tooltip doesn't hide when was visible and inventory window was closed using keyboard
374 lines
9.2 KiB
Go
374 lines
9.2 KiB
Go
package d2player
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2records"
|
|
|
|
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
|
|
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
|
|
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2resource"
|
|
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2util"
|
|
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2asset"
|
|
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2item/diablo2item"
|
|
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2ui"
|
|
)
|
|
|
|
const (
|
|
frameInventoryTopLeft = 4
|
|
frameInventoryTopRight = 5
|
|
frameInventoryBottomLeft = 6
|
|
frameInventoryBottomRight = 7
|
|
)
|
|
|
|
const (
|
|
invCloseButtonX, invCloseButtonY = 419, 449
|
|
invGoldButtonX, invGoldButtonY = 485, 455
|
|
invGoldLabelX, invGoldLabelY = 510, 455
|
|
)
|
|
|
|
// NewInventory creates an inventory instance and returns a pointer to it
|
|
func NewInventory(asset *d2asset.AssetManager,
|
|
ui *d2ui.UIManager,
|
|
l d2util.LogLevel,
|
|
gold int,
|
|
record *d2records.InventoryRecord) (*Inventory, error) {
|
|
itemTooltip := ui.NewTooltip(d2resource.FontFormal11, d2resource.PaletteStatic, d2ui.TooltipXCenter, d2ui.TooltipYBottom)
|
|
|
|
itemFactory, err := diablo2item.NewItemFactory(asset)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("during creating new item factory: %s", err)
|
|
}
|
|
|
|
mgp := NewMoveGoldPanel(asset, ui, gold, l)
|
|
|
|
inventory := &Inventory{
|
|
asset: asset,
|
|
uiManager: ui,
|
|
item: itemFactory,
|
|
grid: NewItemGrid(asset, ui, l, record),
|
|
originX: record.Panel.Left,
|
|
itemTooltip: itemTooltip,
|
|
// originY: record.Panel.Top,
|
|
originY: 0, // expansion data has these all offset by +60 ...
|
|
gold: gold,
|
|
moveGoldPanel: mgp,
|
|
}
|
|
|
|
inventory.moveGoldPanel.SetOnCloseCb(func() { inventory.onCloseGoldPanel() })
|
|
|
|
inventory.Logger = d2util.NewLogger()
|
|
inventory.Logger.SetLevel(l)
|
|
inventory.Logger.SetPrefix(logPrefix)
|
|
|
|
return inventory, nil
|
|
}
|
|
|
|
// Inventory represents the inventory
|
|
type Inventory struct {
|
|
asset *d2asset.AssetManager
|
|
item *diablo2item.ItemFactory
|
|
uiManager *d2ui.UIManager
|
|
panel *d2ui.Sprite
|
|
goldLabel *d2ui.Label
|
|
grid *ItemGrid
|
|
itemTooltip *d2ui.Tooltip
|
|
panelGroup *d2ui.WidgetGroup
|
|
hoverX int
|
|
hoverY int
|
|
originX int
|
|
originY int
|
|
lastMouseX int
|
|
lastMouseY int
|
|
hovering bool
|
|
isOpen bool
|
|
onCloseCb func()
|
|
gold int
|
|
moveGoldPanel *MoveGoldPanel
|
|
|
|
*d2util.Logger
|
|
}
|
|
|
|
// Toggle negates the open state of the inventory
|
|
func (g *Inventory) Toggle() {
|
|
if g.isOpen {
|
|
g.Close()
|
|
} else {
|
|
g.Open()
|
|
}
|
|
}
|
|
|
|
// Load the resources required by the inventory
|
|
func (g *Inventory) Load() {
|
|
var err error
|
|
|
|
g.panelGroup = g.uiManager.NewWidgetGroup(d2ui.RenderPriorityInventory)
|
|
|
|
frame := g.uiManager.NewUIFrame(d2ui.FrameRight)
|
|
g.panelGroup.AddWidget(frame)
|
|
|
|
g.panel, err = g.uiManager.NewSprite(d2resource.InventoryCharacterPanel, d2resource.PaletteSky)
|
|
if err != nil {
|
|
g.Error(err.Error())
|
|
}
|
|
|
|
closeButton := g.uiManager.NewButton(d2ui.ButtonTypeSquareClose, "")
|
|
closeButton.SetVisible(false)
|
|
closeButton.SetPosition(invCloseButtonX, invCloseButtonY)
|
|
closeButton.OnActivated(func() { g.Close() })
|
|
g.panelGroup.AddWidget(closeButton)
|
|
|
|
goldButton := g.uiManager.NewButton(d2ui.ButtonTypeGoldCoin, "")
|
|
goldButton.SetVisible(false)
|
|
goldButton.SetPosition(invGoldButtonX, invGoldButtonY)
|
|
goldButton.OnActivated(func() { g.onGoldClicked() })
|
|
|
|
// nolint:gocritic // this variable will be used in future
|
|
// deposite := g.asset.TranslateString("strGoldDeposit")
|
|
drop := g.asset.TranslateString("strGoldDrop")
|
|
// nolint:gocritic // this variable will be used in future
|
|
// withdraw := g.asset.TranslateString("strGoldWithdraw")
|
|
|
|
tooltip := g.uiManager.NewTooltip(d2resource.Font16, d2resource.PaletteSky, d2ui.TooltipXCenter, d2ui.TooltipYBottom)
|
|
// here should be switch-case statement for each of move-gold button descr
|
|
tooltip.SetText(drop)
|
|
tooltip.SetPosition(invGoldButtonX, invGoldButtonY)
|
|
goldButton.SetTooltip(tooltip)
|
|
|
|
g.panelGroup.AddWidget(goldButton)
|
|
|
|
g.goldLabel = g.uiManager.NewLabel(d2resource.Font16, d2resource.PaletteStatic)
|
|
g.goldLabel.Alignment = d2ui.HorizontalAlignLeft
|
|
g.goldLabel.SetText(fmt.Sprintln(g.moveGoldPanel.gold))
|
|
g.goldLabel.SetPosition(invGoldLabelX, invGoldLabelY)
|
|
g.panelGroup.AddWidget(g.goldLabel)
|
|
|
|
// https://github.com/OpenDiablo2/OpenDiablo2/issues/795
|
|
testInventoryCodes := [][]string{
|
|
{"kit", "Crimson", "of the Bat", "of Frost"},
|
|
{"rin", "Steel", "of Shock"},
|
|
{"jav"},
|
|
{"buc"},
|
|
}
|
|
|
|
inventoryItems := make([]InventoryItem, 0)
|
|
|
|
for idx := range testInventoryCodes {
|
|
item, itemErr := g.item.NewItem(testInventoryCodes[idx]...)
|
|
if itemErr != nil {
|
|
continue
|
|
}
|
|
|
|
item.Identify()
|
|
inventoryItems = append(inventoryItems, item)
|
|
}
|
|
|
|
// https://github.com/OpenDiablo2/OpenDiablo2/issues/795
|
|
testEquippedItemCodes := map[d2enum.EquippedSlot][]string{
|
|
d2enum.EquippedSlotLeftArm: {"wnd"},
|
|
d2enum.EquippedSlotRightArm: {"buc"},
|
|
d2enum.EquippedSlotHead: {"crn"},
|
|
d2enum.EquippedSlotTorso: {"plt"},
|
|
d2enum.EquippedSlotLegs: {"vbt"},
|
|
d2enum.EquippedSlotBelt: {"vbl"},
|
|
d2enum.EquippedSlotGloves: {"lgl"},
|
|
d2enum.EquippedSlotLeftHand: {"rin"},
|
|
d2enum.EquippedSlotRightHand: {"rin"},
|
|
d2enum.EquippedSlotNeck: {"amu"},
|
|
}
|
|
|
|
for slot := range testEquippedItemCodes {
|
|
item, itemErr := g.item.NewItem(testEquippedItemCodes[slot]...)
|
|
if itemErr != nil {
|
|
continue
|
|
}
|
|
|
|
g.grid.ChangeEquippedSlot(slot, item)
|
|
}
|
|
|
|
_, err = g.grid.Add(inventoryItems...)
|
|
if err != nil {
|
|
g.Errorf("could not add items to the inventory, err: %v", err.Error())
|
|
}
|
|
|
|
g.moveGoldPanel.Load()
|
|
|
|
g.panelGroup.SetVisible(false)
|
|
}
|
|
|
|
// Open opens the inventory
|
|
func (g *Inventory) Open() {
|
|
g.isOpen = true
|
|
g.panelGroup.SetVisible(true)
|
|
}
|
|
|
|
// Close closes the inventory
|
|
func (g *Inventory) Close() {
|
|
g.isOpen = false
|
|
g.moveGoldPanel.Close()
|
|
g.panelGroup.SetVisible(false)
|
|
g.itemTooltip.SetVisible(false)
|
|
g.onCloseCb()
|
|
}
|
|
|
|
// SetOnCloseCb the callback run on closing the inventory
|
|
func (g *Inventory) SetOnCloseCb(cb func()) {
|
|
g.onCloseCb = cb
|
|
}
|
|
|
|
func (g *Inventory) onGoldClicked() {
|
|
g.Info("Move gold action clicked")
|
|
g.toggleMoveGoldPanel()
|
|
}
|
|
|
|
func (g *Inventory) toggleMoveGoldPanel() {
|
|
g.moveGoldPanel.Toggle()
|
|
}
|
|
|
|
func (g *Inventory) onCloseGoldPanel() {
|
|
|
|
}
|
|
|
|
// IsOpen returns true if the inventory is open
|
|
func (g *Inventory) IsOpen() bool {
|
|
return g.isOpen
|
|
}
|
|
|
|
// Advance advances the state of the Inventory
|
|
func (g *Inventory) Advance(_ float64) {
|
|
if !g.IsOpen() {
|
|
return
|
|
}
|
|
|
|
g.goldLabel.SetText(fmt.Sprintln(g.moveGoldPanel.gold))
|
|
}
|
|
|
|
// Render draws the inventory onto the given surface
|
|
func (g *Inventory) Render(target d2interface.Surface) {
|
|
if !g.isOpen {
|
|
return
|
|
}
|
|
|
|
g.renderFrame(target)
|
|
|
|
g.grid.Render(target)
|
|
g.showItemDescriptionTooltip()
|
|
}
|
|
|
|
func (g *Inventory) renderFrame(target d2interface.Surface) {
|
|
frames := []int{
|
|
frameInventoryTopLeft,
|
|
frameInventoryTopRight,
|
|
frameInventoryBottomRight,
|
|
frameInventoryBottomLeft,
|
|
}
|
|
|
|
x, y := g.originX+1, g.originY
|
|
y += 64
|
|
|
|
for _, frame := range frames {
|
|
if err := g.panel.SetCurrentFrame(frame); err != nil {
|
|
g.Error(err.Error())
|
|
return
|
|
}
|
|
|
|
w, h := g.panel.GetCurrentFrameSize()
|
|
|
|
g.panel.SetPosition(x, y+h)
|
|
g.panel.Render(target)
|
|
|
|
switch frame {
|
|
case frameInventoryTopLeft:
|
|
x += w
|
|
case frameInventoryTopRight:
|
|
y += h
|
|
case frameInventoryBottomRight:
|
|
x = g.originX + 1
|
|
}
|
|
}
|
|
}
|
|
|
|
func (g *Inventory) showItemDescriptionTooltip() {
|
|
hoveringNow := g.checkEquippedSlotsHover()
|
|
|
|
if hoveringNow {
|
|
g.hovering = true
|
|
return
|
|
}
|
|
|
|
hoveringNow = g.checkGridSlotsHover()
|
|
|
|
if !hoveringNow {
|
|
g.itemTooltip.SetVisible(false)
|
|
}
|
|
|
|
g.hovering = hoveringNow
|
|
}
|
|
|
|
func (g *Inventory) checkGridSlotsHover() bool {
|
|
hovering := false
|
|
|
|
for idx := range g.grid.items {
|
|
item := g.grid.items[idx]
|
|
ix, iy := g.grid.SlotToScreen(item.InventoryGridSlot())
|
|
iw, ih := g.grid.sprites[item.GetItemCode()].GetCurrentFrameSize()
|
|
mx, my := g.lastMouseX, g.lastMouseY
|
|
hovering = hovering || ((mx > ix) && (mx < ix+iw) && (my > iy) && (my < iy+ih))
|
|
|
|
if hovering {
|
|
if !g.hovering {
|
|
// set the initial hover coordinates
|
|
// this is so that moving mouse doesnt move the description
|
|
g.hoverX, g.hoverY = mx, my
|
|
}
|
|
|
|
g.showGridItemDescriptionTooltip(item)
|
|
|
|
break
|
|
}
|
|
}
|
|
|
|
return hovering
|
|
}
|
|
|
|
func (g *Inventory) checkEquippedSlotsHover() bool {
|
|
hovering := false
|
|
|
|
for _, slot := range g.grid.equipmentSlots {
|
|
mx, my := g.lastMouseX, g.lastMouseY
|
|
|
|
hovering = hovering || ((mx > slot.x) && (mx < slot.x+slot.width) && (my < slot.y) && (my > slot.y-slot.height))
|
|
if hovering {
|
|
if !g.hovering {
|
|
g.hoverX, g.hoverY = mx, my
|
|
}
|
|
|
|
g.showEquippedItemDescriptionTooltip(slot)
|
|
|
|
break
|
|
}
|
|
}
|
|
|
|
return hovering
|
|
}
|
|
|
|
func (g *Inventory) showGridItemDescriptionTooltip(i InventoryItem) {
|
|
if !g.moveGoldPanel.IsOpen() {
|
|
lines := i.GetItemDescription()
|
|
g.itemTooltip.SetTextLines(lines)
|
|
_, y := g.grid.SlotToScreen(i.InventoryGridSlot())
|
|
|
|
g.itemTooltip.SetPosition(g.hoverX, y)
|
|
g.itemTooltip.SetVisible(true)
|
|
}
|
|
}
|
|
|
|
func (g *Inventory) showEquippedItemDescriptionTooltip(slot EquipmentSlot) {
|
|
if !g.moveGoldPanel.IsOpen() {
|
|
lines := slot.item.GetItemDescription()
|
|
g.itemTooltip.SetTextLines(lines)
|
|
g.itemTooltip.SetPosition(g.hoverX, slot.y)
|
|
g.itemTooltip.SetVisible(true)
|
|
}
|
|
}
|