573 lines
21 KiB
Go

package items
import (
"sync"
"time"
)
// Item effect types
type ItemEffectType int
const (
NoEffectType ItemEffectType = 0
EffectCureTypeTrauma ItemEffectType = 1
EffectCureTypeArcane ItemEffectType = 2
EffectCureTypeNoxious ItemEffectType = 3
EffectCureTypeElemental ItemEffectType = 4
EffectCureTypeCurse ItemEffectType = 5
EffectCureTypeMagic ItemEffectType = 6
EffectCureTypeAll ItemEffectType = 7
)
// Inventory slot types
type InventorySlotType int
const (
HouseVault InventorySlotType = -5
SharedBank InventorySlotType = -4
Bank InventorySlotType = -3
Overflow InventorySlotType = -2
UnknownInvSlotType InventorySlotType = -1
BaseInventory InventorySlotType = 0
)
// Lock reasons for items
type LockReason uint32
const (
LockReasonNone LockReason = 0
LockReasonHouse LockReason = 1 << 0
LockReasonCrafting LockReason = 1 << 1
LockReasonShop LockReason = 1 << 2
)
// Add item types for tracking how items were added
type AddItemType int
const (
NotSet AddItemType = 0
BuyFromBroker AddItemType = 1
GMCommand AddItemType = 2
)
// ItemStatsValues represents the complete stat bonuses from an item
type ItemStatsValues struct {
// Base stats
Str int16 `json:"str"`
Sta int16 `json:"sta"`
Agi int16 `json:"agi"`
Wis int16 `json:"wis"`
Int int16 `json:"int"`
// Resistances
VsSlash int16 `json:"vs_slash"`
VsCrush int16 `json:"vs_crush"`
VsPierce int16 `json:"vs_pierce"`
VsPhysical int16 `json:"vs_physical"`
VsHeat int16 `json:"vs_heat"`
VsCold int16 `json:"vs_cold"`
VsMagic int16 `json:"vs_magic"`
VsMental int16 `json:"vs_mental"`
VsDivine int16 `json:"vs_divine"`
VsDisease int16 `json:"vs_disease"`
VsPoison int16 `json:"vs_poison"`
// Pools
Health int16 `json:"health"`
Power int16 `json:"power"`
Concentration int8 `json:"concentration"`
// Abilities and damage
AbilityModifier int16 `json:"ability_modifier"`
CriticalMitigation int16 `json:"critical_mitigation"`
ExtraShieldBlockChance int16 `json:"extra_shield_block_chance"`
BeneficialCritChance int16 `json:"beneficial_crit_chance"`
CritBonus int16 `json:"crit_bonus"`
Potency int16 `json:"potency"`
HateGainMod int16 `json:"hate_gain_mod"`
AbilityReuseSpeed int16 `json:"ability_reuse_speed"`
AbilityCastingSpeed int16 `json:"ability_casting_speed"`
AbilityRecoverySpeed int16 `json:"ability_recovery_speed"`
SpellReuseSpeed int16 `json:"spell_reuse_speed"`
SpellMultiAttackChance int16 `json:"spell_multi_attack_chance"`
DPS int16 `json:"dps"`
AttackSpeed int16 `json:"attack_speed"`
MultiAttackChance int16 `json:"multi_attack_chance"`
Flurry int16 `json:"flurry"`
AEAutoattackChance int16 `json:"ae_autoattack_chance"`
Strikethrough int16 `json:"strikethrough"`
Accuracy int16 `json:"accuracy"`
OffensiveSpeed int16 `json:"offensive_speed"`
// Uncontested stats
UncontestedParry float32 `json:"uncontested_parry"`
UncontestedBlock float32 `json:"uncontested_block"`
UncontestedDodge float32 `json:"uncontested_dodge"`
UncontestedRiposte float32 `json:"uncontested_riposte"`
// Other
SizeMod float32 `json:"size_mod"`
}
// ItemCore contains the core data for an item instance
type ItemCore struct {
ItemID int32 `json:"item_id"`
SOEId int32 `json:"soe_id"`
BagID int32 `json:"bag_id"`
InvSlotID int32 `json:"inv_slot_id"`
SlotID int16 `json:"slot_id"`
EquipSlotID int16 `json:"equip_slot_id"` // used when a bag is equipped
AppearanceType int16 `json:"appearance_type"` // 0 for combat armor, 1 for appearance armor
Index int8 `json:"index"`
Icon int16 `json:"icon"`
ClassicIcon int16 `json:"classic_icon"`
Count int16 `json:"count"`
Tier int8 `json:"tier"`
NumSlots int8 `json:"num_slots"`
UniqueID int64 `json:"unique_id"`
NumFreeSlots int8 `json:"num_free_slots"`
RecommendedLevel int16 `json:"recommended_level"`
ItemLocked bool `json:"item_locked"`
LockFlags int32 `json:"lock_flags"`
NewItem bool `json:"new_item"`
NewIndex int16 `json:"new_index"`
}
// ItemStat represents a single stat on an item
type ItemStat struct {
StatName string `json:"stat_name"`
StatType int32 `json:"stat_type"`
StatSubtype int16 `json:"stat_subtype"`
StatTypeCombined int16 `json:"stat_type_combined"`
Value float32 `json:"value"`
Level int8 `json:"level"`
}
// ItemSet represents an item set piece
type ItemSet struct {
ItemID int32 `json:"item_id"`
ItemCRC int32 `json:"item_crc"`
ItemIcon int16 `json:"item_icon"`
ItemStackSize int16 `json:"item_stack_size"`
ItemListColor int32 `json:"item_list_color"`
Name string `json:"name"`
Language int8 `json:"language"`
}
// Classifications represents item classifications
type Classifications struct {
ClassificationID int32 `json:"classification_id"`
ClassificationName string `json:"classification_name"`
}
// ItemLevelOverride represents level overrides for specific classes
type ItemLevelOverride struct {
AdventureClass int8 `json:"adventure_class"`
TradeskillClass int8 `json:"tradeskill_class"`
Level int16 `json:"level"`
}
// ItemClass represents class requirements for an item
type ItemClass struct {
AdventureClass int8 `json:"adventure_class"`
TradeskillClass int8 `json:"tradeskill_class"`
Level int16 `json:"level"`
}
// ItemAppearance represents visual appearance data
type ItemAppearance struct {
Type int16 `json:"type"`
Red int8 `json:"red"`
Green int8 `json:"green"`
Blue int8 `json:"blue"`
HighlightRed int8 `json:"highlight_red"`
HighlightGreen int8 `json:"highlight_green"`
HighlightBlue int8 `json:"highlight_blue"`
}
// QuestRewardData represents quest reward information
type QuestRewardData struct {
QuestID int32 `json:"quest_id"`
IsTemporary bool `json:"is_temporary"`
Description string `json:"description"`
IsCollection bool `json:"is_collection"`
HasDisplayed bool `json:"has_displayed"`
TmpCoin int64 `json:"tmp_coin"`
TmpStatus int32 `json:"tmp_status"`
DbSaved bool `json:"db_saved"`
DbIndex int32 `json:"db_index"`
}
// Generic_Info contains general item information
type GenericInfo struct {
ShowName int8 `json:"show_name"`
CreatorFlag int8 `json:"creator_flag"`
ItemFlags int16 `json:"item_flags"`
ItemFlags2 int16 `json:"item_flags2"`
Condition int8 `json:"condition"`
Weight int32 `json:"weight"` // num/10
SkillReq1 int32 `json:"skill_req1"`
SkillReq2 int32 `json:"skill_req2"`
SkillMin int16 `json:"skill_min"`
ItemType int8 `json:"item_type"`
AppearanceID int16 `json:"appearance_id"`
AppearanceRed int8 `json:"appearance_red"`
AppearanceGreen int8 `json:"appearance_green"`
AppearanceBlue int8 `json:"appearance_blue"`
AppearanceHighlightRed int8 `json:"appearance_highlight_red"`
AppearanceHighlightGreen int8 `json:"appearance_highlight_green"`
AppearanceHighlightBlue int8 `json:"appearance_highlight_blue"`
Collectable int8 `json:"collectable"`
OffersQuestID int32 `json:"offers_quest_id"`
PartOfQuestID int32 `json:"part_of_quest_id"`
MaxCharges int16 `json:"max_charges"`
DisplayCharges int8 `json:"display_charges"`
AdventureClasses int64 `json:"adventure_classes"`
TradeskillClasses int64 `json:"tradeskill_classes"`
AdventureDefaultLevel int16 `json:"adventure_default_level"`
TradeskillDefaultLevel int16 `json:"tradeskill_default_level"`
Usable int8 `json:"usable"`
Harvest int8 `json:"harvest"`
BodyDrop int8 `json:"body_drop"`
PvPDescription int8 `json:"pvp_description"`
MercOnly int8 `json:"merc_only"`
MountOnly int8 `json:"mount_only"`
SetID int32 `json:"set_id"`
CollectableUnk int8 `json:"collectable_unk"`
OffersQuestName string `json:"offers_quest_name"`
RequiredByQuestName string `json:"required_by_quest_name"`
TransmutedMaterial int8 `json:"transmuted_material"`
}
// ArmorInfo contains armor-specific information
type ArmorInfo struct {
MitigationLow int16 `json:"mitigation_low"`
MitigationHigh int16 `json:"mitigation_high"`
}
// AdornmentInfo contains adornment-specific information
type AdornmentInfo struct {
Duration float32 `json:"duration"`
ItemTypes int16 `json:"item_types"`
SlotType int16 `json:"slot_type"`
}
// WeaponInfo contains weapon-specific information
type WeaponInfo struct {
WieldType int16 `json:"wield_type"`
DamageLow1 int16 `json:"damage_low1"`
DamageHigh1 int16 `json:"damage_high1"`
DamageLow2 int16 `json:"damage_low2"`
DamageHigh2 int16 `json:"damage_high2"`
DamageLow3 int16 `json:"damage_low3"`
DamageHigh3 int16 `json:"damage_high3"`
Delay int16 `json:"delay"`
Rating float32 `json:"rating"`
}
// ShieldInfo contains shield-specific information
type ShieldInfo struct {
ArmorInfo ArmorInfo `json:"armor_info"`
}
// RangedInfo contains ranged weapon information
type RangedInfo struct {
WeaponInfo WeaponInfo `json:"weapon_info"`
RangeLow int16 `json:"range_low"`
RangeHigh int16 `json:"range_high"`
}
// BagInfo contains bag-specific information
type BagInfo struct {
NumSlots int8 `json:"num_slots"`
WeightReduction int16 `json:"weight_reduction"`
}
// FoodInfo contains food/drink information
type FoodInfo struct {
Type int8 `json:"type"` // 0=water, 1=food
Level int8 `json:"level"`
Duration float32 `json:"duration"`
Satiation int8 `json:"satiation"`
}
// BaubleInfo contains bauble-specific information
type BaubleInfo struct {
Cast int16 `json:"cast"`
Recovery int16 `json:"recovery"`
Duration int32 `json:"duration"`
Recast float32 `json:"recast"`
DisplaySlotOptional int8 `json:"display_slot_optional"`
DisplayCastTime int8 `json:"display_cast_time"`
DisplayBaubleType int8 `json:"display_bauble_type"`
EffectRadius float32 `json:"effect_radius"`
MaxAOETargets int32 `json:"max_aoe_targets"`
DisplayUntilCancelled int8 `json:"display_until_cancelled"`
}
// BookInfo contains book-specific information
type BookInfo struct {
Language int8 `json:"language"`
Author string `json:"author"`
Title string `json:"title"`
}
// BookInfoPages represents a book page
type BookInfoPages struct {
Page int8 `json:"page"`
PageText string `json:"page_text"`
PageTextVAlign int8 `json:"page_text_valign"`
PageTextHAlign int8 `json:"page_text_halign"`
}
// SkillInfo contains skill book information
type SkillInfo struct {
SpellID int32 `json:"spell_id"`
SpellTier int32 `json:"spell_tier"`
}
// HouseItemInfo contains house item information
type HouseItemInfo struct {
StatusRentReduction int32 `json:"status_rent_reduction"`
CoinRentReduction float32 `json:"coin_rent_reduction"`
HouseOnly int8 `json:"house_only"`
HouseLocation int8 `json:"house_location"` // 0 = floor, 1 = ceiling, 2 = wall
}
// HouseContainerInfo contains house container information
type HouseContainerInfo struct {
AllowedTypes int64 `json:"allowed_types"`
NumSlots int8 `json:"num_slots"`
BrokerCommission int8 `json:"broker_commission"`
FenceCommission int8 `json:"fence_commission"`
}
// RecipeBookInfo contains recipe book information
type RecipeBookInfo struct {
Recipes []uint32 `json:"recipes"`
RecipeID int32 `json:"recipe_id"`
Uses int8 `json:"uses"`
}
// ItemSetInfo contains item set information
type ItemSetInfo struct {
ItemID int32 `json:"item_id"`
ItemCRC int32 `json:"item_crc"`
ItemIcon int16 `json:"item_icon"`
ItemStackSize int32 `json:"item_stack_size"`
ItemListColor int32 `json:"item_list_color"`
SOEItemIDUnsigned int32 `json:"soe_item_id_unsigned"`
SOEItemCRCUnsigned int32 `json:"soe_item_crc_unsigned"`
}
// ThrownInfo contains thrown weapon information
type ThrownInfo struct {
Range int32 `json:"range"`
DamageModifier int32 `json:"damage_modifier"`
HitBonus float32 `json:"hit_bonus"`
DamageType int32 `json:"damage_type"`
}
// ItemEffect represents an item effect
type ItemEffect struct {
Effect string `json:"effect"`
Percentage int8 `json:"percentage"`
SubBulletFlag int8 `json:"sub_bullet_flag"`
}
// BookPage represents a book page
type BookPage struct {
Page int8 `json:"page"`
PageText string `json:"page_text"`
VAlign int8 `json:"valign"`
HAlign int8 `json:"halign"`
}
// ItemStatString represents a string-based item stat
type ItemStatString struct {
StatString string `json:"stat_string"`
}
// Item represents a complete item with all its properties
type Item struct {
// Basic item information
LowerName string `json:"lower_name"`
Name string `json:"name"`
Description string `json:"description"`
StackCount int16 `json:"stack_count"`
SellPrice int32 `json:"sell_price"`
SellStatus int32 `json:"sell_status"`
MaxSellValue int32 `json:"max_sell_value"`
BrokerPrice int64 `json:"broker_price"`
// Search and state flags
IsSearchStoreItem bool `json:"is_search_store_item"`
IsSearchInInventory bool `json:"is_search_in_inventory"`
SaveNeeded bool `json:"save_needed"`
NoBuyBack bool `json:"no_buy_back"`
NoSale bool `json:"no_sale"`
NeedsDeletion bool `json:"needs_deletion"`
Crafted bool `json:"crafted"`
Tinkered bool `json:"tinkered"`
// Item metadata
WeaponType int8 `json:"weapon_type"`
Adornment string `json:"adornment"`
Creator string `json:"creator"`
SellerName string `json:"seller_name"`
SellerCharID int32 `json:"seller_char_id"`
SellerHouseID int64 `json:"seller_house_id"`
Created time.Time `json:"created"`
GroupedCharIDs map[int32]bool `json:"grouped_char_ids"`
EffectType ItemEffectType `json:"effect_type"`
BookLanguage int8 `json:"book_language"`
// Adornment slots
Adorn0 int32 `json:"adorn0"`
Adorn1 int32 `json:"adorn1"`
Adorn2 int32 `json:"adorn2"`
// Spell information
SpellID int32 `json:"spell_id"`
SpellTier int8 `json:"spell_tier"`
ItemScript string `json:"item_script"`
// Collections and arrays
Classifications []*Classifications `json:"classifications"`
ItemStats []*ItemStat `json:"item_stats"`
ItemSets []*ItemSet `json:"item_sets"`
ItemStringStats []*ItemStatString `json:"item_string_stats"`
ItemLevelOverrides []*ItemLevelOverride `json:"item_level_overrides"`
ItemEffects []*ItemEffect `json:"item_effects"`
BookPages []*BookPage `json:"book_pages"`
SlotData []int8 `json:"slot_data"`
// Core item data
Details ItemCore `json:"details"`
GenericInfo GenericInfo `json:"generic_info"`
// Type-specific information (pointers to allow nil for unused types)
WeaponInfo *WeaponInfo `json:"weapon_info,omitempty"`
RangedInfo *RangedInfo `json:"ranged_info,omitempty"`
ArmorInfo *ArmorInfo `json:"armor_info,omitempty"`
AdornmentInfo *AdornmentInfo `json:"adornment_info,omitempty"`
BagInfo *BagInfo `json:"bag_info,omitempty"`
FoodInfo *FoodInfo `json:"food_info,omitempty"`
BaubleInfo *BaubleInfo `json:"bauble_info,omitempty"`
BookInfo *BookInfo `json:"book_info,omitempty"`
BookInfoPages *BookInfoPages `json:"book_info_pages,omitempty"`
HouseItemInfo *HouseItemInfo `json:"house_item_info,omitempty"`
HouseContainerInfo *HouseContainerInfo `json:"house_container_info,omitempty"`
SkillInfo *SkillInfo `json:"skill_info,omitempty"`
RecipeBookInfo *RecipeBookInfo `json:"recipe_book_info,omitempty"`
ItemSetInfo *ItemSetInfo `json:"item_set_info,omitempty"`
ThrownInfo *ThrownInfo `json:"thrown_info,omitempty"`
// Thread safety
mutex sync.RWMutex
}
// MasterItemList manages all items in the game
type MasterItemList struct {
items map[int32]*Item `json:"items"`
mappedItemStatsStrings map[string]int32 `json:"mapped_item_stats_strings"`
mappedItemStatTypeIDs map[int32]string `json:"mapped_item_stat_type_ids"`
brokerItemMap map[*VersionRange]map[int64]int64 `json:"-"` // Complex type, exclude from JSON
mutex sync.RWMutex
}
// VersionRange represents a version range for broker item mapping
type VersionRange struct {
MinVersion int32 `json:"min_version"`
MaxVersion int32 `json:"max_version"`
}
// PlayerItemList manages a player's inventory
type PlayerItemList struct {
maxSavedIndex int32 `json:"max_saved_index"`
indexedItems map[int32]*Item `json:"indexed_items"`
items map[int32]map[int8]map[int16]*Item `json:"items"`
overflowItems []*Item `json:"overflow_items"`
packetCount int16 `json:"packet_count"`
xorPacket []byte `json:"-"` // Exclude from JSON
origPacket []byte `json:"-"` // Exclude from JSON
mutex sync.RWMutex
}
// EquipmentItemList manages equipped items for a character
type EquipmentItemList struct {
items [NumSlots]*Item `json:"items"`
appearanceType int8 `json:"appearance_type"` // 0 for normal equip, 1 for appearance
xorPacket []byte `json:"-"` // Exclude from JSON
origPacket []byte `json:"-"` // Exclude from JSON
mutex sync.RWMutex
}
// ItemManagerStats represents statistics about item management
type ItemManagerStats struct {
TotalItems int32 `json:"total_items"`
ItemsByType map[int8]int32 `json:"items_by_type"`
ItemsByTier map[int8]int32 `json:"items_by_tier"`
PlayersWithItems int32 `json:"players_with_items"`
TotalItemInstances int64 `json:"total_item_instances"`
AverageItemsPerPlayer float32 `json:"average_items_per_player"`
LastUpdate time.Time `json:"last_update"`
}
// ItemSearchCriteria represents search criteria for items
type ItemSearchCriteria struct {
Name string `json:"name"`
ItemType int64 `json:"item_type"`
LocationType int64 `json:"location_type"`
BrokerType int64 `json:"broker_type"`
MinPrice int64 `json:"min_price"`
MaxPrice int64 `json:"max_price"`
MinSkill int8 `json:"min_skill"`
MaxSkill int8 `json:"max_skill"`
Seller string `json:"seller"`
Adornment string `json:"adornment"`
MinTier int8 `json:"min_tier"`
MaxTier int8 `json:"max_tier"`
MinLevel int16 `json:"min_level"`
MaxLevel int16 `json:"max_level"`
ItemClass int8 `json:"item_class"`
AdditionalCriteria map[string]string `json:"additional_criteria"`
}
// ItemValidationResult represents the result of item validation
type ItemValidationResult struct {
Valid bool `json:"valid"`
Errors []string `json:"errors,omitempty"`
}
// ItemError represents an item-specific error
type ItemError struct {
message string
}
func (e *ItemError) Error() string {
return e.message
}
// NewItemError creates a new item error
func NewItemError(message string) *ItemError {
return &ItemError{message: message}
}
// IsItemError checks if an error is an ItemError
func IsItemError(err error) bool {
_, ok := err.(*ItemError)
return ok
}
// Common item errors
var (
ErrItemNotFound = NewItemError("item not found")
ErrInvalidItem = NewItemError("invalid item")
ErrItemLocked = NewItemError("item is locked")
ErrInsufficientSpace = NewItemError("insufficient inventory space")
ErrCannotEquip = NewItemError("cannot equip item")
ErrCannotTrade = NewItemError("cannot trade item")
ErrItemExpired = NewItemError("item has expired")
)