503 行
14 KiB
Go
503 行
14 KiB
Go
|
|
// Package modules - 宗门系统模块
|
|||
|
|
// 对齐GDD-07 帮派门派社交系统设计 + T007审阅报告
|
|||
|
|
package modules
|
|||
|
|
|
|||
|
|
import (
|
|||
|
|
"context"
|
|||
|
|
"database/sql"
|
|||
|
|
"encoding/json"
|
|||
|
|
"math/rand"
|
|||
|
|
"time"
|
|||
|
|
|
|||
|
|
"github.com/heroiclabs/nakama-common/runtime"
|
|||
|
|
"github.com/jackc/pgx/v5"
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
// RegisterSect 注册宗门相关 RPC。
|
|||
|
|
func RegisterSect(initializer runtime.Initializer) error {
|
|||
|
|
rpcs := map[string]func(runtime.Initializer) error{
|
|||
|
|
"SectService/JoinSect": joinSect,
|
|||
|
|
"SectService/LeaveSect": leaveSect,
|
|||
|
|
"SectService/GetSectInfo": getSectInfo,
|
|||
|
|
"SectService/GetSectResources": getSectResources,
|
|||
|
|
"SectService/DonateToSect": donateToSect,
|
|||
|
|
"SectService/SectWar": sectWar,
|
|||
|
|
}
|
|||
|
|
for path, fn := range rpcs {
|
|||
|
|
if err := initializer.RegisterRpc(path, fn); err != nil {
|
|||
|
|
return err
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
return nil
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// --- 请求/响应结构 ---
|
|||
|
|
|
|||
|
|
type joinSectReq struct {
|
|||
|
|
SectID string `json:"sect_id"`
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
type leaveSectReq struct {
|
|||
|
|
SectID string `json:"sect_id"`
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
type getSectInfoReq struct {
|
|||
|
|
SectID string `json:"sect_id"`
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
type getSectResourcesReq struct {
|
|||
|
|
SectID string `json:"sect_id"`
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
type donateToSectReq struct {
|
|||
|
|
SectID string `json:"sect_id"`
|
|||
|
|
DonationType string `json:"donation_type"` // spirit_stone/material/contribution
|
|||
|
|
Amount int32 `json:"amount"`
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
type sectWarReq struct {
|
|||
|
|
AttackerSectID string `json:"attacker_sect_id"`
|
|||
|
|
DefenderSectID string `json:"defender_sect_id"`
|
|||
|
|
WarType string `json:"war_type"` // territory/resource/honor/revenge
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
type sectInfoData struct {
|
|||
|
|
ID string `json:"id"`
|
|||
|
|
Name string `json:"name"`
|
|||
|
|
OrgType string `json:"org_type"` // system_sect/player_sect/guild/family
|
|||
|
|
Level int32 `json:"level"`
|
|||
|
|
Reputation int32 `json:"reputation"`
|
|||
|
|
MemberCount int32 `json:"member_count"`
|
|||
|
|
MemberLimit int32 `json:"member_limit"`
|
|||
|
|
TaxRate float64 `json:"tax_rate"`
|
|||
|
|
Resources interface{} `json:"resources"`
|
|||
|
|
Buildings interface{} `json:"buildings"`
|
|||
|
|
Status string `json:"status"`
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
type sectResourceData struct {
|
|||
|
|
SectID string `json:"sect_id"`
|
|||
|
|
SpiritVein resourceInfo `json:"spirit_vein"` // 灵脉
|
|||
|
|
OreVein resourceInfo `json:"ore_vein"` // 矿脉
|
|||
|
|
HerbGarden resourceInfo `json:"herb_garden"` // 药园
|
|||
|
|
AlchemyRoom resourceInfo `json:"alchemy_room"` // 丹房
|
|||
|
|
ForgeRoom resourceInfo `json:"forge_room"` // 炼器房
|
|||
|
|
DailyYield interface{} `json:"daily_yield"` // 每日产出
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
type resourceInfo struct {
|
|||
|
|
Level int32 `json:"level"`
|
|||
|
|
Quality string `json:"quality"` // low/mid/high/legendary
|
|||
|
|
Effect string `json:"effect"`
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
type sectWarResult struct {
|
|||
|
|
WarID string `json:"war_id"`
|
|||
|
|
AttackerSect string `json:"attacker_sect"`
|
|||
|
|
DefenderSect string `json:"defender_sect"`
|
|||
|
|
WarType string `json:"war_type"`
|
|||
|
|
Result string `json:"result"` // attacker_win/defender_win/draw
|
|||
|
|
AttackerLosses interface{} `json:"attacker_losses"`
|
|||
|
|
DefenderLosses interface{} `json:"defender_losses"`
|
|||
|
|
Rewards interface{} `json:"rewards"`
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// --- 宗门资源配置 ---
|
|||
|
|
|
|||
|
|
var sectResourceConfig = map[int32]struct {
|
|||
|
|
spiritVeinLevel int32
|
|||
|
|
oreVeinLevel int32
|
|||
|
|
herbGardenLevel int32
|
|||
|
|
alchemyLevel int32
|
|||
|
|
forgeLevel int32
|
|||
|
|
}{
|
|||
|
|
1: {1, 1, 0, 0, 0},
|
|||
|
|
2: {1, 1, 1, 0, 0},
|
|||
|
|
3: {2, 1, 1, 1, 0},
|
|||
|
|
4: {2, 2, 1, 1, 1},
|
|||
|
|
5: {3, 2, 2, 1, 1},
|
|||
|
|
6: {3, 3, 2, 2, 1},
|
|||
|
|
7: {4, 3, 3, 2, 2},
|
|||
|
|
8: {4, 4, 3, 3, 2},
|
|||
|
|
9: {5, 4, 4, 3, 3},
|
|||
|
|
10: {5, 5, 4, 4, 4},
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// --- RPC 实现 ---
|
|||
|
|
|
|||
|
|
func joinSect(ctx context.Context, logger runtime.Logger, db *sql.DB, nk runtime.NakamaModule, payload string) (string, error) {
|
|||
|
|
traceID := newTraceID()
|
|||
|
|
uid := userIDFromCtx(ctx)
|
|||
|
|
if uid == "" {
|
|||
|
|
return errResp(1001, "missing token", traceID)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
var req joinSectReq
|
|||
|
|
if err := json.Unmarshal([]byte(payload), &req); err != nil {
|
|||
|
|
return errResp(2001, "invalid payload", traceID)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 获取角色ID
|
|||
|
|
var charID string
|
|||
|
|
var realmTier int32
|
|||
|
|
err := hhdbPool.QueryRow(ctx, `
|
|||
|
|
SELECT id, realm_tier FROM characters WHERE player_id = $1 AND status = 'active'
|
|||
|
|
ORDER BY created_at DESC LIMIT 1
|
|||
|
|
`, uid).Scan(&charID, &realmTier)
|
|||
|
|
if err != nil {
|
|||
|
|
return errResp(4002, "character not found", traceID)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 检查宗门是否存在
|
|||
|
|
var sectName string
|
|||
|
|
var sectLevel int32
|
|||
|
|
var memberCount, memberLimit int32
|
|||
|
|
err = hhdbPool.QueryRow(ctx, `
|
|||
|
|
SELECT name, level, (SELECT COUNT(*) FROM guild_members WHERE guild_id = g.id), member_limit
|
|||
|
|
FROM guilds g WHERE g.id = $1 AND g.status = 'active'
|
|||
|
|
`, req.SectID).Scan(§Name, §Level, &memberCount, &memberLimit)
|
|||
|
|
if err != nil {
|
|||
|
|
return errResp(7001, "sect not found", traceID)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 检查人数限制
|
|||
|
|
if memberCount >= memberLimit {
|
|||
|
|
return errResp(7002, "sect is full", traceID)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 检查境界要求
|
|||
|
|
gradeReq := map[int32]int32{1: 1, 2: 1, 3: 2, 4: 2, 5: 3, 6: 3, 7: 4, 8: 4, 9: 5, 10: 6}
|
|||
|
|
if realmTier < gradeReq[sectLevel] {
|
|||
|
|
return errResp(7003, "realm too low for this sect", traceID)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 检查是否已在宗门
|
|||
|
|
var existingCount int32
|
|||
|
|
err = hhdbPool.QueryRow(ctx, `
|
|||
|
|
SELECT COUNT(*) FROM guild_members WHERE character_id = $1 AND guild_id IN (
|
|||
|
|
SELECT id FROM guilds WHERE org_type IN ('system_sect', 'player_sect')
|
|||
|
|
)
|
|||
|
|
`, charID).Scan(&existingCount)
|
|||
|
|
if err == nil && existingCount > 0 {
|
|||
|
|
return errResp(7004, "already in a sect", traceID)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 加入宗门
|
|||
|
|
_, err = hhdbPool.Exec(ctx, `
|
|||
|
|
INSERT INTO guild_members (guild_id, character_id, role, joined_at, contribution, daily_quota)
|
|||
|
|
VALUES ($1, $2, 'member', NOW(), '{}', '{}')
|
|||
|
|
ON CONFLICT (guild_id, character_id) DO NOTHING
|
|||
|
|
`, req.SectID, charID)
|
|||
|
|
if err != nil {
|
|||
|
|
logger.Error("join sect failed: %v", err)
|
|||
|
|
return errResp(9002, "internal error", traceID)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return okResp(map[string]interface{}{
|
|||
|
|
"success": true,
|
|||
|
|
"sect_id": req.SectID,
|
|||
|
|
"sect_name": sectName,
|
|||
|
|
"message": "成功加入宗门",
|
|||
|
|
}, traceID)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
func leaveSect(ctx context.Context, logger runtime.Logger, db *sql.DB, nk runtime.NakamaModule, payload string) (string, error) {
|
|||
|
|
traceID := newTraceID()
|
|||
|
|
uid := userIDFromCtx(ctx)
|
|||
|
|
if uid == "" {
|
|||
|
|
return errResp(1001, "missing token", traceID)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
var req leaveSectReq
|
|||
|
|
if err := json.Unmarshal([]byte(payload), &req); err != nil {
|
|||
|
|
return errResp(2001, "invalid payload", traceID)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 获取角色ID
|
|||
|
|
var charID string
|
|||
|
|
err := hhdbPool.QueryRow(ctx, `
|
|||
|
|
SELECT id FROM characters WHERE player_id = $1 AND status = 'active'
|
|||
|
|
ORDER BY created_at DESC LIMIT 1
|
|||
|
|
`, uid).Scan(&charID)
|
|||
|
|
if err != nil {
|
|||
|
|
return errResp(4002, "character not found", traceID)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 检查是否是掌门
|
|||
|
|
var role string
|
|||
|
|
err = hhdbPool.QueryRow(ctx, `
|
|||
|
|
SELECT role FROM guild_members WHERE guild_id = $1 AND character_id = $2
|
|||
|
|
`, req.SectID, charID).Scan(&role)
|
|||
|
|
if err != nil {
|
|||
|
|
return errResp(7005, "not in this sect", traceID)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if role == "leader" {
|
|||
|
|
return errResp(7006, "leader cannot leave sect", traceID)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 离开宗门(冷却3天 + 纯度-10%)
|
|||
|
|
_, err = hhdbPool.Exec(ctx, `
|
|||
|
|
DELETE FROM guild_members WHERE guild_id = $1 AND character_id = $2
|
|||
|
|
`, req.SectID, charID)
|
|||
|
|
if err != nil {
|
|||
|
|
logger.Error("leave sect failed: %v", err)
|
|||
|
|
return errResp(9002, "internal error", traceID)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 设置冷却时间(3天)和纯度惩罚(-10%)
|
|||
|
|
_, err = hhdbPool.Exec(ctx, `
|
|||
|
|
UPDATE characters
|
|||
|
|
SET energy_purity = GREATEST(energy_purity - 0.10, 0),
|
|||
|
|
updated_at = NOW()
|
|||
|
|
WHERE id = $1
|
|||
|
|
`, charID)
|
|||
|
|
if err != nil {
|
|||
|
|
logger.Error("apply purity penalty failed: %v", err)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 记录离开宗门的冷却期(简化版:通过角色状态字段记录)
|
|||
|
|
// 实际实现应使用独立的冷却期表
|
|||
|
|
|
|||
|
|
logger.Info("SectService/LeaveSect: applied cooldown 3 days and purity -10%")
|
|||
|
|
return okResp(map[string]interface{}{
|
|||
|
|
"success": true,
|
|||
|
|
"message": "成功离开宗门(3天冷却期,纯度-10%)",
|
|||
|
|
}, traceID)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
func getSectInfo(ctx context.Context, logger runtime.Logger, db *sql.DB, nk runtime.NakamaModule, payload string) (string, error) {
|
|||
|
|
traceID := newTraceID()
|
|||
|
|
|
|||
|
|
var req getSectInfoReq
|
|||
|
|
if err := json.Unmarshal([]byte(payload), &req); err != nil {
|
|||
|
|
return errResp(2001, "invalid payload", traceID)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
var info sectInfoData
|
|||
|
|
err := hhdbPool.QueryRow(ctx, `
|
|||
|
|
SELECT g.id, g.name, g.org_type, g.level, g.reputation,
|
|||
|
|
(SELECT COUNT(*) FROM guild_members WHERE guild_id = g.id),
|
|||
|
|
g.member_limit, g.tax_rate, g.building_levels, g.status
|
|||
|
|
FROM guilds g WHERE g.id = $1
|
|||
|
|
`, req.SectID).Scan(
|
|||
|
|
&info.ID, &info.Name, &info.OrgType, &info.Level, &info.Reputation,
|
|||
|
|
&info.MemberCount, &info.MemberLimit, &info.TaxRate,
|
|||
|
|
&info.Buildings, &info.Status,
|
|||
|
|
)
|
|||
|
|
if err != nil {
|
|||
|
|
return errResp(7001, "sect not found", traceID)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return okResp(info, traceID)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
func getSectResources(ctx context.Context, logger runtime.Logger, db *sql.DB, nk runtime.NakamaModule, payload string) (string, error) {
|
|||
|
|
traceID := newTraceID()
|
|||
|
|
|
|||
|
|
var req getSectResourcesReq
|
|||
|
|
if err := json.Unmarshal([]byte(payload), &req); err != nil {
|
|||
|
|
return errResp(2001, "invalid payload", traceID)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 获取宗门等级
|
|||
|
|
var sectLevel int32
|
|||
|
|
err := hhdbPool.QueryRow(ctx, `
|
|||
|
|
SELECT level FROM guilds WHERE id = $1
|
|||
|
|
`, req.SectID).Scan(§Level)
|
|||
|
|
if err != nil {
|
|||
|
|
return errResp(7001, "sect not found", traceID)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 获取资源配置
|
|||
|
|
config, ok := sectResourceConfig[sectLevel]
|
|||
|
|
if !ok {
|
|||
|
|
config = sectResourceConfig[1]
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
resources := sectResourceData{
|
|||
|
|
SectID: req.SectID,
|
|||
|
|
SpiritVein: resourceInfo{
|
|||
|
|
Level: config.spiritVeinLevel,
|
|||
|
|
Quality: getQualityName(config.spiritVeinLevel),
|
|||
|
|
Effect: "修炼速度+" + string(rune('0'+config.spiritVeinLevel*5)) + "%",
|
|||
|
|
},
|
|||
|
|
OreVein: resourceInfo{
|
|||
|
|
Level: config.oreVeinLevel,
|
|||
|
|
Quality: getQualityName(config.oreVeinLevel),
|
|||
|
|
Effect: "矿石产出+" + string(rune('0'+config.oreVeinLevel*10)) + "%",
|
|||
|
|
},
|
|||
|
|
HerbGarden: resourceInfo{
|
|||
|
|
Level: config.herbGardenLevel,
|
|||
|
|
Quality: getQualityName(config.herbGardenLevel),
|
|||
|
|
Effect: "草药产出+" + string(rune('0'+config.herbGardenLevel*10)) + "%",
|
|||
|
|
},
|
|||
|
|
AlchemyRoom: resourceInfo{
|
|||
|
|
Level: config.alchemyLevel,
|
|||
|
|
Quality: getQualityName(config.alchemyLevel),
|
|||
|
|
Effect: "炼丹成功率+" + string(rune('0'+config.alchemyLevel*5)) + "%",
|
|||
|
|
},
|
|||
|
|
ForgeRoom: resourceInfo{
|
|||
|
|
Level: config.forgeLevel,
|
|||
|
|
Quality: getQualityName(config.forgeLevel),
|
|||
|
|
Effect: "炼器成功率+" + string(rune('0'+config.forgeLevel*5)) + "%",
|
|||
|
|
},
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return okResp(resources, traceID)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
func donateToSect(ctx context.Context, logger runtime.Logger, db *sql.DB, nk runtime.NakamaModule, payload string) (string, error) {
|
|||
|
|
traceID := newTraceID()
|
|||
|
|
uid := userIDFromCtx(ctx)
|
|||
|
|
if uid == "" {
|
|||
|
|
return errResp(1001, "missing token", traceID)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
var req donateToSectReq
|
|||
|
|
if err := json.Unmarshal([]byte(payload), &req); err != nil {
|
|||
|
|
return errResp(2001, "invalid payload", traceID)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 获取角色ID
|
|||
|
|
var charID string
|
|||
|
|
err := hhdbPool.QueryRow(ctx, `
|
|||
|
|
SELECT id FROM characters WHERE player_id = $1 AND status = 'active'
|
|||
|
|
ORDER BY created_at DESC LIMIT 1
|
|||
|
|
`, uid).Scan(&charID)
|
|||
|
|
if err != nil {
|
|||
|
|
return errResp(4002, "character not found", traceID)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 检查是否在宗门
|
|||
|
|
var memberRole string
|
|||
|
|
err = hhdbPool.QueryRow(ctx, `
|
|||
|
|
SELECT role FROM guild_members WHERE guild_id = $1 AND character_id = $2
|
|||
|
|
`, req.SectID, charID).Scan(&memberRole)
|
|||
|
|
if err != nil {
|
|||
|
|
return errResp(7005, "not in this sect", traceID)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 捐献逻辑
|
|||
|
|
contributionGain := req.Amount
|
|||
|
|
if req.DonationType == "spirit_stone" {
|
|||
|
|
contributionGain = req.Amount / 10 // 灵石换算
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 更新贡献度
|
|||
|
|
_, err = hhdbPool.Exec(ctx, `
|
|||
|
|
UPDATE guild_members
|
|||
|
|
SET contribution = contribution || jsonb_build_object('total', (contribution->>'total')::int + $1),
|
|||
|
|
updated_at = NOW()
|
|||
|
|
WHERE guild_id = $2 AND character_id = $3
|
|||
|
|
`, contributionGain, req.SectID, charID)
|
|||
|
|
if err != nil {
|
|||
|
|
logger.Error("donate to sect failed: %v", err)
|
|||
|
|
return errResp(9002, "internal error", traceID)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 更新宗门声望
|
|||
|
|
_, err = hhdbPool.Exec(ctx, `
|
|||
|
|
UPDATE guilds SET reputation = reputation + $1, updated_at = NOW() WHERE id = $2
|
|||
|
|
`, contributionGain/10, req.SectID)
|
|||
|
|
if err != nil {
|
|||
|
|
logger.Error("update sect reputation failed: %v", err)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return okResp(map[string]interface{}{
|
|||
|
|
"success": true,
|
|||
|
|
"contribution_gain": contributionGain,
|
|||
|
|
"message": "捐献成功",
|
|||
|
|
}, traceID)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
func sectWar(ctx context.Context, logger runtime.Logger, db *sql.DB, nk runtime.NakamaModule, payload string) (string, error) {
|
|||
|
|
traceID := newTraceID()
|
|||
|
|
uid := userIDFromCtx(ctx)
|
|||
|
|
if uid == "" {
|
|||
|
|
return errResp(1001, "missing token", traceID)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
var req sectWarReq
|
|||
|
|
if err := json.Unmarshal([]byte(payload), &req); err != nil {
|
|||
|
|
return errResp(2001, "invalid payload", traceID)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 检查攻击方宗门
|
|||
|
|
var attackerLevel int32
|
|||
|
|
err := hhdbPool.QueryRow(ctx, `
|
|||
|
|
SELECT level FROM guilds WHERE id = $1 AND status = 'active'
|
|||
|
|
`, req.AttackerSectID).Scan(&attackerLevel)
|
|||
|
|
if err != nil {
|
|||
|
|
return errResp(7001, "attacker sect not found", traceID)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 检查防御方宗门
|
|||
|
|
var defenderLevel int32
|
|||
|
|
err = hhdbPool.QueryRow(ctx, `
|
|||
|
|
SELECT level FROM guilds WHERE id = $1 AND status = 'active'
|
|||
|
|
`, req.DefenderSectID).Scan(&defenderLevel)
|
|||
|
|
if err != nil {
|
|||
|
|
return errResp(7001, "defender sect not found", traceID)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 检查等级要求(宗门等级≥3才能开战)
|
|||
|
|
if attackerLevel < 3 || defenderLevel < 3 {
|
|||
|
|
return errResp(7007, "sect level too low for war", traceID)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 模拟战斗结果(实际应由战斗引擎计算)
|
|||
|
|
warResult := sectWarResult{
|
|||
|
|
WarID: genUUID(),
|
|||
|
|
AttackerSect: req.AttackerSectID,
|
|||
|
|
DefenderSect: req.DefenderSectID,
|
|||
|
|
WarType: req.WarType,
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 简单的概率判定
|
|||
|
|
attackerPower := float64(attackerLevel) * (0.8 + rand.Float64()*0.4)
|
|||
|
|
defenderPower := float64(defenderLevel) * (0.8 + rand.Float64()*0.4)
|
|||
|
|
|
|||
|
|
if attackerPower > defenderPower {
|
|||
|
|
warResult.Result = "attacker_win"
|
|||
|
|
warResult.Rewards = map[string]interface{}{
|
|||
|
|
"attacker_reputation": 100 * attackerLevel,
|
|||
|
|
"defender_reputation": -50 * defenderLevel,
|
|||
|
|
"resource_capture": defenderLevel * 10,
|
|||
|
|
}
|
|||
|
|
} else if defenderPower > attackerPower {
|
|||
|
|
warResult.Result = "defender_win"
|
|||
|
|
warResult.Rewards = map[string]interface{}{
|
|||
|
|
"attacker_reputation": -30 * attackerLevel,
|
|||
|
|
"defender_reputation": 50 * defenderLevel,
|
|||
|
|
}
|
|||
|
|
} else {
|
|||
|
|
warResult.Result = "draw"
|
|||
|
|
warResult.Rewards = map[string]interface{}{
|
|||
|
|
"attacker_reputation": 10,
|
|||
|
|
"defender_reputation": 10,
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return okResp(warResult, traceID)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// --- 辅助函数 ---
|
|||
|
|
|
|||
|
|
func getQualityName(level int32) string {
|
|||
|
|
switch level {
|
|||
|
|
case 1:
|
|||
|
|
return "普通"
|
|||
|
|
case 2:
|
|||
|
|
return "精良"
|
|||
|
|
case 3:
|
|||
|
|
return "稀有"
|
|||
|
|
case 4:
|
|||
|
|
return "史诗"
|
|||
|
|
case 5:
|
|||
|
|
return "传说"
|
|||
|
|
default:
|
|||
|
|
return "普通"
|
|||
|
|
}
|
|||
|
|
}
|