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 }