207 lines
6.0 KiB
Go
207 lines
6.0 KiB
Go
package trade
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
)
|
|
|
|
// CalculateCoins converts a total copper amount to coin denominations
|
|
// Converted from C++ Trade::CalculateCoins
|
|
func CalculateCoins(totalCopper int64) CoinAmounts {
|
|
coins := CoinAmounts{}
|
|
remaining := totalCopper
|
|
|
|
// Calculate platinum (1,000,000 copper = 1 platinum)
|
|
if remaining >= CoinsPlatinumThreshold {
|
|
coins.Platinum = int32(remaining / CoinsPlatinumThreshold)
|
|
remaining -= int64(coins.Platinum) * CoinsPlatinumThreshold
|
|
}
|
|
|
|
// Calculate gold (10,000 copper = 1 gold)
|
|
if remaining >= CoinsGoldThreshold {
|
|
coins.Gold = int32(remaining / CoinsGoldThreshold)
|
|
remaining -= int64(coins.Gold) * CoinsGoldThreshold
|
|
}
|
|
|
|
// Calculate silver (100 copper = 1 silver)
|
|
if remaining >= CoinsSilverThreshold {
|
|
coins.Silver = int32(remaining / CoinsSilverThreshold)
|
|
remaining -= int64(coins.Silver) * CoinsSilverThreshold
|
|
}
|
|
|
|
// Remaining is copper
|
|
if remaining > 0 {
|
|
coins.Copper = int32(remaining)
|
|
}
|
|
|
|
return coins
|
|
}
|
|
|
|
// CoinsToCopper converts coin denominations to total copper
|
|
func CoinsToCopper(coins CoinAmounts) int64 {
|
|
total := int64(coins.Copper)
|
|
total += int64(coins.Silver) * CoinsSilverThreshold
|
|
total += int64(coins.Gold) * CoinsGoldThreshold
|
|
total += int64(coins.Platinum) * CoinsPlatinumThreshold
|
|
return total
|
|
}
|
|
|
|
// FormatCoins returns a human-readable string representation of coins
|
|
func FormatCoins(totalCopper int64) string {
|
|
if totalCopper == 0 {
|
|
return "0 copper"
|
|
}
|
|
|
|
coins := CalculateCoins(totalCopper)
|
|
parts := make([]string, 0, 4)
|
|
|
|
if coins.Platinum > 0 {
|
|
parts = append(parts, fmt.Sprintf("%d platinum", coins.Platinum))
|
|
}
|
|
if coins.Gold > 0 {
|
|
parts = append(parts, fmt.Sprintf("%d gold", coins.Gold))
|
|
}
|
|
if coins.Silver > 0 {
|
|
parts = append(parts, fmt.Sprintf("%d silver", coins.Silver))
|
|
}
|
|
if coins.Copper > 0 {
|
|
parts = append(parts, fmt.Sprintf("%d copper", coins.Copper))
|
|
}
|
|
|
|
return strings.Join(parts, ", ")
|
|
}
|
|
|
|
// ValidateTradeSlot checks if a slot number is valid for a participant
|
|
func ValidateTradeSlot(slot int8, maxSlots int8) bool {
|
|
return slot >= 0 && slot < maxSlots
|
|
}
|
|
|
|
// ValidateTradeQuantity checks if a quantity is valid for trading
|
|
func ValidateTradeQuantity(quantity, available int32) bool {
|
|
return quantity > 0 && quantity <= available
|
|
}
|
|
|
|
// FormatTradeError returns a formatted error message for trade operations
|
|
func FormatTradeError(code int32) string {
|
|
switch code {
|
|
case TradeResultSuccess:
|
|
return "Success"
|
|
case TradeResultAlreadyInTrade:
|
|
return "Item is already in the trade"
|
|
case TradeResultNoTrade:
|
|
return "Item cannot be traded"
|
|
case TradeResultHeirloom:
|
|
return "Heirloom item cannot be traded to this player"
|
|
case TradeResultInvalidSlot:
|
|
return "Invalid or occupied trade slot"
|
|
case TradeResultSlotOutOfRange:
|
|
return "Trade slot is out of range"
|
|
case TradeResultInsufficientQty:
|
|
return "Insufficient quantity to trade"
|
|
default:
|
|
return fmt.Sprintf("Unknown trade error: %d", code)
|
|
}
|
|
}
|
|
|
|
// GetClientMaxSlots returns the maximum trade slots for a client version
|
|
// Converted from C++ Trade constructor logic
|
|
func GetClientMaxSlots(clientVersion int32) int8 {
|
|
if clientVersion <= 561 {
|
|
return TradeMaxSlotsLegacy
|
|
}
|
|
return TradeMaxSlotsDefault
|
|
}
|
|
|
|
// IsValidTradeState checks if a trade operation is valid for the current state
|
|
func IsValidTradeState(state TradeState, operation string) bool {
|
|
switch operation {
|
|
case "add_item", "remove_item", "add_coins", "remove_coins", "accept":
|
|
return state == TradeStateActive
|
|
case "cancel":
|
|
return state == TradeStateActive
|
|
case "complete":
|
|
return state == TradeStateAccepted
|
|
default:
|
|
return false
|
|
}
|
|
}
|
|
|
|
// GenerateTradeLogEntry creates a log entry for trade operations
|
|
func GenerateTradeLogEntry(tradeID string, operation string, entityID int32, details interface{}) string {
|
|
return fmt.Sprintf("[Trade:%s] %s by entity %d: %v", tradeID, operation, entityID, details)
|
|
}
|
|
|
|
// CompareTradeItems checks if two trade item infos are equivalent
|
|
func CompareTradeItems(item1, item2 TradeItemInfo) bool {
|
|
if item1.Item == nil && item2.Item == nil {
|
|
return item1.Quantity == item2.Quantity
|
|
}
|
|
|
|
if item1.Item == nil || item2.Item == nil {
|
|
return false
|
|
}
|
|
|
|
return item1.Item.GetID() == item2.Item.GetID() &&
|
|
item1.Quantity == item2.Quantity
|
|
}
|
|
|
|
// CalculateTradeValue estimates the total value of items and coins in a trade
|
|
// This is a helper function for trade balancing and analysis
|
|
func CalculateTradeValue(participant *TradeParticipant) map[string]interface{} {
|
|
value := make(map[string]interface{})
|
|
|
|
// Add coin value
|
|
value["coins"] = participant.Coins
|
|
value["coins_formatted"] = FormatCoins(participant.Coins)
|
|
|
|
// Add item information
|
|
itemCount := len(participant.Items)
|
|
value["item_count"] = itemCount
|
|
|
|
if itemCount > 0 {
|
|
items := make([]map[string]interface{}, 0, itemCount)
|
|
for slot, itemInfo := range participant.Items {
|
|
itemData := make(map[string]interface{})
|
|
itemData["slot"] = slot
|
|
itemData["quantity"] = itemInfo.Quantity
|
|
if itemInfo.Item != nil {
|
|
itemData["item_id"] = itemInfo.Item.GetID()
|
|
itemData["item_name"] = itemInfo.Item.GetName()
|
|
}
|
|
items = append(items, itemData)
|
|
}
|
|
value["items"] = items
|
|
}
|
|
|
|
return value
|
|
}
|
|
|
|
// ValidateTradeCompletion checks if a trade is ready to be completed
|
|
func ValidateTradeCompletion(trade *Trade) []string {
|
|
errors := make([]string, 0)
|
|
|
|
if trade.GetState() != TradeStateActive {
|
|
errors = append(errors, "Trade is not in active state")
|
|
return errors
|
|
}
|
|
|
|
// Check if both parties have accepted
|
|
trader1Accepted := trade.HasAcceptedTrade(trade.GetTrader1ID())
|
|
trader2Accepted := trade.HasAcceptedTrade(trade.GetTrader2ID())
|
|
|
|
if !trader1Accepted {
|
|
errors = append(errors, "Trader 1 has not accepted the trade")
|
|
}
|
|
|
|
if !trader2Accepted {
|
|
errors = append(errors, "Trader 2 has not accepted the trade")
|
|
}
|
|
|
|
// TODO: Add additional validation when entity system is available:
|
|
// - Verify entities still exist and are online
|
|
// - Check inventory space for received items
|
|
// - Validate coin amounts against actual entity wealth
|
|
// - Check for item/trade restrictions that may have changed
|
|
|
|
return errors
|
|
} |