181 行
5.3 KiB
Go
181 行
5.3 KiB
Go
|
|
// Package modules - 怪物生成引擎模块
|
||
|
|
// 对齐GDD-19 怪物图鉴与生成引擎
|
||
|
|
package modules
|
||
|
|
|
||
|
|
import (
|
||
|
|
"context"
|
||
|
|
"database/sql"
|
||
|
|
"encoding/json"
|
||
|
|
"math/rand"
|
||
|
|
"time"
|
||
|
|
|
||
|
|
"github.com/heroiclabs/nakama-common/runtime"
|
||
|
|
)
|
||
|
|
|
||
|
|
// RegisterMonster 注册怪物相关 RPC。
|
||
|
|
func RegisterMonster(initializer runtime.Initializer) error {
|
||
|
|
rpcs := map[string]func(runtime.Initializer) 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 := (req.Page - 1) * req.PageSize
|
||
|
|
end := start + 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)
|
||
|
|
}
|