eq2go/internal/player/experience.go

312 lines
7.3 KiB
Go

package player
import (
"eq2emu/internal/entity"
"time"
)
// GetXPVitality returns the player's adventure XP vitality
func (p *Player) GetXPVitality() float32 {
return p.GetInfoStruct().GetXPVitality()
}
// GetTSXPVitality returns the player's tradeskill XP vitality
func (p *Player) GetTSXPVitality() float32 {
return p.GetInfoStruct().GetTSXPVitality()
}
// AdventureXPEnabled returns whether adventure XP is enabled
func (p *Player) AdventureXPEnabled() bool {
return p.GetInfoStruct().GetXPDebt() < 95.0 && p.GetCharacterFlag(CF_COMBAT_EXPERIENCE_ENABLED)
}
// TradeskillXPEnabled returns whether tradeskill XP is enabled
func (p *Player) TradeskillXPEnabled() bool {
return p.GetInfoStruct().GetTSXPDebt() < 95.0 && p.GetCharacterFlag(CF_QUEST_EXPERIENCE_ENABLED)
}
// SetNeededXP sets the needed XP to a specific value
func (p *Player) SetNeededXP(val int32) {
p.GetInfoStruct().SetXPNeeded(val)
}
// SetNeededXP sets the needed XP based on current level
func (p *Player) SetNeededXPByLevel() {
p.GetInfoStruct().SetXPNeeded(GetNeededXPByLevel(p.GetLevel()))
}
// SetXP sets the current XP
func (p *Player) SetXP(val int32) {
p.GetInfoStruct().SetXP(val)
}
// SetNeededTSXP sets the needed tradeskill XP to a specific value
func (p *Player) SetNeededTSXP(val int32) {
p.GetInfoStruct().SetTSXPNeeded(val)
}
// SetNeededTSXPByLevel sets the needed tradeskill XP based on current level
func (p *Player) SetNeededTSXPByLevel() {
p.GetInfoStruct().SetTSXPNeeded(GetNeededXPByLevel(p.GetTSLevel()))
}
// SetTSXP sets the current tradeskill XP
func (p *Player) SetTSXP(val int32) {
p.GetInfoStruct().SetTSXP(val)
}
// GetNeededXP returns the XP needed for next level
func (p *Player) GetNeededXP() int32 {
return p.GetInfoStruct().GetXPNeeded()
}
// GetXPDebt returns the current XP debt percentage
func (p *Player) GetXPDebt() float32 {
return p.GetInfoStruct().GetXPDebt()
}
// GetXP returns the current XP
func (p *Player) GetXP() int32 {
return p.GetInfoStruct().GetXP()
}
// GetNeededTSXP returns the tradeskill XP needed for next level
func (p *Player) GetNeededTSXP() int32 {
return p.GetInfoStruct().GetTSXPNeeded()
}
// GetTSXP returns the current tradeskill XP
func (p *Player) GetTSXP() int32 {
return p.GetInfoStruct().GetTSXP()
}
// AddXP adds adventure XP to the player
func (p *Player) AddXP(xpAmount int32) bool {
if xpAmount <= 0 {
return false
}
info := p.GetInfoStruct()
currentXP := info.GetXP()
neededXP := info.GetXPNeeded()
totalXP := currentXP + xpAmount
// Check if we've reached next level
if totalXP >= neededXP {
// Level up!
if p.GetLevel() < 100 { // Assuming max level is 100
// Calculate overflow XP
overflow := totalXP - neededXP
// Level up
p.SetLevel(p.GetLevel()+1, true)
p.SetNeededXPByLevel()
// Set XP to overflow amount
p.SetXP(overflow)
// TODO: Send level up packet/message
// TODO: Update stats for new level
// TODO: Check for new abilities/spells
return true
} else {
// At max level, just set to max
p.SetXP(neededXP - 1)
}
} else {
p.SetXP(totalXP)
}
// TODO: Send XP update packet
p.SetCharSheetChanged(true)
return true
}
// AddTSXP adds tradeskill XP to the player
func (p *Player) AddTSXP(xpAmount int32) bool {
if xpAmount <= 0 {
return false
}
info := p.GetInfoStruct()
currentXP := info.GetTSXP()
neededXP := info.GetTSXPNeeded()
totalXP := currentXP + xpAmount
// Check if we've reached next level
if totalXP >= neededXP {
// Level up!
if p.GetTSLevel() < 100 { // Assuming max TS level is 100
// Calculate overflow XP
overflow := totalXP - neededXP
// Level up
p.SetTSLevel(p.GetTSLevel() + 1)
p.SetNeededTSXPByLevel()
// Set XP to overflow amount
p.SetTSXP(overflow)
// TODO: Send level up packet/message
// TODO: Update stats for new level
// TODO: Check for new recipes
return true
} else {
// At max level, just set to max
p.SetTSXP(neededXP - 1)
}
} else {
p.SetTSXP(totalXP)
}
// TODO: Send XP update packet
p.SetCharSheetChanged(true)
return true
}
// DoubleXPEnabled returns whether double XP is enabled
func (p *Player) DoubleXPEnabled() bool {
// TODO: Check for double XP events, potions, etc.
return false
}
// CalculateXP calculates the XP reward from a victim
func (p *Player) CalculateXP(victim *entity.Spawn) float32 {
if victim == nil {
return 0
}
// TODO: Implement full XP calculation formula
// This is a simplified version
victimLevel := victim.GetLevel()
playerLevel := p.GetLevel()
levelDiff := int(victimLevel) - int(playerLevel)
// Base XP value
baseXP := float32(100 + (victimLevel * 10))
// Level difference modifier
var levelMod float32 = 1.0
if levelDiff < -5 {
// Grey con, minimal XP
levelMod = 0.1
} else if levelDiff < -2 {
// Green con, reduced XP
levelMod = 0.5
} else if levelDiff <= 2 {
// Blue/White con, normal XP
levelMod = 1.0
} else if levelDiff <= 4 {
// Yellow con, bonus XP
levelMod = 1.2
} else {
// Orange/Red con, high bonus XP
levelMod = 1.5
}
// Group modifier
groupMod := float32(1.0)
if p.group != nil {
// TODO: Calculate group bonus
groupMod = 0.8 // Simplified group penalty
}
// Vitality modifier
vitalityMod := float32(1.0)
if p.GetXPVitality() > 0 {
vitalityMod = 2.0 // Double XP with vitality
}
// Double XP modifier
doubleXPMod := float32(1.0)
if p.DoubleXPEnabled() {
doubleXPMod = 2.0
}
totalXP := baseXP * levelMod * groupMod * vitalityMod * doubleXPMod
return totalXP
}
// CalculateTSXP calculates tradeskill XP for a given level
func (p *Player) CalculateTSXP(level int8) float32 {
// TODO: Implement tradeskill XP calculation
// This is a simplified version
levelDiff := int(level) - int(p.GetTSLevel())
baseXP := float32(50 + (level * 5))
// Level difference modifier
var levelMod float32 = 1.0
if levelDiff < -5 {
levelMod = 0.1
} else if levelDiff < -2 {
levelMod = 0.5
} else if levelDiff <= 2 {
levelMod = 1.0
} else if levelDiff <= 4 {
levelMod = 1.2
} else {
levelMod = 1.5
}
// Vitality modifier
vitalityMod := float32(1.0)
if p.GetTSXPVitality() > 0 {
vitalityMod = 2.0
}
return baseXP * levelMod * vitalityMod
}
// CalculateOfflineDebtRecovery calculates debt recovery while offline
func (p *Player) CalculateOfflineDebtRecovery(unixTimestamp int32) {
currentTime := int32(time.Now().Unix())
timeDiff := currentTime - unixTimestamp
if timeDiff <= 0 {
return
}
// Calculate hours offline
hoursOffline := float32(timeDiff) / 3600.0
// Debt recovery rate per hour (example: 1% per hour)
debtRecoveryRate := float32(1.0)
// Calculate adventure debt recovery
currentDebt := p.GetInfoStruct().GetXPDebt()
if currentDebt > 0 {
recovery := debtRecoveryRate * hoursOffline
newDebt := currentDebt - recovery
if newDebt < 0 {
newDebt = 0
}
p.GetInfoStruct().SetXPDebt(newDebt)
}
// Calculate tradeskill debt recovery
currentTSDebt := p.GetInfoStruct().GetTSXPDebt()
if currentTSDebt > 0 {
recovery := debtRecoveryRate * hoursOffline
newDebt := currentTSDebt - recovery
if newDebt < 0 {
newDebt = 0
}
p.GetInfoStruct().SetTSXPDebt(newDebt)
}
}
// GetTSLevel returns the player's tradeskill level
func (p *Player) GetTSLevel() int8 {
return p.GetInfoStruct().GetTSLevel()
}
// SetTSLevel sets the player's tradeskill level
func (p *Player) SetTSLevel(level int8) {
p.GetInfoStruct().SetTSLevel(level)
p.SetCharSheetChanged(true)
}