eq2go/internal/quests/rewards.go

427 lines
11 KiB
Go

package quests
// Reward management methods for Quest
// AddRewardCoins adds coin rewards
func (q *Quest) AddRewardCoins(copper, silver, gold, platinum int32) {
q.RewardCoins = int64(copper) + int64(silver)*100 + int64(gold)*10000 + int64(platinum)*1000000
q.SetSaveNeeded(true)
}
// AddRewardCoinsMax sets the maximum coin reward
func (q *Quest) AddRewardCoinsMax(coins int64) {
q.RewardCoinsMax = coins
q.SetSaveNeeded(true)
}
// AddRewardFaction adds a faction reward
func (q *Quest) AddRewardFaction(factionID int32, amount int32) {
q.RewardFactions[factionID] = amount
q.SetSaveNeeded(true)
}
// RemoveRewardFaction removes a faction reward
func (q *Quest) RemoveRewardFaction(factionID int32) bool {
if _, exists := q.RewardFactions[factionID]; exists {
delete(q.RewardFactions, factionID)
q.SetSaveNeeded(true)
return true
}
return false
}
// SetRewardStatus sets the status point reward
func (q *Quest) SetRewardStatus(amount int32) {
q.RewardStatus = amount
q.SetSaveNeeded(true)
}
// SetRewardComment sets the reward comment text
func (q *Quest) SetRewardComment(comment string) {
q.RewardComment = comment
q.SetSaveNeeded(true)
}
// SetRewardXP sets the experience point reward
func (q *Quest) SetRewardXP(xp int32) {
q.RewardExp = xp
q.SetSaveNeeded(true)
}
// SetRewardTSXP sets the tradeskill experience point reward
func (q *Quest) SetRewardTSXP(xp int32) {
q.RewardTSExp = xp
q.SetSaveNeeded(true)
}
// SetGeneratedCoin sets the generated coin amount
func (q *Quest) SetGeneratedCoin(coin int64) {
q.GeneratedCoin = coin
q.SetSaveNeeded(true)
}
// GetCoinsReward returns the base coin reward
func (q *Quest) GetCoinsReward() int64 {
return q.RewardCoins
}
// GetCoinsRewardMax returns the maximum coin reward
func (q *Quest) GetCoinsRewardMax() int64 {
return q.RewardCoinsMax
}
// GetGeneratedCoin returns the generated coin amount
func (q *Quest) GetGeneratedCoin() int64 {
return q.GeneratedCoin
}
// GetExpReward returns the experience point reward
func (q *Quest) GetExpReward() int32 {
return q.RewardExp
}
// GetTSExpReward returns the tradeskill experience point reward
func (q *Quest) GetTSExpReward() int32 {
return q.RewardTSExp
}
// GetStatusPoints returns the status point reward
func (q *Quest) GetStatusPoints() int32 {
return q.RewardStatus
}
// GetRewardFactions returns the faction rewards map
func (q *Quest) GetRewardFactions() map[int32]int32 {
return q.RewardFactions
}
// GetRewardFaction returns the faction reward amount for a specific faction
func (q *Quest) GetRewardFaction(factionID int32) (int32, bool) {
amount, exists := q.RewardFactions[factionID]
return amount, exists
}
// HasRewardFaction checks if a faction has a reward
func (q *Quest) HasRewardFaction(factionID int32) bool {
_, exists := q.RewardFactions[factionID]
return exists
}
// ClearAllRewards removes all rewards
func (q *Quest) ClearAllRewards() {
q.RewardCoins = 0
q.RewardCoinsMax = 0
q.RewardStatus = 0
q.RewardComment = ""
q.RewardExp = 0
q.RewardTSExp = 0
q.GeneratedCoin = 0
q.RewardFactions = make(map[int32]int32)
q.SetSaveNeeded(true)
}
// Temporary reward methods
// SetStatusTmpReward sets the temporary status reward
func (q *Quest) SetStatusTmpReward(status int32) {
q.TmpRewardStatus = status
q.SetSaveNeeded(true)
}
// GetStatusTmpReward returns the temporary status reward
func (q *Quest) GetStatusTmpReward() int32 {
return q.TmpRewardStatus
}
// SetCoinTmpReward sets the temporary coin reward
func (q *Quest) SetCoinTmpReward(coins int64) {
q.TmpRewardCoins = coins
q.SetSaveNeeded(true)
}
// GetCoinTmpReward returns the temporary coin reward
func (q *Quest) GetCoinTmpReward() int64 {
return q.TmpRewardCoins
}
// ClearTmpRewards clears temporary rewards
func (q *Quest) ClearTmpRewards() {
q.TmpRewardStatus = 0
q.TmpRewardCoins = 0
q.SetSaveNeeded(true)
}
// Status earning methods
// SetStatusToEarnMin sets the minimum status to earn
func (q *Quest) SetStatusToEarnMin(value int32) {
q.StatusToEarnMin = value
q.SetSaveNeeded(true)
}
// GetStatusToEarnMin returns the minimum status to earn
func (q *Quest) GetStatusToEarnMin() int32 {
return q.StatusToEarnMin
}
// SetStatusToEarnMax sets the maximum status to earn
func (q *Quest) SetStatusToEarnMax(value int32) {
q.StatusToEarnMax = value
q.SetSaveNeeded(true)
}
// GetStatusToEarnMax returns the maximum status to earn
func (q *Quest) GetStatusToEarnMax() int32 {
return q.StatusToEarnMax
}
// SetStatusEarned sets the quest status earned
func (q *Quest) SetStatusEarned(status int32) {
q.Status = status
q.SetSaveNeeded(true)
}
// GetStatusEarned returns the quest status earned
func (q *Quest) GetStatusEarned() int32 {
return q.Status
}
// Reward calculation methods
// CalculateCoinsReward calculates the actual coin reward based on level and other factors
func (q *Quest) CalculateCoinsReward(playerLevel int8) int64 {
baseReward := q.RewardCoins
if baseReward <= 0 {
return 0
}
// Use generated coin if set
if q.GeneratedCoin > 0 {
return q.GeneratedCoin
}
// Level-based coin scaling (simplified version)
levelMultiplier := float64(playerLevel) / float64(q.Level)
if levelMultiplier > 1.5 {
levelMultiplier = 1.5 // Cap the multiplier
} else if levelMultiplier < 0.5 {
levelMultiplier = 0.5 // Floor the multiplier
}
calculatedReward := int64(float64(baseReward) * levelMultiplier)
// Apply max reward cap if set
if q.RewardCoinsMax > 0 && calculatedReward > q.RewardCoinsMax {
calculatedReward = q.RewardCoinsMax
}
return calculatedReward
}
// CalculateExpReward calculates the actual experience reward based on level and other factors
func (q *Quest) CalculateExpReward(playerLevel int8) int32 {
baseReward := q.RewardExp
if baseReward <= 0 {
return 0
}
// Level-based experience scaling
if playerLevel > q.Level {
// Reduced XP for overleveled players
levelDiff := playerLevel - q.Level
reduction := float64(levelDiff) * 0.1
if reduction > 0.8 {
reduction = 0.8 // Max 80% reduction
}
return int32(float64(baseReward) * (1.0 - reduction))
} else if playerLevel < q.Level {
// Bonus XP for underleveled players (small bonus)
levelDiff := q.Level - playerLevel
bonus := float64(levelDiff) * 0.05
if bonus > 0.25 {
bonus = 0.25 // Max 25% bonus
}
return int32(float64(baseReward) * (1.0 + bonus))
}
return baseReward
}
// CalculateTSExpReward calculates the actual tradeskill experience reward
func (q *Quest) CalculateTSExpReward(playerTSLevel int8) int32 {
baseReward := q.RewardTSExp
if baseReward <= 0 {
return 0
}
// Similar scaling as regular XP but for tradeskill level
if playerTSLevel > q.Level {
levelDiff := playerTSLevel - q.Level
reduction := float64(levelDiff) * 0.1
if reduction > 0.8 {
reduction = 0.8
}
return int32(float64(baseReward) * (1.0 - reduction))
} else if playerTSLevel < q.Level {
levelDiff := q.Level - playerTSLevel
bonus := float64(levelDiff) * 0.05
if bonus > 0.25 {
bonus = 0.25
}
return int32(float64(baseReward) * (1.0 + bonus))
}
return baseReward
}
// CalculateStatusReward calculates the actual status reward
func (q *Quest) CalculateStatusReward() int32 {
// Use status earned if set, otherwise use base reward status
if q.Status > 0 {
return q.Status
}
return q.RewardStatus
}
// Reward validation methods
// ValidateRewards validates all quest rewards
func (q *Quest) ValidateRewards() error {
// Validate coin rewards
if q.RewardCoins < 0 {
return fmt.Errorf("reward coins cannot be negative")
}
if q.RewardCoinsMax < 0 {
return fmt.Errorf("reward coins max cannot be negative")
}
if q.RewardCoinsMax > 0 && q.RewardCoinsMax < q.RewardCoins {
return fmt.Errorf("reward coins max cannot be less than base reward coins")
}
// Validate experience rewards
if q.RewardExp < 0 {
return fmt.Errorf("reward experience cannot be negative")
}
if q.RewardTSExp < 0 {
return fmt.Errorf("reward tradeskill experience cannot be negative")
}
// Validate status rewards
if q.RewardStatus < 0 {
return fmt.Errorf("reward status cannot be negative")
}
if q.Status < 0 {
return fmt.Errorf("status earned cannot be negative")
}
// Validate temporary rewards
if q.TmpRewardCoins < 0 {
return fmt.Errorf("temporary reward coins cannot be negative")
}
if q.TmpRewardStatus < 0 {
return fmt.Errorf("temporary reward status cannot be negative")
}
// Validate status to earn ranges
if q.StatusToEarnMin < 0 {
return fmt.Errorf("status to earn min cannot be negative")
}
if q.StatusToEarnMax < 0 {
return fmt.Errorf("status to earn max cannot be negative")
}
if q.StatusToEarnMax > 0 && q.StatusToEarnMax < q.StatusToEarnMin {
return fmt.Errorf("status to earn max cannot be less than min")
}
// Validate faction rewards
for factionID, amount := range q.RewardFactions {
if factionID <= 0 {
return fmt.Errorf("invalid faction ID in rewards: %d", factionID)
}
// Faction amounts can be negative (reputation loss)
if amount < -50000 || amount > 50000 {
return fmt.Errorf("faction reward amount out of range for faction %d: %d", factionID, amount)
}
}
// Validate reward comment length
if len(q.RewardComment) > MaxCompleteActionLength {
return fmt.Errorf("reward comment too long (max %d)", MaxCompleteActionLength)
}
return nil
}
// Helper methods for coin conversion
// ConvertCoinsToComponents breaks down coins into copper, silver, gold, platinum
func ConvertCoinsToComponents(totalCoins int64) (copper, silver, gold, platinum int32) {
platinum = int32(totalCoins / 1000000)
remaining := totalCoins % 1000000
gold = int32(remaining / 10000)
remaining = remaining % 10000
silver = int32(remaining / 100)
copper = int32(remaining % 100)
return copper, silver, gold, platinum
}
// ConvertComponentsToCoins converts individual coin components to total coins
func ConvertComponentsToCoins(copper, silver, gold, platinum int32) int64 {
return int64(copper) + int64(silver)*100 + int64(gold)*10000 + int64(platinum)*1000000
}
// FormatCoinsString formats coins as a readable string
func FormatCoinsString(totalCoins int64) string {
if totalCoins == 0 {
return "0 copper"
}
copper, silver, gold, platinum := ConvertCoinsToComponents(totalCoins)
var parts []string
if platinum > 0 {
parts = append(parts, fmt.Sprintf("%d platinum", platinum))
}
if gold > 0 {
parts = append(parts, fmt.Sprintf("%d gold", gold))
}
if silver > 0 {
parts = append(parts, fmt.Sprintf("%d silver", silver))
}
if copper > 0 {
parts = append(parts, fmt.Sprintf("%d copper", copper))
}
if len(parts) == 0 {
return "0 copper"
}
if len(parts) == 1 {
return parts[0]
}
// Join with commas and "and" for the last item
result := ""
for i, part := range parts {
if i == 0 {
result = part
} else if i == len(parts)-1 {
result += " and " + part
} else {
result += ", " + part
}
}
return result
}