eq2go/internal/trade/types.go

189 lines
5.0 KiB
Go

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)
}