package ai import ( "a301_game_server/internal/combat" "a301_game_server/internal/entity" "a301_game_server/pkg/mathutil" pb "a301_game_server/proto/gen/pb" ) // MobDef defines a mob template loaded from data. type MobDef struct { ID uint32 Name string Level int32 HP int32 MP int32 Str int32 Dex int32 Int int32 MoveSpeed float32 // units per second AggroRange float32 // distance to start chasing AttackRange float32 AttackSkill uint32 // skill ID used for auto-attack LeashRange float32 // max distance from spawn before returning ExpReward int64 LootTable []LootEntry } // LootEntry defines a possible drop. type LootEntry struct { ItemID uint32 Quantity int32 Chance float32 // 0.0 - 1.0 } // Mob is a server-controlled enemy entity. type Mob struct { id uint64 def *MobDef position mathutil.Vec3 rotation float32 hp int32 maxHP int32 mp int32 maxMP int32 spawnPos mathutil.Vec3 alive bool // AI state state AIState targetID uint64 // entity being chased/attacked } // NewMob creates a mob from a definition at the given position. func NewMob(id uint64, def *MobDef, spawnPos mathutil.Vec3) *Mob { return &Mob{ id: id, def: def, position: spawnPos, spawnPos: spawnPos, hp: def.HP, maxHP: def.HP, mp: def.MP, maxMP: def.MP, alive: true, state: StateIdle, } } // Entity interface func (m *Mob) EntityID() uint64 { return m.id } func (m *Mob) EntityType() entity.Type { return entity.TypeMob } func (m *Mob) Position() mathutil.Vec3 { return m.position } func (m *Mob) SetPosition(p mathutil.Vec3) { m.position = p } func (m *Mob) Rotation() float32 { return m.rotation } func (m *Mob) SetRotation(r float32) { m.rotation = r } // Combatant interface func (m *Mob) HP() int32 { return m.hp } func (m *Mob) MaxHP() int32 { return m.maxHP } func (m *Mob) SetHP(hp int32) { if hp < 0 { hp = 0 } if hp > m.maxHP { hp = m.maxHP } m.hp = hp m.alive = hp > 0 } func (m *Mob) MP() int32 { return m.mp } func (m *Mob) SetMP(mp int32) { if mp < 0 { mp = 0 } m.mp = mp } func (m *Mob) IsAlive() bool { return m.alive } func (m *Mob) Stats() combat.CombatStats { return combat.CombatStats{ Str: m.def.Str, Dex: m.def.Dex, Int: m.def.Int, Level: m.def.Level, } } func (m *Mob) Def() *MobDef { return m.def } func (m *Mob) SpawnPos() mathutil.Vec3 { return m.spawnPos } func (m *Mob) State() AIState { return m.state } func (m *Mob) SetState(s AIState) { m.state = s } func (m *Mob) TargetID() uint64 { return m.targetID } func (m *Mob) SetTargetID(id uint64) { m.targetID = id } func (m *Mob) ToProto() *pb.EntityState { return &pb.EntityState{ EntityId: m.id, Name: m.def.Name, Position: &pb.Vector3{X: m.position.X, Y: m.position.Y, Z: m.position.Z}, Rotation: m.rotation, Hp: m.hp, MaxHp: m.maxHP, Level: m.def.Level, EntityType: pb.EntityType_ENTITY_TYPE_MOB, } } // Reset restores the mob to full health at its spawn position. func (m *Mob) Reset() { m.hp = m.maxHP m.mp = m.maxMP m.position = m.spawnPos m.alive = true m.state = StateIdle m.targetID = 0 }