eq2go/internal/player/combat.go
2025-08-06 17:55:41 -05:00

290 lines
7.0 KiB
Go

package player
import (
"eq2emu/internal/entity"
)
// InCombat sets the player's combat state
func (p *Player) InCombat(val bool, ranged bool) {
if val {
// Entering combat
if ranged {
p.SetCharacterFlag(CF_RANGED_AUTO_ATTACK)
p.SetRangeAttack(true)
} else {
p.SetCharacterFlag(CF_AUTO_ATTACK)
}
// Set combat state
prevState := p.GetPlayerEngageCommands()
if ranged {
p.SetPlayerEngageCommands(prevState | RANGE_COMBAT_STATE)
} else {
p.SetPlayerEngageCommands(prevState | MELEE_COMBAT_STATE)
}
} else {
// Leaving combat
if ranged {
p.ResetCharacterFlag(CF_RANGED_AUTO_ATTACK)
p.SetRangeAttack(false)
prevState := p.GetPlayerEngageCommands()
p.SetPlayerEngageCommands(prevState & ^RANGE_COMBAT_STATE)
} else {
p.ResetCharacterFlag(CF_AUTO_ATTACK)
prevState := p.GetPlayerEngageCommands()
p.SetPlayerEngageCommands(prevState & ^MELEE_COMBAT_STATE)
}
// Clear combat target if leaving all combat
if p.GetPlayerEngageCommands() == 0 {
p.combatTarget = nil
}
}
p.SetCharSheetChanged(true)
}
// ProcessCombat processes combat actions
func (p *Player) ProcessCombat() {
// Check if in combat
if p.GetPlayerEngageCommands() == 0 {
return
}
// Check if we have a valid target
if p.combatTarget == nil || IsDead(p.combatTarget) {
p.StopCombat(0)
return
}
// Check distance to target
distance := p.GetDistance(p.combatTarget.GetX(), p.combatTarget.GetY(), p.combatTarget.GetZ(), true)
// Process based on combat type
if p.rangeAttack {
// Ranged combat
maxRange := p.GetRangeWeaponRange()
if distance > maxRange {
// Too far for ranged
// TODO: Send out of range message
return
}
// TODO: Process ranged auto-attack
} else {
// Melee combat
maxRange := p.GetMeleeWeaponRange()
if distance > maxRange {
// Too far for melee
// TODO: Send out of range message
return
}
// TODO: Process melee auto-attack
}
}
// GetRangeWeaponRange returns the range of the equipped ranged weapon
func (p *Player) GetRangeWeaponRange() float32 {
// TODO: Get from equipped ranged weapon
return 35.0 // Default bow range
}
// GetMeleeWeaponRange returns the range of melee weapons
func (p *Player) GetMeleeWeaponRange() float32 {
// TODO: Adjust based on weapon type and mob size
return 5.0 // Default melee range
}
// SetCombatTarget sets the current combat target
func (p *Player) SetCombatTarget(target *entity.Entity) {
p.combatTarget = target
}
// GetCombatTarget returns the current combat target
func (p *Player) GetCombatTarget() *entity.Entity {
return p.combatTarget
}
// DamageEquippedItems damages equipped items by durability
func (p *Player) DamageEquippedItems(amount int8, client *Client) bool {
// TODO: Implement item durability damage
// This would:
// 1. Get all equipped items
// 2. Reduce durability by amount
// 3. Check if any items broke
// 4. Send updates to client
return false
}
// GetTSArrowColor returns the arrow color for tradeskill con
func (p *Player) GetTSArrowColor(level int8) int8 {
levelDiff := int(level) - int(p.GetTSLevel())
if levelDiff >= 10 {
return 4 // Red
} else if levelDiff >= 5 {
return 3 // Orange
} else if levelDiff >= 1 {
return 2 // Yellow
} else if levelDiff >= -5 {
return 1 // White
} else if levelDiff >= -9 {
return 0 // Blue
} else {
return 6 // Green
}
}
// CheckLevelStatus checks and updates level-based statuses
func (p *Player) CheckLevelStatus(newLevel int16) bool {
// TODO: Implement level status checks
// This would check things like:
// - Mentoring status
// - Level-locked abilities
// - Zone level requirements
// - etc.
return true
}
// CalculatePlayerHPPower calculates HP and Power for the player
func (p *Player) CalculatePlayerHPPower(newLevel int16) {
if newLevel == 0 {
newLevel = int16(p.GetLevel())
}
// TODO: Implement proper HP/Power calculation
// This is a simplified version
// Base HP calculation
baseHP := int32(50 + (newLevel * 20))
staminaBonus := int32(p.GetInfoStruct().GetSta() * 10)
totalHP := baseHP + staminaBonus
// Base Power calculation
basePower := int32(50 + (newLevel * 10))
primaryStatBonus := p.GetPrimaryStat() * 10
totalPower := basePower + primaryStatBonus
// Set the values
p.SetTotalHP(totalHP)
p.SetTotalPower(totalPower)
// Set current values if needed
if p.GetHP() > totalHP {
p.SetHP(totalHP)
}
if p.GetPower() > totalPower {
p.SetPower(totalPower)
}
}
// IsAllowedCombatEquip checks if combat equipment changes are allowed
func (p *Player) IsAllowedCombatEquip(slot int8, sendMessage bool) bool {
// Can't change equipment while:
// - Dead
// - In combat (for certain slots)
// - Casting
// - Stunned/Mezzed
if p.IsDead() {
if sendMessage {
// TODO: Send "You cannot change equipment while dead" message
}
return false
}
// Check if in combat
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 == -1 { // -1 = all slots
if sendMessage {
// TODO: Send "You cannot change that equipment in combat" message
}
return false
}
}
}
// Check if casting
if p.IsCasting() {
if sendMessage {
// TODO: Send "You cannot change equipment while casting" message
}
return false
}
// Check control effects
if p.IsStunned() || p.IsMezzed() {
if sendMessage {
// TODO: Send appropriate message
}
return false
}
return true
}
// IsCasting returns whether the player is currently casting
func (p *Player) IsCasting() bool {
// TODO: Check actual casting state
return false
}
// DismissAllPets dismisses all of the player's pets
func (p *Player) DismissAllPets() {
// TODO: Implement pet dismissal
// This would:
// 1. Get all pets (combat, non-combat, deity, etc.)
// 2. Remove them from world
// 3. Clear pet references
// 4. Send updates to client
}
// MentorTarget mentors the current target
func (p *Player) MentorTarget() {
target := p.GetTarget()
if target == nil {
// TODO: Send "Invalid mentor target" message
return
}
targetPlayer, ok := target.(*Player)
if !ok {
return
}
// Check if target is valid for mentoring
if targetPlayer.GetLevel() >= p.GetLevel() {
// TODO: Send "Target must be lower level" message
return
}
// Set mentor stats
p.SetMentorStats(int32(targetPlayer.GetLevel()), targetPlayer.GetCharacterID(), true)
}
// SetMentorStats sets the player's effective level for mentoring
func (p *Player) SetMentorStats(effectiveLevel int32, targetCharID int32, updateStats bool) {
if effectiveLevel < 1 || effectiveLevel > int32(p.GetLevel()) {
effectiveLevel = int32(p.GetLevel())
}
p.GetInfoStruct().SetEffectiveLevel(int16(effectiveLevel))
if updateStats {
// TODO: Recalculate all stats for new effective level
p.CalculatePlayerHPPower(int16(effectiveLevel))
// TODO: Update other stats (mitigation, avoidance, etc.)
}
if effectiveLevel < int32(p.GetLevel()) {
p.EnableResetMentorship()
}
p.SetCharSheetChanged(true)
}