lawless/server/modules/monster.go

179 行
5.4 KiB
Go

// Package modules - 怪物生成引擎模块
// 对齐GDD-19 怪物图鉴与生成引擎
package modules
import (
"context"
"database/sql"
"encoding/json"
"github.com/heroiclabs/nakama-common/runtime"
)
// RegisterMonster 注册怪物相关 RPC。
func RegisterMonster(initializer runtime.Initializer) error {
rpcs := map[string]func(context.Context, runtime.Logger, *sql.DB, runtime.NakamaModule, string) (string, error){
"MonsterService/GetMonsterInfo": getMonsterInfo,
"MonsterService/GetMonsterList": getMonsterList,
"MonsterService/GetMonsterDrops": getMonsterDrops,
}
for path, fn := range rpcs {
if err := initializer.RegisterRpc(path, fn); err != nil {
return err
}
}
return nil
}
type getMonsterInfoReq struct {
MonsterID string `json:"monster_id"`
}
type getMonsterListReq struct {
WorldTier int32 `json:"world_tier"`
MonsterType string `json:"monster_type"` // wild/elite/boss
Page int32 `json:"page"`
PageSize int32 `json:"page_size"`
}
type getMonsterDropsReq struct {
MonsterID string `json:"monster_id"`
}
type monsterInfoData struct {
ID string `json:"id"`
Name string `json:"name"`
MonsterType string `json:"monster_type"` // wild/elite/boss
WorldTier int32 `json:"world_tier"`
RealmTier int32 `json:"realm_tier"`
HP int32 `json:"hp"`
Attack int32 `json:"attack"`
Defense int32 `json:"defense"`
Elements interface{} `json:"elements"`
Drops interface{} `json:"drops"`
SpawnRate float64 `json:"spawn_rate"`
IsAggressive bool `json:"is_aggressive"`
}
type monsterDropData struct {
ItemID string `json:"item_id"`
ItemName string `json:"item_name"`
DropRate float64 `json:"drop_rate"`
MinQuantity int32 `json:"min_quantity"`
MaxQuantity int32 `json:"max_quantity"`
}
// 怪物模板配置
var monsterTemplates = map[string]monsterInfoData{
"wild_boar": {
ID: "wild_boar", Name: "野猪", MonsterType: "wild",
WorldTier: 1, RealmTier: 1, HP: 100, Attack: 8, Defense: 3,
Elements: []string{"none"}, SpawnRate: 0.8, IsAggressive: false,
},
"wolf": {
ID: "wolf", Name: "灰狼", MonsterType: "wild",
WorldTier: 1, RealmTier: 1, HP: 120, Attack: 12, Defense: 5,
Elements: []string{"none"}, SpawnRate: 0.7, IsAggressive: true,
},
"forest_troll": {
ID: "forest_troll", Name: "森林巨魔", MonsterType: "elite",
WorldTier: 2, RealmTier: 2, HP: 500, Attack: 35, Defense: 20,
Elements: []string{"wood"}, SpawnRate: 0.3, IsAggressive: true,
},
"fire_spirit": {
ID: "fire_spirit", Name: "火焰精灵", MonsterType: "elite",
WorldTier: 3, RealmTier: 3, HP: 800, Attack: 55, Defense: 30,
Elements: []string{"fire"}, SpawnRate: 0.2, IsAggressive: true,
},
"ancient_dragon": {
ID: "ancient_dragon", Name: "远古巨龙", MonsterType: "boss",
WorldTier: 5, RealmTier: 6, HP: 50000, Attack: 500, Defense: 300,
Elements: []string{"fire", "lightning"}, SpawnRate: 0.01, IsAggressive: true,
},
"chaos_guardian": {
ID: "chaos_guardian", Name: "混沌守卫", MonsterType: "boss",
WorldTier: 6, RealmTier: 8, HP: 200000, Attack: 2000, Defense: 1500,
Elements: []string{"chaos"}, SpawnRate: 0.005, IsAggressive: true,
},
}
func getMonsterInfo(ctx context.Context, logger runtime.Logger, db *sql.DB, nk runtime.NakamaModule, payload string) (string, error) {
traceID := newTraceID()
var req getMonsterInfoReq
if err := json.Unmarshal([]byte(payload), &req); err != nil {
return errResp(2001, "invalid payload", traceID)
}
monster, ok := monsterTemplates[req.MonsterID]
if !ok {
return errResp(8501, "monster not found", traceID)
}
return okResp(monster, traceID)
}
func getMonsterList(ctx context.Context, logger runtime.Logger, db *sql.DB, nk runtime.NakamaModule, payload string) (string, error) {
traceID := newTraceID()
var req getMonsterListReq
if err := json.Unmarshal([]byte(payload), &req); err != nil {
return errResp(2001, "invalid payload", traceID)
}
if req.Page < 1 {
req.Page = 1
}
if req.PageSize < 1 || req.PageSize > 50 {
req.PageSize = 20
}
// 筛选怪物
var monsters []monsterInfoData
for _, m := range monsterTemplates {
if m.WorldTier == req.WorldTier {
if req.MonsterType == "" || m.MonsterType == req.MonsterType {
monsters = append(monsters, m)
}
}
}
// 分页
start := int((req.Page - 1) * req.PageSize)
end := start + int(req.PageSize)
if start > len(monsters) {
monsters = []monsterInfoData{}
} else if end > len(monsters) {
monsters = monsters[start:]
} else {
monsters = monsters[start:end]
}
return okResp(map[string]interface{}{
"monsters": monsters,
"count": len(monsters),
"page": req.Page,
}, traceID)
}
func getMonsterDrops(ctx context.Context, logger runtime.Logger, db *sql.DB, nk runtime.NakamaModule, payload string) (string, error) {
traceID := newTraceID()
var req getMonsterDropsReq
if err := json.Unmarshal([]byte(payload), &req); err != nil {
return errResp(2001, "invalid payload", traceID)
}
// 模拟掉落表
drops := []monsterDropData{
{ItemID: "material_hide", ItemName: "兽皮", DropRate: 0.8, MinQuantity: 1, MaxQuantity: 3},
{ItemID: "material_bone", ItemName: "兽骨", DropRate: 0.6, MinQuantity: 1, MaxQuantity: 2},
{ItemID: "material_fang", ItemName: "兽牙", DropRate: 0.3, MinQuantity: 1, MaxQuantity: 1},
}
return okResp(map[string]interface{}{
"monster_id": req.MonsterID,
"drops": drops,
}, traceID)
}