eq2go/internal/items/item.go

1012 lines
24 KiB
Go

package items
import (
"fmt"
"strconv"
"strings"
"sync"
"time"
)
// NewItem creates a new item instance
func NewItem() *Item {
return &Item{
Details: ItemCore{
UniqueID: NextUniqueID(),
Count: 1,
},
GenericInfo: GenericInfo{
Condition: DefaultItemCondition,
},
GroupedCharIDs: make(map[int32]bool),
Created: time.Now(),
}
}
// NewItemFromTemplate creates a new item from an existing item template
func NewItemFromTemplate(template *Item) *Item {
if template == nil {
return NewItem()
}
item := &Item{
// Copy basic information
LowerName: template.LowerName,
Name: template.Name,
Description: template.Description,
StackCount: template.StackCount,
SellPrice: template.SellPrice,
SellStatus: template.SellStatus,
MaxSellValue: template.MaxSellValue,
// Copy metadata
WeaponType: template.WeaponType,
SpellID: template.SpellID,
SpellTier: template.SpellTier,
ItemScript: template.ItemScript,
BookLanguage: template.BookLanguage,
EffectType: template.EffectType,
// Initialize new instance data
Details: ItemCore{
ItemID: template.Details.ItemID,
UniqueID: NextUniqueID(),
Count: 1,
Icon: template.Details.Icon,
ClassicIcon: template.Details.ClassicIcon,
Tier: template.Details.Tier,
RecommendedLevel: template.Details.RecommendedLevel,
},
GenericInfo: template.GenericInfo,
GroupedCharIDs: make(map[int32]bool),
Created: time.Now(),
}
// Copy type-specific information
if template.WeaponInfo != nil {
weaponInfo := *template.WeaponInfo
item.WeaponInfo = &weaponInfo
}
if template.RangedInfo != nil {
rangedInfo := *template.RangedInfo
item.RangedInfo = &rangedInfo
}
if template.ArmorInfo != nil {
armorInfo := *template.ArmorInfo
item.ArmorInfo = &armorInfo
}
if template.AdornmentInfo != nil {
adornmentInfo := *template.AdornmentInfo
item.AdornmentInfo = &adornmentInfo
}
if template.BagInfo != nil {
bagInfo := *template.BagInfo
item.BagInfo = &bagInfo
}
if template.FoodInfo != nil {
foodInfo := *template.FoodInfo
item.FoodInfo = &foodInfo
}
if template.BaubleInfo != nil {
baubleInfo := *template.BaubleInfo
item.BaubleInfo = &baubleInfo
}
if template.BookInfo != nil {
bookInfo := *template.BookInfo
item.BookInfo = &bookInfo
}
if template.HouseItemInfo != nil {
houseItemInfo := *template.HouseItemInfo
item.HouseItemInfo = &houseItemInfo
}
if template.HouseContainerInfo != nil {
houseContainerInfo := *template.HouseContainerInfo
item.HouseContainerInfo = &houseContainerInfo
}
if template.SkillInfo != nil {
skillInfo := *template.SkillInfo
item.SkillInfo = &skillInfo
}
if template.RecipeBookInfo != nil {
recipeBookInfo := *template.RecipeBookInfo
item.RecipeBookInfo = &recipeBookInfo
}
if template.ItemSetInfo != nil {
itemSetInfo := *template.ItemSetInfo
item.ItemSetInfo = &itemSetInfo
}
if template.ThrownInfo != nil {
thrownInfo := *template.ThrownInfo
item.ThrownInfo = &thrownInfo
}
// Copy collections (deep copy)
if len(template.Classifications) > 0 {
item.Classifications = make([]*Classifications, len(template.Classifications))
for i, c := range template.Classifications {
classification := *c
item.Classifications[i] = &classification
}
}
if len(template.ItemStats) > 0 {
item.ItemStats = make([]*ItemStat, len(template.ItemStats))
for i, s := range template.ItemStats {
stat := *s
item.ItemStats[i] = &stat
}
}
if len(template.ItemSets) > 0 {
item.ItemSets = make([]*ItemSet, len(template.ItemSets))
for i, s := range template.ItemSets {
set := *s
item.ItemSets[i] = &set
}
}
if len(template.ItemStringStats) > 0 {
item.ItemStringStats = make([]*ItemStatString, len(template.ItemStringStats))
for i, s := range template.ItemStringStats {
stat := *s
item.ItemStringStats[i] = &stat
}
}
if len(template.ItemLevelOverrides) > 0 {
item.ItemLevelOverrides = make([]*ItemLevelOverride, len(template.ItemLevelOverrides))
for i, o := range template.ItemLevelOverrides {
override := *o
item.ItemLevelOverrides[i] = &override
}
}
if len(template.ItemEffects) > 0 {
item.ItemEffects = make([]*ItemEffect, len(template.ItemEffects))
for i, e := range template.ItemEffects {
effect := *e
item.ItemEffects[i] = &effect
}
}
if len(template.BookPages) > 0 {
item.BookPages = make([]*BookPage, len(template.BookPages))
for i, p := range template.BookPages {
page := *p
item.BookPages[i] = &page
}
}
if len(template.SlotData) > 0 {
item.SlotData = make([]int8, len(template.SlotData))
copy(item.SlotData, template.SlotData)
}
return item
}
// Copy creates a deep copy of the item
func (i *Item) Copy() *Item {
if i == nil {
return nil
}
i.mutex.RLock()
defer i.mutex.RUnlock()
return NewItemFromTemplate(i)
}
// AddEffect adds an effect to the item
func (i *Item) AddEffect(effect string, percentage int8, subBulletFlag int8) {
i.mutex.Lock()
defer i.mutex.Unlock()
itemEffect := &ItemEffect{
Effect: effect,
Percentage: percentage,
SubBulletFlag: subBulletFlag,
}
i.ItemEffects = append(i.ItemEffects, itemEffect)
}
// AddBookPage adds a page to the book item
func (i *Item) AddBookPage(page int8, pageText string, vAlign int8, hAlign int8) {
i.mutex.Lock()
defer i.mutex.Unlock()
bookPage := &BookPage{
Page: page,
PageText: pageText,
VAlign: vAlign,
HAlign: hAlign,
}
i.BookPages = append(i.BookPages, bookPage)
}
// GetMaxSellValue returns the maximum sell value for the item
func (i *Item) GetMaxSellValue() int32 {
i.mutex.RLock()
defer i.mutex.RUnlock()
return i.MaxSellValue
}
// SetMaxSellValue sets the maximum sell value for the item
func (i *Item) SetMaxSellValue(val int32) {
i.mutex.Lock()
defer i.mutex.Unlock()
i.MaxSellValue = val
}
// GetOverrideLevel gets the level override for specific classes
func (i *Item) GetOverrideLevel(adventureClass int8, tradeskillClass int8) int16 {
i.mutex.RLock()
defer i.mutex.RUnlock()
for _, override := range i.ItemLevelOverrides {
if override.AdventureClass == adventureClass && override.TradeskillClass == tradeskillClass {
return override.Level
}
}
return 0
}
// AddLevelOverride adds a level override for specific classes
func (i *Item) AddLevelOverride(adventureClass int8, tradeskillClass int8, level int16) {
i.mutex.Lock()
defer i.mutex.Unlock()
override := &ItemLevelOverride{
AdventureClass: adventureClass,
TradeskillClass: tradeskillClass,
Level: level,
}
i.ItemLevelOverrides = append(i.ItemLevelOverrides, override)
}
// CheckClassLevel checks if the item meets class and level requirements
func (i *Item) CheckClassLevel(adventureClass int8, tradeskillClass int8, level int16) bool {
i.mutex.RLock()
defer i.mutex.RUnlock()
// Check for specific level override
overrideLevel := i.GetOverrideLevel(adventureClass, tradeskillClass)
if overrideLevel > 0 {
return level >= overrideLevel
}
// Check general requirements
if adventureClass > 0 && i.GenericInfo.AdventureDefaultLevel > 0 {
return level >= i.GenericInfo.AdventureDefaultLevel
}
if tradeskillClass > 0 && i.GenericInfo.TradeskillDefaultLevel > 0 {
return level >= i.GenericInfo.TradeskillDefaultLevel
}
return true
}
// CheckClass checks if the item can be used by the specified classes
func (i *Item) CheckClass(adventureClass int8, tradeskillClass int8) bool {
i.mutex.RLock()
defer i.mutex.RUnlock()
// Check adventure class requirements
if adventureClass > 0 && i.GenericInfo.AdventureClasses > 0 {
classBit := int64(1 << uint(adventureClass))
if (i.GenericInfo.AdventureClasses & classBit) == 0 {
return false
}
}
// Check tradeskill class requirements
if tradeskillClass > 0 && i.GenericInfo.TradeskillClasses > 0 {
classBit := int64(1 << uint(tradeskillClass))
if (i.GenericInfo.TradeskillClasses & classBit) == 0 {
return false
}
}
return true
}
// SetAppearance sets the appearance information for the item
func (i *Item) SetAppearance(appearanceType int16, red int8, green int8, blue int8, highlightRed int8, highlightGreen int8, highlightBlue int8) {
i.mutex.Lock()
defer i.mutex.Unlock()
i.GenericInfo.AppearanceID = appearanceType
i.GenericInfo.AppearanceRed = red
i.GenericInfo.AppearanceGreen = green
i.GenericInfo.AppearanceBlue = blue
i.GenericInfo.AppearanceHighlightRed = highlightRed
i.GenericInfo.AppearanceHighlightGreen = highlightGreen
i.GenericInfo.AppearanceHighlightBlue = highlightBlue
}
// AddStat adds a stat to the item
func (i *Item) AddStat(stat *ItemStat) {
if stat == nil {
return
}
i.mutex.Lock()
defer i.mutex.Unlock()
statCopy := *stat
// Ensure StatTypeCombined is set correctly
statCopy.StatTypeCombined = (int16(statCopy.StatType) << 8) | statCopy.StatSubtype
i.ItemStats = append(i.ItemStats, &statCopy)
}
// AddStatByValues adds a stat using individual values
func (i *Item) AddStatByValues(statType int32, subType int16, value float32, level int8, name string) {
i.mutex.Lock()
defer i.mutex.Unlock()
stat := &ItemStat{
StatName: name,
StatType: statType,
StatSubtype: subType,
StatTypeCombined: (int16(statType) << 8) | subType,
Value: value,
Level: level,
}
i.ItemStats = append(i.ItemStats, stat)
}
// HasStat checks if the item has a specific stat
func (i *Item) HasStat(statID uint32, statName string) bool {
i.mutex.RLock()
defer i.mutex.RUnlock()
for _, stat := range i.ItemStats {
if statName != "" && strings.EqualFold(stat.StatName, statName) {
return true
}
// Check by stat ID - removed > 0 check since ItemStatStr is 0
if statName == "" && uint32(stat.StatTypeCombined) == statID {
return true
}
}
return false
}
// AddSet adds an item set to the item
func (i *Item) AddSet(set *ItemSet) {
if set == nil {
return
}
i.mutex.Lock()
defer i.mutex.Unlock()
setCopy := *set
i.ItemSets = append(i.ItemSets, &setCopy)
}
// AddSetByValues adds an item set using individual values
func (i *Item) AddSetByValues(itemID int32, itemCRC int32, itemIcon int16, itemStackSize int32, itemListColor int32, name string, language int8) {
i.mutex.Lock()
defer i.mutex.Unlock()
set := &ItemSet{
ItemID: itemID,
ItemCRC: itemCRC,
ItemIcon: itemIcon,
ItemStackSize: int16(itemStackSize),
ItemListColor: itemListColor,
Name: name,
Language: language,
}
i.ItemSets = append(i.ItemSets, set)
}
// DeleteItemSets removes all item sets from the item
func (i *Item) DeleteItemSets() {
i.mutex.Lock()
defer i.mutex.Unlock()
i.ItemSets = nil
}
// AddStatString adds a string stat to the item
func (i *Item) AddStatString(statString *ItemStatString) {
if statString == nil {
return
}
i.mutex.Lock()
defer i.mutex.Unlock()
statCopy := *statString
i.ItemStringStats = append(i.ItemStringStats, &statCopy)
}
// SetWeaponType sets the weapon type
func (i *Item) SetWeaponType(weaponType int8) {
i.mutex.Lock()
defer i.mutex.Unlock()
i.WeaponType = weaponType
}
// GetWeaponType gets the weapon type
func (i *Item) GetWeaponType() int8 {
i.mutex.RLock()
defer i.mutex.RUnlock()
return i.WeaponType
}
// HasSlot checks if the item can be equipped in specific slots
func (i *Item) HasSlot(slot int8, slot2 int8) bool {
i.mutex.RLock()
defer i.mutex.RUnlock()
for _, slotData := range i.SlotData {
if slotData == slot || (slot2 != -1 && slotData == slot2) {
return true
}
}
return false
}
// HasAdorn0 checks if the item has an adornment in slot 0
func (i *Item) HasAdorn0() bool {
i.mutex.RLock()
defer i.mutex.RUnlock()
return i.Adorn0 > 0
}
// HasAdorn1 checks if the item has an adornment in slot 1
func (i *Item) HasAdorn1() bool {
i.mutex.RLock()
defer i.mutex.RUnlock()
return i.Adorn1 > 0
}
// HasAdorn2 checks if the item has an adornment in slot 2
func (i *Item) HasAdorn2() bool {
i.mutex.RLock()
defer i.mutex.RUnlock()
return i.Adorn2 > 0
}
// SetItemType sets the item type
func (i *Item) SetItemType(itemType int8) {
i.mutex.Lock()
defer i.mutex.Unlock()
i.GenericInfo.ItemType = itemType
}
// CheckFlag checks if the item has a specific flag set
func (i *Item) CheckFlag(flag int32) bool {
i.mutex.RLock()
defer i.mutex.RUnlock()
return (int32(i.GenericInfo.ItemFlags) & flag) != 0
}
// CheckFlag2 checks if the item has a specific flag2 set
func (i *Item) CheckFlag2(flag int32) bool {
i.mutex.RLock()
defer i.mutex.RUnlock()
return (int32(i.GenericInfo.ItemFlags2) & flag) != 0
}
// AddSlot adds a slot to the item's slot data
func (i *Item) AddSlot(slotID int8) {
i.mutex.Lock()
defer i.mutex.Unlock()
// Check if slot already exists
for _, slot := range i.SlotData {
if slot == slotID {
return
}
}
i.SlotData = append(i.SlotData, slotID)
}
// SetSlots sets the slots using a bitmask
func (i *Item) SetSlots(slots int32) {
i.mutex.Lock()
defer i.mutex.Unlock()
i.SlotData = nil
// Convert bitmask to slot array
for slotID := int8(0); slotID < 32; slotID++ {
if (slots & (1 << uint(slotID))) != 0 {
i.SlotData = append(i.SlotData, slotID)
}
}
}
// GetIcon returns the appropriate icon for the given client version
func (i *Item) GetIcon(version int16) int16 {
i.mutex.RLock()
defer i.mutex.RUnlock()
// Use classic icon for older clients
if version < 1000 && i.Details.ClassicIcon > 0 {
return i.Details.ClassicIcon
}
return i.Details.Icon
}
// TryLockItem attempts to lock the item for a specific reason
func (i *Item) TryLockItem(reason LockReason) bool {
i.mutex.Lock()
defer i.mutex.Unlock()
if i.Details.ItemLocked {
// Check if already locked for this reason
if (LockReason(i.Details.LockFlags) & reason) != 0 {
return true // Already locked for this reason
}
return false // Locked for different reason
}
i.Details.ItemLocked = true
i.Details.LockFlags = int32(reason)
return true
}
// TryUnlockItem attempts to unlock the item for a specific reason
func (i *Item) TryUnlockItem(reason LockReason) bool {
i.mutex.Lock()
defer i.mutex.Unlock()
if !i.Details.ItemLocked {
return true // Already unlocked
}
// Remove the specific lock reason
currentFlags := LockReason(i.Details.LockFlags)
newFlags := currentFlags & ^reason
if newFlags == 0 {
// No more lock reasons, unlock the item
i.Details.ItemLocked = false
i.Details.LockFlags = 0
} else {
// Still have other lock reasons
i.Details.LockFlags = int32(newFlags)
}
return true
}
// IsItemLocked checks if the item is locked
func (i *Item) IsItemLocked() bool {
i.mutex.RLock()
defer i.mutex.RUnlock()
return i.Details.ItemLocked
}
// IsItemLockedFor checks if the item is locked for a specific reason
func (i *Item) IsItemLockedFor(reason LockReason) bool {
i.mutex.RLock()
defer i.mutex.RUnlock()
if !i.Details.ItemLocked {
return false
}
return (LockReason(i.Details.LockFlags) & reason) != 0
}
// SetItemScript sets the item script
func (i *Item) SetItemScript(script string) {
i.mutex.Lock()
defer i.mutex.Unlock()
i.ItemScript = script
}
// GetItemScript returns the item script
func (i *Item) GetItemScript() string {
i.mutex.RLock()
defer i.mutex.RUnlock()
return i.ItemScript
}
// CalculateRepairCost calculates the repair cost for the item
func (i *Item) CalculateRepairCost() int32 {
i.mutex.RLock()
defer i.mutex.RUnlock()
// Basic repair cost calculation based on item level and condition
baseRepairCost := int32(i.Details.RecommendedLevel * 10)
// Adjust based on condition (lower condition = higher repair cost)
conditionMultiplier := float32(100-i.GenericInfo.Condition) / 100.0
return int32(float32(baseRepairCost) * conditionMultiplier)
}
// CreateItemLink creates an item link for chat/display
func (i *Item) CreateItemLink(clientVersion int16, useUniqueID bool) string {
i.mutex.RLock()
defer i.mutex.RUnlock()
var builder strings.Builder
builder.WriteString("[item:")
if useUniqueID {
builder.WriteString(strconv.FormatInt(i.Details.UniqueID, 10))
} else {
builder.WriteString(strconv.FormatInt(int64(i.Details.ItemID), 10))
}
builder.WriteString(":")
builder.WriteString(strconv.FormatInt(int64(i.Details.Count), 10))
builder.WriteString(":")
builder.WriteString(strconv.FormatInt(int64(i.Details.Tier), 10))
builder.WriteString("]")
builder.WriteString(i.Name)
builder.WriteString("[/item]")
return builder.String()
}
// Validate validates the item data
func (i *Item) Validate() *ItemValidationResult {
i.mutex.RLock()
defer i.mutex.RUnlock()
result := &ItemValidationResult{Valid: true}
// Check required fields
if i.Name == "" {
result.Valid = false
result.Errors = append(result.Errors, "item name is required")
}
if len(i.Name) > MaxItemNameLength {
result.Valid = false
result.Errors = append(result.Errors, fmt.Sprintf("item name exceeds maximum length of %d", MaxItemNameLength))
}
if len(i.Description) > MaxItemDescLength {
result.Valid = false
result.Errors = append(result.Errors, fmt.Sprintf("item description exceeds maximum length of %d", MaxItemDescLength))
}
if i.Details.ItemID <= 0 {
result.Valid = false
result.Errors = append(result.Errors, "item ID must be positive")
}
if i.Details.Count <= 0 {
result.Valid = false
result.Errors = append(result.Errors, "item count must be positive")
}
if i.GenericInfo.Condition < 0 || i.GenericInfo.Condition > 100 {
result.Valid = false
result.Errors = append(result.Errors, "item condition must be between 0 and 100")
}
// Validate item type-specific data
switch i.GenericInfo.ItemType {
case ItemTypeWeapon:
if i.WeaponInfo == nil {
result.Valid = false
result.Errors = append(result.Errors, "weapon items must have weapon info")
}
case ItemTypeArmor:
if i.ArmorInfo == nil {
result.Valid = false
result.Errors = append(result.Errors, "armor items must have armor info")
}
case ItemTypeBag:
if i.BagInfo == nil {
result.Valid = false
result.Errors = append(result.Errors, "bag items must have bag info")
}
}
return result
}
// String returns a string representation of the item
func (i *Item) String() string {
i.mutex.RLock()
defer i.mutex.RUnlock()
return fmt.Sprintf("Item{ID: %d, Name: %s, Type: %d, Count: %d}",
i.Details.ItemID, i.Name, i.GenericInfo.ItemType, i.Details.Count)
}
// Global unique ID counter
var (
uniqueIDCounter int64 = 1
uniqueIDMutex sync.Mutex
)
// NextUniqueID generates the next unique ID for items
func NextUniqueID() int64 {
uniqueIDMutex.Lock()
defer uniqueIDMutex.Unlock()
id := uniqueIDCounter
uniqueIDCounter++
return id
}
// Item type checking methods
// IsNormal checks if the item is a normal item
func (i *Item) IsNormal() bool {
i.mutex.RLock()
defer i.mutex.RUnlock()
return i.GenericInfo.ItemType == ItemTypeNormal
}
// IsWeapon checks if the item is a weapon
func (i *Item) IsWeapon() bool {
i.mutex.RLock()
defer i.mutex.RUnlock()
return i.GenericInfo.ItemType == ItemTypeWeapon
}
// IsArmor checks if the item is armor
func (i *Item) IsArmor() bool {
i.mutex.RLock()
defer i.mutex.RUnlock()
return i.GenericInfo.ItemType == ItemTypeArmor
}
// IsRanged checks if the item is a ranged weapon
func (i *Item) IsRanged() bool {
i.mutex.RLock()
defer i.mutex.RUnlock()
return i.GenericInfo.ItemType == ItemTypeRanged
}
// IsBag checks if the item is a bag
func (i *Item) IsBag() bool {
i.mutex.RLock()
defer i.mutex.RUnlock()
return i.GenericInfo.ItemType == ItemTypeBag
}
// IsFood checks if the item is food
func (i *Item) IsFood() bool {
i.mutex.RLock()
defer i.mutex.RUnlock()
return i.GenericInfo.ItemType == ItemTypeFood
}
// IsBauble checks if the item is a bauble
func (i *Item) IsBauble() bool {
i.mutex.RLock()
defer i.mutex.RUnlock()
return i.GenericInfo.ItemType == ItemTypeBauble
}
// IsSkill checks if the item is a skill item
func (i *Item) IsSkill() bool {
i.mutex.RLock()
defer i.mutex.RUnlock()
return i.GenericInfo.ItemType == ItemTypeSkill
}
// IsHouseItem checks if the item is a house item
func (i *Item) IsHouseItem() bool {
i.mutex.RLock()
defer i.mutex.RUnlock()
return i.GenericInfo.ItemType == ItemTypeHouse
}
// IsHouseContainer checks if the item is a house container
func (i *Item) IsHouseContainer() bool {
i.mutex.RLock()
defer i.mutex.RUnlock()
return i.GenericInfo.ItemType == ItemTypeHouseContainer
}
// IsShield checks if the item is a shield
func (i *Item) IsShield() bool {
i.mutex.RLock()
defer i.mutex.RUnlock()
return i.GenericInfo.ItemType == ItemTypeShield
}
// IsAdornment checks if the item is an adornment
func (i *Item) IsAdornment() bool {
i.mutex.RLock()
defer i.mutex.RUnlock()
return i.GenericInfo.ItemType == ItemTypeAdornment
}
// IsBook checks if the item is a book
func (i *Item) IsBook() bool {
i.mutex.RLock()
defer i.mutex.RUnlock()
return i.GenericInfo.ItemType == ItemTypeBook
}
// IsThrown checks if the item is a thrown weapon
func (i *Item) IsThrown() bool {
i.mutex.RLock()
defer i.mutex.RUnlock()
return i.GenericInfo.ItemType == ItemTypeThrown
}
// IsHarvest checks if the item is harvestable
func (i *Item) IsHarvest() bool {
i.mutex.RLock()
defer i.mutex.RUnlock()
return i.GenericInfo.Harvest > 0
}
// IsBodyDrop checks if the item drops on death
func (i *Item) IsBodyDrop() bool {
i.mutex.RLock()
defer i.mutex.RUnlock()
return i.GenericInfo.BodyDrop > 0
}
// IsCollectable checks if the item is collectable
func (i *Item) IsCollectable() bool {
i.mutex.RLock()
defer i.mutex.RUnlock()
return i.GenericInfo.Collectable > 0
}
// Additional broker-specific type checks
// IsAmmo checks if the item is ammunition
func (i *Item) IsAmmo() bool {
// TODO: Implement ammo detection logic based on item properties
return false
}
// IsChainArmor checks if the item is chain armor
func (i *Item) IsChainArmor() bool {
// TODO: Implement chain armor detection logic
return false
}
// IsCloak checks if the item is a cloak
func (i *Item) IsCloak() bool {
// TODO: Implement cloak detection logic
return false
}
// IsClothArmor checks if the item is cloth armor
func (i *Item) IsClothArmor() bool {
// TODO: Implement cloth armor detection logic
return false
}
// IsCrushWeapon checks if the item is a crush weapon
func (i *Item) IsCrushWeapon() bool {
// TODO: Implement crush weapon detection logic
return false
}
// IsFoodFood checks if the item is food (not drink)
func (i *Item) IsFoodFood() bool {
i.mutex.RLock()
defer i.mutex.RUnlock()
return i.IsFood() && i.FoodInfo != nil && i.FoodInfo.Type == 1
}
// IsFoodDrink checks if the item is a drink
func (i *Item) IsFoodDrink() bool {
i.mutex.RLock()
defer i.mutex.RUnlock()
return i.IsFood() && i.FoodInfo != nil && i.FoodInfo.Type == 0
}
// IsJewelry checks if the item is jewelry
func (i *Item) IsJewelry() bool {
// TODO: Implement jewelry detection logic
return false
}
// IsLeatherArmor checks if the item is leather armor
func (i *Item) IsLeatherArmor() bool {
// TODO: Implement leather armor detection logic
return false
}
// IsMisc checks if the item is miscellaneous
func (i *Item) IsMisc() bool {
// TODO: Implement misc item detection logic
return false
}
// IsPierceWeapon checks if the item is a pierce weapon
func (i *Item) IsPierceWeapon() bool {
// TODO: Implement pierce weapon detection logic
return false
}
// IsPlateArmor checks if the item is plate armor
func (i *Item) IsPlateArmor() bool {
// TODO: Implement plate armor detection logic
return false
}
// IsPoison checks if the item is poison
func (i *Item) IsPoison() bool {
// TODO: Implement poison detection logic
return false
}
// IsPotion checks if the item is a potion
func (i *Item) IsPotion() bool {
// TODO: Implement potion detection logic
return false
}
// IsRecipeBook checks if the item is a recipe book
func (i *Item) IsRecipeBook() bool {
i.mutex.RLock()
defer i.mutex.RUnlock()
return i.GenericInfo.ItemType == ItemTypeRecipe
}
// IsSalesDisplay checks if the item is a sales display
func (i *Item) IsSalesDisplay() bool {
// TODO: Implement sales display detection logic
return false
}
// IsSlashWeapon checks if the item is a slash weapon
func (i *Item) IsSlashWeapon() bool {
// TODO: Implement slash weapon detection logic
return false
}
// IsSpellScroll checks if the item is a spell scroll
func (i *Item) IsSpellScroll() bool {
// TODO: Implement spell scroll detection logic
return false
}
// IsTinkered checks if the item is tinkered
func (i *Item) IsTinkered() bool {
i.mutex.RLock()
defer i.mutex.RUnlock()
return i.Tinkered
}
// IsTradeskill checks if the item is a tradeskill item
func (i *Item) IsTradeskill() bool {
// TODO: Implement tradeskill item detection logic
return false
}
// Item system initialized
func init() {
// Items system initialized
}