1
1
mirror of https://github.com/OpenDiablo2/OpenDiablo2 synced 2024-06-20 06:05:23 +00:00

Feature/player equipment ui (#419)

* Add basic EquipmentSlot struct

* Add Load function to EquipmentSlot

* Move EquipmentSlot struct to inventory_grid.go

* Add equipmentSlots arg to ItemGrid struct

* Add basic rendering of equipment slots.

* Change rendering of equipment slots to simply use their static x and y

* Add ChangeEquippedSlot function

* Add initialization to all equipped slots types.

* Fix Y locations of equipment slots

* Move default equipment slots to a genEquipmentSlotsMap function.

* Change Item to item

* Fix coordinates

* Change usage of string to EquippedSlotType when dealing with different slots in rendering.

* Fix import error

* Remove neck example

* Add loading sprites of equipped items.

* Clean code in Inventory rendering

* Clean code in Inventory rendering

* Clean code in Inventory rendering

* Change default items that get rendered.

* Change default items that get rendered.

* Add width and height to EquipementSlot struct

* Fill in width and height to current equipment slots.

* Fix Y setting of equipment slots

* Rename variables for clean code.

* Change handling nil itemSprite to condition instead of loop return.

* Split Render function to 2 functions.

* Add TODO

* Change comment to start with capital I
This commit is contained in:
Ripolak 2020-06-23 21:12:30 +03:00 committed by GitHub
parent b640385623
commit 2332bd7b58
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 184 additions and 42 deletions

View File

@ -0,0 +1,16 @@
package d2enum
type EquippedSlotType int
const (
Head EquippedSlotType = 1
Torso EquippedSlotType = 2
Legs EquippedSlotType = 3
RightArm EquippedSlotType = 4
LeftArm EquippedSlotType = 5
LeftHand EquippedSlotType = 6
RightHand EquippedSlotType = 7
Neck EquippedSlotType = 8
Belt EquippedSlotType = 9
Gloves EquippedSlotType = 10
)

View File

@ -0,0 +1,86 @@
package d2player
import "github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
type EquipmentSlot struct {
item InventoryItem
x int
y int
width int
height int
}
func genEquipmentSlotsMap() map[d2enum.EquippedSlotType]EquipmentSlot {
return map[d2enum.EquippedSlotType]EquipmentSlot{
d2enum.LeftArm: {
item: nil,
x: 418,
y: 224,
width: 61,
height: 116,
},
d2enum.RightArm: {
item: nil,
x: 648,
y: 224,
width: 61,
height: 116,
},
d2enum.Head: {
item: nil,
x: 532,
y: 125,
width: 62,
height: 62,
},
d2enum.Neck: {
item: nil,
x: 604,
y: 125,
width: 32,
height: 32,
},
d2enum.Torso: {
item: nil,
x: 532,
y: 224,
width: 62,
height: 90,
},
d2enum.Belt: {
item: nil,
x: 533,
y: 269,
width: 62,
height: 32,
},
d2enum.LeftHand: {
item: nil,
x: 491,
y: 268,
width: 32,
height: 32,
},
d2enum.RightHand: {
item: nil,
x: 606,
y: 268,
width: 32,
height: 32,
},
d2enum.Gloves: {
item: nil,
x: 417,
y: 299,
width: 62,
height: 62,
},
d2enum.Legs: {
item: nil,
x: 648,
y: 299,
width: 62,
height: 62,
},
}
}

View File

@ -1,6 +1,7 @@
package d2player package d2player
import ( import (
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2resource" "github.com/OpenDiablo2/OpenDiablo2/d2common/d2resource"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2asset" "github.com/OpenDiablo2/OpenDiablo2/d2core/d2asset"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2inventory" "github.com/OpenDiablo2/OpenDiablo2/d2core/d2inventory"
@ -49,14 +50,22 @@ func (g *Inventory) Load() {
animation, _ = d2asset.LoadAnimation(d2resource.InventoryCharacterPanel, d2resource.PaletteSky) animation, _ = d2asset.LoadAnimation(d2resource.InventoryCharacterPanel, d2resource.PaletteSky)
g.panel, _ = d2ui.LoadSprite(animation) g.panel, _ = d2ui.LoadSprite(animation)
items := []InventoryItem{ items := []InventoryItem{
d2inventory.GetWeaponItemByCode("wnd"), d2inventory.GetWeaponItemByCode("wnd"),
d2inventory.GetWeaponItemByCode("sst"), d2inventory.GetWeaponItemByCode("sst"),
d2inventory.GetWeaponItemByCode("jav"), d2inventory.GetWeaponItemByCode("jav"),
d2inventory.GetArmorItemByCode("buc"), d2inventory.GetArmorItemByCode("buc"),
d2inventory.GetWeaponItemByCode("clb"), d2inventory.GetWeaponItemByCode("clb"),
// TODO: Load the player's actual items
} }
g.grid.ChangeEquippedSlot(d2enum.LeftArm, d2inventory.GetWeaponItemByCode("wnd"))
g.grid.ChangeEquippedSlot(d2enum.RightArm, d2inventory.GetArmorItemByCode("buc"))
g.grid.ChangeEquippedSlot(d2enum.Head, d2inventory.GetArmorItemByCode("crn"))
g.grid.ChangeEquippedSlot(d2enum.Torso, d2inventory.GetArmorItemByCode("plt"))
g.grid.ChangeEquippedSlot(d2enum.Legs, d2inventory.GetArmorItemByCode("vbt"))
g.grid.ChangeEquippedSlot(d2enum.Belt, d2inventory.GetArmorItemByCode("vbl"))
g.grid.ChangeEquippedSlot(d2enum.Gloves, d2inventory.GetArmorItemByCode("lgl"))
// TODO: Load the player's actual items
g.grid.Add(items...) g.grid.Add(items...)
} }

View File

@ -3,6 +3,7 @@ package d2player
import ( import (
"errors" "errors"
"fmt" "fmt"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
"log" "log"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2asset" "github.com/OpenDiablo2/OpenDiablo2/d2core/d2asset"
@ -24,23 +25,25 @@ var ErrorInventoryFull = errors.New("inventory full")
// Reusable grid for use with player and merchant inventory. // Reusable grid for use with player and merchant inventory.
// Handles layout and rendering item icons based on code. // Handles layout and rendering item icons based on code.
type ItemGrid struct { type ItemGrid struct {
items []InventoryItem items []InventoryItem
width int equipmentSlots map[d2enum.EquippedSlotType]EquipmentSlot
height int width int
originX int height int
originY int originX int
sprites map[string]*d2ui.Sprite originY int
slotSize int sprites map[string]*d2ui.Sprite
slotSize int
} }
func NewItemGrid(width int, height int, originX int, originY int) *ItemGrid { func NewItemGrid(width int, height int, originX int, originY int) *ItemGrid {
return &ItemGrid{ return &ItemGrid{
width: width, width: width,
height: height, height: height,
originX: originX, originX: originX,
originY: originY, originY: originY,
slotSize: 29, slotSize: 29,
sprites: make(map[string]*d2ui.Sprite), sprites: make(map[string]*d2ui.Sprite),
equipmentSlots: genEquipmentSlotsMap(),
} }
} }
@ -69,6 +72,12 @@ func (g *ItemGrid) GetSlot(x int, y int) InventoryItem {
return nil return nil
} }
func (g *ItemGrid) ChangeEquippedSlot(slot d2enum.EquippedSlotType, item InventoryItem) {
var curItem = g.equipmentSlots[slot]
curItem.item = item
g.equipmentSlots[slot] = curItem
}
// Add places a given set of items into the first available slots. // Add places a given set of items into the first available slots.
// Returns a count of the number of items which could be inserted. // Returns a count of the number of items which could be inserted.
func (g *ItemGrid) Add(items ...InventoryItem) (int, error) { func (g *ItemGrid) Add(items ...InventoryItem) (int, error) {
@ -89,15 +98,9 @@ func (g *ItemGrid) Add(items ...InventoryItem) (int, error) {
return added, err return added, err
} }
// Load reads the inventory sprites for items into local cache for rendering. func (g *ItemGrid) loadItem(item InventoryItem) {
func (g *ItemGrid) Load(items ...InventoryItem) { if _, exists := g.sprites[item.GetItemCode()]; !exists {
var itemSprite *d2ui.Sprite var itemSprite *d2ui.Sprite
for _, item := range items {
if _, exists := g.sprites[item.GetItemCode()]; exists {
// Already loaded, don't reload.
continue
}
// TODO: Put the pattern into D2Shared // TODO: Put the pattern into D2Shared
animation, err := d2asset.LoadAnimation( animation, err := d2asset.LoadAnimation(
@ -106,13 +109,26 @@ func (g *ItemGrid) Load(items ...InventoryItem) {
) )
if err != nil { if err != nil {
log.Printf("failed to load sprite for item (%s): %v", item.GetItemCode(), err) log.Printf("failed to load sprite for item (%s): %v", item.GetItemCode(), err)
continue return
} }
itemSprite, err = d2ui.LoadSprite(animation) itemSprite, err = d2ui.LoadSprite(animation)
if err != nil {
log.Printf("Failed to load sprite, error: " + err.Error())
}
g.sprites[item.GetItemCode()] = itemSprite g.sprites[item.GetItemCode()] = itemSprite
} }
}
// Load reads the inventory sprites for items into local cache for rendering.
func (g *ItemGrid) Load(items ...InventoryItem) {
for _, item := range items {
g.loadItem(item)
}
for _, eq := range g.equipmentSlots {
if eq.item != nil {
g.loadItem(eq.item)
}
}
} }
// Walk from top left to bottom right until a position large enough to hold the item is found. // Walk from top left to bottom right until a position large enough to hold the item is found.
@ -183,23 +199,38 @@ func (g *ItemGrid) Remove(item InventoryItem) {
g.items = g.items[:n] g.items = g.items[:n]
} }
func (g *ItemGrid) Render(target d2render.Surface) { func (g *ItemGrid) renderItem(item InventoryItem, target d2render.Surface, x int, y int) {
for _, item := range g.items { itemSprite := g.sprites[item.GetItemCode()]
if item == nil { if itemSprite != nil {
continue itemSprite.SetPosition(x, y)
} itemSprite.GetCurrentFrameSize()
itemSprite := g.sprites[item.GetItemCode()]
if itemSprite == nil {
// In case it failed to load.
// TODO: fallback to something
continue
}
slotX, slotY := g.SlotToScreen(item.InventoryGridSlot())
_, h := itemSprite.GetCurrentFrameSize()
itemSprite.SetPosition(slotX, slotY+h)
_ = itemSprite.Render(target) _ = itemSprite.Render(target)
}
}
func (g *ItemGrid) Render(target d2render.Surface) {
g.renderInventoryItems(target)
g.renderEquippedItems(target)
}
func (g *ItemGrid) renderInventoryItems(target d2render.Surface) {
for _, item := range g.items {
itemSprite := g.sprites[item.GetItemCode()]
slotX, slotY := g.SlotToScreen(item.InventoryGridSlot())
_, h := itemSprite.GetCurrentFrameSize()
slotY = slotY + h
g.renderItem(item, target, slotX, slotY)
}
}
func (g *ItemGrid) renderEquippedItems(target d2render.Surface) {
for _, eq := range g.equipmentSlots {
if eq.item != nil {
itemSprite := g.sprites[eq.item.GetItemCode()]
itemWidth, itemHeight := itemSprite.GetCurrentFrameSize()
var x = eq.x + ((eq.width - itemWidth) / 2)
var y = eq.y - ((eq.height - itemHeight) / 2)
g.renderItem(eq.item, target, x, y)
}
} }
} }