728 lines
20 KiB
Go
728 lines
20 KiB
Go
package items
|
|
|
|
import (
|
|
"fmt"
|
|
"log"
|
|
"sync"
|
|
"time"
|
|
)
|
|
|
|
// SpellManager defines the interface for spell-related operations needed by items
|
|
type SpellManager interface {
|
|
// GetSpell retrieves spell information by ID and tier
|
|
GetSpell(spellID uint32, tier int8) (Spell, error)
|
|
|
|
// GetSpellsBySkill gets spells associated with a skill
|
|
GetSpellsBySkill(skillID uint32) ([]uint32, error)
|
|
|
|
// ValidateSpellID checks if a spell ID is valid
|
|
ValidateSpellID(spellID uint32) bool
|
|
}
|
|
|
|
// PlayerManager defines the interface for player-related operations needed by items
|
|
type PlayerManager interface {
|
|
// GetPlayer retrieves player information by ID
|
|
GetPlayer(playerID uint32) (Player, error)
|
|
|
|
// GetPlayerLevel gets a player's current level
|
|
GetPlayerLevel(playerID uint32) (int16, error)
|
|
|
|
// GetPlayerClass gets a player's adventure class
|
|
GetPlayerClass(playerID uint32) (int8, error)
|
|
|
|
// GetPlayerRace gets a player's race
|
|
GetPlayerRace(playerID uint32) (int8, error)
|
|
|
|
// SendMessageToPlayer sends a message to a player
|
|
SendMessageToPlayer(playerID uint32, channel int8, message string) error
|
|
|
|
// GetPlayerName gets a player's name
|
|
GetPlayerName(playerID uint32) (string, error)
|
|
}
|
|
|
|
// PacketManager defines the interface for packet-related operations
|
|
type PacketManager interface {
|
|
// SendPacketToPlayer sends a packet to a specific player
|
|
SendPacketToPlayer(playerID uint32, packetData []byte) error
|
|
|
|
// QueuePacketForPlayer queues a packet for delayed sending
|
|
QueuePacketForPlayer(playerID uint32, packetData []byte) error
|
|
|
|
// GetClientVersion gets the client version for a player
|
|
GetClientVersion(playerID uint32) (int16, error)
|
|
|
|
// SerializeItem serializes an item for network transmission
|
|
SerializeItem(item *Item, clientVersion int16, player Player) ([]byte, error)
|
|
}
|
|
|
|
// RuleManager defines the interface for rules/configuration access
|
|
type RuleManager interface {
|
|
// GetBool retrieves a boolean rule value
|
|
GetBool(category, rule string) bool
|
|
|
|
// GetInt32 retrieves an int32 rule value
|
|
GetInt32(category, rule string) int32
|
|
|
|
// GetFloat retrieves a float rule value
|
|
GetFloat(category, rule string) float32
|
|
|
|
// GetString retrieves a string rule value
|
|
GetString(category, rule string) string
|
|
}
|
|
|
|
// DatabaseService defines the interface for item persistence operations
|
|
type DatabaseService interface {
|
|
// LoadItems loads all item templates from the database
|
|
LoadItems(masterList *MasterItemList) error
|
|
|
|
// SaveItem saves an item template to the database
|
|
SaveItem(item *Item) error
|
|
|
|
// DeleteItem removes an item template from the database
|
|
DeleteItem(itemID int32) error
|
|
|
|
// LoadPlayerItems loads a player's inventory from the database
|
|
LoadPlayerItems(playerID uint32) (*PlayerItemList, error)
|
|
|
|
// SavePlayerItems saves a player's inventory to the database
|
|
SavePlayerItems(playerID uint32, itemList *PlayerItemList) error
|
|
|
|
// LoadPlayerEquipment loads a player's equipment from the database
|
|
LoadPlayerEquipment(playerID uint32, appearanceType int8) (*EquipmentItemList, error)
|
|
|
|
// SavePlayerEquipment saves a player's equipment to the database
|
|
SavePlayerEquipment(playerID uint32, equipment *EquipmentItemList) error
|
|
|
|
// LoadItemStats loads item stat mappings from the database
|
|
LoadItemStats() (map[string]int32, map[int32]string, error)
|
|
|
|
// SaveItemStat saves an item stat mapping to the database
|
|
SaveItemStat(statID int32, statName string) error
|
|
}
|
|
|
|
// QuestManager defines the interface for quest-related item operations
|
|
type QuestManager interface {
|
|
// CheckQuestPrerequisites checks if a player meets quest prerequisites for an item
|
|
CheckQuestPrerequisites(playerID uint32, questID int32) bool
|
|
|
|
// GetQuestRewards gets quest rewards for an item
|
|
GetQuestRewards(questID int32) ([]*QuestRewardData, error)
|
|
|
|
// IsQuestItem checks if an item is a quest item
|
|
IsQuestItem(itemID int32) bool
|
|
}
|
|
|
|
// BrokerManager defines the interface for broker/marketplace operations
|
|
type BrokerManager interface {
|
|
// SearchItems searches for items on the broker
|
|
SearchItems(criteria *ItemSearchCriteria) ([]*Item, error)
|
|
|
|
// ListItem lists an item on the broker
|
|
ListItem(playerID uint32, item *Item, price int64) error
|
|
|
|
// BuyItem purchases an item from the broker
|
|
BuyItem(playerID uint32, itemID int32, sellerID uint32) error
|
|
|
|
// GetItemPrice gets the current market price for an item
|
|
GetItemPrice(itemID int32) (int64, error)
|
|
}
|
|
|
|
// CraftingManager defines the interface for crafting-related item operations
|
|
type CraftingManager interface {
|
|
// CanCraftItem checks if a player can craft an item
|
|
CanCraftItem(playerID uint32, itemID int32) bool
|
|
|
|
// GetCraftingRequirements gets crafting requirements for an item
|
|
GetCraftingRequirements(itemID int32) ([]CraftingRequirement, error)
|
|
|
|
// CraftItem handles item crafting
|
|
CraftItem(playerID uint32, itemID int32, quality int8) (*Item, error)
|
|
}
|
|
|
|
// HousingManager defines the interface for housing-related item operations
|
|
type HousingManager interface {
|
|
// CanPlaceItem checks if an item can be placed in a house
|
|
CanPlaceItem(playerID uint32, houseID int32, item *Item) bool
|
|
|
|
// PlaceItem places an item in a house
|
|
PlaceItem(playerID uint32, houseID int32, item *Item, location HouseLocation) error
|
|
|
|
// RemoveItem removes an item from a house
|
|
RemoveItem(playerID uint32, houseID int32, itemID int32) error
|
|
|
|
// GetHouseItems gets all items in a house
|
|
GetHouseItems(houseID int32) ([]*Item, error)
|
|
}
|
|
|
|
// LootManager defines the interface for loot-related operations
|
|
type LootManager interface {
|
|
// GenerateLoot generates loot for a loot table
|
|
GenerateLoot(lootTableID int32, playerLevel int16) ([]*Item, error)
|
|
|
|
// DistributeLoot distributes loot to players
|
|
DistributeLoot(items []*Item, playerIDs []uint32, lootMethod int8) error
|
|
|
|
// CanLootItem checks if a player can loot an item
|
|
CanLootItem(playerID uint32, item *Item) bool
|
|
}
|
|
|
|
// Data structures used by the interfaces
|
|
|
|
// Spell represents a spell in the game
|
|
type Spell interface {
|
|
GetID() uint32
|
|
GetName() string
|
|
GetIcon() uint32
|
|
GetIconBackdrop() uint32
|
|
GetTier() int8
|
|
GetDescription() string
|
|
}
|
|
|
|
// Player represents a player in the game
|
|
type Player interface {
|
|
GetID() uint32
|
|
GetName() string
|
|
GetLevel() int16
|
|
GetAdventureClass() int8
|
|
GetTradeskillClass() int8
|
|
GetRace() int8
|
|
GetGender() int8
|
|
GetAlignment() int8
|
|
}
|
|
|
|
// CraftingRequirement represents a crafting requirement
|
|
type CraftingRequirement struct {
|
|
ItemID int32 `json:"item_id"`
|
|
Quantity int16 `json:"quantity"`
|
|
Skill int32 `json:"skill"`
|
|
Level int16 `json:"level"`
|
|
}
|
|
|
|
// HouseLocation represents a location within a house
|
|
type HouseLocation struct {
|
|
X float32 `json:"x"`
|
|
Y float32 `json:"y"`
|
|
Z float32 `json:"z"`
|
|
Heading float32 `json:"heading"`
|
|
Pitch float32 `json:"pitch"`
|
|
Roll float32 `json:"roll"`
|
|
Location int8 `json:"location"` // 0=floor, 1=ceiling, 2=wall
|
|
}
|
|
|
|
// ItemSystemAdapter provides a high-level interface to the complete item system
|
|
type ItemSystemAdapter struct {
|
|
masterList *MasterItemList
|
|
playerLists map[uint32]*PlayerItemList
|
|
equipmentLists map[uint32]*EquipmentItemList
|
|
spellManager SpellManager
|
|
playerManager PlayerManager
|
|
packetManager PacketManager
|
|
ruleManager RuleManager
|
|
databaseService DatabaseService
|
|
questManager QuestManager
|
|
brokerManager BrokerManager
|
|
craftingManager CraftingManager
|
|
housingManager HousingManager
|
|
lootManager LootManager
|
|
mutex sync.RWMutex
|
|
}
|
|
|
|
// NewItemSystemAdapter creates a new item system adapter with all dependencies
|
|
func NewItemSystemAdapter(
|
|
masterList *MasterItemList,
|
|
spellManager SpellManager,
|
|
playerManager PlayerManager,
|
|
packetManager PacketManager,
|
|
ruleManager RuleManager,
|
|
databaseService DatabaseService,
|
|
questManager QuestManager,
|
|
brokerManager BrokerManager,
|
|
craftingManager CraftingManager,
|
|
housingManager HousingManager,
|
|
lootManager LootManager,
|
|
) *ItemSystemAdapter {
|
|
return &ItemSystemAdapter{
|
|
masterList: masterList,
|
|
playerLists: make(map[uint32]*PlayerItemList),
|
|
equipmentLists: make(map[uint32]*EquipmentItemList),
|
|
spellManager: spellManager,
|
|
playerManager: playerManager,
|
|
packetManager: packetManager,
|
|
ruleManager: ruleManager,
|
|
databaseService: databaseService,
|
|
questManager: questManager,
|
|
brokerManager: brokerManager,
|
|
craftingManager: craftingManager,
|
|
housingManager: housingManager,
|
|
lootManager: lootManager,
|
|
}
|
|
}
|
|
|
|
// Initialize sets up the item system (loads items from database, etc.)
|
|
func (isa *ItemSystemAdapter) Initialize() error {
|
|
// Load items from database
|
|
err := isa.databaseService.LoadItems(isa.masterList)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// Load item stat mappings
|
|
statsStrings, statsIDs, err := isa.databaseService.LoadItemStats()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
isa.masterList.mutex.Lock()
|
|
isa.masterList.mappedItemStatsStrings = statsStrings
|
|
isa.masterList.mappedItemStatTypeIDs = statsIDs
|
|
isa.masterList.mutex.Unlock()
|
|
|
|
return nil
|
|
}
|
|
|
|
// GetPlayerInventory gets or loads a player's inventory
|
|
func (isa *ItemSystemAdapter) GetPlayerInventory(playerID uint32) (*PlayerItemList, error) {
|
|
isa.mutex.Lock()
|
|
defer isa.mutex.Unlock()
|
|
|
|
if itemList, exists := isa.playerLists[playerID]; exists {
|
|
return itemList, nil
|
|
}
|
|
|
|
// Load from database
|
|
itemList, err := isa.databaseService.LoadPlayerItems(playerID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if itemList == nil {
|
|
itemList = NewPlayerItemList()
|
|
}
|
|
|
|
isa.playerLists[playerID] = itemList
|
|
return itemList, nil
|
|
}
|
|
|
|
// GetPlayerEquipment gets or loads a player's equipment
|
|
func (isa *ItemSystemAdapter) GetPlayerEquipment(playerID uint32, appearanceType int8) (*EquipmentItemList, error) {
|
|
isa.mutex.Lock()
|
|
defer isa.mutex.Unlock()
|
|
|
|
key := uint32(playerID)*10 + uint32(appearanceType)
|
|
if equipment, exists := isa.equipmentLists[key]; exists {
|
|
return equipment, nil
|
|
}
|
|
|
|
// Load from database
|
|
equipment, err := isa.databaseService.LoadPlayerEquipment(playerID, appearanceType)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if equipment == nil {
|
|
equipment = NewEquipmentItemList()
|
|
equipment.SetAppearanceType(appearanceType)
|
|
}
|
|
|
|
isa.equipmentLists[key] = equipment
|
|
return equipment, nil
|
|
}
|
|
|
|
// SavePlayerData saves a player's item data
|
|
func (isa *ItemSystemAdapter) SavePlayerData(playerID uint32) error {
|
|
isa.mutex.RLock()
|
|
defer isa.mutex.RUnlock()
|
|
|
|
// Save inventory
|
|
if itemList, exists := isa.playerLists[playerID]; exists {
|
|
err := isa.databaseService.SavePlayerItems(playerID, itemList)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
// Save equipment (both normal and appearance)
|
|
for key, equipment := range isa.equipmentLists {
|
|
if key/10 == playerID {
|
|
err := isa.databaseService.SavePlayerEquipment(playerID, equipment)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// GiveItemToPlayer gives an item to a player
|
|
func (isa *ItemSystemAdapter) GiveItemToPlayer(playerID uint32, itemID int32, quantity int16, addType AddItemType) error {
|
|
// Get item template
|
|
itemTemplate := isa.masterList.GetItem(itemID)
|
|
if itemTemplate == nil {
|
|
return ErrItemNotFound
|
|
}
|
|
|
|
// Create item instance
|
|
item := NewItemFromTemplate(itemTemplate)
|
|
item.Details.Count = quantity
|
|
|
|
// Get player inventory
|
|
inventory, err := isa.GetPlayerInventory(playerID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// Try to add item to inventory
|
|
if !inventory.AddItem(item) {
|
|
return ErrInsufficientSpace
|
|
}
|
|
|
|
// Send update to player
|
|
player, err := isa.playerManager.GetPlayer(playerID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
clientVersion, _ := isa.packetManager.GetClientVersion(playerID)
|
|
packetData, err := isa.packetManager.SerializeItem(item, clientVersion, player)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return isa.packetManager.SendPacketToPlayer(playerID, packetData)
|
|
}
|
|
|
|
// RemoveItemFromPlayer removes an item from a player
|
|
func (isa *ItemSystemAdapter) RemoveItemFromPlayer(playerID uint32, uniqueID int32, quantity int16) error {
|
|
inventory, err := isa.GetPlayerInventory(playerID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
item := inventory.GetItemFromUniqueID(uniqueID, true, true)
|
|
if item == nil {
|
|
return ErrItemNotFound
|
|
}
|
|
|
|
// Check if item can be removed
|
|
if item.IsItemLocked() {
|
|
return ErrItemLocked
|
|
}
|
|
|
|
if item.Details.Count <= quantity {
|
|
// Remove entire stack
|
|
inventory.RemoveItem(item, true, true)
|
|
} else {
|
|
// Reduce quantity
|
|
item.Details.Count -= quantity
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// EquipItem equips an item for a player
|
|
func (isa *ItemSystemAdapter) EquipItem(playerID uint32, uniqueID int32, slot int8, appearanceType int8) error {
|
|
inventory, err := isa.GetPlayerInventory(playerID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
equipment, err := isa.GetPlayerEquipment(playerID, appearanceType)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// Get item from inventory
|
|
item := inventory.GetItemFromUniqueID(uniqueID, false, true)
|
|
if item == nil {
|
|
return ErrItemNotFound
|
|
}
|
|
|
|
// Check if item can be equipped
|
|
if !equipment.CanItemBeEquippedInSlot(item, slot) {
|
|
return ErrCannotEquip
|
|
}
|
|
|
|
// Check class/race/level requirements
|
|
player, err := isa.playerManager.GetPlayer(playerID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if !item.CheckClass(player.GetAdventureClass(), player.GetTradeskillClass()) {
|
|
return ErrCannotEquip
|
|
}
|
|
|
|
if !item.CheckClassLevel(player.GetAdventureClass(), player.GetTradeskillClass(), player.GetLevel()) {
|
|
return ErrCannotEquip
|
|
}
|
|
|
|
// Remove from inventory
|
|
inventory.RemoveItem(item, false, true)
|
|
|
|
// Check if slot is occupied and unequip current item
|
|
currentItem := equipment.GetItem(slot)
|
|
if currentItem != nil {
|
|
equipment.RemoveItem(slot, false)
|
|
inventory.AddItem(currentItem)
|
|
}
|
|
|
|
// Equip new item
|
|
equipment.SetItem(slot, item, false)
|
|
|
|
return nil
|
|
}
|
|
|
|
// UnequipItem unequips an item for a player
|
|
func (isa *ItemSystemAdapter) UnequipItem(playerID uint32, slot int8, appearanceType int8) error {
|
|
inventory, err := isa.GetPlayerInventory(playerID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
equipment, err := isa.GetPlayerEquipment(playerID, appearanceType)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// Get equipped item
|
|
item := equipment.GetItem(slot)
|
|
if item == nil {
|
|
return ErrItemNotFound
|
|
}
|
|
|
|
// Check if item can be unequipped
|
|
if item.IsItemLocked() {
|
|
return ErrItemLocked
|
|
}
|
|
|
|
// Remove from equipment
|
|
equipment.RemoveItem(slot, false)
|
|
|
|
// Add to inventory
|
|
if !inventory.AddItem(item) {
|
|
// Inventory full, add to overflow
|
|
inventory.AddOverflowItem(item)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// MoveItem moves an item within a player's inventory
|
|
func (isa *ItemSystemAdapter) MoveItem(playerID uint32, fromBagID int32, fromSlot int16, toBagID int32, toSlot int16, appearanceType int8) error {
|
|
inventory, err := isa.GetPlayerInventory(playerID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// Get item from source location
|
|
item := inventory.GetItem(fromBagID, fromSlot, appearanceType)
|
|
if item == nil {
|
|
return ErrItemNotFound
|
|
}
|
|
|
|
// Check if item is locked
|
|
if item.IsItemLocked() {
|
|
return ErrItemLocked
|
|
}
|
|
|
|
// Move item
|
|
inventory.MoveItem(item, toBagID, toSlot, appearanceType, true)
|
|
|
|
return nil
|
|
}
|
|
|
|
// SearchBrokerItems searches for items on the broker
|
|
func (isa *ItemSystemAdapter) SearchBrokerItems(criteria *ItemSearchCriteria) ([]*Item, error) {
|
|
if isa.brokerManager == nil {
|
|
return nil, fmt.Errorf("broker manager not available")
|
|
}
|
|
|
|
return isa.brokerManager.SearchItems(criteria)
|
|
}
|
|
|
|
// CraftItem handles item crafting
|
|
func (isa *ItemSystemAdapter) CraftItem(playerID uint32, itemID int32, quality int8) (*Item, error) {
|
|
if isa.craftingManager == nil {
|
|
return nil, fmt.Errorf("crafting manager not available")
|
|
}
|
|
|
|
// Check if player can craft the item
|
|
if !isa.craftingManager.CanCraftItem(playerID, itemID) {
|
|
return nil, fmt.Errorf("player cannot craft this item")
|
|
}
|
|
|
|
// Craft the item
|
|
return isa.craftingManager.CraftItem(playerID, itemID, quality)
|
|
}
|
|
|
|
// GetPlayerItemStats returns statistics about a player's items
|
|
func (isa *ItemSystemAdapter) GetPlayerItemStats(playerID uint32) (map[string]interface{}, error) {
|
|
inventory, err := isa.GetPlayerInventory(playerID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
equipment, err := isa.GetPlayerEquipment(playerID, BaseEquipment)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Calculate equipment bonuses
|
|
bonuses := equipment.CalculateEquipmentBonuses()
|
|
|
|
return map[string]interface{}{
|
|
"player_id": playerID,
|
|
"total_items": inventory.GetNumberOfItems(),
|
|
"equipped_items": equipment.GetNumberOfItems(),
|
|
"inventory_weight": inventory.GetWeight(),
|
|
"equipment_weight": equipment.GetWeight(),
|
|
"free_slots": inventory.GetNumberOfFreeSlots(),
|
|
"overflow_items": len(inventory.GetOverflowItemList()),
|
|
"stat_bonuses": bonuses,
|
|
"last_update": time.Now(),
|
|
}, nil
|
|
}
|
|
|
|
// GetSystemStats returns comprehensive statistics about the item system
|
|
func (isa *ItemSystemAdapter) GetSystemStats() map[string]interface{} {
|
|
isa.mutex.RLock()
|
|
defer isa.mutex.RUnlock()
|
|
|
|
masterStats := isa.masterList.GetStats()
|
|
|
|
return map[string]interface{}{
|
|
"total_item_templates": masterStats.TotalItems,
|
|
"items_by_type": masterStats.ItemsByType,
|
|
"items_by_tier": masterStats.ItemsByTier,
|
|
"active_players": len(isa.playerLists),
|
|
"cached_inventories": len(isa.playerLists),
|
|
"cached_equipment": len(isa.equipmentLists),
|
|
"last_update": time.Now(),
|
|
}
|
|
}
|
|
|
|
// ClearPlayerData removes cached data for a player (e.g., when they log out)
|
|
func (isa *ItemSystemAdapter) ClearPlayerData(playerID uint32) {
|
|
isa.mutex.Lock()
|
|
defer isa.mutex.Unlock()
|
|
|
|
// Remove inventory
|
|
delete(isa.playerLists, playerID)
|
|
|
|
// Remove equipment
|
|
keysToDelete := make([]uint32, 0)
|
|
for key := range isa.equipmentLists {
|
|
if key/10 == playerID {
|
|
keysToDelete = append(keysToDelete, key)
|
|
}
|
|
}
|
|
|
|
for _, key := range keysToDelete {
|
|
delete(isa.equipmentLists, key)
|
|
}
|
|
}
|
|
|
|
// ValidatePlayerItems validates all items for a player
|
|
func (isa *ItemSystemAdapter) ValidatePlayerItems(playerID uint32) *ItemValidationResult {
|
|
result := &ItemValidationResult{Valid: true}
|
|
|
|
// Validate inventory
|
|
inventory, err := isa.GetPlayerInventory(playerID)
|
|
if err != nil {
|
|
result.Valid = false
|
|
result.Errors = append(result.Errors, fmt.Sprintf("Failed to load inventory: %v", err))
|
|
return result
|
|
}
|
|
|
|
allItems := inventory.GetAllItems()
|
|
for index, item := range allItems {
|
|
itemResult := item.Validate()
|
|
if !itemResult.Valid {
|
|
result.Valid = false
|
|
for _, itemErr := range itemResult.Errors {
|
|
result.Errors = append(result.Errors, fmt.Sprintf("Inventory item %d: %s", index, itemErr))
|
|
}
|
|
}
|
|
}
|
|
|
|
// Validate equipment
|
|
equipment, err := isa.GetPlayerEquipment(playerID, BaseEquipment)
|
|
if err != nil {
|
|
result.Valid = false
|
|
result.Errors = append(result.Errors, fmt.Sprintf("Failed to load equipment: %v", err))
|
|
return result
|
|
}
|
|
|
|
equipResult := equipment.ValidateEquipment()
|
|
if !equipResult.Valid {
|
|
result.Valid = false
|
|
result.Errors = append(result.Errors, equipResult.Errors...)
|
|
}
|
|
|
|
return result
|
|
}
|
|
|
|
// MockImplementations for testing
|
|
|
|
// MockSpellManager is a mock implementation of SpellManager for testing
|
|
type MockSpellManager struct {
|
|
spells map[uint32]MockSpell
|
|
}
|
|
|
|
// MockSpell is a mock implementation of Spell for testing
|
|
type MockSpell struct {
|
|
id uint32
|
|
name string
|
|
icon uint32
|
|
iconBackdrop uint32
|
|
tier int8
|
|
description string
|
|
}
|
|
|
|
func (ms MockSpell) GetID() uint32 { return ms.id }
|
|
func (ms MockSpell) GetName() string { return ms.name }
|
|
func (ms MockSpell) GetIcon() uint32 { return ms.icon }
|
|
func (ms MockSpell) GetIconBackdrop() uint32 { return ms.iconBackdrop }
|
|
func (ms MockSpell) GetTier() int8 { return ms.tier }
|
|
func (ms MockSpell) GetDescription() string { return ms.description }
|
|
|
|
func (msm *MockSpellManager) GetSpell(spellID uint32, tier int8) (Spell, error) {
|
|
if spell, exists := msm.spells[spellID]; exists {
|
|
return spell, nil
|
|
}
|
|
return nil, fmt.Errorf("spell not found: %d", spellID)
|
|
}
|
|
|
|
func (msm *MockSpellManager) GetSpellsBySkill(skillID uint32) ([]uint32, error) {
|
|
return []uint32{}, nil
|
|
}
|
|
|
|
func (msm *MockSpellManager) ValidateSpellID(spellID uint32) bool {
|
|
_, exists := msm.spells[spellID]
|
|
return exists
|
|
}
|
|
|
|
// NewMockSpellManager creates a new mock spell manager
|
|
func NewMockSpellManager() *MockSpellManager {
|
|
return &MockSpellManager{
|
|
spells: make(map[uint32]MockSpell),
|
|
}
|
|
}
|
|
|
|
// AddMockSpell adds a mock spell for testing
|
|
func (msm *MockSpellManager) AddMockSpell(id uint32, name string, icon uint32, tier int8, description string) {
|
|
msm.spells[id] = MockSpell{
|
|
id: id,
|
|
name: name,
|
|
icon: icon,
|
|
iconBackdrop: icon + 1000,
|
|
tier: tier,
|
|
description: description,
|
|
}
|
|
}
|
|
|
|
func init() {
|
|
log.Printf("Item system interfaces initialized")
|
|
}
|