304 lines
7.1 KiB
Go
304 lines
7.1 KiB
Go
package player
|
|
|
|
import (
|
|
"time"
|
|
|
|
"eq2emu/internal/spawn"
|
|
)
|
|
|
|
// GetXPVitality returns the player's adventure XP vitality
|
|
func (p *Player) GetXPVitality() float32 {
|
|
return p.GetInfoStructXPVitality()
|
|
}
|
|
|
|
// GetTSXPVitality returns the player's tradeskill XP vitality
|
|
func (p *Player) GetTSXPVitality() float32 {
|
|
return p.GetInfoStructTSXPVitality()
|
|
}
|
|
|
|
// AdventureXPEnabled returns whether adventure XP is enabled
|
|
func (p *Player) AdventureXPEnabled() bool {
|
|
return p.GetInfoStructXPDebt() < 95.0 && p.GetCharacterFlag(CF_COMBAT_EXPERIENCE_ENABLED)
|
|
}
|
|
|
|
// TradeskillXPEnabled returns whether tradeskill XP is enabled
|
|
func (p *Player) TradeskillXPEnabled() bool {
|
|
return p.GetInfoStructTSXPDebt() < 95.0 && p.GetCharacterFlag(CF_QUEST_EXPERIENCE_ENABLED)
|
|
}
|
|
|
|
// SetNeededXP sets the needed XP to a specific value
|
|
func (p *Player) SetNeededXP(val int32) {
|
|
p.SetInfoStructXPNeeded(float64(val))
|
|
}
|
|
|
|
// SetNeededXP sets the needed XP based on current level
|
|
func (p *Player) SetNeededXPByLevel() {
|
|
p.SetInfoStructXPNeeded(float64(GetNeededXPByLevel(p.GetLevel())))
|
|
}
|
|
|
|
// SetXP sets the current XP
|
|
func (p *Player) SetXP(val int32) {
|
|
p.SetInfoStructXP(float64(val))
|
|
}
|
|
|
|
// SetNeededTSXP sets the needed tradeskill XP to a specific value
|
|
func (p *Player) SetNeededTSXP(val int32) {
|
|
p.SetInfoStructTSXPNeeded(float64(val))
|
|
}
|
|
|
|
// SetNeededTSXPByLevel sets the needed tradeskill XP based on current level
|
|
func (p *Player) SetNeededTSXPByLevel() {
|
|
p.SetInfoStructTSXPNeeded(float64(GetNeededXPByLevel(p.GetTSLevel())))
|
|
}
|
|
|
|
// SetTSXP sets the current tradeskill XP
|
|
func (p *Player) SetTSXP(val int32) {
|
|
p.SetInfoStructTSXP(float64(val))
|
|
}
|
|
|
|
// GetNeededXP returns the XP needed for next level
|
|
func (p *Player) GetNeededXP() int32 {
|
|
return int32(p.GetInfoStructXPNeeded())
|
|
}
|
|
|
|
// GetXPDebt returns the current XP debt percentage
|
|
func (p *Player) GetXPDebt() float32 {
|
|
return p.GetInfoStructXPDebt()
|
|
}
|
|
|
|
// GetXP returns the current XP
|
|
func (p *Player) GetXP() int32 {
|
|
return int32(p.GetInfoStructXP())
|
|
}
|
|
|
|
// GetNeededTSXP returns the tradeskill XP needed for next level
|
|
func (p *Player) GetNeededTSXP() int32 {
|
|
return int32(p.GetInfoStructTSXPNeeded())
|
|
}
|
|
|
|
// GetTSXP returns the current tradeskill XP
|
|
func (p *Player) GetTSXP() int32 {
|
|
return int32(p.GetInfoStructTSXP())
|
|
}
|
|
|
|
// AddXP adds adventure XP to the player
|
|
func (p *Player) AddXP(xpAmount int32) bool {
|
|
if xpAmount <= 0 {
|
|
return false
|
|
}
|
|
|
|
currentXP := int32(p.GetInfoStructXP())
|
|
neededXP := int32(p.GetInfoStructXPNeeded())
|
|
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(int16(p.GetLevel())+1)
|
|
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 false
|
|
}
|
|
|
|
// AddTSXP adds tradeskill XP to the player
|
|
func (p *Player) AddTSXP(xpAmount int32) bool {
|
|
if xpAmount <= 0 {
|
|
return false
|
|
}
|
|
|
|
currentXP := int32(p.GetInfoStructTSXP())
|
|
neededXP := int32(p.GetInfoStructTSXPNeeded())
|
|
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 *spawn.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.GetInfoStructXPDebt()
|
|
if currentDebt > 0 {
|
|
recovery := debtRecoveryRate * hoursOffline
|
|
newDebt := currentDebt - recovery
|
|
if newDebt < 0 {
|
|
newDebt = 0
|
|
}
|
|
p.SetInfoStructXPDebt(newDebt)
|
|
}
|
|
|
|
// Calculate tradeskill debt recovery
|
|
currentTSDebt := p.GetInfoStructTSXPDebt()
|
|
if currentTSDebt > 0 {
|
|
recovery := debtRecoveryRate * hoursOffline
|
|
newDebt := currentTSDebt - recovery
|
|
if newDebt < 0 {
|
|
newDebt = 0
|
|
}
|
|
p.SetInfoStructTSXPDebt(newDebt)
|
|
}
|
|
}
|
|
|
|
// Note: GetTSLevel is now implemented in stubs.go
|
|
|
|
// Note: SetTSLevel is now implemented in stubs.go
|