package trade import ( "sync" "time" ) // TradeItemInfo represents an item in a trade slot // Converted from C++ TradeItemInfo struct type TradeItemInfo struct { Item *Item // TODO: Replace with actual Item type when available Quantity int32 // Quantity of the item being traded } // CoinAmounts represents the breakdown of coins in EQ2 currency type CoinAmounts struct { Platinum int32 // Platinum coins Gold int32 // Gold coins Silver int32 // Silver coins Copper int32 // Copper coins (base unit) } // TradeState represents the current state of a trade type TradeState int32 const ( TradeStateActive TradeState = 0 // Trade is active and ongoing TradeStateAccepted TradeState = 1 // Trade has been accepted by both parties TradeStateCanceled TradeState = 2 // Trade was canceled TradeStateCompleted TradeState = 3 // Trade was completed successfully ) // TradeValidationError represents validation errors during trade operations type TradeValidationError struct { Code int32 // Error code from trade constants Message string // Human readable error message } // Error implements the error interface func (e *TradeValidationError) Error() string { return e.Message } // TradeParticipant represents one side of a trade type TradeParticipant struct { EntityID int32 // Entity ID of the participant Items map[int8]TradeItemInfo // Items being traded by slot Coins int64 // Total coins being offered (in copper) HasAccepted bool // Whether participant has accepted the trade MaxSlots int8 // Maximum trade slots for this participant IsBot bool // Whether this participant is a bot ClientVersion int32 // Client version (affects slot count) } // NewTradeParticipant creates a new trade participant func NewTradeParticipant(entityID int32, isBot bool, clientVersion int32) *TradeParticipant { maxSlots := TradeMaxSlotsDefault if clientVersion <= 561 { maxSlots = TradeMaxSlotsLegacy } return &TradeParticipant{ EntityID: entityID, Items: make(map[int8]TradeItemInfo), Coins: 0, HasAccepted: false, MaxSlots: int8(maxSlots), IsBot: isBot, ClientVersion: clientVersion, } } // GetNextFreeSlot finds the next available slot for items func (tp *TradeParticipant) GetNextFreeSlot() int8 { for slot := int8(0); slot < tp.MaxSlots; slot++ { if _, exists := tp.Items[slot]; !exists { return slot } } return TradeSlotAutoFind // No free slots available } // HasItem checks if participant has a specific item in trade func (tp *TradeParticipant) HasItem(itemID int32) bool { for _, itemInfo := range tp.Items { if itemInfo.Item != nil && itemInfo.Item.GetID() == itemID { return true } } return false } // GetItemCount returns the total number of items in trade func (tp *TradeParticipant) GetItemCount() int { return len(tp.Items) } // ClearItems removes all items from the trade func (tp *TradeParticipant) ClearItems() { tp.Items = make(map[int8]TradeItemInfo) } // GetCoinAmounts converts total copper to coin denominations func (tp *TradeParticipant) GetCoinAmounts() CoinAmounts { return CalculateCoins(tp.Coins) } // Item represents a placeholder item interface // TODO: Replace with actual Item implementation when available type Item interface { GetID() int32 GetName() string GetQuantity() int32 GetIcon(version int32) int32 IsNoTrade() bool IsHeirloom() bool IsAttuned() bool GetCreationTime() time.Time GetGroupCharacterIDs() []int32 } // Entity represents a placeholder entity interface // TODO: Replace with actual Entity implementation when available type Entity interface { GetID() int32 GetName() string IsPlayer() bool IsBot() bool HasCoins(amount int64) bool GetClientVersion() int32 } // TradeManager handles multiple active trades type TradeManager struct { trades map[int32]*Trade // Active trades by trader1 ID mutex sync.RWMutex // Thread safety } // NewTradeManager creates a new trade manager func NewTradeManager() *TradeManager { return &TradeManager{ trades: make(map[int32]*Trade), } } // GetTrade retrieves an active trade for an entity func (tm *TradeManager) GetTrade(entityID int32) *Trade { tm.mutex.RLock() defer tm.mutex.RUnlock() // Check if entity is trader1 if trade, exists := tm.trades[entityID]; exists { return trade } // Check if entity is trader2 for _, trade := range tm.trades { if trade.GetTrader2ID() == entityID { return trade } } return nil } // AddTrade adds a new trade to management func (tm *TradeManager) AddTrade(trade *Trade) { tm.mutex.Lock() defer tm.mutex.Unlock() tm.trades[trade.GetTrader1ID()] = trade } // RemoveTrade removes a trade from management func (tm *TradeManager) RemoveTrade(trader1ID int32) { tm.mutex.Lock() defer tm.mutex.Unlock() delete(tm.trades, trader1ID) } // GetActiveTradeCount returns the number of active trades func (tm *TradeManager) GetActiveTradeCount() int { tm.mutex.RLock() defer tm.mutex.RUnlock() return len(tm.trades) }