服务端(Go): - GM 塞背包/带属性装备发放:在线角色推送 op14 增量物品行,背包实时刷新,无需回角色选择界面 - GM 改金币/改等级:去掉在线拒绝,落库后推送 op14 钱包/op37 等级状态,在线实时刷新 - 等级端点统一切换到新版 GMSetCharacterLevel(自带在线刷新) - 无限/锁死疲劳模式 + 燃烧疲劳:每房间消耗 2 点、打怪与通关经验双倍 - 燃烧疲劳开关时给所有在线角色推送系统提示(op12 mode 0) - 深渊史诗掉率:GM 全局倍率 + 城镇增益药剂窗口倍率,真实接入掉落结算 启动器(Python/JS): - 标题栏自绘、窗口 1204x717、禁止拖拽改大小、仅最小化/关闭 - GM 工具:疲劳与燃烧、深渊史诗掉率、拍卖行上架(单一定价对齐) - 拍卖行上架前端对齐服务端单一价格语义,修复 400 报错
128 lines
4.8 KiB
Go
128 lines
4.8 KiB
Go
package raid
|
||
|
||
import "testing"
|
||
|
||
// 前哨基地/兵站本营的领主是**固定的**(操作员 2026-10-01 复核历史截图后的口径):
|
||
// 战况表上每个格子画的就是那一只,服务端必须让实际出现的是同一只 —— 所以这里不抽签,
|
||
// 而是按格子位置钉死:上 → maze 0、中 → 1、下 → 2。
|
||
//
|
||
// 只有 maze 张数 > 1 的设施区域才会登记;雷达/炮塔/传送站只有一张图,不登记。
|
||
func TestFiendWarFixtureMazesAreFixedByCellPosition(t *testing.T) {
|
||
config := &FiendWarBattleConfig{
|
||
Raid: &AntonConfig{PhaseMax: 1, MemberMax: 8},
|
||
Rules: []FiendWarRule{{}},
|
||
Areas: map[int]FiendWarArea{
|
||
6: {Index: 6, Dungeon: 4954}, // 普通作战区域:由兵种定图
|
||
15: {Index: 15, Dungeon: 4963, Kind: "radar"}, // 单图
|
||
17: {Index: 17, Dungeon: 4965, Kind: "battery"}, // 单图
|
||
19: {Index: 19, Dungeon: 4967, Kind: "top outpost"}, // 上哨 → maze 0
|
||
21: {Index: 21, Dungeon: 4969, Kind: "mid outpost"}, // 中哨 → maze 1
|
||
23: {Index: 23, Dungeon: 4971, Kind: "bot outpost"}, // 下哨 → maze 2
|
||
27: {Index: 27, Dungeon: 4975, Kind: "top command center"},
|
||
28: {Index: 28, Dungeon: 4976, Kind: "mid command center"},
|
||
29: {Index: 29, Dungeon: 4977, Kind: "bot command center"},
|
||
30: {Index: 30, Dungeon: 4978, Kind: "top boss"}, // 单图
|
||
},
|
||
}
|
||
b, err := NewFiendWarBattle(config)
|
||
if err != nil {
|
||
t.Fatal(err)
|
||
}
|
||
if _, ok := b.MazeForArea(6); ok {
|
||
t.Fatal("普通作战区域不该登记固定图:它的图由区域里那只兵种决定")
|
||
}
|
||
for _, id := range []int{15, 17, 30} {
|
||
if _, ok := b.MazeForArea(id); ok {
|
||
t.Fatalf("单图设施 %d 不该登记(恒为 0)", id)
|
||
}
|
||
}
|
||
for id, want := range map[int]int{19: 0, 21: 1, 23: 2, 27: 0, 28: 1, 29: 2} {
|
||
maze, ok := b.MazeForArea(id)
|
||
if !ok {
|
||
t.Fatalf("多图设施 %d 没有登记固定图", id)
|
||
}
|
||
if maze != want {
|
||
t.Fatalf("设施 %d 的固定图 = %d,want %d(上/中/下 对应 0/1/2)", id, maze, want)
|
||
}
|
||
}
|
||
|
||
// 固定就是把随机性去掉:建一百次战场,同一格的图必须**一模一样**。
|
||
for range 100 {
|
||
fresh, err := NewFiendWarBattle(config)
|
||
if err != nil {
|
||
t.Fatal(err)
|
||
}
|
||
for id, want := range map[int]int{19: 0, 21: 1, 23: 2, 27: 0, 28: 1, 29: 2} {
|
||
if maze, _ := fresh.MazeForArea(id); maze != want {
|
||
t.Fatalf("重建战场后设施 %d 的图变成了 %d,want %d —— 说明还在抽签", id, maze, want)
|
||
}
|
||
}
|
||
}
|
||
|
||
// 快照必须带上这张固定图:战况表是从 Clone 出来的 state 上发的。
|
||
clone := b.Clone()
|
||
original, _ := b.MazeForArea(19)
|
||
cloned, ok := clone.MazeForArea(19)
|
||
if !ok || cloned != original {
|
||
t.Fatalf("Clone 丢了固定图:%d -> %d(ok=%t)", original, cloned, ok)
|
||
}
|
||
clone.FixtureMazes[19] = (original + 1) % 3
|
||
if again, _ := b.MazeForArea(19); again != original {
|
||
t.Fatal("Clone 改固定图影响到了原战场")
|
||
}
|
||
}
|
||
|
||
// 表本身的自洽性:四只军团领主、两只原生怪领主,互不相同且非 0;
|
||
// 每个设施副本的 maze 张数就是它在 PVF 里的张数(1 或 3)。
|
||
func TestFiendWarMonsterTablesAreWellFormed(t *testing.T) {
|
||
if len(fiendWarArmyBossIDs) != 4 {
|
||
t.Fatalf("军团领主应有 4 只([ENEMY CREATE RATE] 1..4),实测 %d", len(fiendWarArmyBossIDs))
|
||
}
|
||
if len(fiendWarOrcBossIDs) != 2 {
|
||
t.Fatalf("原生怪领主应有 2 只(maze 4/5),实测 %d", len(fiendWarOrcBossIDs))
|
||
}
|
||
seen := map[uint32]string{}
|
||
for i, id := range fiendWarArmyBossIDs {
|
||
if id == 0 {
|
||
t.Fatalf("军团领主 %d 为空", i+1)
|
||
}
|
||
seen[id] = "army"
|
||
}
|
||
for i, id := range fiendWarOrcBossIDs {
|
||
if id == 0 {
|
||
t.Fatalf("原生怪领主 %d 为空", i+1)
|
||
}
|
||
seen[id] = "orc"
|
||
}
|
||
if len(seen) != 6 {
|
||
t.Fatalf("六只领主里有重复:%v", seen)
|
||
}
|
||
wantMazes := map[int]int{4963: 1, 4965: 1, 4967: 3, 4969: 3, 4971: 3, 4975: 3, 4976: 3, 4977: 3, 4953: 1, 4978: 1}
|
||
if len(FiendWarFixtureBossIDs) != len(wantMazes) {
|
||
t.Fatalf("设施副本应有 %d 个,实测 %d", len(wantMazes), len(FiendWarFixtureBossIDs))
|
||
}
|
||
for dungeon, want := range wantMazes {
|
||
bosses, ok := FiendWarFixtureBossIDs[dungeon]
|
||
if !ok {
|
||
t.Fatalf("缺副本 %d", dungeon)
|
||
}
|
||
if len(bosses) != want {
|
||
t.Fatalf("副本 %d 的 maze 张数 = %d,want %d", dungeon, len(bosses), want)
|
||
}
|
||
for maze, id := range bosses {
|
||
if id == 0 {
|
||
t.Fatalf("副本 %d maze %d 的领主为空", dungeon, maze)
|
||
}
|
||
}
|
||
}
|
||
// 三个前哨、三个兵站本营共用同一组领主(同一组 .map 的三张 maze)。
|
||
for _, pair := range [][2]int{{4967, 4969}, {4969, 4971}, {4975, 4976}, {4976, 4977}} {
|
||
left, right := FiendWarFixtureBossIDs[pair[0]], FiendWarFixtureBossIDs[pair[1]]
|
||
for i := range left {
|
||
if left[i] != right[i] {
|
||
t.Fatalf("副本 %d/%d 的 maze %d 领主不一致:%d vs %d", pair[0], pair[1], i, left[i], right[i])
|
||
}
|
||
}
|
||
}
|
||
}
|