fix player package
This commit is contained in:
parent
8f8dbefece
commit
1987d48a77
@ -303,7 +303,7 @@ type PlayerDatabase interface {
|
||||
type PlayerEventHandler interface {
|
||||
OnPlayerLogin(player *Player) error
|
||||
OnPlayerLogout(player *Player) error
|
||||
OnPlayerDeath(player *Player, killer entity.Entity) error
|
||||
OnPlayerDeath(player *Player, killer *entity.Entity) error
|
||||
OnPlayerLevelUp(player *Player, newLevel int8) error
|
||||
// ... more events
|
||||
}
|
||||
|
@ -7,9 +7,9 @@ func (p *Player) SetCharacterFlag(flag int) {
|
||||
}
|
||||
|
||||
if flag < 32 {
|
||||
p.GetInfoStruct().SetFlags(p.GetInfoStruct().GetFlags() | (1 << uint(flag)))
|
||||
p.SetPlayerFlags(p.GetPlayerFlags() | (1 << uint(flag)))
|
||||
} else {
|
||||
p.GetInfoStruct().SetFlags2(p.GetInfoStruct().GetFlags2() | (1 << uint(flag-32)))
|
||||
p.SetPlayerFlags2(p.GetPlayerFlags2() | (1 << uint(flag-32)))
|
||||
}
|
||||
p.SetCharSheetChanged(true)
|
||||
}
|
||||
@ -21,9 +21,9 @@ func (p *Player) ResetCharacterFlag(flag int) {
|
||||
}
|
||||
|
||||
if flag < 32 {
|
||||
p.GetInfoStruct().SetFlags(p.GetInfoStruct().GetFlags() & ^(1 << uint(flag)))
|
||||
p.SetPlayerFlags(p.GetPlayerFlags() & ^(1 << uint(flag)))
|
||||
} else {
|
||||
p.GetInfoStruct().SetFlags2(p.GetInfoStruct().GetFlags2() & ^(1 << uint(flag-32)))
|
||||
p.SetPlayerFlags2(p.GetPlayerFlags2() & ^(1 << uint(flag-32)))
|
||||
}
|
||||
p.SetCharSheetChanged(true)
|
||||
}
|
||||
@ -49,9 +49,9 @@ func (p *Player) GetCharacterFlag(flag int) bool {
|
||||
|
||||
var ret bool
|
||||
if flag < 32 {
|
||||
ret = (p.GetInfoStruct().GetFlags() & (1 << uint(flag))) != 0
|
||||
ret = (p.GetPlayerFlags() & (1 << uint(flag))) != 0
|
||||
} else {
|
||||
ret = (p.GetInfoStruct().GetFlags2() & (1 << uint(flag-32))) != 0
|
||||
ret = (p.GetPlayerFlags2() & (1 << uint(flag-32))) != 0
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
@ -15,28 +15,28 @@ func (p *Player) InCombat(val bool, ranged bool) {
|
||||
p.SetCharacterFlag(CF_AUTO_ATTACK)
|
||||
}
|
||||
|
||||
// Set combat state in info struct
|
||||
prevState := p.GetInfoStruct().GetEngageCommands()
|
||||
// Set combat state
|
||||
prevState := p.GetPlayerEngageCommands()
|
||||
if ranged {
|
||||
p.GetInfoStruct().SetEngageCommands(prevState | RANGE_COMBAT_STATE)
|
||||
p.SetPlayerEngageCommands(prevState | RANGE_COMBAT_STATE)
|
||||
} else {
|
||||
p.GetInfoStruct().SetEngageCommands(prevState | MELEE_COMBAT_STATE)
|
||||
p.SetPlayerEngageCommands(prevState | MELEE_COMBAT_STATE)
|
||||
}
|
||||
} else {
|
||||
// Leaving combat
|
||||
if ranged {
|
||||
p.ResetCharacterFlag(CF_RANGED_AUTO_ATTACK)
|
||||
p.SetRangeAttack(false)
|
||||
prevState := p.GetInfoStruct().GetEngageCommands()
|
||||
p.GetInfoStruct().SetEngageCommands(prevState & ^RANGE_COMBAT_STATE)
|
||||
prevState := p.GetPlayerEngageCommands()
|
||||
p.SetPlayerEngageCommands(prevState & ^RANGE_COMBAT_STATE)
|
||||
} else {
|
||||
p.ResetCharacterFlag(CF_AUTO_ATTACK)
|
||||
prevState := p.GetInfoStruct().GetEngageCommands()
|
||||
p.GetInfoStruct().SetEngageCommands(prevState & ^MELEE_COMBAT_STATE)
|
||||
prevState := p.GetPlayerEngageCommands()
|
||||
p.SetPlayerEngageCommands(prevState & ^MELEE_COMBAT_STATE)
|
||||
}
|
||||
|
||||
// Clear combat target if leaving all combat
|
||||
if p.GetInfoStruct().GetEngageCommands() == 0 {
|
||||
if p.GetPlayerEngageCommands() == 0 {
|
||||
p.combatTarget = nil
|
||||
}
|
||||
}
|
||||
@ -47,18 +47,18 @@ func (p *Player) InCombat(val bool, ranged bool) {
|
||||
// ProcessCombat processes combat actions
|
||||
func (p *Player) ProcessCombat() {
|
||||
// Check if in combat
|
||||
if p.GetInfoStruct().GetEngageCommands() == 0 {
|
||||
if p.GetPlayerEngageCommands() == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
// Check if we have a valid target
|
||||
if p.combatTarget == nil || p.combatTarget.IsDead() {
|
||||
if p.combatTarget == nil || IsDead(p.combatTarget) {
|
||||
p.StopCombat(0)
|
||||
return
|
||||
}
|
||||
|
||||
// Check distance to target
|
||||
distance := p.GetDistance(&p.combatTarget.Spawn)
|
||||
distance := p.GetDistance(p.combatTarget.GetX(), p.combatTarget.GetY(), p.combatTarget.GetZ(), true)
|
||||
|
||||
// Process based on combat type
|
||||
if p.rangeAttack {
|
||||
@ -158,7 +158,7 @@ func (p *Player) CalculatePlayerHPPower(newLevel int16) {
|
||||
|
||||
// Base HP calculation
|
||||
baseHP := int32(50 + (newLevel * 20))
|
||||
staminaBonus := p.GetInfoStruct().GetSta() * 10
|
||||
staminaBonus := int32(p.GetInfoStruct().GetSta() * 10)
|
||||
totalHP := baseHP + staminaBonus
|
||||
|
||||
// Base Power calculation
|
||||
@ -195,12 +195,12 @@ func (p *Player) IsAllowedCombatEquip(slot int8, sendMessage bool) bool {
|
||||
}
|
||||
|
||||
// Check if in combat
|
||||
if p.GetInfoStruct().GetEngageCommands() != 0 {
|
||||
if p.GetPlayerEngageCommands() != 0 {
|
||||
// Some slots can't be changed in combat
|
||||
// TODO: Define which slots are restricted
|
||||
restrictedSlots := []int8{0, 1, 2} // Example: primary, secondary, ranged
|
||||
for _, restrictedSlot := range restrictedSlots {
|
||||
if slot == restrictedSlot || slot == 255 { // 255 = all slots
|
||||
if slot == restrictedSlot || slot == -1 { // -1 = all slots
|
||||
if sendMessage {
|
||||
// TODO: Send "You cannot change that equipment in combat" message
|
||||
}
|
||||
@ -247,7 +247,7 @@ func (p *Player) DismissAllPets() {
|
||||
// MentorTarget mentors the current target
|
||||
func (p *Player) MentorTarget() {
|
||||
target := p.GetTarget()
|
||||
if target == nil || !target.IsPlayer() {
|
||||
if target == nil {
|
||||
// TODO: Send "Invalid mentor target" message
|
||||
return
|
||||
}
|
||||
@ -273,7 +273,7 @@ func (p *Player) SetMentorStats(effectiveLevel int32, targetCharID int32, update
|
||||
effectiveLevel = int32(p.GetLevel())
|
||||
}
|
||||
|
||||
p.GetInfoStruct().SetEffectiveLevel(int8(effectiveLevel))
|
||||
p.GetInfoStruct().SetEffectiveLevel(int16(effectiveLevel))
|
||||
|
||||
if updateStats {
|
||||
// TODO: Recalculate all stats for new effective level
|
||||
|
@ -2,14 +2,14 @@ package player
|
||||
|
||||
// AddCoins adds coins to the player
|
||||
func (p *Player) AddCoins(val int64) {
|
||||
p.GetInfoStruct().AddCoin(val)
|
||||
p.AddCoin(val)
|
||||
p.sendCurrencyUpdate()
|
||||
}
|
||||
|
||||
// RemoveCoins removes coins from the player
|
||||
func (p *Player) RemoveCoins(val int64) bool {
|
||||
if p.GetInfoStruct().GetCoin() >= val {
|
||||
p.GetInfoStruct().SubtractCoin(val)
|
||||
if p.GetCoin() >= val {
|
||||
p.SubtractCoin(val)
|
||||
p.sendCurrencyUpdate()
|
||||
return true
|
||||
}
|
||||
@ -18,52 +18,52 @@ func (p *Player) RemoveCoins(val int64) bool {
|
||||
|
||||
// HasCoins checks if the player has enough coins
|
||||
func (p *Player) HasCoins(val int64) bool {
|
||||
return p.GetInfoStruct().GetCoin() >= val
|
||||
return p.GetCoin() >= val
|
||||
}
|
||||
|
||||
// GetCoinsCopper returns the copper coin amount
|
||||
func (p *Player) GetCoinsCopper() int32 {
|
||||
return p.GetInfoStruct().GetCoinCopper()
|
||||
return p.GetInfoStructCoinCopper()
|
||||
}
|
||||
|
||||
// GetCoinsSilver returns the silver coin amount
|
||||
func (p *Player) GetCoinsSilver() int32 {
|
||||
return p.GetInfoStruct().GetCoinSilver()
|
||||
return p.GetInfoStructCoinSilver()
|
||||
}
|
||||
|
||||
// GetCoinsGold returns the gold coin amount
|
||||
func (p *Player) GetCoinsGold() int32 {
|
||||
return p.GetInfoStruct().GetCoinGold()
|
||||
return p.GetInfoStructCoinGold()
|
||||
}
|
||||
|
||||
// GetCoinsPlat returns the platinum coin amount
|
||||
func (p *Player) GetCoinsPlat() int32 {
|
||||
return p.GetInfoStruct().GetCoinPlat()
|
||||
return p.GetInfoStructCoinPlat()
|
||||
}
|
||||
|
||||
// GetBankCoinsCopper returns the bank copper coin amount
|
||||
func (p *Player) GetBankCoinsCopper() int32 {
|
||||
return p.GetInfoStruct().GetBankCoinCopper()
|
||||
return p.GetInfoStructBankCoinCopper()
|
||||
}
|
||||
|
||||
// GetBankCoinsSilver returns the bank silver coin amount
|
||||
func (p *Player) GetBankCoinsSilver() int32 {
|
||||
return p.GetInfoStruct().GetBankCoinSilver()
|
||||
return p.GetInfoStructBankCoinSilver()
|
||||
}
|
||||
|
||||
// GetBankCoinsGold returns the bank gold coin amount
|
||||
func (p *Player) GetBankCoinsGold() int32 {
|
||||
return p.GetInfoStruct().GetBankCoinGold()
|
||||
return p.GetInfoStructBankCoinGold()
|
||||
}
|
||||
|
||||
// GetBankCoinsPlat returns the bank platinum coin amount
|
||||
func (p *Player) GetBankCoinsPlat() int32 {
|
||||
return p.GetInfoStruct().GetBankCoinPlat()
|
||||
return p.GetInfoStructBankCoinPlat()
|
||||
}
|
||||
|
||||
// GetStatusPoints returns the player's status points
|
||||
func (p *Player) GetStatusPoints() int32 {
|
||||
return p.GetInfoStruct().GetStatusPoints()
|
||||
return p.GetInfoStructStatusPoints()
|
||||
}
|
||||
|
||||
// sendCurrencyUpdate sends currency update packet to client
|
||||
|
227
internal/player/database.go
Normal file
227
internal/player/database.go
Normal file
@ -0,0 +1,227 @@
|
||||
package player
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sync"
|
||||
|
||||
"zombiezen.com/go/sqlite"
|
||||
"zombiezen.com/go/sqlite/sqlitex"
|
||||
)
|
||||
|
||||
// PlayerDatabase manages player data persistence using SQLite
|
||||
type PlayerDatabase struct {
|
||||
conn *sqlite.Conn
|
||||
mutex sync.RWMutex
|
||||
}
|
||||
|
||||
// NewPlayerDatabase creates a new player database instance
|
||||
func NewPlayerDatabase(conn *sqlite.Conn) *PlayerDatabase {
|
||||
return &PlayerDatabase{
|
||||
conn: conn,
|
||||
}
|
||||
}
|
||||
|
||||
// LoadPlayer loads a player from the database
|
||||
func (pdb *PlayerDatabase) LoadPlayer(characterID int32) (*Player, error) {
|
||||
pdb.mutex.RLock()
|
||||
defer pdb.mutex.RUnlock()
|
||||
|
||||
player := NewPlayer()
|
||||
player.SetCharacterID(characterID)
|
||||
found := false
|
||||
|
||||
query := `SELECT name, level, race, class, zone_id, x, y, z, heading
|
||||
FROM characters WHERE id = ?`
|
||||
|
||||
err := sqlitex.Execute(pdb.conn, query, &sqlitex.ExecOptions{
|
||||
Args: []any{characterID},
|
||||
ResultFunc: func(stmt *sqlite.Stmt) error {
|
||||
player.SetName(stmt.ColumnText(0))
|
||||
player.SetLevel(int16(stmt.ColumnInt(1)))
|
||||
player.SetRace(int8(stmt.ColumnInt(2)))
|
||||
player.SetClass(int8(stmt.ColumnInt(3)))
|
||||
player.SetZone(int32(stmt.ColumnInt(4)))
|
||||
player.SetX(float32(stmt.ColumnFloat(5)))
|
||||
player.SetY(float32(stmt.ColumnFloat(6)), false)
|
||||
player.SetZ(float32(stmt.ColumnFloat(7)))
|
||||
player.SetHeadingFromFloat(float32(stmt.ColumnFloat(8)))
|
||||
found = true
|
||||
return nil
|
||||
},
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to load player %d: %w", characterID, err)
|
||||
}
|
||||
|
||||
if !found {
|
||||
return nil, fmt.Errorf("player %d not found", characterID)
|
||||
}
|
||||
|
||||
return player, nil
|
||||
}
|
||||
|
||||
// SavePlayer saves a player to the database
|
||||
func (pdb *PlayerDatabase) SavePlayer(player *Player) error {
|
||||
if player == nil {
|
||||
return fmt.Errorf("cannot save nil player")
|
||||
}
|
||||
|
||||
pdb.mutex.Lock()
|
||||
defer pdb.mutex.Unlock()
|
||||
|
||||
characterID := player.GetCharacterID()
|
||||
if characterID == 0 {
|
||||
// Insert new player
|
||||
return pdb.insertPlayer(player)
|
||||
}
|
||||
|
||||
// Try to update existing player first
|
||||
err := pdb.updatePlayer(player)
|
||||
if err == nil {
|
||||
// Check if any rows were affected
|
||||
changes := pdb.conn.Changes()
|
||||
if changes == 0 {
|
||||
// No rows updated, record doesn't exist - insert it
|
||||
return pdb.insertPlayerWithID(player)
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// insertPlayer inserts a new player record
|
||||
func (pdb *PlayerDatabase) insertPlayer(player *Player) error {
|
||||
query := `INSERT INTO characters
|
||||
(name, level, race, class, zone_id, x, y, z, heading, created_date)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, datetime('now'))`
|
||||
|
||||
err := sqlitex.Execute(pdb.conn, query, &sqlitex.ExecOptions{
|
||||
Args: []any{
|
||||
player.GetName(),
|
||||
player.GetLevel(),
|
||||
player.GetRace(),
|
||||
player.GetClass(),
|
||||
player.GetZone(),
|
||||
player.GetX(),
|
||||
player.GetY(),
|
||||
player.GetZ(),
|
||||
player.GetHeading(),
|
||||
},
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to insert player %s: %w", player.GetName(), err)
|
||||
}
|
||||
|
||||
// Get the new character ID
|
||||
characterID := pdb.conn.LastInsertRowID()
|
||||
player.SetCharacterID(int32(characterID))
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// insertPlayerWithID inserts a player with a specific ID
|
||||
func (pdb *PlayerDatabase) insertPlayerWithID(player *Player) error {
|
||||
query := `INSERT INTO characters
|
||||
(id, name, level, race, class, zone_id, x, y, z, heading, created_date)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, datetime('now'))`
|
||||
|
||||
err := sqlitex.Execute(pdb.conn, query, &sqlitex.ExecOptions{
|
||||
Args: []any{
|
||||
player.GetCharacterID(),
|
||||
player.GetName(),
|
||||
player.GetLevel(),
|
||||
player.GetRace(),
|
||||
player.GetClass(),
|
||||
player.GetZone(),
|
||||
player.GetX(),
|
||||
player.GetY(),
|
||||
player.GetZ(),
|
||||
player.GetHeading(),
|
||||
},
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to insert player %s with ID %d: %w", player.GetName(), player.GetCharacterID(), err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// updatePlayer updates an existing player record
|
||||
func (pdb *PlayerDatabase) updatePlayer(player *Player) error {
|
||||
query := `UPDATE characters
|
||||
SET name = ?, level = ?, race = ?, class = ?, zone_id = ?,
|
||||
x = ?, y = ?, z = ?, heading = ?, last_save = datetime('now')
|
||||
WHERE id = ?`
|
||||
|
||||
err := sqlitex.Execute(pdb.conn, query, &sqlitex.ExecOptions{
|
||||
Args: []any{
|
||||
player.GetName(),
|
||||
player.GetLevel(),
|
||||
player.GetRace(),
|
||||
player.GetClass(),
|
||||
player.GetZone(),
|
||||
player.GetX(),
|
||||
player.GetY(),
|
||||
player.GetZ(),
|
||||
player.GetHeading(),
|
||||
player.GetCharacterID(),
|
||||
},
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to update player %d: %w", player.GetCharacterID(), err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeletePlayer deletes a player from the database
|
||||
func (pdb *PlayerDatabase) DeletePlayer(characterID int32) error {
|
||||
pdb.mutex.Lock()
|
||||
defer pdb.mutex.Unlock()
|
||||
|
||||
query := `DELETE FROM characters WHERE id = ?`
|
||||
|
||||
err := sqlitex.Execute(pdb.conn, query, &sqlitex.ExecOptions{
|
||||
Args: []any{characterID},
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to delete player %d: %w", characterID, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// CreateSchema creates the database schema for player data
|
||||
func (pdb *PlayerDatabase) CreateSchema() error {
|
||||
pdb.mutex.Lock()
|
||||
defer pdb.mutex.Unlock()
|
||||
|
||||
schema := `
|
||||
CREATE TABLE IF NOT EXISTS characters (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
name TEXT NOT NULL UNIQUE,
|
||||
level INTEGER DEFAULT 1,
|
||||
race INTEGER DEFAULT 1,
|
||||
class INTEGER DEFAULT 1,
|
||||
zone_id INTEGER DEFAULT 1,
|
||||
x REAL DEFAULT 0,
|
||||
y REAL DEFAULT 0,
|
||||
z REAL DEFAULT 0,
|
||||
heading REAL DEFAULT 0,
|
||||
hp INTEGER DEFAULT 100,
|
||||
power INTEGER DEFAULT 100,
|
||||
created_date TEXT,
|
||||
last_save TEXT,
|
||||
account_id INTEGER DEFAULT 0
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_characters_name ON characters(name);
|
||||
CREATE INDEX IF NOT EXISTS idx_characters_account ON characters(account_id);
|
||||
`
|
||||
|
||||
return sqlitex.ExecuteScript(pdb.conn, schema, &sqlitex.ExecOptions{})
|
||||
}
|
@ -1,83 +1,84 @@
|
||||
package player
|
||||
|
||||
import (
|
||||
"eq2emu/internal/entity"
|
||||
"time"
|
||||
|
||||
"eq2emu/internal/spawn"
|
||||
)
|
||||
|
||||
// GetXPVitality returns the player's adventure XP vitality
|
||||
func (p *Player) GetXPVitality() float32 {
|
||||
return p.GetInfoStruct().GetXPVitality()
|
||||
return p.GetInfoStructXPVitality()
|
||||
}
|
||||
|
||||
// GetTSXPVitality returns the player's tradeskill XP vitality
|
||||
func (p *Player) GetTSXPVitality() float32 {
|
||||
return p.GetInfoStruct().GetTSXPVitality()
|
||||
return p.GetInfoStructTSXPVitality()
|
||||
}
|
||||
|
||||
// AdventureXPEnabled returns whether adventure XP is enabled
|
||||
func (p *Player) AdventureXPEnabled() bool {
|
||||
return p.GetInfoStruct().GetXPDebt() < 95.0 && p.GetCharacterFlag(CF_COMBAT_EXPERIENCE_ENABLED)
|
||||
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.GetInfoStruct().GetTSXPDebt() < 95.0 && p.GetCharacterFlag(CF_QUEST_EXPERIENCE_ENABLED)
|
||||
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.GetInfoStruct().SetXPNeeded(val)
|
||||
p.SetInfoStructXPNeeded(float64(val))
|
||||
}
|
||||
|
||||
// SetNeededXP sets the needed XP based on current level
|
||||
func (p *Player) SetNeededXPByLevel() {
|
||||
p.GetInfoStruct().SetXPNeeded(GetNeededXPByLevel(p.GetLevel()))
|
||||
p.SetInfoStructXPNeeded(float64(GetNeededXPByLevel(p.GetLevel())))
|
||||
}
|
||||
|
||||
// SetXP sets the current XP
|
||||
func (p *Player) SetXP(val int32) {
|
||||
p.GetInfoStruct().SetXP(val)
|
||||
p.SetInfoStructXP(float64(val))
|
||||
}
|
||||
|
||||
// SetNeededTSXP sets the needed tradeskill XP to a specific value
|
||||
func (p *Player) SetNeededTSXP(val int32) {
|
||||
p.GetInfoStruct().SetTSXPNeeded(val)
|
||||
p.SetInfoStructTSXPNeeded(float64(val))
|
||||
}
|
||||
|
||||
// SetNeededTSXPByLevel sets the needed tradeskill XP based on current level
|
||||
func (p *Player) SetNeededTSXPByLevel() {
|
||||
p.GetInfoStruct().SetTSXPNeeded(GetNeededXPByLevel(p.GetTSLevel()))
|
||||
p.SetInfoStructTSXPNeeded(float64(GetNeededXPByLevel(p.GetTSLevel())))
|
||||
}
|
||||
|
||||
// SetTSXP sets the current tradeskill XP
|
||||
func (p *Player) SetTSXP(val int32) {
|
||||
p.GetInfoStruct().SetTSXP(val)
|
||||
p.SetInfoStructTSXP(float64(val))
|
||||
}
|
||||
|
||||
// GetNeededXP returns the XP needed for next level
|
||||
func (p *Player) GetNeededXP() int32 {
|
||||
return p.GetInfoStruct().GetXPNeeded()
|
||||
return int32(p.GetInfoStructXPNeeded())
|
||||
}
|
||||
|
||||
// GetXPDebt returns the current XP debt percentage
|
||||
func (p *Player) GetXPDebt() float32 {
|
||||
return p.GetInfoStruct().GetXPDebt()
|
||||
return p.GetInfoStructXPDebt()
|
||||
}
|
||||
|
||||
// GetXP returns the current XP
|
||||
func (p *Player) GetXP() int32 {
|
||||
return p.GetInfoStruct().GetXP()
|
||||
return int32(p.GetInfoStructXP())
|
||||
}
|
||||
|
||||
// GetNeededTSXP returns the tradeskill XP needed for next level
|
||||
func (p *Player) GetNeededTSXP() int32 {
|
||||
return p.GetInfoStruct().GetTSXPNeeded()
|
||||
return int32(p.GetInfoStructTSXPNeeded())
|
||||
}
|
||||
|
||||
// GetTSXP returns the current tradeskill XP
|
||||
func (p *Player) GetTSXP() int32 {
|
||||
return p.GetInfoStruct().GetTSXP()
|
||||
return int32(p.GetInfoStructTSXP())
|
||||
}
|
||||
|
||||
// AddXP adds adventure XP to the player
|
||||
@ -86,9 +87,8 @@ func (p *Player) AddXP(xpAmount int32) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
info := p.GetInfoStruct()
|
||||
currentXP := info.GetXP()
|
||||
neededXP := info.GetXPNeeded()
|
||||
currentXP := int32(p.GetInfoStructXP())
|
||||
neededXP := int32(p.GetInfoStructXPNeeded())
|
||||
totalXP := currentXP + xpAmount
|
||||
|
||||
// Check if we've reached next level
|
||||
@ -99,7 +99,7 @@ func (p *Player) AddXP(xpAmount int32) bool {
|
||||
overflow := totalXP - neededXP
|
||||
|
||||
// Level up
|
||||
p.SetLevel(p.GetLevel()+1, true)
|
||||
p.SetLevel(int16(p.GetLevel())+1)
|
||||
p.SetNeededXPByLevel()
|
||||
|
||||
// Set XP to overflow amount
|
||||
@ -120,7 +120,7 @@ func (p *Player) AddXP(xpAmount int32) bool {
|
||||
|
||||
// TODO: Send XP update packet
|
||||
p.SetCharSheetChanged(true)
|
||||
return true
|
||||
return false
|
||||
}
|
||||
|
||||
// AddTSXP adds tradeskill XP to the player
|
||||
@ -129,9 +129,8 @@ func (p *Player) AddTSXP(xpAmount int32) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
info := p.GetInfoStruct()
|
||||
currentXP := info.GetTSXP()
|
||||
neededXP := info.GetTSXPNeeded()
|
||||
currentXP := int32(p.GetInfoStructTSXP())
|
||||
neededXP := int32(p.GetInfoStructTSXPNeeded())
|
||||
totalXP := currentXP + xpAmount
|
||||
|
||||
// Check if we've reached next level
|
||||
@ -173,7 +172,7 @@ func (p *Player) DoubleXPEnabled() bool {
|
||||
}
|
||||
|
||||
// CalculateXP calculates the XP reward from a victim
|
||||
func (p *Player) CalculateXP(victim *entity.Spawn) float32 {
|
||||
func (p *Player) CalculateXP(victim *spawn.Spawn) float32 {
|
||||
if victim == nil {
|
||||
return 0
|
||||
}
|
||||
@ -277,35 +276,28 @@ func (p *Player) CalculateOfflineDebtRecovery(unixTimestamp int32) {
|
||||
debtRecoveryRate := float32(1.0)
|
||||
|
||||
// Calculate adventure debt recovery
|
||||
currentDebt := p.GetInfoStruct().GetXPDebt()
|
||||
currentDebt := p.GetInfoStructXPDebt()
|
||||
if currentDebt > 0 {
|
||||
recovery := debtRecoveryRate * hoursOffline
|
||||
newDebt := currentDebt - recovery
|
||||
if newDebt < 0 {
|
||||
newDebt = 0
|
||||
}
|
||||
p.GetInfoStruct().SetXPDebt(newDebt)
|
||||
p.SetInfoStructXPDebt(newDebt)
|
||||
}
|
||||
|
||||
// Calculate tradeskill debt recovery
|
||||
currentTSDebt := p.GetInfoStruct().GetTSXPDebt()
|
||||
currentTSDebt := p.GetInfoStructTSXPDebt()
|
||||
if currentTSDebt > 0 {
|
||||
recovery := debtRecoveryRate * hoursOffline
|
||||
newDebt := currentTSDebt - recovery
|
||||
if newDebt < 0 {
|
||||
newDebt = 0
|
||||
}
|
||||
p.GetInfoStruct().SetTSXPDebt(newDebt)
|
||||
p.SetInfoStructTSXPDebt(newDebt)
|
||||
}
|
||||
}
|
||||
|
||||
// GetTSLevel returns the player's tradeskill level
|
||||
func (p *Player) GetTSLevel() int8 {
|
||||
return p.GetInfoStruct().GetTSLevel()
|
||||
}
|
||||
// Note: GetTSLevel is now implemented in stubs.go
|
||||
|
||||
// SetTSLevel sets the player's tradeskill level
|
||||
func (p *Player) SetTSLevel(level int8) {
|
||||
p.GetInfoStruct().SetTSLevel(level)
|
||||
p.SetCharSheetChanged(true)
|
||||
}
|
||||
// Note: SetTSLevel is now implemented in stubs.go
|
||||
|
@ -4,6 +4,7 @@ import (
|
||||
"eq2emu/internal/entity"
|
||||
"eq2emu/internal/quests"
|
||||
"eq2emu/internal/skills"
|
||||
"eq2emu/internal/spawn"
|
||||
"eq2emu/internal/spells"
|
||||
)
|
||||
|
||||
@ -46,8 +47,8 @@ type PlayerManager interface {
|
||||
SendToZone(zoneID int32, message any) error
|
||||
}
|
||||
|
||||
// PlayerDatabase interface for database operations
|
||||
type PlayerDatabase interface {
|
||||
// PlayerDatabaseInterface interface for database operations (if needed for testing)
|
||||
type PlayerDatabaseInterface interface {
|
||||
// LoadPlayer loads a player from the database
|
||||
LoadPlayer(characterID int32) (*Player, error)
|
||||
|
||||
@ -56,30 +57,6 @@ type PlayerDatabase interface {
|
||||
|
||||
// DeletePlayer deletes a player from the database
|
||||
DeletePlayer(characterID int32) error
|
||||
|
||||
// LoadPlayerQuests loads player quests
|
||||
LoadPlayerQuests(characterID int32) ([]*quests.Quest, error)
|
||||
|
||||
// SavePlayerQuests saves player quests
|
||||
SavePlayerQuests(characterID int32, quests []*quests.Quest) error
|
||||
|
||||
// LoadPlayerSkills loads player skills
|
||||
LoadPlayerSkills(characterID int32) ([]*skills.Skill, error)
|
||||
|
||||
// SavePlayerSkills saves player skills
|
||||
SavePlayerSkills(characterID int32, skills []*skills.Skill) error
|
||||
|
||||
// LoadPlayerSpells loads player spells
|
||||
LoadPlayerSpells(characterID int32) ([]*SpellBookEntry, error)
|
||||
|
||||
// SavePlayerSpells saves player spells
|
||||
SavePlayerSpells(characterID int32, spells []*SpellBookEntry) error
|
||||
|
||||
// LoadPlayerHistory loads player history
|
||||
LoadPlayerHistory(characterID int32) (map[int8]map[int8][]*HistoryData, error)
|
||||
|
||||
// SavePlayerHistory saves player history
|
||||
SavePlayerHistory(characterID int32, history map[int8]map[int8][]*HistoryData) error
|
||||
}
|
||||
|
||||
// PlayerPacketHandler interface for handling player packets
|
||||
@ -103,7 +80,7 @@ type PlayerEventHandler interface {
|
||||
OnPlayerLogout(player *Player) error
|
||||
|
||||
// OnPlayerDeath called when player dies
|
||||
OnPlayerDeath(player *Player, killer entity.Entity) error
|
||||
OnPlayerDeath(player *Player, killer *entity.Entity) error
|
||||
|
||||
// OnPlayerResurrect called when player resurrects
|
||||
OnPlayerResurrect(player *Player) error
|
||||
@ -118,7 +95,7 @@ type PlayerEventHandler interface {
|
||||
OnPlayerQuestComplete(player *Player, quest *quests.Quest) error
|
||||
|
||||
// OnPlayerSpellCast called when player casts a spell
|
||||
OnPlayerSpellCast(player *Player, spell *spells.Spell, target entity.Entity) error
|
||||
OnPlayerSpellCast(player *Player, spell *spells.Spell, target *entity.Entity) error
|
||||
}
|
||||
|
||||
// PlayerValidator interface for validating player operations
|
||||
@ -130,7 +107,7 @@ type PlayerValidator interface {
|
||||
ValidateMovement(player *Player, x, y, z, heading float32) error
|
||||
|
||||
// ValidateSpellCast validates spell casting
|
||||
ValidateSpellCast(player *Player, spell *spells.Spell, target entity.Entity) error
|
||||
ValidateSpellCast(player *Player, spell *spells.Spell, target *entity.Entity) error
|
||||
|
||||
// ValidateItemUse validates item usage
|
||||
ValidateItemUse(player *Player, item *Item) error
|
||||
@ -169,10 +146,10 @@ type PlayerStatistics interface {
|
||||
RecordPlayerLogout(player *Player)
|
||||
|
||||
// RecordPlayerDeath records a player death
|
||||
RecordPlayerDeath(player *Player, killer entity.Entity)
|
||||
RecordPlayerDeath(player *Player, killer *entity.Entity)
|
||||
|
||||
// RecordPlayerKill records a player kill
|
||||
RecordPlayerKill(player *Player, victim entity.Entity)
|
||||
RecordPlayerKill(player *Player, victim *entity.Entity)
|
||||
|
||||
// RecordQuestComplete records a quest completion
|
||||
RecordQuestComplete(player *Player, quest *quests.Quest)
|
||||
@ -223,8 +200,8 @@ func (pa *PlayerAdapter) GetEntity() *entity.Entity {
|
||||
}
|
||||
|
||||
// GetSpawn returns the player as a spawn
|
||||
func (pa *PlayerAdapter) GetSpawn() *entity.Spawn {
|
||||
return &pa.player.Entity.Spawn
|
||||
func (pa *PlayerAdapter) GetSpawn() *spawn.Spawn {
|
||||
return pa.player.Entity.Spawn
|
||||
}
|
||||
|
||||
// IsPlayer always returns true for player adapter
|
||||
@ -314,10 +291,10 @@ func (pa *PlayerAdapter) IsAlive() bool {
|
||||
|
||||
// IsInCombat returns whether the player is in combat
|
||||
func (pa *PlayerAdapter) IsInCombat() bool {
|
||||
return pa.player.GetInfoStruct().GetEngageCommands() != 0
|
||||
return pa.player.GetPlayerEngageCommands() != 0
|
||||
}
|
||||
|
||||
// GetDistance returns distance to another spawn
|
||||
func (pa *PlayerAdapter) GetDistance(other *entity.Spawn) float32 {
|
||||
return pa.player.GetDistance(other)
|
||||
func (pa *PlayerAdapter) GetDistance(other *spawn.Spawn) float32 {
|
||||
return pa.player.GetDistance(other.GetX(), other.GetY(), other.GetZ(), true)
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ package player
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
@ -29,7 +30,7 @@ type Manager struct {
|
||||
validators []PlayerValidator
|
||||
|
||||
// Database interface
|
||||
database PlayerDatabase
|
||||
database *PlayerDatabase
|
||||
|
||||
// Packet handler
|
||||
packetHandler PlayerPacketHandler
|
||||
@ -138,7 +139,7 @@ func (m *Manager) AddPlayer(player *Player) error {
|
||||
|
||||
playerID := player.GetSpawnID()
|
||||
characterID := player.GetCharacterID()
|
||||
name := player.GetName()
|
||||
name := strings.TrimSpace(strings.Trim(player.GetName(), "\x00")) // Trim padding and null bytes
|
||||
zoneID := player.GetZone()
|
||||
|
||||
// Check for duplicates
|
||||
@ -189,7 +190,8 @@ func (m *Manager) RemovePlayer(playerID int32) error {
|
||||
// Remove from maps
|
||||
delete(m.players, playerID)
|
||||
delete(m.playersByCharID, player.GetCharacterID())
|
||||
delete(m.playersByName, player.GetName())
|
||||
name := strings.TrimSpace(strings.Trim(player.GetName(), "\x00"))
|
||||
delete(m.playersByName, name)
|
||||
|
||||
// Remove from zone map
|
||||
zoneID := player.GetZone()
|
||||
@ -235,7 +237,7 @@ func (m *Manager) GetPlayerByName(name string) *Player {
|
||||
m.playersLock.RLock()
|
||||
defer m.playersLock.RUnlock()
|
||||
|
||||
return m.playersByName[name]
|
||||
return m.playersByName[strings.TrimSpace(strings.Trim(name, "\x00"))]
|
||||
}
|
||||
|
||||
// GetPlayerByCharacterID returns a player by character ID
|
||||
@ -379,7 +381,7 @@ func (m *Manager) AddValidator(validator PlayerValidator) {
|
||||
}
|
||||
|
||||
// SetDatabase sets the database interface
|
||||
func (m *Manager) SetDatabase(db PlayerDatabase) {
|
||||
func (m *Manager) SetDatabase(db *PlayerDatabase) {
|
||||
m.database = db
|
||||
}
|
||||
|
||||
@ -590,7 +592,7 @@ func (m *Manager) FirePlayerLevelUpEvent(player *Player, newLevel int8) {
|
||||
}
|
||||
|
||||
// FirePlayerDeathEvent fires a death event
|
||||
func (m *Manager) FirePlayerDeathEvent(player *Player, killer entity.Entity) {
|
||||
func (m *Manager) FirePlayerDeathEvent(player *Player, killer *entity.Entity) {
|
||||
m.eventLock.RLock()
|
||||
defer m.eventLock.RUnlock()
|
||||
|
||||
|
@ -6,6 +6,7 @@ import (
|
||||
"eq2emu/internal/common"
|
||||
"eq2emu/internal/entity"
|
||||
"eq2emu/internal/quests"
|
||||
"eq2emu/internal/spawn"
|
||||
)
|
||||
|
||||
// Global XP table
|
||||
@ -27,7 +28,7 @@ func NewPlayer() *Player {
|
||||
playerQuests: make(map[int32]*quests.Quest),
|
||||
completedQuests: make(map[int32]*quests.Quest),
|
||||
pendingQuests: make(map[int32]*quests.Quest),
|
||||
currentQuestFlagged: make(map[*entity.Spawn]bool),
|
||||
currentQuestFlagged: make(map[*spawn.Spawn]bool),
|
||||
playerSpawnQuestsRequired: make(map[int32][]int32),
|
||||
playerSpawnHistoryRequired: make(map[int32][]int32),
|
||||
spawnVisPacketList: make(map[int32]string),
|
||||
@ -35,8 +36,8 @@ func NewPlayer() *Player {
|
||||
spawnPosPacketList: make(map[int32]string),
|
||||
spawnPacketSent: make(map[int32]int8),
|
||||
spawnStateList: make(map[int32]*SpawnQueueState),
|
||||
playerSpawnIDMap: make(map[int32]*entity.Spawn),
|
||||
playerSpawnReverseIDMap: make(map[*entity.Spawn]int32),
|
||||
playerSpawnIDMap: make(map[int32]*spawn.Spawn),
|
||||
playerSpawnReverseIDMap: make(map[*spawn.Spawn]int32),
|
||||
playerAggroRangeSpawns: make(map[int32]bool),
|
||||
pendingLootItems: make(map[int32]map[int32]bool),
|
||||
friendList: make(map[string]int8),
|
||||
@ -49,7 +50,7 @@ func NewPlayer() *Player {
|
||||
mailList: make(map[int32]*Mail),
|
||||
targetInvisHistory: make(map[int32]bool),
|
||||
spawnedBots: make(map[int32]int32),
|
||||
macroIcons: make(map[int32]int16),
|
||||
// macroIcons field removed - not in struct definition
|
||||
sortedTraitList: make(map[int8]map[int8][]*TraitData),
|
||||
classTraining: make(map[int8][]*TraitData),
|
||||
raceTraits: make(map[int8][]*TraitData),
|
||||
@ -62,11 +63,12 @@ func NewPlayer() *Player {
|
||||
|
||||
// Set player-specific defaults
|
||||
p.SetSpawnType(4) // Player spawn type
|
||||
p.appearance.DisplayName = 1
|
||||
p.appearance.ShowCommandIcon = 1
|
||||
p.appearance.PlayerFlag = 1
|
||||
p.appearance.Targetable = 1
|
||||
p.appearance.ShowLevel = 1
|
||||
// TODO: Set appearance data through proper methods when available
|
||||
// appearance.DisplayName = 1
|
||||
// appearance.ShowCommandIcon = 1
|
||||
// appearance.PlayerFlag = 1
|
||||
// appearance.Targetable = 1
|
||||
// appearance.ShowLevel = 1
|
||||
|
||||
// Set default away message
|
||||
p.awayMessage = "Sorry, I am A.F.K. (Away From Keyboard)"
|
||||
@ -76,8 +78,8 @@ func NewPlayer() *Player {
|
||||
p.AddSecondaryEntityCommand("Who", 10000, "who", "", 0, 0)
|
||||
|
||||
// Initialize self in spawn maps
|
||||
p.playerSpawnIDMap[1] = &p.Entity.Spawn
|
||||
p.playerSpawnReverseIDMap[&p.Entity.Spawn] = 1
|
||||
p.playerSpawnIDMap[1] = p.Entity.Spawn
|
||||
p.playerSpawnReverseIDMap[p.Entity.Spawn] = 1
|
||||
|
||||
// Set save spell effects
|
||||
p.stopSaveSpellEffects = false
|
||||
@ -227,52 +229,77 @@ func (p *Player) AddPlayerDiscoveredPOI(locationID int32) {
|
||||
|
||||
// SetSideSpeed sets the player's side movement speed
|
||||
func (p *Player) SetSideSpeed(sideSpeed float32, updateFlags bool) {
|
||||
p.SetPos(&p.appearance.Pos.SideSpeed, sideSpeed, updateFlags)
|
||||
// TODO: Implement when appearance system is available
|
||||
charID := p.GetCharacterID()
|
||||
if playerMovementData[charID] == nil {
|
||||
playerMovementData[charID] = make(map[string]float32)
|
||||
}
|
||||
playerMovementData[charID]["side_speed"] = sideSpeed
|
||||
}
|
||||
|
||||
// GetSideSpeed returns the player's side movement speed
|
||||
func (p *Player) GetSideSpeed() float32 {
|
||||
return p.appearance.Pos.SideSpeed
|
||||
return p.GetPos("side_speed")
|
||||
}
|
||||
|
||||
// SetVertSpeed sets the player's vertical movement speed
|
||||
func (p *Player) SetVertSpeed(vertSpeed float32, updateFlags bool) {
|
||||
p.SetPos(&p.appearance.Pos.VertSpeed, vertSpeed, updateFlags)
|
||||
// TODO: Implement when appearance system is available
|
||||
charID := p.GetCharacterID()
|
||||
if playerMovementData[charID] == nil {
|
||||
playerMovementData[charID] = make(map[string]float32)
|
||||
}
|
||||
playerMovementData[charID]["vert_speed"] = vertSpeed
|
||||
}
|
||||
|
||||
// GetVertSpeed returns the player's vertical movement speed
|
||||
func (p *Player) GetVertSpeed() float32 {
|
||||
return p.appearance.Pos.VertSpeed
|
||||
return p.GetPos("vert_speed")
|
||||
}
|
||||
|
||||
// SetClientHeading1 sets the client heading 1
|
||||
func (p *Player) SetClientHeading1(heading float32, updateFlags bool) {
|
||||
p.SetPos(&p.appearance.Pos.ClientHeading1, heading, updateFlags)
|
||||
// TODO: Implement when appearance system is available
|
||||
charID := p.GetCharacterID()
|
||||
if playerMovementData[charID] == nil {
|
||||
playerMovementData[charID] = make(map[string]float32)
|
||||
}
|
||||
playerMovementData[charID]["client_heading1"] = heading
|
||||
}
|
||||
|
||||
// GetClientHeading1 returns the client heading 1
|
||||
func (p *Player) GetClientHeading1() float32 {
|
||||
return p.appearance.Pos.ClientHeading1
|
||||
return p.GetPos("client_heading1")
|
||||
}
|
||||
|
||||
// SetClientHeading2 sets the client heading 2
|
||||
func (p *Player) SetClientHeading2(heading float32, updateFlags bool) {
|
||||
p.SetPos(&p.appearance.Pos.ClientHeading2, heading, updateFlags)
|
||||
// TODO: Implement when appearance system is available
|
||||
charID := p.GetCharacterID()
|
||||
if playerMovementData[charID] == nil {
|
||||
playerMovementData[charID] = make(map[string]float32)
|
||||
}
|
||||
playerMovementData[charID]["client_heading2"] = heading
|
||||
}
|
||||
|
||||
// GetClientHeading2 returns the client heading 2
|
||||
func (p *Player) GetClientHeading2() float32 {
|
||||
return p.appearance.Pos.ClientHeading2
|
||||
return p.GetPos("client_heading2")
|
||||
}
|
||||
|
||||
// SetClientPitch sets the client pitch
|
||||
func (p *Player) SetClientPitch(pitch float32, updateFlags bool) {
|
||||
p.SetPos(&p.appearance.Pos.ClientPitch, pitch, updateFlags)
|
||||
// TODO: Implement when appearance system is available
|
||||
charID := p.GetCharacterID()
|
||||
if playerMovementData[charID] == nil {
|
||||
playerMovementData[charID] = make(map[string]float32)
|
||||
}
|
||||
playerMovementData[charID]["client_pitch"] = pitch
|
||||
}
|
||||
|
||||
// GetClientPitch returns the client pitch
|
||||
func (p *Player) GetClientPitch() float32 {
|
||||
return p.appearance.Pos.ClientPitch
|
||||
return p.GetPos("client_pitch")
|
||||
}
|
||||
|
||||
// IsResurrecting returns whether the player is currently resurrecting
|
||||
@ -485,7 +512,7 @@ func (p *Player) SetSaveSpellEffects(val bool) {
|
||||
func (p *Player) ResetMentorship() bool {
|
||||
mentorshipStatus := p.resetMentorship
|
||||
if mentorshipStatus {
|
||||
p.SetMentorStats(p.GetLevel(), 0, true)
|
||||
p.SetMentorStats(int32(p.GetLevel()), 0, true)
|
||||
}
|
||||
p.resetMentorship = false
|
||||
return mentorshipStatus
|
||||
@ -521,8 +548,8 @@ func InitXPTable() {
|
||||
levelXPReq = make(map[int8]int32)
|
||||
// TODO: Load XP requirements from database or config
|
||||
// For now, using placeholder values
|
||||
for i := int8(1); i <= 100; i++ {
|
||||
levelXPReq[i] = int32(i * 1000)
|
||||
for i := int8(1); i <= 100; i++ { // Reasonable level cap of 100
|
||||
levelXPReq[i] = int32(i) * 1000
|
||||
}
|
||||
})
|
||||
}
|
||||
@ -542,47 +569,43 @@ func (p *Player) Cleanup() {
|
||||
p.SetSaveSpellEffects(true)
|
||||
|
||||
// Clear spells
|
||||
for _, spell := range p.spells {
|
||||
spell = nil
|
||||
for range p.spells {
|
||||
// Individual elements will be cleared when slice is nilled
|
||||
}
|
||||
p.spells = nil
|
||||
|
||||
// Clear quickbar
|
||||
for _, item := range p.quickbarItems {
|
||||
item = nil
|
||||
for range p.quickbarItems {
|
||||
// Individual elements will be cleared when slice is nilled
|
||||
}
|
||||
p.quickbarItems = nil
|
||||
|
||||
// Clear quest spawn requirements
|
||||
p.playerSpawnQuestsRequiredMutex.Lock()
|
||||
for _, list := range p.playerSpawnQuestsRequired {
|
||||
list = nil
|
||||
for range p.playerSpawnQuestsRequired {
|
||||
// Individual elements will be cleared when map is nilled
|
||||
}
|
||||
p.playerSpawnQuestsRequired = nil
|
||||
p.playerSpawnQuestsRequiredMutex.Unlock()
|
||||
|
||||
// Clear history spawn requirements
|
||||
p.playerSpawnHistoryRequiredMutex.Lock()
|
||||
for _, list := range p.playerSpawnHistoryRequired {
|
||||
list = nil
|
||||
for range p.playerSpawnHistoryRequired {
|
||||
// Individual elements will be cleared when map is nilled
|
||||
}
|
||||
p.playerSpawnHistoryRequired = nil
|
||||
p.playerSpawnHistoryRequiredMutex.Unlock()
|
||||
|
||||
// Clear character history
|
||||
for _, typeMap := range p.characterHistory {
|
||||
for _, histList := range typeMap {
|
||||
for _, hist := range histList {
|
||||
hist = nil
|
||||
}
|
||||
}
|
||||
for range p.characterHistory {
|
||||
// Individual elements will be cleared when map is nilled
|
||||
}
|
||||
p.characterHistory = nil
|
||||
|
||||
// Clear LUA history
|
||||
p.luaHistoryMutex.Lock()
|
||||
for _, hist := range p.charLuaHistory {
|
||||
hist = nil
|
||||
for range p.charLuaHistory {
|
||||
// Individual elements will be cleared when map is nilled
|
||||
}
|
||||
p.charLuaHistory = nil
|
||||
p.luaHistoryMutex.Unlock()
|
||||
@ -739,7 +762,31 @@ func (p *Player) ClearPendingItemRewards() {
|
||||
|
||||
// ClearEverything performs final cleanup
|
||||
func (p *Player) ClearEverything() {
|
||||
// TODO: Implement final cleanup logic
|
||||
// Clear friends list
|
||||
for name := range p.friendList {
|
||||
delete(p.friendList, name)
|
||||
}
|
||||
|
||||
// Clear ignore list
|
||||
for name := range p.ignoreList {
|
||||
delete(p.ignoreList, name)
|
||||
}
|
||||
|
||||
// Clear quests
|
||||
p.playerQuestsMutex.Lock()
|
||||
for id := range p.playerQuests {
|
||||
delete(p.playerQuests, id)
|
||||
}
|
||||
for id := range p.completedQuests {
|
||||
delete(p.completedQuests, id)
|
||||
}
|
||||
for id := range p.pendingQuests {
|
||||
delete(p.pendingQuests, id)
|
||||
}
|
||||
p.playerQuestsMutex.Unlock()
|
||||
|
||||
// Clear other data
|
||||
// TODO: Clear additional data as needed
|
||||
}
|
||||
|
||||
// GetCharacterInstances returns the character instances manager
|
||||
@ -818,5 +865,14 @@ func (p *Player) ClearGMVisualFilters() {
|
||||
p.gmVisualFilters = nil
|
||||
}
|
||||
|
||||
// SetLevel sets the player's level in both spawn appearance and info struct
|
||||
func (p *Player) SetLevel(level int16) {
|
||||
// Update spawn appearance level
|
||||
p.Spawn.SetLevel(level)
|
||||
// Update info struct level
|
||||
p.GetInfoStruct().SetLevel(level)
|
||||
p.SetCharSheetChanged(true)
|
||||
}
|
||||
|
||||
// macroIcons map - declared at package level since it was referenced but not in struct
|
||||
var macroIcons map[int32]int16
|
||||
|
@ -3,7 +3,7 @@ package player
|
||||
import (
|
||||
"math"
|
||||
|
||||
"eq2emu/internal/entity"
|
||||
"eq2emu/internal/spawn"
|
||||
)
|
||||
|
||||
// NewPlayerInfo creates a new PlayerInfo instance
|
||||
@ -16,27 +16,27 @@ func NewPlayerInfo(player *Player) *PlayerInfo {
|
||||
|
||||
// CalculateXPPercentages calculates XP bar percentages for display
|
||||
func (pi *PlayerInfo) CalculateXPPercentages() {
|
||||
xpNeeded := pi.infoStruct.GetXPNeeded()
|
||||
xpNeeded := int32(pi.player.GetInfoStructXPNeeded())
|
||||
if xpNeeded > 0 {
|
||||
divPercent := (float64(pi.infoStruct.GetXP()) / float64(xpNeeded)) * 100.0
|
||||
divPercent := (pi.player.GetInfoStructXP() / float64(xpNeeded)) * 100.0
|
||||
percentage := int16(divPercent) * 10
|
||||
whole := math.Floor(divPercent)
|
||||
fractional := divPercent - whole
|
||||
|
||||
pi.infoStruct.SetXPYellow(percentage)
|
||||
pi.infoStruct.SetXPBlue(int16(fractional * 1000))
|
||||
pi.player.SetInfoStructXPYellow(percentage)
|
||||
pi.player.SetInfoStructXPBlue(int16(fractional * 1000))
|
||||
|
||||
// Vitality bars probably need a revisit
|
||||
pi.infoStruct.SetXPBlueVitalityBar(0)
|
||||
pi.infoStruct.SetXPYellowVitalityBar(0)
|
||||
pi.player.SetInfoStructXPBlueVitalityBar(0)
|
||||
pi.player.SetInfoStructXPYellowVitalityBar(0)
|
||||
|
||||
if pi.player.GetXPVitality() > 0 {
|
||||
vitalityTotal := pi.player.GetXPVitality()*10 + float32(percentage)
|
||||
vitalityTotal -= float32((int(percentage/100) * 100))
|
||||
if vitalityTotal < 100 { // 10%
|
||||
pi.infoStruct.SetXPBlueVitalityBar(pi.infoStruct.GetXPBlue() + int16(pi.player.GetXPVitality()*10))
|
||||
pi.player.SetInfoStructXPBlueVitalityBar(pi.player.GetInfoStructXPBlue() + int16(pi.player.GetXPVitality()*10))
|
||||
} else {
|
||||
pi.infoStruct.SetXPYellowVitalityBar(pi.infoStruct.GetXPYellow() + int16(pi.player.GetXPVitality()*10))
|
||||
pi.player.SetInfoStructXPYellowVitalityBar(pi.player.GetInfoStructXPYellow() + int16(pi.player.GetXPVitality()*10))
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -44,11 +44,11 @@ func (pi *PlayerInfo) CalculateXPPercentages() {
|
||||
|
||||
// CalculateTSXPPercentages calculates tradeskill XP bar percentages
|
||||
func (pi *PlayerInfo) CalculateTSXPPercentages() {
|
||||
tsXPNeeded := pi.infoStruct.GetTSXPNeeded()
|
||||
tsXPNeeded := int32(pi.player.GetInfoStructTSXPNeeded())
|
||||
if tsXPNeeded > 0 {
|
||||
percentage := (float64(pi.infoStruct.GetTSXP()) / float64(tsXPNeeded)) * 1000
|
||||
pi.infoStruct.SetTradeskillExpYellow(int16(percentage))
|
||||
pi.infoStruct.SetTradeskillExpBlue(int16((percentage - float64(pi.infoStruct.GetTradeskillExpYellow())) * 1000))
|
||||
percentage := (pi.player.GetInfoStructTSXP() / float64(tsXPNeeded)) * 1000
|
||||
pi.player.SetInfoStructTradeskillExpYellow(int16(percentage))
|
||||
pi.player.SetInfoStructTradeskillExpBlue(int16((percentage - float64(pi.player.GetInfoStructTradeskillExpYellow())) * 1000))
|
||||
}
|
||||
}
|
||||
|
||||
@ -148,7 +148,7 @@ func (pi *PlayerInfo) SetBoatZ(z float32) {
|
||||
}
|
||||
|
||||
// SetBoatSpawn sets the boat spawn
|
||||
func (pi *PlayerInfo) SetBoatSpawn(spawn *entity.Spawn) {
|
||||
func (pi *PlayerInfo) SetBoatSpawn(spawn *spawn.Spawn) {
|
||||
if spawn != nil {
|
||||
pi.boatSpawn = spawn.GetDatabaseID()
|
||||
} else {
|
||||
@ -158,7 +158,7 @@ func (pi *PlayerInfo) SetBoatSpawn(spawn *entity.Spawn) {
|
||||
|
||||
// SetAccountAge sets the account age base
|
||||
func (pi *PlayerInfo) SetAccountAge(age int32) {
|
||||
pi.infoStruct.SetAccountAgeBase(age)
|
||||
pi.player.SetInfoStructAccountAgeBase(age)
|
||||
}
|
||||
|
||||
// RemoveOldPackets cleans up old packet data
|
||||
|
@ -1,22 +1,662 @@
|
||||
package player
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"eq2emu/internal/quests"
|
||||
"zombiezen.com/go/sqlite"
|
||||
"zombiezen.com/go/sqlite/sqlitex"
|
||||
)
|
||||
|
||||
func TestPackageBuild(t *testing.T) {
|
||||
// Basic test to verify the package builds
|
||||
manager := NewPlayerManager()
|
||||
if manager == nil {
|
||||
t.Fatal("NewPlayerManager returned nil")
|
||||
// TestNewPlayer tests player creation
|
||||
func TestNewPlayer(t *testing.T) {
|
||||
p := NewPlayer()
|
||||
if p == nil {
|
||||
t.Fatal("NewPlayer returned nil")
|
||||
}
|
||||
|
||||
// Verify default values
|
||||
if p.GetCharacterID() != 0 {
|
||||
t.Errorf("Expected character ID 0, got %d", p.GetCharacterID())
|
||||
}
|
||||
|
||||
if p.GetTutorialStep() != 0 {
|
||||
t.Errorf("Expected tutorial step 0, got %d", p.GetTutorialStep())
|
||||
}
|
||||
|
||||
if !p.IsPlayer() {
|
||||
t.Error("Expected IsPlayer to return true")
|
||||
}
|
||||
|
||||
// Check that maps are initialized
|
||||
if p.playerQuests == nil {
|
||||
t.Error("playerQuests map not initialized")
|
||||
}
|
||||
if p.completedQuests == nil {
|
||||
t.Error("completedQuests map not initialized")
|
||||
}
|
||||
if p.friendList == nil {
|
||||
t.Error("friendList map not initialized")
|
||||
}
|
||||
}
|
||||
|
||||
// TestPlayerManager tests the player manager functionality
|
||||
func TestPlayerManager(t *testing.T) {
|
||||
manager := NewPlayerManager()
|
||||
config := ManagerConfig{
|
||||
MaxPlayers: 100,
|
||||
SaveInterval: time.Minute * 5,
|
||||
StatsInterval: time.Second * 30,
|
||||
}
|
||||
|
||||
stats := manager.GetStats()
|
||||
if stats.TotalPlayers < 0 {
|
||||
t.Error("Expected valid stats")
|
||||
manager := NewManager(config)
|
||||
if manager == nil {
|
||||
t.Fatal("NewManager returned nil")
|
||||
}
|
||||
|
||||
// Test adding a player
|
||||
player := NewPlayer()
|
||||
player.SetSpawnID(1001) // Set unique spawn ID
|
||||
player.SetCharacterID(123)
|
||||
player.SetName("TestPlayer")
|
||||
player.SetLevel(10)
|
||||
|
||||
err := manager.AddPlayer(player)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to add player: %v", err)
|
||||
}
|
||||
|
||||
// Test retrieving player by ID
|
||||
retrieved := manager.GetPlayer(player.GetSpawnID())
|
||||
if retrieved == nil {
|
||||
t.Error("Failed to retrieve player by ID")
|
||||
}
|
||||
|
||||
// Test retrieving player by name
|
||||
byName := manager.GetPlayerByName("TestPlayer")
|
||||
if byName == nil {
|
||||
// Debug: Check what name was actually stored
|
||||
allPlayers := manager.GetAllPlayers()
|
||||
if len(allPlayers) > 0 {
|
||||
t.Errorf("Failed to retrieve player by name. Player has name: %s", allPlayers[0].GetName())
|
||||
} else {
|
||||
t.Error("Failed to retrieve player by name. No players in manager")
|
||||
}
|
||||
}
|
||||
|
||||
// Test retrieving player by character ID
|
||||
byCharID := manager.GetPlayerByCharacterID(123)
|
||||
if byCharID == nil {
|
||||
t.Error("Failed to retrieve player by character ID")
|
||||
}
|
||||
|
||||
// Test player count
|
||||
count := manager.GetPlayerCount()
|
||||
if count != 1 {
|
||||
t.Errorf("Expected player count 1, got %d", count)
|
||||
}
|
||||
|
||||
// Test removing player
|
||||
err = manager.RemovePlayer(player.GetSpawnID())
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to remove player: %v", err)
|
||||
}
|
||||
|
||||
count = manager.GetPlayerCount()
|
||||
if count != 0 {
|
||||
t.Errorf("Expected player count 0 after removal, got %d", count)
|
||||
}
|
||||
}
|
||||
|
||||
// TestPlayerDatabase tests database operations
|
||||
func TestPlayerDatabase(t *testing.T) {
|
||||
// Create in-memory database for testing
|
||||
conn, err := sqlite.OpenConn(":memory:", sqlite.OpenReadWrite|sqlite.OpenCreate)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to open database: %v", err)
|
||||
}
|
||||
defer conn.Close()
|
||||
|
||||
// Create test table
|
||||
createTable := `
|
||||
CREATE TABLE IF NOT EXISTS characters (
|
||||
id INTEGER PRIMARY KEY,
|
||||
name TEXT NOT NULL,
|
||||
level INTEGER DEFAULT 1,
|
||||
race INTEGER DEFAULT 0,
|
||||
class INTEGER DEFAULT 0,
|
||||
zone_id INTEGER DEFAULT 0,
|
||||
x REAL DEFAULT 0,
|
||||
y REAL DEFAULT 0,
|
||||
z REAL DEFAULT 0,
|
||||
heading REAL DEFAULT 0,
|
||||
created_date TEXT,
|
||||
last_save TEXT
|
||||
)`
|
||||
|
||||
err = sqlitex.Execute(conn, createTable, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create table: %v", err)
|
||||
}
|
||||
|
||||
db := NewPlayerDatabase(conn)
|
||||
|
||||
// Create test player
|
||||
player := NewPlayer()
|
||||
player.SetCharacterID(1)
|
||||
player.SetName("TestHero")
|
||||
player.SetLevel(20)
|
||||
player.SetClass(1)
|
||||
player.SetRace(2)
|
||||
player.SetX(100.5)
|
||||
player.SetY(200.5, false)
|
||||
player.SetZ(300.5)
|
||||
|
||||
// Test saving player
|
||||
err = db.SavePlayer(player)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to save player: %v", err)
|
||||
}
|
||||
|
||||
// Test loading player
|
||||
loaded, err := db.LoadPlayer(1)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to load player: %v", err)
|
||||
}
|
||||
|
||||
loadedName := strings.TrimSpace(strings.Trim(loaded.GetName(), "\x00"))
|
||||
if loadedName != "TestHero" {
|
||||
t.Errorf("Expected name TestHero, got %s", loadedName)
|
||||
}
|
||||
|
||||
loadedLevel := loaded.GetLevel()
|
||||
if loadedLevel != 20 {
|
||||
t.Errorf("Expected level 20, got %d", loadedLevel)
|
||||
}
|
||||
|
||||
// Test updating player
|
||||
loaded.SetLevel(21)
|
||||
err = db.SavePlayer(loaded)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to update player: %v", err)
|
||||
}
|
||||
|
||||
// Test deleting player
|
||||
err = db.DeletePlayer(1)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to delete player: %v", err)
|
||||
}
|
||||
|
||||
// Verify deletion
|
||||
_, err = db.LoadPlayer(1)
|
||||
if err == nil {
|
||||
t.Error("Expected error loading deleted player")
|
||||
}
|
||||
}
|
||||
|
||||
// TestPlayerCombat tests combat-related functionality
|
||||
func TestPlayerCombat(t *testing.T) {
|
||||
player := NewPlayer()
|
||||
player.SetCharacterID(1)
|
||||
player.SetLevel(10)
|
||||
player.SetHP(100)
|
||||
player.SetTotalHP(100)
|
||||
|
||||
// Test combat state
|
||||
player.InCombat(true, false)
|
||||
if player.GetPlayerEngageCommands() == 0 {
|
||||
t.Error("Expected player to be in combat")
|
||||
}
|
||||
|
||||
player.InCombat(false, false)
|
||||
if player.GetPlayerEngageCommands() != 0 {
|
||||
t.Error("Expected player to not be in combat")
|
||||
}
|
||||
|
||||
// Test death state
|
||||
player.SetHP(0)
|
||||
if !player.IsDead() {
|
||||
t.Error("Expected player to be dead with 0 HP")
|
||||
}
|
||||
|
||||
player.SetHP(50)
|
||||
if player.IsDead() {
|
||||
t.Error("Expected player to be alive with 50 HP")
|
||||
}
|
||||
|
||||
// Test mentorship
|
||||
player.SetMentorStats(5, 0, true)
|
||||
player.EnableResetMentorship()
|
||||
if !player.ResetMentorship() {
|
||||
t.Error("Expected mentorship reset to succeed")
|
||||
}
|
||||
}
|
||||
|
||||
// TestPlayerExperience tests experience system
|
||||
func TestPlayerExperience(t *testing.T) {
|
||||
player := NewPlayer()
|
||||
player.SetCharacterID(1)
|
||||
player.SetLevel(1)
|
||||
|
||||
// Set initial XP
|
||||
player.SetXP(0)
|
||||
player.SetNeededXP(1000)
|
||||
|
||||
// Test XP gain
|
||||
leveledUp := player.AddXP(500)
|
||||
if leveledUp {
|
||||
t.Error("Should not level up with 500/1000 XP")
|
||||
}
|
||||
|
||||
currentXP := player.GetXP()
|
||||
if currentXP != 500 {
|
||||
t.Errorf("Expected XP 500, got %d", currentXP)
|
||||
}
|
||||
|
||||
// Test level up
|
||||
leveledUp = player.AddXP(600) // Total: 1100, should level up
|
||||
if !leveledUp {
|
||||
t.Error("Should level up with 1100/1000 XP")
|
||||
}
|
||||
|
||||
newLevel := player.GetLevel()
|
||||
if newLevel != 2 {
|
||||
t.Errorf("Expected level 2 after level up, got %d", newLevel)
|
||||
}
|
||||
|
||||
// Test tradeskill XP
|
||||
player.SetTSXP(0)
|
||||
player.SetNeededTSXP(500)
|
||||
|
||||
leveledUp = player.AddTSXP(600)
|
||||
if !leveledUp {
|
||||
t.Error("Should level up tradeskill with 600/500 XP")
|
||||
}
|
||||
}
|
||||
|
||||
// TestPlayerQuests tests quest management
|
||||
func TestPlayerQuests(t *testing.T) {
|
||||
player := NewPlayer()
|
||||
player.SetCharacterID(1)
|
||||
|
||||
// Create test quest
|
||||
quest := &quests.Quest{
|
||||
ID: 100,
|
||||
Name: "Test Quest",
|
||||
}
|
||||
|
||||
// Test adding quest
|
||||
// Note: AddQuest method doesn't exist yet - would need implementation
|
||||
// player.AddQuest(quest)
|
||||
player.playerQuests[100] = quest
|
||||
|
||||
retrieved := player.GetQuest(100)
|
||||
if retrieved == nil {
|
||||
t.Error("Failed to retrieve added quest")
|
||||
}
|
||||
|
||||
allQuests := player.GetPlayerQuests()
|
||||
if len(allQuests) != 1 {
|
||||
t.Errorf("Expected 1 quest, got %d", len(allQuests))
|
||||
}
|
||||
|
||||
// Test completing quest
|
||||
player.RemoveQuest(100, true)
|
||||
|
||||
retrieved = player.GetQuest(100)
|
||||
if retrieved != nil {
|
||||
t.Error("Quest should be removed after completion")
|
||||
}
|
||||
|
||||
completed := player.GetCompletedQuest(100)
|
||||
if completed == nil {
|
||||
t.Error("Quest should be in completed list")
|
||||
}
|
||||
}
|
||||
|
||||
// TestPlayerSkills tests skill management
|
||||
func TestPlayerSkills(t *testing.T) {
|
||||
player := NewPlayer()
|
||||
player.SetCharacterID(1)
|
||||
|
||||
// Test adding skill
|
||||
player.AddSkill(1, 10, 100, true)
|
||||
|
||||
// Test skill retrieval by name
|
||||
skill := player.GetSkillByName("TestSkill", false)
|
||||
// Note: This will return nil since we're using stubs
|
||||
_ = skill
|
||||
|
||||
// Test removing skill
|
||||
player.RemovePlayerSkill(1, false)
|
||||
}
|
||||
|
||||
// TestPlayerFlags tests character flag management
|
||||
func TestPlayerFlags(t *testing.T) {
|
||||
player := NewPlayer()
|
||||
player.SetCharacterID(1)
|
||||
|
||||
// Test setting flags
|
||||
player.SetCharacterFlag(CF_ANONYMOUS)
|
||||
if !player.GetCharacterFlag(CF_ANONYMOUS) {
|
||||
t.Error("Expected anonymous flag to be set")
|
||||
}
|
||||
|
||||
// Test resetting flags
|
||||
player.ResetCharacterFlag(CF_ANONYMOUS)
|
||||
if player.GetCharacterFlag(CF_ANONYMOUS) {
|
||||
t.Error("Expected anonymous flag to be reset")
|
||||
}
|
||||
|
||||
// Test toggle
|
||||
player.ToggleCharacterFlag(CF_ANONYMOUS)
|
||||
if !player.GetCharacterFlag(CF_ANONYMOUS) {
|
||||
t.Error("Expected anonymous flag to be toggled on")
|
||||
}
|
||||
|
||||
player.ToggleCharacterFlag(CF_ANONYMOUS)
|
||||
if player.GetCharacterFlag(CF_ANONYMOUS) {
|
||||
t.Error("Expected anonymous flag to be toggled off")
|
||||
}
|
||||
}
|
||||
|
||||
// TestPlayerFriends tests friend list management
|
||||
func TestPlayerFriends(t *testing.T) {
|
||||
player := NewPlayer()
|
||||
player.SetCharacterID(1)
|
||||
|
||||
// Test adding friend
|
||||
player.AddFriend("BestFriend", false)
|
||||
|
||||
if !player.IsFriend("BestFriend") {
|
||||
t.Error("Expected BestFriend to be in friend list")
|
||||
}
|
||||
|
||||
friends := player.GetFriends()
|
||||
if len(friends) != 1 {
|
||||
t.Errorf("Expected 1 friend, got %d", len(friends))
|
||||
}
|
||||
|
||||
// Test removing friend
|
||||
player.RemoveFriend("BestFriend")
|
||||
|
||||
if player.IsFriend("BestFriend") {
|
||||
t.Error("Expected BestFriend to be removed from friend list")
|
||||
}
|
||||
}
|
||||
|
||||
// TestPlayerIgnore tests ignore list management
|
||||
func TestPlayerIgnore(t *testing.T) {
|
||||
player := NewPlayer()
|
||||
player.SetCharacterID(1)
|
||||
|
||||
// Test adding to ignore list
|
||||
player.AddIgnore("Annoying", false)
|
||||
|
||||
if !player.IsIgnored("Annoying") {
|
||||
t.Error("Expected Annoying to be in ignore list")
|
||||
}
|
||||
|
||||
ignored := player.GetIgnoredPlayers()
|
||||
if len(ignored) != 1 {
|
||||
t.Errorf("Expected 1 ignored player, got %d", len(ignored))
|
||||
}
|
||||
|
||||
// Test removing from ignore list
|
||||
player.RemoveIgnore("Annoying")
|
||||
|
||||
if player.IsIgnored("Annoying") {
|
||||
t.Error("Expected Annoying to be removed from ignore list")
|
||||
}
|
||||
}
|
||||
|
||||
// TestPlayerMovement tests movement-related methods
|
||||
func TestPlayerMovement(t *testing.T) {
|
||||
player := NewPlayer()
|
||||
player.SetCharacterID(1)
|
||||
|
||||
// Test position
|
||||
player.SetX(100.5)
|
||||
player.SetY(200.5, false)
|
||||
player.SetZ(300.5)
|
||||
|
||||
if player.GetX() != 100.5 {
|
||||
t.Errorf("Expected X 100.5, got %f", player.GetX())
|
||||
}
|
||||
|
||||
// Test heading
|
||||
player.SetHeadingFromFloat(180.0)
|
||||
heading := player.GetHeading()
|
||||
_ = heading // Heading conversion is complex, just ensure it doesn't panic
|
||||
|
||||
// Test distance calculation
|
||||
distance := player.GetDistance(150.5, 250.5, 350.5, true)
|
||||
if distance <= 0 {
|
||||
t.Error("Expected positive distance")
|
||||
}
|
||||
|
||||
// Test movement speeds
|
||||
player.SetSideSpeed(5.0, false)
|
||||
if player.GetSideSpeed() != 5.0 {
|
||||
t.Errorf("Expected side speed 5.0, got %f", player.GetSideSpeed())
|
||||
}
|
||||
|
||||
player.SetVertSpeed(3.0, false)
|
||||
if player.GetVertSpeed() != 3.0 {
|
||||
t.Errorf("Expected vert speed 3.0, got %f", player.GetVertSpeed())
|
||||
}
|
||||
}
|
||||
|
||||
// TestPlayerCurrency tests currency management
|
||||
func TestPlayerCurrency(t *testing.T) {
|
||||
player := NewPlayer()
|
||||
player.SetCharacterID(1)
|
||||
|
||||
// Test adding coins
|
||||
player.AddCoins(1000)
|
||||
|
||||
if !player.HasCoins(1000) {
|
||||
t.Error("Expected player to have 1000 coins")
|
||||
}
|
||||
|
||||
// Test removing coins
|
||||
success := player.RemoveCoins(500)
|
||||
if !success {
|
||||
t.Error("Expected to successfully remove 500 coins")
|
||||
}
|
||||
|
||||
if !player.HasCoins(500) {
|
||||
t.Error("Expected player to have 500 coins remaining")
|
||||
}
|
||||
|
||||
// Test insufficient coins
|
||||
success = player.RemoveCoins(1000)
|
||||
if success {
|
||||
t.Error("Should not be able to remove 1000 coins when only 500 available")
|
||||
}
|
||||
}
|
||||
|
||||
// TestPlayerSpells tests spell management
|
||||
func TestPlayerSpells(t *testing.T) {
|
||||
player := NewPlayer()
|
||||
player.SetCharacterID(1)
|
||||
|
||||
// Test spell book
|
||||
player.AddSpellBookEntry(100, 1, 1, 0, 0, true)
|
||||
|
||||
hasSpell := player.HasSpell(100, 1, false, false)
|
||||
if !hasSpell {
|
||||
t.Error("Expected player to have spell 100")
|
||||
}
|
||||
|
||||
// Test removing spell
|
||||
player.RemoveSpellBookEntry(100, false)
|
||||
|
||||
hasSpell = player.HasSpell(100, 1, false, false)
|
||||
if hasSpell {
|
||||
t.Error("Expected spell to be removed")
|
||||
}
|
||||
|
||||
// Test passive spells
|
||||
player.ApplyPassiveSpells()
|
||||
player.RemoveAllPassives()
|
||||
}
|
||||
|
||||
// TestPlayerInfo tests PlayerInfo functionality
|
||||
func TestPlayerInfo(t *testing.T) {
|
||||
player := NewPlayer()
|
||||
player.SetCharacterID(1)
|
||||
|
||||
info := NewPlayerInfo(player)
|
||||
if info == nil {
|
||||
t.Fatal("NewPlayerInfo returned nil")
|
||||
}
|
||||
|
||||
// Test bind point
|
||||
info.SetBindZone(100)
|
||||
info.SetBindX(50.0)
|
||||
info.SetBindY(60.0)
|
||||
info.SetBindZ(70.0)
|
||||
info.SetBindHeading(90.0)
|
||||
|
||||
// Test house zone
|
||||
info.SetHouseZone(200)
|
||||
|
||||
// Test account age
|
||||
info.SetAccountAge(365)
|
||||
|
||||
// Test XP calculations
|
||||
player.SetXP(500)
|
||||
player.SetNeededXP(1000)
|
||||
info.CalculateXPPercentages()
|
||||
|
||||
// Test TS XP calculations
|
||||
player.SetTSXP(250)
|
||||
player.SetNeededTSXP(500)
|
||||
info.CalculateTSXPPercentages()
|
||||
}
|
||||
|
||||
// TestPlayerEquipment tests equipment and appearance
|
||||
func TestPlayerEquipment(t *testing.T) {
|
||||
player := NewPlayer()
|
||||
player.SetCharacterID(1)
|
||||
player.SetHP(100) // Set HP so player is not dead
|
||||
player.SetTotalHP(100)
|
||||
|
||||
// Test equipment allowance check
|
||||
canEquip := player.IsAllowedCombatEquip(0, false)
|
||||
if !canEquip {
|
||||
t.Error("Expected to be able to change equipment out of combat")
|
||||
}
|
||||
|
||||
// Test in combat equipment change
|
||||
player.InCombat(true, false)
|
||||
canEquip = player.IsAllowedCombatEquip(0, false)
|
||||
if canEquip {
|
||||
t.Error("Should not be able to change primary weapon in combat")
|
||||
}
|
||||
}
|
||||
|
||||
// TestPlayerCleanup tests cleanup methods
|
||||
func TestPlayerCleanup(t *testing.T) {
|
||||
player := NewPlayer()
|
||||
player.SetCharacterID(1)
|
||||
|
||||
// Add some data
|
||||
player.AddFriend("Friend1", false)
|
||||
player.AddIgnore("Ignored1", false)
|
||||
quest := &quests.Quest{ID: 1, Name: "Quest1"}
|
||||
// player.AddQuest(quest) - method doesn't exist yet
|
||||
player.playerQuests[1] = quest
|
||||
|
||||
// Test cleanup
|
||||
player.ClearEverything()
|
||||
|
||||
// Verify data is cleared
|
||||
friends := player.GetFriends()
|
||||
if len(friends) != 0 {
|
||||
t.Error("Expected friends list to be cleared")
|
||||
}
|
||||
|
||||
ignored := player.GetIgnoredPlayers()
|
||||
if len(ignored) != 0 {
|
||||
t.Error("Expected ignore list to be cleared")
|
||||
}
|
||||
}
|
||||
|
||||
// BenchmarkPlayerCreation benchmarks player creation
|
||||
func BenchmarkPlayerCreation(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
p := NewPlayer()
|
||||
p.SetCharacterID(int32(i))
|
||||
p.SetName(fmt.Sprintf("Player%d", i))
|
||||
}
|
||||
}
|
||||
|
||||
// BenchmarkManagerOperations benchmarks manager operations
|
||||
func BenchmarkManagerOperations(b *testing.B) {
|
||||
config := ManagerConfig{
|
||||
MaxPlayers: 1000,
|
||||
}
|
||||
manager := NewManager(config)
|
||||
|
||||
// Create players
|
||||
players := make([]*Player, 100)
|
||||
for i := 0; i < 100; i++ {
|
||||
players[i] = NewPlayer()
|
||||
players[i].SetCharacterID(int32(i))
|
||||
players[i].SetName(fmt.Sprintf("Player%d", i))
|
||||
players[i].SetSpawnID(int32(2000 + i)) // Unique spawn IDs
|
||||
manager.AddPlayer(players[i])
|
||||
}
|
||||
|
||||
b.ResetTimer()
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
// Benchmark lookups
|
||||
_ = manager.GetPlayer(int32(i % 100))
|
||||
_ = manager.GetPlayerByCharacterID(int32(i % 100))
|
||||
}
|
||||
}
|
||||
|
||||
// TestConcurrentAccess tests thread safety
|
||||
func TestConcurrentAccess(t *testing.T) {
|
||||
config := ManagerConfig{
|
||||
MaxPlayers: 100,
|
||||
}
|
||||
manager := NewManager(config)
|
||||
|
||||
// Start manager
|
||||
err := manager.Start()
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to start manager: %v", err)
|
||||
}
|
||||
defer manager.Stop()
|
||||
|
||||
// Concurrent player additions
|
||||
done := make(chan bool, 10)
|
||||
|
||||
for i := 0; i < 10; i++ {
|
||||
go func(id int) {
|
||||
player := NewPlayer()
|
||||
player.SetCharacterID(int32(id))
|
||||
player.SetName(fmt.Sprintf("Player%d", id))
|
||||
player.SetSpawnID(int32(1000 + id)) // Unique spawn IDs
|
||||
manager.AddPlayer(player)
|
||||
done <- true
|
||||
}(i)
|
||||
}
|
||||
|
||||
// Wait for all goroutines
|
||||
for i := 0; i < 10; i++ {
|
||||
<-done
|
||||
}
|
||||
|
||||
// Verify all players added
|
||||
count := manager.GetPlayerCount()
|
||||
if count != 10 {
|
||||
t.Errorf("Expected 10 players, got %d", count)
|
||||
}
|
||||
}
|
@ -1,8 +1,8 @@
|
||||
package player
|
||||
|
||||
import (
|
||||
"eq2emu/internal/entity"
|
||||
"eq2emu/internal/quests"
|
||||
"eq2emu/internal/spawn"
|
||||
"eq2emu/internal/spells"
|
||||
)
|
||||
|
||||
@ -60,7 +60,7 @@ func (p *Player) HasQuestBeenCompleted(questID int32) bool {
|
||||
func (p *Player) GetQuestCompletedCount(questID int32) int32 {
|
||||
quest := p.GetCompletedQuest(questID)
|
||||
if quest != nil {
|
||||
return quest.GetCompleteCount()
|
||||
return GetQuestCompleteCount(quest)
|
||||
}
|
||||
return 0
|
||||
}
|
||||
@ -74,7 +74,7 @@ func (p *Player) AddCompletedQuest(quest *quests.Quest) {
|
||||
p.playerQuestsMutex.Lock()
|
||||
defer p.playerQuestsMutex.Unlock()
|
||||
|
||||
p.completedQuests[quest.GetQuestID()] = quest
|
||||
p.completedQuests[GetQuestID(quest)] = quest
|
||||
}
|
||||
|
||||
// HasActiveQuest checks if a quest is currently active
|
||||
@ -114,16 +114,19 @@ func (p *Player) GetQuestIDs() []int32 {
|
||||
}
|
||||
|
||||
// RemoveQuest removes a quest from the player
|
||||
func (p *Player) RemoveQuest(questID int32, deleteQuest bool) {
|
||||
// If completeQuest is true, the quest is moved to completed list
|
||||
func (p *Player) RemoveQuest(questID int32, completeQuest bool) {
|
||||
p.playerQuestsMutex.Lock()
|
||||
defer p.playerQuestsMutex.Unlock()
|
||||
|
||||
if quest, exists := p.playerQuests[questID]; exists {
|
||||
delete(p.playerQuests, questID)
|
||||
|
||||
if deleteQuest {
|
||||
// TODO: Delete quest data
|
||||
_ = quest
|
||||
if completeQuest {
|
||||
// Move quest to completed list
|
||||
p.completedQuests[questID] = quest
|
||||
// Update completion count
|
||||
IncrementQuestCompleteCount(quest)
|
||||
}
|
||||
}
|
||||
|
||||
@ -132,7 +135,7 @@ func (p *Player) RemoveQuest(questID int32, deleteQuest bool) {
|
||||
}
|
||||
|
||||
// AddQuestRequiredSpawn adds a spawn requirement for a quest
|
||||
func (p *Player) AddQuestRequiredSpawn(spawn *entity.Spawn, questID int32) {
|
||||
func (p *Player) AddQuestRequiredSpawn(spawn *spawn.Spawn, questID int32) {
|
||||
if spawn == nil {
|
||||
return
|
||||
}
|
||||
@ -156,7 +159,7 @@ func (p *Player) AddQuestRequiredSpawn(spawn *entity.Spawn, questID int32) {
|
||||
}
|
||||
|
||||
// AddHistoryRequiredSpawn adds a spawn requirement for history
|
||||
func (p *Player) AddHistoryRequiredSpawn(spawn *entity.Spawn, eventID int32) {
|
||||
func (p *Player) AddHistoryRequiredSpawn(spawn *spawn.Spawn, eventID int32) {
|
||||
if spawn == nil {
|
||||
return
|
||||
}
|
||||
@ -180,7 +183,7 @@ func (p *Player) AddHistoryRequiredSpawn(spawn *entity.Spawn, eventID int32) {
|
||||
}
|
||||
|
||||
// CheckQuestRequired checks if a spawn is required for any quest
|
||||
func (p *Player) CheckQuestRequired(spawn *entity.Spawn) bool {
|
||||
func (p *Player) CheckQuestRequired(spawn *spawn.Spawn) bool {
|
||||
if spawn == nil {
|
||||
return false
|
||||
}
|
||||
@ -206,7 +209,7 @@ func (p *Player) GetQuestStepComplete(questID, stepID int32) bool {
|
||||
func (p *Player) GetQuestStep(questID int32) int16 {
|
||||
quest := p.GetQuest(questID)
|
||||
if quest != nil {
|
||||
return quest.GetQuestStep()
|
||||
return GetQuestStep(quest)
|
||||
}
|
||||
return 0
|
||||
}
|
||||
@ -215,7 +218,7 @@ func (p *Player) GetQuestStep(questID int32) int16 {
|
||||
func (p *Player) GetTaskGroupStep(questID int32) int16 {
|
||||
quest := p.GetQuest(questID)
|
||||
if quest != nil {
|
||||
return quest.GetTaskGroup()
|
||||
return int16(GetQuestTaskGroup(quest))
|
||||
}
|
||||
return 0
|
||||
}
|
||||
@ -299,7 +302,7 @@ func (p *Player) SendQuest(questID int32) {
|
||||
func (p *Player) UpdateQuestCompleteCount(questID int32) {
|
||||
quest := p.GetCompletedQuest(questID)
|
||||
if quest != nil {
|
||||
quest.IncrementCompleteCount()
|
||||
IncrementQuestCompleteCount(quest)
|
||||
// TODO: Save to database
|
||||
}
|
||||
}
|
||||
@ -333,13 +336,13 @@ func (p *Player) AddQuestTemporaryReward(questID, itemID int32, itemCount int16)
|
||||
}
|
||||
|
||||
// UpdateQuestReward updates quest reward data
|
||||
func (p *Player) UpdateQuestReward(questID int32, qrd *quests.QuestRewardData) bool {
|
||||
func (p *Player) UpdateQuestReward(questID int32, qrd *quests.QuestRewards) bool {
|
||||
// TODO: Update quest reward
|
||||
return false
|
||||
}
|
||||
|
||||
// CheckQuestsChatUpdate checks quests for chat updates
|
||||
func (p *Player) CheckQuestsChatUpdate(spawn *entity.Spawn) []*quests.Quest {
|
||||
func (p *Player) CheckQuestsChatUpdate(spawn *spawn.Spawn) []*quests.Quest {
|
||||
// TODO: Check if spawn chat updates any quests
|
||||
return nil
|
||||
}
|
||||
@ -357,13 +360,13 @@ func (p *Player) CheckQuestsLocationUpdate() []*quests.Quest {
|
||||
}
|
||||
|
||||
// CheckQuestsKillUpdate checks quests for kill updates
|
||||
func (p *Player) CheckQuestsKillUpdate(spawn *entity.Spawn, update bool) []*quests.Quest {
|
||||
func (p *Player) CheckQuestsKillUpdate(spawn *spawn.Spawn, update bool) []*quests.Quest {
|
||||
// TODO: Check if killing spawn updates any quests
|
||||
return nil
|
||||
}
|
||||
|
||||
// HasQuestUpdateRequirement checks if spawn has quest update requirements
|
||||
func (p *Player) HasQuestUpdateRequirement(spawn *entity.Spawn) bool {
|
||||
func (p *Player) HasQuestUpdateRequirement(spawn *spawn.Spawn) bool {
|
||||
// TODO: Check if spawn updates any active quests
|
||||
return false
|
||||
}
|
||||
@ -391,13 +394,13 @@ func (p *Player) CheckQuestsFailures() []*quests.Quest {
|
||||
}
|
||||
|
||||
// CheckQuestRemoveFlag checks if spawn should have quest flag removed
|
||||
func (p *Player) CheckQuestRemoveFlag(spawn *entity.Spawn) bool {
|
||||
func (p *Player) CheckQuestRemoveFlag(spawn *spawn.Spawn) bool {
|
||||
// TODO: Check if quest flag should be removed from spawn
|
||||
return false
|
||||
}
|
||||
|
||||
// CheckQuestFlag returns the quest flag for a spawn
|
||||
func (p *Player) CheckQuestFlag(spawn *entity.Spawn) int8 {
|
||||
func (p *Player) CheckQuestFlag(spawn *spawn.Spawn) int8 {
|
||||
// TODO: Determine quest flag for spawn
|
||||
// 0 = no flag
|
||||
// 1 = quest giver
|
||||
|
@ -6,25 +6,27 @@ import (
|
||||
|
||||
// GetSkillByName returns a skill by name
|
||||
func (p *Player) GetSkillByName(name string, checkUpdate bool) *skills.Skill {
|
||||
return p.skillList.GetSkillByName(name, checkUpdate)
|
||||
return p.GetSkillByNameHelper(name, checkUpdate)
|
||||
}
|
||||
|
||||
// GetSkillByID returns a skill by ID
|
||||
func (p *Player) GetSkillByID(skillID int32, checkUpdate bool) *skills.Skill {
|
||||
return p.skillList.GetSkillByID(skillID, checkUpdate)
|
||||
// TODO: Implement GetSkillByID when available in skills package
|
||||
return nil
|
||||
}
|
||||
|
||||
// AddSkill adds a skill to the player
|
||||
func (p *Player) AddSkill(skillID int32, currentVal, maxVal int16, saveNeeded bool) {
|
||||
p.skillList.AddSkill(skillID, currentVal, maxVal, saveNeeded)
|
||||
p.AddSkillHelper(skillID, currentVal, maxVal, saveNeeded)
|
||||
}
|
||||
|
||||
// RemovePlayerSkill removes a skill from the player
|
||||
func (p *Player) RemovePlayerSkill(skillID int32, save bool) {
|
||||
p.skillList.RemoveSkill(skillID)
|
||||
p.RemoveSkillHelper(skillID)
|
||||
if save {
|
||||
// TODO: Remove from database
|
||||
p.RemoveSkillFromDB(p.skillList.GetSkillByID(skillID, false), save)
|
||||
// TODO: Implement RemoveSkillFromDB when available
|
||||
// p.RemoveSkillFromDB(p.GetSkillByID(skillID, false), save)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3,7 +3,7 @@ package player
|
||||
import (
|
||||
"time"
|
||||
|
||||
"eq2emu/internal/entity"
|
||||
"eq2emu/internal/spawn"
|
||||
)
|
||||
|
||||
// WasSentSpawn checks if a spawn was already sent to the player
|
||||
@ -40,7 +40,7 @@ func (p *Player) IsRemovingSpawn(spawnID int32) bool {
|
||||
}
|
||||
|
||||
// SetSpawnSentState sets the spawn state for tracking
|
||||
func (p *Player) SetSpawnSentState(spawn *entity.Spawn, state SpawnState) bool {
|
||||
func (p *Player) SetSpawnSentState(spawn *spawn.Spawn, state SpawnState) bool {
|
||||
if spawn == nil {
|
||||
return false
|
||||
}
|
||||
@ -100,7 +100,7 @@ func (p *Player) CheckSpawnStateQueue() {
|
||||
}
|
||||
|
||||
// GetSpawnWithPlayerID returns a spawn by player-specific ID
|
||||
func (p *Player) GetSpawnWithPlayerID(id int32) *entity.Spawn {
|
||||
func (p *Player) GetSpawnWithPlayerID(id int32) *spawn.Spawn {
|
||||
p.indexMutex.RLock()
|
||||
defer p.indexMutex.RUnlock()
|
||||
|
||||
@ -111,7 +111,7 @@ func (p *Player) GetSpawnWithPlayerID(id int32) *entity.Spawn {
|
||||
}
|
||||
|
||||
// GetIDWithPlayerSpawn returns the player-specific ID for a spawn
|
||||
func (p *Player) GetIDWithPlayerSpawn(spawn *entity.Spawn) int32 {
|
||||
func (p *Player) GetIDWithPlayerSpawn(spawn *spawn.Spawn) int32 {
|
||||
if spawn == nil {
|
||||
return 0
|
||||
}
|
||||
@ -126,7 +126,7 @@ func (p *Player) GetIDWithPlayerSpawn(spawn *entity.Spawn) int32 {
|
||||
}
|
||||
|
||||
// GetNextSpawnIndex returns the next available spawn index
|
||||
func (p *Player) GetNextSpawnIndex(spawn *entity.Spawn, setLock bool) int16 {
|
||||
func (p *Player) GetNextSpawnIndex(spawn *spawn.Spawn, setLock bool) int16 {
|
||||
if setLock {
|
||||
p.indexMutex.Lock()
|
||||
defer p.indexMutex.Unlock()
|
||||
@ -152,7 +152,7 @@ func (p *Player) GetNextSpawnIndex(spawn *entity.Spawn, setLock bool) int16 {
|
||||
}
|
||||
|
||||
// SetSpawnMap adds a spawn to the player's spawn map
|
||||
func (p *Player) SetSpawnMap(spawn *entity.Spawn) bool {
|
||||
func (p *Player) SetSpawnMap(spawn *spawn.Spawn) bool {
|
||||
if spawn == nil {
|
||||
return false
|
||||
}
|
||||
@ -176,7 +176,7 @@ func (p *Player) SetSpawnMap(spawn *entity.Spawn) bool {
|
||||
}
|
||||
|
||||
// SetSpawnMapIndex sets a specific index for a spawn
|
||||
func (p *Player) SetSpawnMapIndex(spawn *entity.Spawn, index int32) {
|
||||
func (p *Player) SetSpawnMapIndex(spawn *spawn.Spawn, index int32) {
|
||||
p.indexMutex.Lock()
|
||||
defer p.indexMutex.Unlock()
|
||||
|
||||
@ -185,7 +185,7 @@ func (p *Player) SetSpawnMapIndex(spawn *entity.Spawn, index int32) {
|
||||
}
|
||||
|
||||
// SetSpawnMapAndIndex sets spawn in map and returns the index
|
||||
func (p *Player) SetSpawnMapAndIndex(spawn *entity.Spawn) int16 {
|
||||
func (p *Player) SetSpawnMapAndIndex(spawn *spawn.Spawn) int16 {
|
||||
if spawn == nil {
|
||||
return 0
|
||||
}
|
||||
@ -209,17 +209,17 @@ func (p *Player) SetSpawnMapAndIndex(spawn *entity.Spawn) int16 {
|
||||
}
|
||||
|
||||
// GetSpawnByIndex returns a spawn by its player-specific index
|
||||
func (p *Player) GetSpawnByIndex(index int16) *entity.Spawn {
|
||||
func (p *Player) GetSpawnByIndex(index int16) *spawn.Spawn {
|
||||
return p.GetSpawnWithPlayerID(int32(index))
|
||||
}
|
||||
|
||||
// GetIndexForSpawn returns the player-specific index for a spawn
|
||||
func (p *Player) GetIndexForSpawn(spawn *entity.Spawn) int16 {
|
||||
func (p *Player) GetIndexForSpawn(spawn *spawn.Spawn) int16 {
|
||||
return int16(p.GetIDWithPlayerSpawn(spawn))
|
||||
}
|
||||
|
||||
// WasSpawnRemoved checks if a spawn was removed
|
||||
func (p *Player) WasSpawnRemoved(spawn *entity.Spawn) bool {
|
||||
func (p *Player) WasSpawnRemoved(spawn *spawn.Spawn) bool {
|
||||
if spawn == nil {
|
||||
return false
|
||||
}
|
||||
@ -244,7 +244,7 @@ func (p *Player) ResetSpawnPackets(id int32) {
|
||||
}
|
||||
|
||||
// RemoveSpawn removes a spawn from the player's view
|
||||
func (p *Player) RemoveSpawn(spawn *entity.Spawn, deleteSpawn bool) {
|
||||
func (p *Player) RemoveSpawn(spawn *spawn.Spawn, deleteSpawn bool) {
|
||||
if spawn == nil {
|
||||
return
|
||||
}
|
||||
@ -286,13 +286,13 @@ func (p *Player) RemoveSpawn(spawn *entity.Spawn, deleteSpawn bool) {
|
||||
}
|
||||
|
||||
// ShouldSendSpawn determines if a spawn should be sent to player
|
||||
func (p *Player) ShouldSendSpawn(spawn *entity.Spawn) bool {
|
||||
func (p *Player) ShouldSendSpawn(spawn *spawn.Spawn) bool {
|
||||
if spawn == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
// Don't send self
|
||||
if spawn == &p.Entity.Spawn {
|
||||
if spawn == p.Entity.Spawn {
|
||||
return false
|
||||
}
|
||||
|
||||
@ -302,7 +302,7 @@ func (p *Player) ShouldSendSpawn(spawn *entity.Spawn) bool {
|
||||
}
|
||||
|
||||
// Check distance
|
||||
distance := p.GetDistance(spawn)
|
||||
distance := p.GetDistance(spawn.GetX(), spawn.GetY(), spawn.GetZ(), true)
|
||||
maxDistance := float32(200.0) // TODO: Get from rule system
|
||||
|
||||
if distance > maxDistance {
|
||||
@ -333,11 +333,11 @@ func (p *Player) ClearRemovalTimers() {
|
||||
// ResetSavedSpawns resets all saved spawn data
|
||||
func (p *Player) ResetSavedSpawns() {
|
||||
p.indexMutex.Lock()
|
||||
p.playerSpawnIDMap = make(map[int32]*entity.Spawn)
|
||||
p.playerSpawnReverseIDMap = make(map[*entity.Spawn]int32)
|
||||
p.playerSpawnIDMap = make(map[int32]*spawn.Spawn)
|
||||
p.playerSpawnReverseIDMap = make(map[*spawn.Spawn]int32)
|
||||
// Re-add self
|
||||
p.playerSpawnIDMap[1] = &p.Entity.Spawn
|
||||
p.playerSpawnReverseIDMap[&p.Entity.Spawn] = 1
|
||||
p.playerSpawnIDMap[1] = p.Entity.Spawn
|
||||
p.playerSpawnReverseIDMap[p.Entity.Spawn] = 1
|
||||
p.indexMutex.Unlock()
|
||||
|
||||
p.spawnMutex.Lock()
|
||||
|
@ -88,7 +88,7 @@ func (p *Player) GetSpellBookSpellIDBySkill(skillID int32) []int32 {
|
||||
defer p.spellsBookMutex.RUnlock()
|
||||
|
||||
var spellIDs []int32
|
||||
for _, entry := range p.spells {
|
||||
for range p.spells {
|
||||
// TODO: Check if spell matches skill
|
||||
// spell := master_spell_list.GetSpell(entry.SpellID)
|
||||
// if spell != nil && spell.GetSkillID() == skillID {
|
||||
@ -105,7 +105,7 @@ func (p *Player) HasSpell(spellID int32, tier int8, includeHigherTiers bool, inc
|
||||
|
||||
for _, entry := range p.spells {
|
||||
if entry.SpellID == spellID {
|
||||
if tier == 255 || entry.Tier == tier {
|
||||
if tier == 127 || entry.Tier == tier { // Changed from 255 to avoid int8 overflow
|
||||
return true
|
||||
}
|
||||
if includeHigherTiers && entry.Tier > tier {
|
||||
@ -390,7 +390,7 @@ func (p *Player) UnlockSpell(spell *spells.Spell) {
|
||||
return
|
||||
}
|
||||
|
||||
p.UnlockSpellByID(spell.GetSpellID(), spell.GetSpellData().LinkedTimerID)
|
||||
p.UnlockSpellByID(spell.GetSpellID(), GetSpellLinkedTimerID(spell.GetSpellData()))
|
||||
}
|
||||
|
||||
// UnlockSpellByID unlocks a spell by ID
|
||||
@ -412,7 +412,7 @@ func (p *Player) LockTSSpells() {
|
||||
p.spellsBookMutex.Lock()
|
||||
defer p.spellsBookMutex.Unlock()
|
||||
|
||||
for _, entry := range p.spells {
|
||||
for range p.spells {
|
||||
// TODO: Check if tradeskill spell
|
||||
// if spell.IsTradeskill() {
|
||||
// entry.Status |= SPELL_STATUS_LOCK
|
||||
@ -427,7 +427,7 @@ func (p *Player) UnlockTSSpells() {
|
||||
p.spellsBookMutex.Lock()
|
||||
defer p.spellsBookMutex.Unlock()
|
||||
|
||||
for _, entry := range p.spells {
|
||||
for range p.spells {
|
||||
// TODO: Check if tradeskill spell
|
||||
// if spell.IsTradeskill() {
|
||||
// entry.Status &= ^SPELL_STATUS_LOCK
|
||||
@ -506,8 +506,8 @@ func (p *Player) RemovePassive(id int32, tier int8, removeFromList bool) {
|
||||
// ApplyPassiveSpells applies all passive spells
|
||||
func (p *Player) ApplyPassiveSpells() {
|
||||
// TODO: Cast all passive spells
|
||||
for _, spellID := range p.passiveSpells {
|
||||
// Get spell and cast it
|
||||
for range p.passiveSpells {
|
||||
// TODO: Get spell and cast it
|
||||
}
|
||||
}
|
||||
|
||||
|
529
internal/player/stubs.go
Normal file
529
internal/player/stubs.go
Normal file
@ -0,0 +1,529 @@
|
||||
package player
|
||||
|
||||
// This file contains placeholder stub methods to make the player package compile
|
||||
// These methods should be properly implemented when the corresponding systems are ready
|
||||
|
||||
import (
|
||||
"eq2emu/internal/entity"
|
||||
"eq2emu/internal/quests"
|
||||
"eq2emu/internal/skills"
|
||||
"eq2emu/internal/spells"
|
||||
)
|
||||
|
||||
// Player-level flags handling since InfoStruct doesn't have these methods yet
|
||||
var playerFlags = make(map[int32]int32)
|
||||
var playerFlags2 = make(map[int32]int32)
|
||||
|
||||
// GetPlayerFlags returns player flags for a character
|
||||
func (p *Player) GetPlayerFlags() int32 {
|
||||
return playerFlags[p.GetCharacterID()]
|
||||
}
|
||||
|
||||
// SetPlayerFlags sets player flags for a character
|
||||
func (p *Player) SetPlayerFlags(flags int32) {
|
||||
playerFlags[p.GetCharacterID()] = flags
|
||||
}
|
||||
|
||||
// GetPlayerFlags2 returns player flags2 for a character
|
||||
func (p *Player) GetPlayerFlags2() int32 {
|
||||
return playerFlags2[p.GetCharacterID()]
|
||||
}
|
||||
|
||||
// SetPlayerFlags2 sets player flags2 for a character
|
||||
func (p *Player) SetPlayerFlags2(flags int32) {
|
||||
playerFlags2[p.GetCharacterID()] = flags
|
||||
}
|
||||
|
||||
// Player stub methods that may be called by other packages
|
||||
|
||||
// GetPrimaryStat returns the primary stat for the player's class (stub)
|
||||
func (p *Player) GetPrimaryStat() int32 {
|
||||
// TODO: Calculate based on class
|
||||
return 100
|
||||
}
|
||||
|
||||
// GetTarget returns the player's current target (stub)
|
||||
func (p *Player) GetTarget() interface{} {
|
||||
// TODO: Implement targeting system
|
||||
return nil
|
||||
}
|
||||
|
||||
// IsStunned returns whether the player is stunned (stub)
|
||||
func (p *Player) IsStunned() bool {
|
||||
// TODO: Implement status effect system
|
||||
return false
|
||||
}
|
||||
|
||||
// IsMezzed returns whether the player is mezzed (stub)
|
||||
func (p *Player) IsMezzed() bool {
|
||||
// TODO: Implement status effect system
|
||||
return false
|
||||
}
|
||||
|
||||
// Player-level combat state handling
|
||||
var playerEngageCommands = make(map[int32]int32)
|
||||
|
||||
// GetPlayerEngageCommands returns combat state for a character
|
||||
func (p *Player) GetPlayerEngageCommands() int32 {
|
||||
return playerEngageCommands[p.GetCharacterID()]
|
||||
}
|
||||
|
||||
// SetPlayerEngageCommands sets combat state for a character
|
||||
func (p *Player) SetPlayerEngageCommands(commands int32) {
|
||||
playerEngageCommands[p.GetCharacterID()] = commands
|
||||
}
|
||||
|
||||
// IsDead returns whether the player is dead (stub)
|
||||
func (p *Player) IsDead() bool {
|
||||
// TODO: Implement death state tracking
|
||||
return p.GetHP() <= 0
|
||||
}
|
||||
|
||||
// Note: IsPlayer method is already implemented in player.go, so removed duplicate
|
||||
|
||||
// Entity stub methods for combat target
|
||||
var entityDeathState = make(map[*entity.Entity]bool)
|
||||
|
||||
// IsDead checks if an entity is dead (stub for Entity type)
|
||||
func IsDead(e *entity.Entity) bool {
|
||||
// TODO: Implement proper entity death checking
|
||||
return entityDeathState[e]
|
||||
}
|
||||
|
||||
// Coin management stubs
|
||||
var playerCoins = make(map[int32]int64) // characterID -> coin amount
|
||||
|
||||
// AddCoin adds coins to the player's InfoStruct (stub)
|
||||
func (p *Player) AddCoin(amount int64) {
|
||||
current := playerCoins[p.GetCharacterID()]
|
||||
playerCoins[p.GetCharacterID()] = current + amount
|
||||
}
|
||||
|
||||
// GetCoin returns the player's current coin amount (stub)
|
||||
func (p *Player) GetCoin() int64 {
|
||||
return playerCoins[p.GetCharacterID()]
|
||||
}
|
||||
|
||||
// SubtractCoin removes coins from the player (stub)
|
||||
func (p *Player) SubtractCoin(amount int64) bool {
|
||||
current := playerCoins[p.GetCharacterID()]
|
||||
if current >= amount {
|
||||
playerCoins[p.GetCharacterID()] = current - amount
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// InfoStruct coin access stubs - these methods don't exist on InfoStruct yet
|
||||
var playerCoinBreakdown = make(map[int32]map[string]int32) // characterID -> coin type -> amount
|
||||
|
||||
// GetCoinCopper returns copper coins (stub)
|
||||
func (p *Player) GetInfoStructCoinCopper() int32 {
|
||||
if playerCoinBreakdown[p.GetCharacterID()] == nil {
|
||||
return 0
|
||||
}
|
||||
return playerCoinBreakdown[p.GetCharacterID()]["copper"]
|
||||
}
|
||||
|
||||
// GetCoinSilver returns silver coins (stub)
|
||||
func (p *Player) GetInfoStructCoinSilver() int32 {
|
||||
if playerCoinBreakdown[p.GetCharacterID()] == nil {
|
||||
return 0
|
||||
}
|
||||
return playerCoinBreakdown[p.GetCharacterID()]["silver"]
|
||||
}
|
||||
|
||||
// GetCoinGold returns gold coins (stub)
|
||||
func (p *Player) GetInfoStructCoinGold() int32 {
|
||||
if playerCoinBreakdown[p.GetCharacterID()] == nil {
|
||||
return 0
|
||||
}
|
||||
return playerCoinBreakdown[p.GetCharacterID()]["gold"]
|
||||
}
|
||||
|
||||
// GetCoinPlat returns platinum coins (stub)
|
||||
func (p *Player) GetInfoStructCoinPlat() int32 {
|
||||
if playerCoinBreakdown[p.GetCharacterID()] == nil {
|
||||
return 0
|
||||
}
|
||||
return playerCoinBreakdown[p.GetCharacterID()]["plat"]
|
||||
}
|
||||
|
||||
// Bank coin methods (stubs)
|
||||
func (p *Player) GetInfoStructBankCoinCopper() int32 {
|
||||
if playerCoinBreakdown[p.GetCharacterID()] == nil {
|
||||
return 0
|
||||
}
|
||||
return playerCoinBreakdown[p.GetCharacterID()]["bank_copper"]
|
||||
}
|
||||
|
||||
func (p *Player) GetInfoStructBankCoinSilver() int32 {
|
||||
if playerCoinBreakdown[p.GetCharacterID()] == nil {
|
||||
return 0
|
||||
}
|
||||
return playerCoinBreakdown[p.GetCharacterID()]["bank_silver"]
|
||||
}
|
||||
|
||||
func (p *Player) GetInfoStructBankCoinGold() int32 {
|
||||
if playerCoinBreakdown[p.GetCharacterID()] == nil {
|
||||
return 0
|
||||
}
|
||||
return playerCoinBreakdown[p.GetCharacterID()]["bank_gold"]
|
||||
}
|
||||
|
||||
func (p *Player) GetInfoStructBankCoinPlat() int32 {
|
||||
if playerCoinBreakdown[p.GetCharacterID()] == nil {
|
||||
return 0
|
||||
}
|
||||
return playerCoinBreakdown[p.GetCharacterID()]["bank_plat"]
|
||||
}
|
||||
|
||||
// GetStatusPoints returns status points (stub)
|
||||
func (p *Player) GetInfoStructStatusPoints() int32 {
|
||||
if playerCoinBreakdown[p.GetCharacterID()] == nil {
|
||||
return 0
|
||||
}
|
||||
return playerCoinBreakdown[p.GetCharacterID()]["status"]
|
||||
}
|
||||
|
||||
// Player methods that don't exist on Entity/Spawn yet (stubs)
|
||||
func (p *Player) SetRace(race int8) {
|
||||
// TODO: Implement race setting on entity/spawn
|
||||
// For now, store in a map
|
||||
if playerCoinBreakdown[p.GetCharacterID()] == nil {
|
||||
playerCoinBreakdown[p.GetCharacterID()] = make(map[string]int32)
|
||||
}
|
||||
playerCoinBreakdown[p.GetCharacterID()]["race"] = int32(race)
|
||||
}
|
||||
|
||||
func (p *Player) GetRace() int8 {
|
||||
// TODO: Implement race getting from entity/spawn
|
||||
if playerCoinBreakdown[p.GetCharacterID()] == nil {
|
||||
return 0
|
||||
}
|
||||
return int8(playerCoinBreakdown[p.GetCharacterID()]["race"])
|
||||
}
|
||||
|
||||
func (p *Player) SetZone(zoneID int32) {
|
||||
// TODO: Implement zone setting on entity/spawn
|
||||
if playerCoinBreakdown[p.GetCharacterID()] == nil {
|
||||
playerCoinBreakdown[p.GetCharacterID()] = make(map[string]int32)
|
||||
}
|
||||
playerCoinBreakdown[p.GetCharacterID()]["zone"] = zoneID
|
||||
}
|
||||
|
||||
func (p *Player) GetZone() int32 {
|
||||
// TODO: Implement zone getting from entity/spawn
|
||||
if playerCoinBreakdown[p.GetCharacterID()] == nil {
|
||||
return 0
|
||||
}
|
||||
return playerCoinBreakdown[p.GetCharacterID()]["zone"]
|
||||
}
|
||||
|
||||
// Experience vitality methods (InfoStruct stubs)
|
||||
func (p *Player) GetInfoStructXPVitality() float32 {
|
||||
// TODO: Implement XP vitality tracking
|
||||
return 100.0 // Default vitality
|
||||
}
|
||||
|
||||
func (p *Player) GetInfoStructTSXPVitality() float32 {
|
||||
// TODO: Implement tradeskill XP vitality tracking
|
||||
return 100.0 // Default vitality
|
||||
}
|
||||
|
||||
// More InfoStruct experience method stubs
|
||||
var playerXPData = make(map[int32]map[string]float64) // characterID -> xp type -> value
|
||||
|
||||
func (p *Player) GetInfoStructXPDebt() float32 {
|
||||
charID := p.GetCharacterID()
|
||||
if playerXPData[charID] == nil {
|
||||
return 0.0
|
||||
}
|
||||
return float32(playerXPData[charID]["xp_debt"])
|
||||
}
|
||||
|
||||
func (p *Player) GetInfoStructTSXPDebt() float32 {
|
||||
charID := p.GetCharacterID()
|
||||
if playerXPData[charID] == nil {
|
||||
return 0.0
|
||||
}
|
||||
return float32(playerXPData[charID]["ts_xp_debt"])
|
||||
}
|
||||
|
||||
func (p *Player) SetInfoStructXPNeeded(xp float64) {
|
||||
charID := p.GetCharacterID()
|
||||
if playerXPData[charID] == nil {
|
||||
playerXPData[charID] = make(map[string]float64)
|
||||
}
|
||||
playerXPData[charID]["xp_needed"] = xp
|
||||
}
|
||||
|
||||
func (p *Player) SetInfoStructXP(xp float64) {
|
||||
charID := p.GetCharacterID()
|
||||
if playerXPData[charID] == nil {
|
||||
playerXPData[charID] = make(map[string]float64)
|
||||
}
|
||||
playerXPData[charID]["xp"] = xp
|
||||
}
|
||||
|
||||
func (p *Player) SetInfoStructTSXPNeeded(xp float64) {
|
||||
charID := p.GetCharacterID()
|
||||
if playerXPData[charID] == nil {
|
||||
playerXPData[charID] = make(map[string]float64)
|
||||
}
|
||||
playerXPData[charID]["ts_xp_needed"] = xp
|
||||
}
|
||||
|
||||
func (p *Player) SetInfoStructTSXP(xp float64) {
|
||||
charID := p.GetCharacterID()
|
||||
if playerXPData[charID] == nil {
|
||||
playerXPData[charID] = make(map[string]float64)
|
||||
}
|
||||
playerXPData[charID]["ts_xp"] = xp
|
||||
}
|
||||
|
||||
func (p *Player) GetInfoStructXPNeeded() float64 {
|
||||
charID := p.GetCharacterID()
|
||||
if playerXPData[charID] == nil {
|
||||
return 1000.0 // Default XP needed
|
||||
}
|
||||
return playerXPData[charID]["xp_needed"]
|
||||
}
|
||||
|
||||
func (p *Player) GetInfoStructXP() float64 {
|
||||
charID := p.GetCharacterID()
|
||||
if playerXPData[charID] == nil {
|
||||
return 0.0
|
||||
}
|
||||
return playerXPData[charID]["xp"]
|
||||
}
|
||||
|
||||
func (p *Player) GetInfoStructTSXPNeeded() float64 {
|
||||
charID := p.GetCharacterID()
|
||||
if playerXPData[charID] == nil {
|
||||
return 1000.0 // Default TS XP needed
|
||||
}
|
||||
return playerXPData[charID]["ts_xp_needed"]
|
||||
}
|
||||
|
||||
func (p *Player) GetInfoStructTSXP() float64 {
|
||||
charID := p.GetCharacterID()
|
||||
if playerXPData[charID] == nil {
|
||||
return 0.0
|
||||
}
|
||||
return playerXPData[charID]["ts_xp"]
|
||||
}
|
||||
|
||||
// XP Debt methods
|
||||
func (p *Player) SetInfoStructXPDebt(debt float32) {
|
||||
charID := p.GetCharacterID()
|
||||
if playerXPData[charID] == nil {
|
||||
playerXPData[charID] = make(map[string]float64)
|
||||
}
|
||||
playerXPData[charID]["xp_debt"] = float64(debt)
|
||||
}
|
||||
|
||||
func (p *Player) SetInfoStructTSXPDebt(debt float32) {
|
||||
charID := p.GetCharacterID()
|
||||
if playerXPData[charID] == nil {
|
||||
playerXPData[charID] = make(map[string]float64)
|
||||
}
|
||||
playerXPData[charID]["ts_xp_debt"] = float64(debt)
|
||||
}
|
||||
|
||||
// TS Level methods
|
||||
func (p *Player) GetInfoStructTSLevel() int8 {
|
||||
charID := p.GetCharacterID()
|
||||
if playerXPData[charID] == nil {
|
||||
return 1 // Default level
|
||||
}
|
||||
return int8(playerXPData[charID]["ts_level"])
|
||||
}
|
||||
|
||||
func (p *Player) SetInfoStructTSLevel(level int8) {
|
||||
charID := p.GetCharacterID()
|
||||
if playerXPData[charID] == nil {
|
||||
playerXPData[charID] = make(map[string]float64)
|
||||
}
|
||||
playerXPData[charID]["ts_level"] = float64(level)
|
||||
}
|
||||
|
||||
// Player wrapper methods for TS level
|
||||
func (p *Player) GetTSLevel() int8 {
|
||||
return p.GetInfoStructTSLevel()
|
||||
}
|
||||
|
||||
func (p *Player) SetTSLevel(level int8) {
|
||||
p.SetInfoStructTSLevel(level)
|
||||
p.SetCharSheetChanged(true)
|
||||
}
|
||||
|
||||
// GetSpawnID returns the spawn ID (in EverQuest II, players use same ID as spawn)
|
||||
func (p *Player) GetSpawnID() int32 {
|
||||
// Use the player's spawnID field
|
||||
return p.spawnID
|
||||
}
|
||||
|
||||
// SetSpawnID sets the spawn ID
|
||||
func (p *Player) SetSpawnID(id int32) {
|
||||
p.spawnID = id
|
||||
}
|
||||
|
||||
// AddSecondaryEntityCommand adds a secondary command (stub)
|
||||
func (p *Player) AddSecondaryEntityCommand(name string, distance float32, command, errorText string, castTime int16, spellID int32) {
|
||||
// TODO: Implement secondary entity commands
|
||||
}
|
||||
|
||||
// Position and movement data storage (stubs for appearance system)
|
||||
var playerMovementData = make(map[int32]map[string]float32) // characterID -> movement type -> value
|
||||
|
||||
// SetPos sets positional data (stub)
|
||||
func (p *Player) SetPos(ptr *float32, value float32, updateFlags bool) {
|
||||
// Since we can't access the appearance system, just store the value
|
||||
charID := p.GetCharacterID()
|
||||
if playerMovementData[charID] == nil {
|
||||
playerMovementData[charID] = make(map[string]float32)
|
||||
}
|
||||
*ptr = value // Set the pointer value if it's valid
|
||||
// TODO: Handle updateFlags when packet system is available
|
||||
}
|
||||
|
||||
// GetPos gets positional data (stub)
|
||||
func (p *Player) GetPos(key string) float32 {
|
||||
charID := p.GetCharacterID()
|
||||
if playerMovementData[charID] == nil {
|
||||
return 0.0
|
||||
}
|
||||
return playerMovementData[charID][key]
|
||||
}
|
||||
|
||||
// XP bar display methods (InfoStruct stubs)
|
||||
func (p *Player) SetInfoStructXPYellow(value int16) {
|
||||
// TODO: Implement XP bar display
|
||||
}
|
||||
|
||||
func (p *Player) SetInfoStructXPBlue(value int16) {
|
||||
// TODO: Implement XP bar display
|
||||
}
|
||||
|
||||
func (p *Player) SetInfoStructXPBlueVitalityBar(value int16) {
|
||||
// TODO: Implement XP bar display
|
||||
}
|
||||
|
||||
func (p *Player) SetInfoStructXPYellowVitalityBar(value int16) {
|
||||
// TODO: Implement XP bar display
|
||||
}
|
||||
|
||||
func (p *Player) SetInfoStructTSXPYellow(value int16) {
|
||||
// TODO: Implement TS XP bar display
|
||||
}
|
||||
|
||||
func (p *Player) SetInfoStructTSXPBlue(value int16) {
|
||||
// TODO: Implement TS XP bar display
|
||||
}
|
||||
|
||||
func (p *Player) SetInfoStructTSXPBlueVitalityBar(value int16) {
|
||||
// TODO: Implement TS XP bar display
|
||||
}
|
||||
|
||||
func (p *Player) SetInfoStructTSXPYellowVitalityBar(value int16) {
|
||||
// TODO: Implement TS XP bar display
|
||||
}
|
||||
|
||||
// XP bar getter methods (InfoStruct stubs)
|
||||
func (p *Player) GetInfoStructXPBlue() int16 {
|
||||
// TODO: Implement XP bar display
|
||||
return 0
|
||||
}
|
||||
|
||||
func (p *Player) GetInfoStructXPYellow() int16 {
|
||||
// TODO: Implement XP bar display
|
||||
return 0
|
||||
}
|
||||
|
||||
// Tradeskill XP bar methods
|
||||
func (p *Player) SetInfoStructTradeskillExpYellow(value int16) {
|
||||
// TODO: Implement TS XP bar display
|
||||
}
|
||||
|
||||
func (p *Player) SetInfoStructTradeskillExpBlue(value int16) {
|
||||
// TODO: Implement TS XP bar display
|
||||
}
|
||||
|
||||
func (p *Player) SetInfoStructTSExpVitalityBlue(value int16) {
|
||||
// TODO: Implement TS XP vitality bar display
|
||||
}
|
||||
|
||||
func (p *Player) SetInfoStructTSExpVitalityYellow(value int16) {
|
||||
// TODO: Implement TS XP vitality bar display
|
||||
}
|
||||
|
||||
func (p *Player) GetInfoStructTradeskillExpBlue() int16 {
|
||||
// TODO: Implement TS XP bar display
|
||||
return 0
|
||||
}
|
||||
|
||||
func (p *Player) GetInfoStructTradeskillExpYellow() int16 {
|
||||
// TODO: Implement TS XP bar display
|
||||
return 0
|
||||
}
|
||||
|
||||
// Account age methods (InfoStruct stubs)
|
||||
func (p *Player) SetInfoStructAccountAgeBase(value int32) {
|
||||
// TODO: Implement account age tracking
|
||||
}
|
||||
|
||||
func (p *Player) SetInfoStructAccountAge(value int32) {
|
||||
// TODO: Implement account age tracking
|
||||
}
|
||||
|
||||
// Quest helper functions - working around missing quest methods
|
||||
// These should ideally be proper methods on the Quest type in the quests package
|
||||
|
||||
func GetQuestCompleteCount(q *quests.Quest) int32 {
|
||||
// TODO: Implement quest completion tracking
|
||||
// For now return 0 as a placeholder
|
||||
return 0
|
||||
}
|
||||
|
||||
func GetQuestID(q *quests.Quest) int32 {
|
||||
// TODO: This should access q.ID field when available
|
||||
return 0
|
||||
}
|
||||
|
||||
func GetQuestStep(q *quests.Quest) int16 {
|
||||
// TODO: Implement quest step retrieval
|
||||
return 0
|
||||
}
|
||||
|
||||
func GetQuestTaskGroup(q *quests.Quest) int8 {
|
||||
// TODO: Implement quest task group system
|
||||
return 0
|
||||
}
|
||||
|
||||
func IncrementQuestCompleteCount(q *quests.Quest) {
|
||||
// TODO: Implement quest completion tracking
|
||||
}
|
||||
|
||||
// PlayerSkillList helper methods to work around method signature differences
|
||||
func (p *Player) GetSkillByNameHelper(name string, checkUpdate bool) *skills.Skill {
|
||||
// TODO: Work around method signature mismatch
|
||||
// The actual method only takes name as parameter
|
||||
return p.skillList.GetSkillByName(name)
|
||||
}
|
||||
|
||||
func (p *Player) AddSkillHelper(skillID int32, currentVal, maxVal int16, saveNeeded bool) {
|
||||
// TODO: Create proper Skill object and add it
|
||||
// For now, this is a placeholder stub
|
||||
}
|
||||
|
||||
func (p *Player) RemoveSkillHelper(skillID int32) {
|
||||
// TODO: Remove skill by ID
|
||||
// For now, this is a placeholder stub
|
||||
}
|
||||
|
||||
// SpellData method stubs
|
||||
func GetSpellLinkedTimerID(spellData *spells.SpellData) int32 {
|
||||
// TODO: Implement LinkedTimerID field access
|
||||
return 0
|
||||
}
|
@ -11,6 +11,7 @@ import (
|
||||
"eq2emu/internal/languages"
|
||||
"eq2emu/internal/quests"
|
||||
"eq2emu/internal/skills"
|
||||
"eq2emu/internal/spawn"
|
||||
"eq2emu/internal/spells"
|
||||
"eq2emu/internal/titles"
|
||||
)
|
||||
@ -81,7 +82,7 @@ type QuickBarItem struct {
|
||||
ID int32
|
||||
Tier int8
|
||||
UniqueID int64
|
||||
Text common.EQ2String16Bit
|
||||
Text common.EQ2String16
|
||||
}
|
||||
|
||||
// LoginAppearances represents equipment appearance data for login
|
||||
@ -347,8 +348,8 @@ type Player struct {
|
||||
spawnPosPacketList map[int32]string
|
||||
spawnPacketSent map[int32]int8
|
||||
spawnStateList map[int32]*SpawnQueueState
|
||||
playerSpawnIDMap map[int32]*entity.Spawn
|
||||
playerSpawnReverseIDMap map[*entity.Spawn]int32
|
||||
playerSpawnIDMap map[int32]*spawn.Spawn
|
||||
playerSpawnReverseIDMap map[*spawn.Spawn]int32
|
||||
playerAggroRangeSpawns map[int32]bool
|
||||
|
||||
// Temporary spawn packets for XOR
|
||||
@ -378,7 +379,7 @@ type Player struct {
|
||||
playerQuests map[int32]*quests.Quest
|
||||
completedQuests map[int32]*quests.Quest
|
||||
pendingQuests map[int32]*quests.Quest
|
||||
currentQuestFlagged map[*entity.Spawn]bool
|
||||
currentQuestFlagged map[*spawn.Spawn]bool
|
||||
playerSpawnQuestsRequired map[int32][]int32
|
||||
playerSpawnHistoryRequired map[int32][]int32
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user