first commit

This commit is contained in:
2026-02-26 17:52:48 +09:00
commit dabf1f3ba9
49 changed files with 14883 additions and 0 deletions

137
internal/ai/mob.go Normal file
View File

@@ -0,0 +1,137 @@
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
}