14 Commits

Author SHA1 Message Date
pan
1bb275607a refactor: 修改英雄图鉴和详情页的排序规则为按职业升序
调整英雄列表排序逻辑,从原有的按品质降序改为按职业升序,保持与养成进度解耦的稳定展示。
2026-09-24 15:45:46 +08:00
pan
95bf2a4e17 feat: 添加回合进度指示 UI 组件及刷新逻辑 2026-09-24 15:44:06 +08:00
pan
3f2989ab55 refactor: 移除性能监控面板相关代码
本次提交移除了 MissionComp 组件中所有性能监控相关的代码,包括:
- 性能监控面板的属性、初始化和更新逻辑
- 相关的导入依赖
- 未使用的变量和方法

这些代码主要用于显示内存、帧率等性能数据,移除后不会影响游戏核心功能,有助于简化代码结构和减少不必要的性能开销。
2026-09-24 14:04:46 +08:00
pan
577a62193c refactor: 重构无限关模式,移除章节概念,统一使用关卡-回合结构 2026-09-23 17:18:05 +08:00
pan
8f89dd11fa feat: 实现无限关卡 Boss 大招系统并重构关卡配置 2026-09-23 10:06:00 +08:00
pan
c10e24709d feat(skill): 新增闪电斩技能6103的动画与配置
1.  更新技能配置表中闪电斩的sp名称为atk6
2.  为atk2/atk3/atk5/atk6添加完整的动画帧与预制体
3.  调整各技能动画时长与攻击帧触发时机
2026-09-22 16:10:40 +08:00
pan
f92502f4f5 feat(skill): 新增召唤目标选择模式与技能优化
1. 新增SummonTMode枚举,支持同一敌人/随机敌人/去重三种召唤目标模式
2. 为多个技能prefab新增召唤参数配置字段
3. 重构索敌逻辑,支持按配置模式选择召唤目标
4. 优化技能伤害与动画配置,新增maxm7技能与动画资源
5. 修复部分技能的碰撞次数与偏移参数
2026-09-22 15:56:27 +08:00
pan
fa58f699d9 fix(hero): 修正技能debuff数值与技能描述
1. 更新多个技能的debuff_value数值为正向加成值
2. 将技能描述中的"前方达人"改为"前方敌人",并补充攻击力占位符
3. 同步更新代码配置中的技能参数与json配置一致
2026-09-22 11:23:55 +08:00
pan
90e8a4a284 feat: 添加三个新技能并更新英雄配置
1. 新增6013闪电、6014小火球、6015小飓风三个技能及对应预制件
2. 更新职业技能列表,为法师和辅助职业新增技能
3. 调整部分英雄技能配置、属性描述与英雄列表
4. 优化部分技能的伤害系数与效果参数
2026-09-22 11:15:49 +08:00
pan
39de30b9b4 refactor(hero config): 批量调整英雄技能与配置参数
1.  统一替换击退、debuff相关参数为暴击属性
2.  更新技能描述与英雄简介文本
3.  调整召唤物、buff数值与触发概率
4.  重构部分技能的生效逻辑与战场技能配置
5.  修正中毒效果的数值符号与参数配置
2026-09-22 09:33:47 +08:00
pan
8707316032 feat(hero-data): 批量更新多名英雄的配置数据
本次提交对多个英雄的角色路径、技能参数、攻击效果、被动光环等配置进行了更新:
1.  修改了易伤剑仙、甲虫领主、控血大师的角色资源路径
2.  调整了多名英雄的技能伤害倍率、控制效果参数
3.  新增/更新了多个英雄的普攻、大招效果与描述
4.  调整了部分英雄的光环配置与团队增益效果
5.  修正了技能的debuff/buff参数、触发概率与持续时长
2026-09-21 17:01:35 +08:00
pan
fdcd81c083 docs(server/data,script): 更新技能触发组文档与文本渲染逻辑
1. 补充技能触发组desc占位符使用说明
2. 新增触发概率与保底叠加值的参数传递
3. 优化技能文本渲染,避免概率描述重复展示
2026-09-21 16:03:10 +08:00
pan
cd9e7296a1 feat(trigger-editor): 添加触发组概率与保底配置功能
1. 新增触发组条目字段t_chance(触发概率)和pity_add(保底叠加),仅攻击/受击组生效
2. 为TriggerGroupEditor传入分组标识,动态显示概率配置表单项
3. 新增条目创建时继承同组末档概率参数的逻辑
4. 更新常量定义与文档说明,补充概率参数使用规则
5. 在前端展示和服务端导出中添加概率相关信息展示
2026-09-21 16:01:41 +08:00
pan
be6d941b90 feat(skill): add trigger probability and pity system for attack/attacked triggers
1. 新增技能触发概率配置与保底叠加机制,仅对攻击/受击触发生效
2. 前端编辑器新增t_chance概率与pity_add保底增量配置项
3. 技能描述文案支持展示触发概率
4. 运行时新增概率判定与保底缓存逻辑,兼容存量配置
2026-09-21 15:25:02 +08:00
51 changed files with 6265 additions and 1955 deletions

View File

@@ -11,29 +11,32 @@
"speed": 1, "speed": 1,
"wrapMode": 1, "wrapMode": 1,
"enableTrsBlending": false, "enableTrsBlending": false,
"_duration": 0.6, "_duration": 0.65,
"_hash": 500763545, "_hash": 500763545,
"_tracks": [ "_tracks": [
{ {
"__id__": 1 "__id__": 1
},
{
"__id__": 7
} }
], ],
"_exoticAnimation": null, "_exoticAnimation": null,
"_events": [ "_events": [
{ {
"frame": 0.2, "frame": 0.3,
"func": "", "func": "",
"params": [] "params": []
}, },
{ {
"frame": 0.2, "frame": 0.3,
"func": "atk", "func": "atk",
"params": [] "params": []
} }
], ],
"_embeddedPlayers": [], "_embeddedPlayers": [],
"_additiveSettings": { "_additiveSettings": {
"__id__": 7 "__id__": 13
}, },
"_auxiliaryCurveEntries": [] "_auxiliaryCurveEntries": []
}, },
@@ -90,7 +93,8 @@
0.4, 0.4,
0.45, 0.45,
0.5, 0.5,
0.55 0.55,
0.6
], ],
"_values": [ "_values": [
{ {
@@ -140,7 +144,98 @@
{ {
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@5d13a", "__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@5d13a",
"__expectedType__": "cc.SpriteFrame" "__expectedType__": "cc.SpriteFrame"
} },
null
]
},
{
"__type__": "cc.animation.ObjectTrack",
"_binding": {
"__type__": "cc.animation.TrackBinding",
"path": {
"__id__": 8
},
"proxy": null
},
"_channel": {
"__id__": 11
}
},
{
"__type__": "cc.animation.TrackPath",
"_paths": [
{
"__id__": 9
},
{
"__id__": 10
},
"spriteFrame"
]
},
{
"__type__": "cc.animation.HierarchyPath",
"path": "slash-horizontal1"
},
{
"__type__": "cc.animation.ComponentPath",
"component": "cc.Sprite"
},
{
"__type__": "cc.animation.Channel",
"_curve": {
"__id__": 12
}
},
{
"__type__": "cc.ObjectCurve",
"_times": [
0.15,
0.2,
0.25,
0.3,
0.35,
0.4,
0.45,
0.5,
0.55,
0.6
],
"_values": [
null,
{
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@d5755",
"__expectedType__": "cc.SpriteFrame"
},
{
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@d5755",
"__expectedType__": "cc.SpriteFrame"
},
{
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@34609",
"__expectedType__": "cc.SpriteFrame"
},
{
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@35b2b",
"__expectedType__": "cc.SpriteFrame"
},
{
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@0e377",
"__expectedType__": "cc.SpriteFrame"
},
{
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@cb59a",
"__expectedType__": "cc.SpriteFrame"
},
{
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@5adf0",
"__expectedType__": "cc.SpriteFrame"
},
{
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@6c6f6",
"__expectedType__": "cc.SpriteFrame"
},
null
] ]
}, },
{ {

View File

@@ -11,29 +11,32 @@
"speed": 1, "speed": 1,
"wrapMode": 1, "wrapMode": 1,
"enableTrsBlending": false, "enableTrsBlending": false,
"_duration": 0.4583333333333333, "_duration": 0.5833333333333334,
"_hash": 500763545, "_hash": 500763545,
"_tracks": [ "_tracks": [
{ {
"__id__": 1 "__id__": 1
},
{
"__id__": 7
} }
], ],
"_exoticAnimation": null, "_exoticAnimation": null,
"_events": [ "_events": [
{ {
"frame": 0.08333333333333333, "frame": 0.16666666666666666,
"func": "", "func": "",
"params": [] "params": []
}, },
{ {
"frame": 0.08333333333333333, "frame": 0.16666666666666666,
"func": "atk", "func": "atk",
"params": [] "params": []
} }
], ],
"_embeddedPlayers": [], "_embeddedPlayers": [],
"_additiveSettings": { "_additiveSettings": {
"__id__": 7 "__id__": 13
}, },
"_auxiliaryCurveEntries": [] "_auxiliaryCurveEntries": []
}, },
@@ -89,7 +92,8 @@
0.2916666666666667, 0.2916666666666667,
0.3333333333333333, 0.3333333333333333,
0.375, 0.375,
0.4166666666666667 0.4166666666666667,
0.4583333333333333
], ],
"_values": [ "_values": [
{ {
@@ -135,7 +139,95 @@
{ {
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@21b99", "__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@21b99",
"__expectedType__": "cc.SpriteFrame" "__expectedType__": "cc.SpriteFrame"
} },
null
]
},
{
"__type__": "cc.animation.ObjectTrack",
"_binding": {
"__type__": "cc.animation.TrackBinding",
"path": {
"__id__": 8
},
"proxy": null
},
"_channel": {
"__id__": 11
}
},
{
"__type__": "cc.animation.TrackPath",
"_paths": [
{
"__id__": 9
},
{
"__id__": 10
},
"spriteFrame"
]
},
{
"__type__": "cc.animation.HierarchyPath",
"path": "slash-horizontal1"
},
{
"__type__": "cc.animation.ComponentPath",
"component": "cc.Sprite"
},
{
"__type__": "cc.animation.Channel",
"_curve": {
"__id__": 12
}
},
{
"__type__": "cc.ObjectCurve",
"_times": [
0,
0.20833333333333334,
0.25,
0.2916666666666667,
0.3333333333333333,
0.375,
0.4166666666666667,
0.4583333333333333,
0.5,
0.5416666666666666
],
"_values": [
null,
null,
{
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@d5755",
"__expectedType__": "cc.SpriteFrame"
},
{
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@34609",
"__expectedType__": "cc.SpriteFrame"
},
{
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@35b2b",
"__expectedType__": "cc.SpriteFrame"
},
{
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@0e377",
"__expectedType__": "cc.SpriteFrame"
},
{
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@cb59a",
"__expectedType__": "cc.SpriteFrame"
},
{
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@5adf0",
"__expectedType__": "cc.SpriteFrame"
},
{
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@6c6f6",
"__expectedType__": "cc.SpriteFrame"
},
null
] ]
}, },
{ {

View File

@@ -11,29 +11,32 @@
"speed": 1, "speed": 1,
"wrapMode": 1, "wrapMode": 1,
"enableTrsBlending": false, "enableTrsBlending": false,
"_duration": 0.4166666666666667, "_duration": 0.7083333333333334,
"_hash": 500763545, "_hash": 500763545,
"_tracks": [ "_tracks": [
{ {
"__id__": 1 "__id__": 1
},
{
"__id__": 7
} }
], ],
"_exoticAnimation": null, "_exoticAnimation": null,
"_events": [ "_events": [
{ {
"frame": 0.08333333333333333, "frame": 0.16666666666666666,
"func": "", "func": "",
"params": [] "params": []
}, },
{ {
"frame": 0.08333333333333333, "frame": 0.16666666666666666,
"func": "atk", "func": "atk",
"params": [] "params": []
} }
], ],
"_embeddedPlayers": [], "_embeddedPlayers": [],
"_additiveSettings": { "_additiveSettings": {
"__id__": 7 "__id__": 13
}, },
"_auxiliaryCurveEntries": [] "_auxiliaryCurveEntries": []
}, },
@@ -88,7 +91,8 @@
0.25, 0.25,
0.2916666666666667, 0.2916666666666667,
0.3333333333333333, 0.3333333333333333,
0.375 0.375,
0.4166666666666667
], ],
"_values": [ "_values": [
{ {
@@ -130,7 +134,115 @@
{ {
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@daa57", "__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@daa57",
"__expectedType__": "cc.SpriteFrame" "__expectedType__": "cc.SpriteFrame"
} },
null
]
},
{
"__type__": "cc.animation.ObjectTrack",
"_binding": {
"__type__": "cc.animation.TrackBinding",
"path": {
"__id__": 8
},
"proxy": null
},
"_channel": {
"__id__": 11
}
},
{
"__type__": "cc.animation.TrackPath",
"_paths": [
{
"__id__": 9
},
{
"__id__": 10
},
"spriteFrame"
]
},
{
"__type__": "cc.animation.HierarchyPath",
"path": "fire-slash-horizontal1"
},
{
"__type__": "cc.animation.ComponentPath",
"component": "cc.Sprite"
},
{
"__type__": "cc.animation.Channel",
"_curve": {
"__id__": 12
}
},
{
"__type__": "cc.ObjectCurve",
"_times": [
0,
0.16666666666666666,
0.20833333333333334,
0.25,
0.2916666666666667,
0.3333333333333333,
0.375,
0.4166666666666667,
0.4583333333333333,
0.5,
0.5416666666666666,
0.5833333333333334,
0.625,
0.6666666666666666
],
"_values": [
null,
null,
{
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@38937",
"__expectedType__": "cc.SpriteFrame"
},
{
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@31859",
"__expectedType__": "cc.SpriteFrame"
},
{
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@33f97",
"__expectedType__": "cc.SpriteFrame"
},
{
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@0ff1b",
"__expectedType__": "cc.SpriteFrame"
},
{
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@4953c",
"__expectedType__": "cc.SpriteFrame"
},
{
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@cb80d",
"__expectedType__": "cc.SpriteFrame"
},
{
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@d0b5c",
"__expectedType__": "cc.SpriteFrame"
},
{
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@4ce52",
"__expectedType__": "cc.SpriteFrame"
},
{
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@90cfe",
"__expectedType__": "cc.SpriteFrame"
},
{
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@17d94",
"__expectedType__": "cc.SpriteFrame"
},
{
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@64baf",
"__expectedType__": "cc.SpriteFrame"
},
null
] ]
}, },
{ {

View File

@@ -11,39 +11,32 @@
"speed": 1, "speed": 1,
"wrapMode": 1, "wrapMode": 1,
"enableTrsBlending": false, "enableTrsBlending": false,
"_duration": 0.625, "_duration": 0.75,
"_hash": 500763545, "_hash": 500763545,
"_tracks": [ "_tracks": [
{ {
"__id__": 1 "__id__": 1
},
{
"__id__": 7
} }
], ],
"_exoticAnimation": null, "_exoticAnimation": null,
"_events": [ "_events": [
{ {
"frame": 0.20833333333333334, "frame": 0.375,
"func": "", "func": "",
"params": [] "params": []
}, },
{ {
"frame": 0.20833333333333334, "frame": 0.375,
"func": "atk",
"params": []
},
{
"frame": 0.4583333333333333,
"func": "",
"params": []
},
{
"frame": 0.4583333333333333,
"func": "atk", "func": "atk",
"params": [] "params": []
} }
], ],
"_embeddedPlayers": [], "_embeddedPlayers": [],
"_additiveSettings": { "_additiveSettings": {
"__id__": 7 "__id__": 13
}, },
"_auxiliaryCurveEntries": [] "_auxiliaryCurveEntries": []
}, },
@@ -103,7 +96,8 @@
0.4583333333333333, 0.4583333333333333,
0.5, 0.5,
0.5416666666666666, 0.5416666666666666,
0.5833333333333334 0.5833333333333334,
0.625
], ],
"_values": [ "_values": [
{ {
@@ -165,7 +159,115 @@
{ {
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@1b470", "__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@1b470",
"__expectedType__": "cc.SpriteFrame" "__expectedType__": "cc.SpriteFrame"
} },
null
]
},
{
"__type__": "cc.animation.ObjectTrack",
"_binding": {
"__type__": "cc.animation.TrackBinding",
"path": {
"__id__": 8
},
"proxy": null
},
"_channel": {
"__id__": 11
}
},
{
"__type__": "cc.animation.TrackPath",
"_paths": [
{
"__id__": 9
},
{
"__id__": 10
},
"spriteFrame"
]
},
{
"__type__": "cc.animation.HierarchyPath",
"path": "electric-slash-horizontal1"
},
{
"__type__": "cc.animation.ComponentPath",
"component": "cc.Sprite"
},
{
"__type__": "cc.animation.Channel",
"_curve": {
"__id__": 12
}
},
{
"__type__": "cc.ObjectCurve",
"_times": [
0,
0.20833333333333334,
0.25,
0.2916666666666667,
0.3333333333333333,
0.375,
0.4166666666666667,
0.4583333333333333,
0.5,
0.5416666666666666,
0.5833333333333334,
0.625,
0.6666666666666666,
0.7083333333333334
],
"_values": [
null,
null,
{
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@f6490",
"__expectedType__": "cc.SpriteFrame"
},
{
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@6c874",
"__expectedType__": "cc.SpriteFrame"
},
{
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@5b5e5",
"__expectedType__": "cc.SpriteFrame"
},
{
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@5cc03",
"__expectedType__": "cc.SpriteFrame"
},
{
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@161b8",
"__expectedType__": "cc.SpriteFrame"
},
{
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@01fef",
"__expectedType__": "cc.SpriteFrame"
},
{
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@70d19",
"__expectedType__": "cc.SpriteFrame"
},
{
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@34499",
"__expectedType__": "cc.SpriteFrame"
},
{
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@9ec10",
"__expectedType__": "cc.SpriteFrame"
},
{
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@9e7f6",
"__expectedType__": "cc.SpriteFrame"
},
{
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@99406",
"__expectedType__": "cc.SpriteFrame"
},
null
] ]
}, },
{ {

View File

@@ -0,0 +1,921 @@
[
{
"__type__": "cc.AnimationClip",
"_name": "fb-8",
"_objFlags": 0,
"__editorExtras__": {
"embeddedPlayerGroups": []
},
"_native": "",
"sample": 20,
"speed": 1,
"wrapMode": 1,
"enableTrsBlending": false,
"_duration": 1.4,
"_hash": 500763545,
"_tracks": [
{
"__id__": 1
},
{
"__id__": 7
},
{
"__id__": 13
},
{
"__id__": 24
}
],
"_exoticAnimation": null,
"_events": [
{
"frame": 0,
"func": "",
"params": []
},
{
"frame": 0,
"func": "atk",
"params": []
},
{
"frame": 0.6,
"func": "",
"params": []
},
{
"frame": 0.6,
"func": "atk",
"params": []
},
{
"frame": 1.2,
"func": "",
"params": []
},
{
"frame": 1.2,
"func": "atk",
"params": []
}
],
"_embeddedPlayers": [],
"_additiveSettings": {
"__id__": 35
},
"_auxiliaryCurveEntries": []
},
{
"__type__": "cc.animation.ObjectTrack",
"_binding": {
"__type__": "cc.animation.TrackBinding",
"path": {
"__id__": 2
},
"proxy": null
},
"_channel": {
"__id__": 5
}
},
{
"__type__": "cc.animation.TrackPath",
"_paths": [
{
"__id__": 3
},
{
"__id__": 4
},
"spriteFrame"
]
},
{
"__type__": "cc.animation.HierarchyPath",
"path": "Node"
},
{
"__type__": "cc.animation.ComponentPath",
"component": "cc.Sprite"
},
{
"__type__": "cc.animation.Channel",
"_curve": {
"__id__": 6
}
},
{
"__type__": "cc.ObjectCurve",
"_times": [
0,
0.05,
0.1,
0.15,
0.2,
0.25,
0.3,
0.35,
0.4,
0.45,
0.5,
0.55,
0.6,
0.65,
0.7,
0.75,
0.8,
0.85,
0.9,
0.95,
1,
1.05,
1.1,
1.15,
1.2,
1.25,
1.3,
1.35
],
"_values": [
{
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@55402",
"__expectedType__": "cc.SpriteFrame"
},
{
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@2ac32",
"__expectedType__": "cc.SpriteFrame"
},
{
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@a38c9",
"__expectedType__": "cc.SpriteFrame"
},
{
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@005f7",
"__expectedType__": "cc.SpriteFrame"
},
{
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@d585f",
"__expectedType__": "cc.SpriteFrame"
},
{
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@740a0",
"__expectedType__": "cc.SpriteFrame"
},
{
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@6b34e",
"__expectedType__": "cc.SpriteFrame"
},
{
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@55402",
"__expectedType__": "cc.SpriteFrame"
},
{
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@2ac32",
"__expectedType__": "cc.SpriteFrame"
},
{
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@a38c9",
"__expectedType__": "cc.SpriteFrame"
},
{
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@005f7",
"__expectedType__": "cc.SpriteFrame"
},
{
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@d585f",
"__expectedType__": "cc.SpriteFrame"
},
{
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@740a0",
"__expectedType__": "cc.SpriteFrame"
},
{
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@6b34e",
"__expectedType__": "cc.SpriteFrame"
},
{
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@55402",
"__expectedType__": "cc.SpriteFrame"
},
{
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@2ac32",
"__expectedType__": "cc.SpriteFrame"
},
{
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@a38c9",
"__expectedType__": "cc.SpriteFrame"
},
{
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@005f7",
"__expectedType__": "cc.SpriteFrame"
},
{
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@d585f",
"__expectedType__": "cc.SpriteFrame"
},
{
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@740a0",
"__expectedType__": "cc.SpriteFrame"
},
{
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@6b34e",
"__expectedType__": "cc.SpriteFrame"
},
{
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@55402",
"__expectedType__": "cc.SpriteFrame"
},
{
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@2ac32",
"__expectedType__": "cc.SpriteFrame"
},
{
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@a38c9",
"__expectedType__": "cc.SpriteFrame"
},
{
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@005f7",
"__expectedType__": "cc.SpriteFrame"
},
{
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@d585f",
"__expectedType__": "cc.SpriteFrame"
},
{
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@740a0",
"__expectedType__": "cc.SpriteFrame"
},
{
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@6b34e",
"__expectedType__": "cc.SpriteFrame"
}
]
},
{
"__type__": "cc.animation.ObjectTrack",
"_binding": {
"__type__": "cc.animation.TrackBinding",
"path": {
"__id__": 8
},
"proxy": null
},
"_channel": {
"__id__": 11
}
},
{
"__type__": "cc.animation.TrackPath",
"_paths": [
{
"__id__": 9
},
{
"__id__": 10
},
"spriteFrame"
]
},
{
"__type__": "cc.animation.HierarchyPath",
"path": "Node-001"
},
{
"__type__": "cc.animation.ComponentPath",
"component": "cc.Sprite"
},
{
"__type__": "cc.animation.Channel",
"_curve": {
"__id__": 12
}
},
{
"__type__": "cc.ObjectCurve",
"_times": [
0,
0.05,
0.1,
0.15,
0.2,
0.25,
0.3,
0.35,
0.4,
0.45,
0.5,
0.55,
0.6,
0.65,
0.7,
0.75,
0.8,
0.85,
0.9,
0.95,
1,
1.05,
1.1,
1.15,
1.2,
1.25,
1.3,
1.35
],
"_values": [
{
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@55402",
"__expectedType__": "cc.SpriteFrame"
},
{
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@2ac32",
"__expectedType__": "cc.SpriteFrame"
},
{
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@a38c9",
"__expectedType__": "cc.SpriteFrame"
},
{
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@005f7",
"__expectedType__": "cc.SpriteFrame"
},
{
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@d585f",
"__expectedType__": "cc.SpriteFrame"
},
{
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@740a0",
"__expectedType__": "cc.SpriteFrame"
},
{
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@6b34e",
"__expectedType__": "cc.SpriteFrame"
},
{
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@55402",
"__expectedType__": "cc.SpriteFrame"
},
{
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@2ac32",
"__expectedType__": "cc.SpriteFrame"
},
{
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@a38c9",
"__expectedType__": "cc.SpriteFrame"
},
{
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@005f7",
"__expectedType__": "cc.SpriteFrame"
},
{
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@d585f",
"__expectedType__": "cc.SpriteFrame"
},
{
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@740a0",
"__expectedType__": "cc.SpriteFrame"
},
{
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@6b34e",
"__expectedType__": "cc.SpriteFrame"
},
{
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@55402",
"__expectedType__": "cc.SpriteFrame"
},
{
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@2ac32",
"__expectedType__": "cc.SpriteFrame"
},
{
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@a38c9",
"__expectedType__": "cc.SpriteFrame"
},
{
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@005f7",
"__expectedType__": "cc.SpriteFrame"
},
{
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@d585f",
"__expectedType__": "cc.SpriteFrame"
},
{
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@740a0",
"__expectedType__": "cc.SpriteFrame"
},
{
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@6b34e",
"__expectedType__": "cc.SpriteFrame"
},
{
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@55402",
"__expectedType__": "cc.SpriteFrame"
},
{
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@2ac32",
"__expectedType__": "cc.SpriteFrame"
},
{
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@a38c9",
"__expectedType__": "cc.SpriteFrame"
},
{
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@005f7",
"__expectedType__": "cc.SpriteFrame"
},
{
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@d585f",
"__expectedType__": "cc.SpriteFrame"
},
{
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@740a0",
"__expectedType__": "cc.SpriteFrame"
},
{
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@6b34e",
"__expectedType__": "cc.SpriteFrame"
}
]
},
{
"__type__": "cc.animation.VectorTrack",
"_binding": {
"__type__": "cc.animation.TrackBinding",
"path": {
"__id__": 14
},
"proxy": null
},
"_channels": [
{
"__id__": 16
},
{
"__id__": 18
},
{
"__id__": 20
},
{
"__id__": 22
}
],
"_nComponents": 3
},
{
"__type__": "cc.animation.TrackPath",
"_paths": [
{
"__id__": 15
},
"position"
]
},
{
"__type__": "cc.animation.HierarchyPath",
"path": "Node"
},
{
"__type__": "cc.animation.Channel",
"_curve": {
"__id__": 17
}
},
{
"__type__": "cc.RealCurve",
"_times": [
0,
0.65,
1.35
],
"_values": [
{
"__type__": "cc.RealKeyframeValue",
"interpolationMode": 0,
"tangentWeightMode": 0,
"value": -70,
"rightTangent": 0,
"rightTangentWeight": 1,
"leftTangent": 0,
"leftTangentWeight": 1,
"easingMethod": 0,
"__editorExtras__": {
"broken": null
}
},
{
"__type__": "cc.RealKeyframeValue",
"interpolationMode": 0,
"tangentWeightMode": 0,
"value": 70,
"rightTangent": 0,
"rightTangentWeight": 1,
"leftTangent": 0,
"leftTangentWeight": 1,
"easingMethod": 0,
"__editorExtras__": {
"broken": null
}
},
{
"__type__": "cc.RealKeyframeValue",
"interpolationMode": 0,
"tangentWeightMode": 0,
"value": -70,
"rightTangent": 0,
"rightTangentWeight": 1,
"leftTangent": 0,
"leftTangentWeight": 1,
"easingMethod": 0,
"__editorExtras__": {
"broken": null
}
}
],
"preExtrapolation": 1,
"postExtrapolation": 1
},
{
"__type__": "cc.animation.Channel",
"_curve": {
"__id__": 19
}
},
{
"__type__": "cc.RealCurve",
"_times": [
0,
0.3,
0.65,
1,
1.35
],
"_values": [
{
"__type__": "cc.RealKeyframeValue",
"interpolationMode": 0,
"tangentWeightMode": 0,
"value": -60,
"rightTangent": 0,
"rightTangentWeight": 1,
"leftTangent": 0,
"leftTangentWeight": 1,
"easingMethod": 0,
"__editorExtras__": {
"broken": null
}
},
{
"__type__": "cc.RealKeyframeValue",
"interpolationMode": 0,
"tangentWeightMode": 0,
"value": -70,
"rightTangent": 0,
"rightTangentWeight": 1,
"leftTangent": 0,
"leftTangentWeight": 1,
"easingMethod": 0,
"__editorExtras__": {
"broken": null
}
},
{
"__type__": "cc.RealKeyframeValue",
"interpolationMode": 0,
"tangentWeightMode": 0,
"value": -60,
"rightTangent": 0,
"rightTangentWeight": 1,
"leftTangent": 0,
"leftTangentWeight": 1,
"easingMethod": 0,
"__editorExtras__": {
"broken": null
}
},
{
"__type__": "cc.RealKeyframeValue",
"interpolationMode": 0,
"tangentWeightMode": 0,
"value": -50,
"rightTangent": 0,
"rightTangentWeight": 1,
"leftTangent": 0,
"leftTangentWeight": 1,
"easingMethod": 0,
"__editorExtras__": {
"broken": null
}
},
{
"__type__": "cc.RealKeyframeValue",
"interpolationMode": 0,
"tangentWeightMode": 0,
"value": -60,
"rightTangent": 0,
"rightTangentWeight": 1,
"leftTangent": 0,
"leftTangentWeight": 1,
"easingMethod": 0,
"__editorExtras__": {
"broken": null
}
}
],
"preExtrapolation": 1,
"postExtrapolation": 1
},
{
"__type__": "cc.animation.Channel",
"_curve": {
"__id__": 21
}
},
{
"__type__": "cc.RealCurve",
"_times": [],
"_values": [],
"preExtrapolation": 1,
"postExtrapolation": 1
},
{
"__type__": "cc.animation.Channel",
"_curve": {
"__id__": 23
}
},
{
"__type__": "cc.RealCurve",
"_times": [],
"_values": [],
"preExtrapolation": 1,
"postExtrapolation": 1
},
{
"__type__": "cc.animation.VectorTrack",
"_binding": {
"__type__": "cc.animation.TrackBinding",
"path": {
"__id__": 25
},
"proxy": null
},
"_channels": [
{
"__id__": 27
},
{
"__id__": 29
},
{
"__id__": 31
},
{
"__id__": 33
}
],
"_nComponents": 3
},
{
"__type__": "cc.animation.TrackPath",
"_paths": [
{
"__id__": 26
},
"position"
]
},
{
"__type__": "cc.animation.HierarchyPath",
"path": "Node-001"
},
{
"__type__": "cc.animation.Channel",
"_curve": {
"__id__": 28
}
},
{
"__type__": "cc.RealCurve",
"_times": [
0,
0.65,
1.35
],
"_values": [
{
"__type__": "cc.RealKeyframeValue",
"interpolationMode": 0,
"tangentWeightMode": 0,
"value": 70,
"rightTangent": 0,
"rightTangentWeight": 1,
"leftTangent": 0,
"leftTangentWeight": 1,
"easingMethod": 0,
"__editorExtras__": {
"broken": null
}
},
{
"__type__": "cc.RealKeyframeValue",
"interpolationMode": 0,
"tangentWeightMode": 0,
"value": -70,
"rightTangent": 0,
"rightTangentWeight": 1,
"leftTangent": 0,
"leftTangentWeight": 1,
"easingMethod": 0,
"__editorExtras__": {
"broken": null
}
},
{
"__type__": "cc.RealKeyframeValue",
"interpolationMode": 0,
"tangentWeightMode": 0,
"value": 70,
"rightTangent": 0,
"rightTangentWeight": 1,
"leftTangent": 0,
"leftTangentWeight": 1,
"easingMethod": 0,
"__editorExtras__": {
"broken": null
}
}
],
"preExtrapolation": 1,
"postExtrapolation": 1
},
{
"__type__": "cc.animation.Channel",
"_curve": {
"__id__": 30
}
},
{
"__type__": "cc.RealCurve",
"_times": [
0,
0.3,
0.65,
1,
1.35
],
"_values": [
{
"__type__": "cc.RealKeyframeValue",
"interpolationMode": 0,
"tangentWeightMode": 0,
"value": -60,
"rightTangent": 0,
"rightTangentWeight": 1,
"leftTangent": 0,
"leftTangentWeight": 1,
"easingMethod": 0,
"__editorExtras__": {
"broken": null
}
},
{
"__type__": "cc.RealKeyframeValue",
"interpolationMode": 0,
"tangentWeightMode": 0,
"value": -50,
"rightTangent": 0,
"rightTangentWeight": 1,
"leftTangent": 0,
"leftTangentWeight": 1,
"easingMethod": 0,
"__editorExtras__": {
"broken": null
}
},
{
"__type__": "cc.RealKeyframeValue",
"interpolationMode": 0,
"tangentWeightMode": 0,
"value": -60,
"rightTangent": 0,
"rightTangentWeight": 1,
"leftTangent": 0,
"leftTangentWeight": 1,
"easingMethod": 0,
"__editorExtras__": {
"broken": null
}
},
{
"__type__": "cc.RealKeyframeValue",
"interpolationMode": 0,
"tangentWeightMode": 0,
"value": -70,
"rightTangent": 0,
"rightTangentWeight": 1,
"leftTangent": 0,
"leftTangentWeight": 1,
"easingMethod": 0,
"__editorExtras__": {
"broken": null
}
},
{
"__type__": "cc.RealKeyframeValue",
"interpolationMode": 0,
"tangentWeightMode": 0,
"value": -60,
"rightTangent": 0,
"rightTangentWeight": 1,
"leftTangent": 0,
"leftTangentWeight": 1,
"easingMethod": 0,
"__editorExtras__": {
"broken": null
}
}
],
"preExtrapolation": 1,
"postExtrapolation": 1
},
{
"__type__": "cc.animation.Channel",
"_curve": {
"__id__": 32
}
},
{
"__type__": "cc.RealCurve",
"_times": [
0,
0.65,
1.35
],
"_values": [
{
"__type__": "cc.RealKeyframeValue",
"interpolationMode": 0,
"tangentWeightMode": 0,
"value": 0,
"rightTangent": 0,
"rightTangentWeight": 1,
"leftTangent": 0,
"leftTangentWeight": 1,
"easingMethod": 0,
"__editorExtras__": {
"broken": null
}
},
{
"__type__": "cc.RealKeyframeValue",
"interpolationMode": 0,
"tangentWeightMode": 0,
"value": 0,
"rightTangent": 0,
"rightTangentWeight": 1,
"leftTangent": 0,
"leftTangentWeight": 1,
"easingMethod": 0,
"__editorExtras__": {
"broken": null
}
},
{
"__type__": "cc.RealKeyframeValue",
"interpolationMode": 0,
"tangentWeightMode": 0,
"value": 0,
"rightTangent": 0,
"rightTangentWeight": 1,
"leftTangent": 0,
"leftTangentWeight": 1,
"easingMethod": 0,
"__editorExtras__": {
"broken": null
}
}
],
"preExtrapolation": 1,
"postExtrapolation": 1
},
{
"__type__": "cc.animation.Channel",
"_curve": {
"__id__": 34
}
},
{
"__type__": "cc.RealCurve",
"_times": [],
"_values": [],
"preExtrapolation": 1,
"postExtrapolation": 1
},
{
"__type__": "cc.AnimationClipAdditiveSettings",
"enabled": false,
"refClip": null
}
]

View File

@@ -0,0 +1,13 @@
{
"ver": "2.0.3",
"importer": "animation-clip",
"imported": true,
"uuid": "b0bec9a1-c3c7-412f-b6de-e27ec78dcc86",
"files": [
".cconb"
],
"subMetas": {},
"userData": {
"name": "fb-8"
}
}

View File

@@ -20,28 +20,31 @@
"_children": [ "_children": [
{ {
"__id__": 2 "__id__": 2
},
{
"__id__": 8
} }
], ],
"_active": true, "_active": true,
"_components": [ "_components": [
{
"__id__": 8
},
{
"__id__": 10
},
{
"__id__": 12
},
{ {
"__id__": 14 "__id__": 14
}, },
{ {
"__id__": 16 "__id__": 16
},
{
"__id__": 18
},
{
"__id__": 20
},
{
"__id__": 22
} }
], ],
"_prefab": { "_prefab": {
"__id__": 18 "__id__": 24
}, },
"_lpos": { "_lpos": {
"__type__": "cc.Vec3", "__type__": "cc.Vec3",
@@ -211,6 +214,139 @@
"targetOverrides": null, "targetOverrides": null,
"nestedPrefabInstanceRoots": null "nestedPrefabInstanceRoots": null
}, },
{
"__type__": "cc.Node",
"_name": "slash-horizontal1",
"_objFlags": 0,
"__editorExtras__": {},
"_parent": {
"__id__": 1
},
"_children": [],
"_active": true,
"_components": [
{
"__id__": 9
},
{
"__id__": 11
}
],
"_prefab": {
"__id__": 13
},
"_lpos": {
"__type__": "cc.Vec3",
"x": 0,
"y": 0,
"z": 0
},
"_lrot": {
"__type__": "cc.Quat",
"x": 0,
"y": 0,
"z": 0,
"w": 1
},
"_lscale": {
"__type__": "cc.Vec3",
"x": 2,
"y": 2,
"z": 1
},
"_mobility": 0,
"_layer": 1073741824,
"_euler": {
"__type__": "cc.Vec3",
"x": 0,
"y": 0,
"z": 0
},
"_id": ""
},
{
"__type__": "cc.UITransform",
"_name": "",
"_objFlags": 0,
"__editorExtras__": {},
"node": {
"__id__": 8
},
"_enabled": true,
"__prefab": {
"__id__": 10
},
"_contentSize": {
"__type__": "cc.Size",
"width": 95,
"height": 48
},
"_anchorPoint": {
"__type__": "cc.Vec2",
"x": 0.5,
"y": 0.5
},
"_id": ""
},
{
"__type__": "cc.CompPrefabInfo",
"fileId": "0aybWnCBJDBb3WOXwo/YxC"
},
{
"__type__": "cc.Sprite",
"_name": "",
"_objFlags": 0,
"__editorExtras__": {},
"node": {
"__id__": 8
},
"_enabled": true,
"__prefab": {
"__id__": 12
},
"_customMaterial": null,
"_srcBlendFactor": 2,
"_dstBlendFactor": 4,
"_color": {
"__type__": "cc.Color",
"r": 255,
"g": 255,
"b": 255,
"a": 255
},
"_spriteFrame": null,
"_type": 0,
"_fillType": 0,
"_sizeMode": 1,
"_fillCenter": {
"__type__": "cc.Vec2",
"x": 0,
"y": 0
},
"_fillStart": 0,
"_fillRange": 0,
"_isTrimmedMode": true,
"_useGrayscale": false,
"_atlas": null,
"_id": ""
},
{
"__type__": "cc.CompPrefabInfo",
"fileId": "45iYWOPyBCNKkmXE+dmADF"
},
{
"__type__": "cc.PrefabInfo",
"root": {
"__id__": 1
},
"asset": {
"__id__": 0
},
"fileId": "bdI0RFo3VCNKhgFojxldzA",
"instance": null,
"targetOverrides": null,
"nestedPrefabInstanceRoots": null
},
{ {
"__type__": "cc.UITransform", "__type__": "cc.UITransform",
"_name": "", "_name": "",
@@ -221,7 +357,7 @@
}, },
"_enabled": true, "_enabled": true,
"__prefab": { "__prefab": {
"__id__": 9 "__id__": 15
}, },
"_contentSize": { "_contentSize": {
"__type__": "cc.Size", "__type__": "cc.Size",
@@ -249,7 +385,7 @@
}, },
"_enabled": true, "_enabled": true,
"__prefab": { "__prefab": {
"__id__": 11 "__id__": 17
}, },
"atk_x": 20, "atk_x": 20,
"atk_y": 40, "atk_y": 40,
@@ -261,6 +397,10 @@
"forceStartX": -1, "forceStartX": -1,
"forceStartY": -1, "forceStartY": -1,
"summon_count": 1, "summon_count": 1,
"summon_target_mode": 0,
"summon_x_offset": 0,
"summon_y_offset": 0,
"summon_interval": 0,
"height_offset": 0, "height_offset": 0,
"_id": "" "_id": ""
}, },
@@ -278,7 +418,7 @@
}, },
"_enabled": true, "_enabled": true,
"__prefab": { "__prefab": {
"__id__": 13 "__id__": 19
}, },
"enabledContactListener": true, "enabledContactListener": true,
"bullet": false, "bullet": false,
@@ -312,7 +452,7 @@
}, },
"_enabled": true, "_enabled": true,
"__prefab": { "__prefab": {
"__id__": 15 "__id__": 21
}, },
"tag": 0, "tag": 0,
"_group": 1, "_group": 1,
@@ -346,7 +486,7 @@
}, },
"_enabled": true, "_enabled": true,
"__prefab": { "__prefab": {
"__id__": 17 "__id__": 23
}, },
"playOnLoad": true, "playOnLoad": true,
"_clips": [ "_clips": [

View File

@@ -20,28 +20,31 @@
"_children": [ "_children": [
{ {
"__id__": 2 "__id__": 2
},
{
"__id__": 8
} }
], ],
"_active": true, "_active": true,
"_components": [ "_components": [
{
"__id__": 8
},
{
"__id__": 10
},
{
"__id__": 12
},
{ {
"__id__": 14 "__id__": 14
}, },
{ {
"__id__": 16 "__id__": 16
},
{
"__id__": 18
},
{
"__id__": 20
},
{
"__id__": 22
} }
], ],
"_prefab": { "_prefab": {
"__id__": 18 "__id__": 24
}, },
"_lpos": { "_lpos": {
"__type__": "cc.Vec3", "__type__": "cc.Vec3",
@@ -211,6 +214,139 @@
"targetOverrides": null, "targetOverrides": null,
"nestedPrefabInstanceRoots": null "nestedPrefabInstanceRoots": null
}, },
{
"__type__": "cc.Node",
"_name": "slash-horizontal1",
"_objFlags": 0,
"__editorExtras__": {},
"_parent": {
"__id__": 1
},
"_children": [],
"_active": true,
"_components": [
{
"__id__": 9
},
{
"__id__": 11
}
],
"_prefab": {
"__id__": 13
},
"_lpos": {
"__type__": "cc.Vec3",
"x": 0,
"y": 0,
"z": 0
},
"_lrot": {
"__type__": "cc.Quat",
"x": 0,
"y": 0,
"z": 0,
"w": 1
},
"_lscale": {
"__type__": "cc.Vec3",
"x": 2,
"y": 2,
"z": 1
},
"_mobility": 0,
"_layer": 1073741824,
"_euler": {
"__type__": "cc.Vec3",
"x": 0,
"y": 0,
"z": 0
},
"_id": ""
},
{
"__type__": "cc.UITransform",
"_name": "",
"_objFlags": 0,
"__editorExtras__": {},
"node": {
"__id__": 8
},
"_enabled": true,
"__prefab": {
"__id__": 10
},
"_contentSize": {
"__type__": "cc.Size",
"width": 95,
"height": 48
},
"_anchorPoint": {
"__type__": "cc.Vec2",
"x": 0.5,
"y": 0.5
},
"_id": ""
},
{
"__type__": "cc.CompPrefabInfo",
"fileId": "82TGDP+iVBv4P1whT99OBW"
},
{
"__type__": "cc.Sprite",
"_name": "",
"_objFlags": 0,
"__editorExtras__": {},
"node": {
"__id__": 8
},
"_enabled": true,
"__prefab": {
"__id__": 12
},
"_customMaterial": null,
"_srcBlendFactor": 2,
"_dstBlendFactor": 4,
"_color": {
"__type__": "cc.Color",
"r": 255,
"g": 255,
"b": 255,
"a": 255
},
"_spriteFrame": null,
"_type": 0,
"_fillType": 0,
"_sizeMode": 1,
"_fillCenter": {
"__type__": "cc.Vec2",
"x": 0,
"y": 0
},
"_fillStart": 0,
"_fillRange": 0,
"_isTrimmedMode": true,
"_useGrayscale": false,
"_atlas": null,
"_id": ""
},
{
"__type__": "cc.CompPrefabInfo",
"fileId": "daC3XwzZFG4JHd5pqsR70r"
},
{
"__type__": "cc.PrefabInfo",
"root": {
"__id__": 1
},
"asset": {
"__id__": 0
},
"fileId": "e8yfxZXCJCU6wnX0/ttDjH",
"instance": null,
"targetOverrides": null,
"nestedPrefabInstanceRoots": null
},
{ {
"__type__": "cc.UITransform", "__type__": "cc.UITransform",
"_name": "", "_name": "",
@@ -221,7 +357,7 @@
}, },
"_enabled": true, "_enabled": true,
"__prefab": { "__prefab": {
"__id__": 9 "__id__": 15
}, },
"_contentSize": { "_contentSize": {
"__type__": "cc.Size", "__type__": "cc.Size",
@@ -249,7 +385,7 @@
}, },
"_enabled": true, "_enabled": true,
"__prefab": { "__prefab": {
"__id__": 11 "__id__": 17
}, },
"atk_x": 20, "atk_x": 20,
"atk_y": 40, "atk_y": 40,
@@ -261,6 +397,10 @@
"forceStartX": -1, "forceStartX": -1,
"forceStartY": -1, "forceStartY": -1,
"summon_count": 1, "summon_count": 1,
"summon_target_mode": 0,
"summon_x_offset": 0,
"summon_y_offset": 0,
"summon_interval": 0,
"height_offset": 0, "height_offset": 0,
"_id": "" "_id": ""
}, },
@@ -278,7 +418,7 @@
}, },
"_enabled": true, "_enabled": true,
"__prefab": { "__prefab": {
"__id__": 13 "__id__": 19
}, },
"enabledContactListener": true, "enabledContactListener": true,
"bullet": false, "bullet": false,
@@ -312,7 +452,7 @@
}, },
"_enabled": true, "_enabled": true,
"__prefab": { "__prefab": {
"__id__": 15 "__id__": 21
}, },
"tag": 0, "tag": 0,
"_group": 1, "_group": 1,
@@ -346,7 +486,7 @@
}, },
"_enabled": true, "_enabled": true,
"__prefab": { "__prefab": {
"__id__": 17 "__id__": 23
}, },
"playOnLoad": true, "playOnLoad": true,
"_clips": [ "_clips": [

View File

@@ -20,28 +20,31 @@
"_children": [ "_children": [
{ {
"__id__": 2 "__id__": 2
},
{
"__id__": 8
} }
], ],
"_active": true, "_active": true,
"_components": [ "_components": [
{
"__id__": 8
},
{
"__id__": 10
},
{
"__id__": 12
},
{ {
"__id__": 14 "__id__": 14
}, },
{ {
"__id__": 16 "__id__": 16
},
{
"__id__": 18
},
{
"__id__": 20
},
{
"__id__": 22
} }
], ],
"_prefab": { "_prefab": {
"__id__": 18 "__id__": 24
}, },
"_lpos": { "_lpos": {
"__type__": "cc.Vec3", "__type__": "cc.Vec3",
@@ -173,7 +176,7 @@
"a": 255 "a": 255
}, },
"_spriteFrame": { "_spriteFrame": {
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@13b06", "__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@7e6d7",
"__expectedType__": "cc.SpriteFrame" "__expectedType__": "cc.SpriteFrame"
}, },
"_type": 0, "_type": 0,
@@ -211,6 +214,139 @@
"targetOverrides": null, "targetOverrides": null,
"nestedPrefabInstanceRoots": null "nestedPrefabInstanceRoots": null
}, },
{
"__type__": "cc.Node",
"_name": "fire-slash-horizontal1",
"_objFlags": 0,
"__editorExtras__": {},
"_parent": {
"__id__": 1
},
"_children": [],
"_active": true,
"_components": [
{
"__id__": 9
},
{
"__id__": 11
}
],
"_prefab": {
"__id__": 13
},
"_lpos": {
"__type__": "cc.Vec3",
"x": 29.777,
"y": 0,
"z": 0
},
"_lrot": {
"__type__": "cc.Quat",
"x": 0,
"y": 0,
"z": 0,
"w": 1
},
"_lscale": {
"__type__": "cc.Vec3",
"x": 2,
"y": 2,
"z": 1
},
"_mobility": 0,
"_layer": 1073741824,
"_euler": {
"__type__": "cc.Vec3",
"x": 0,
"y": 0,
"z": 0
},
"_id": ""
},
{
"__type__": "cc.UITransform",
"_name": "",
"_objFlags": 0,
"__editorExtras__": {},
"node": {
"__id__": 8
},
"_enabled": true,
"__prefab": {
"__id__": 10
},
"_contentSize": {
"__type__": "cc.Size",
"width": 95,
"height": 48
},
"_anchorPoint": {
"__type__": "cc.Vec2",
"x": 0.5,
"y": 0.5
},
"_id": ""
},
{
"__type__": "cc.CompPrefabInfo",
"fileId": "61GNVJPatIJoTFQpCuL1tc"
},
{
"__type__": "cc.Sprite",
"_name": "",
"_objFlags": 0,
"__editorExtras__": {},
"node": {
"__id__": 8
},
"_enabled": true,
"__prefab": {
"__id__": 12
},
"_customMaterial": null,
"_srcBlendFactor": 2,
"_dstBlendFactor": 4,
"_color": {
"__type__": "cc.Color",
"r": 255,
"g": 255,
"b": 255,
"a": 255
},
"_spriteFrame": null,
"_type": 0,
"_fillType": 0,
"_sizeMode": 1,
"_fillCenter": {
"__type__": "cc.Vec2",
"x": 0,
"y": 0
},
"_fillStart": 0,
"_fillRange": 0,
"_isTrimmedMode": true,
"_useGrayscale": false,
"_atlas": null,
"_id": ""
},
{
"__type__": "cc.CompPrefabInfo",
"fileId": "64tuHxFsxBMK3c6Rl+GQll"
},
{
"__type__": "cc.PrefabInfo",
"root": {
"__id__": 1
},
"asset": {
"__id__": 0
},
"fileId": "05Mo/yQRtK5YAX1chbWL76",
"instance": null,
"targetOverrides": null,
"nestedPrefabInstanceRoots": null
},
{ {
"__type__": "cc.UITransform", "__type__": "cc.UITransform",
"_name": "", "_name": "",
@@ -221,7 +357,7 @@
}, },
"_enabled": true, "_enabled": true,
"__prefab": { "__prefab": {
"__id__": 9 "__id__": 15
}, },
"_contentSize": { "_contentSize": {
"__type__": "cc.Size", "__type__": "cc.Size",
@@ -249,7 +385,7 @@
}, },
"_enabled": true, "_enabled": true,
"__prefab": { "__prefab": {
"__id__": 11 "__id__": 17
}, },
"atk_x": 20, "atk_x": 20,
"atk_y": 40, "atk_y": 40,
@@ -261,6 +397,10 @@
"forceStartX": -1, "forceStartX": -1,
"forceStartY": -1, "forceStartY": -1,
"summon_count": 1, "summon_count": 1,
"summon_target_mode": 0,
"summon_x_offset": 0,
"summon_y_offset": 0,
"summon_interval": 0,
"height_offset": 0, "height_offset": 0,
"_id": "" "_id": ""
}, },
@@ -278,7 +418,7 @@
}, },
"_enabled": true, "_enabled": true,
"__prefab": { "__prefab": {
"__id__": 13 "__id__": 19
}, },
"enabledContactListener": true, "enabledContactListener": true,
"bullet": false, "bullet": false,
@@ -312,7 +452,7 @@
}, },
"_enabled": true, "_enabled": true,
"__prefab": { "__prefab": {
"__id__": 15 "__id__": 21
}, },
"tag": 0, "tag": 0,
"_group": 1, "_group": 1,
@@ -346,7 +486,7 @@
}, },
"_enabled": true, "_enabled": true,
"__prefab": { "__prefab": {
"__id__": 17 "__id__": 23
}, },
"playOnLoad": true, "playOnLoad": true,
"_clips": [ "_clips": [

View File

@@ -20,28 +20,31 @@
"_children": [ "_children": [
{ {
"__id__": 2 "__id__": 2
},
{
"__id__": 8
} }
], ],
"_active": true, "_active": true,
"_components": [ "_components": [
{
"__id__": 8
},
{
"__id__": 10
},
{
"__id__": 12
},
{ {
"__id__": 14 "__id__": 14
}, },
{ {
"__id__": 16 "__id__": 16
},
{
"__id__": 18
},
{
"__id__": 20
},
{
"__id__": 22
} }
], ],
"_prefab": { "_prefab": {
"__id__": 18 "__id__": 24
}, },
"_lpos": { "_lpos": {
"__type__": "cc.Vec3", "__type__": "cc.Vec3",
@@ -211,6 +214,142 @@
"targetOverrides": null, "targetOverrides": null,
"nestedPrefabInstanceRoots": null "nestedPrefabInstanceRoots": null
}, },
{
"__type__": "cc.Node",
"_name": "electric-slash-horizontal1",
"_objFlags": 0,
"__editorExtras__": {},
"_parent": {
"__id__": 1
},
"_children": [],
"_active": true,
"_components": [
{
"__id__": 9
},
{
"__id__": 11
}
],
"_prefab": {
"__id__": 13
},
"_lpos": {
"__type__": "cc.Vec3",
"x": 25.352,
"y": 0,
"z": 0
},
"_lrot": {
"__type__": "cc.Quat",
"x": 0,
"y": 0,
"z": 0,
"w": 1
},
"_lscale": {
"__type__": "cc.Vec3",
"x": 2,
"y": 2,
"z": 1
},
"_mobility": 0,
"_layer": 1073741824,
"_euler": {
"__type__": "cc.Vec3",
"x": 0,
"y": 0,
"z": 0
},
"_id": ""
},
{
"__type__": "cc.UITransform",
"_name": "",
"_objFlags": 0,
"__editorExtras__": {},
"node": {
"__id__": 8
},
"_enabled": true,
"__prefab": {
"__id__": 10
},
"_contentSize": {
"__type__": "cc.Size",
"width": 95,
"height": 48
},
"_anchorPoint": {
"__type__": "cc.Vec2",
"x": 0.5,
"y": 0.5
},
"_id": ""
},
{
"__type__": "cc.CompPrefabInfo",
"fileId": "598QTUIYhAD5NxyPBcSrlV"
},
{
"__type__": "cc.Sprite",
"_name": "",
"_objFlags": 0,
"__editorExtras__": {},
"node": {
"__id__": 8
},
"_enabled": true,
"__prefab": {
"__id__": 12
},
"_customMaterial": null,
"_srcBlendFactor": 2,
"_dstBlendFactor": 4,
"_color": {
"__type__": "cc.Color",
"r": 255,
"g": 255,
"b": 255,
"a": 255
},
"_spriteFrame": {
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@f6490",
"__expectedType__": "cc.SpriteFrame"
},
"_type": 0,
"_fillType": 0,
"_sizeMode": 1,
"_fillCenter": {
"__type__": "cc.Vec2",
"x": 0,
"y": 0
},
"_fillStart": 0,
"_fillRange": 0,
"_isTrimmedMode": true,
"_useGrayscale": false,
"_atlas": null,
"_id": ""
},
{
"__type__": "cc.CompPrefabInfo",
"fileId": "79xdyqEqhFdZmXNHgUvUaA"
},
{
"__type__": "cc.PrefabInfo",
"root": {
"__id__": 1
},
"asset": {
"__id__": 0
},
"fileId": "d1hgL10YVE8a0CvDCyOdTd",
"instance": null,
"targetOverrides": null,
"nestedPrefabInstanceRoots": null
},
{ {
"__type__": "cc.UITransform", "__type__": "cc.UITransform",
"_name": "", "_name": "",
@@ -221,7 +360,7 @@
}, },
"_enabled": true, "_enabled": true,
"__prefab": { "__prefab": {
"__id__": 9 "__id__": 15
}, },
"_contentSize": { "_contentSize": {
"__type__": "cc.Size", "__type__": "cc.Size",
@@ -249,7 +388,7 @@
}, },
"_enabled": true, "_enabled": true,
"__prefab": { "__prefab": {
"__id__": 11 "__id__": 17
}, },
"atk_x": 20, "atk_x": 20,
"atk_y": 40, "atk_y": 40,
@@ -261,6 +400,10 @@
"forceStartX": -1, "forceStartX": -1,
"forceStartY": -1, "forceStartY": -1,
"summon_count": 1, "summon_count": 1,
"summon_target_mode": 0,
"summon_x_offset": 0,
"summon_y_offset": 0,
"summon_interval": 0,
"height_offset": 0, "height_offset": 0,
"_id": "" "_id": ""
}, },
@@ -278,7 +421,7 @@
}, },
"_enabled": true, "_enabled": true,
"__prefab": { "__prefab": {
"__id__": 13 "__id__": 19
}, },
"enabledContactListener": true, "enabledContactListener": true,
"bullet": false, "bullet": false,
@@ -312,7 +455,7 @@
}, },
"_enabled": true, "_enabled": true,
"__prefab": { "__prefab": {
"__id__": 15 "__id__": 21
}, },
"tag": 0, "tag": 0,
"_group": 1, "_group": 1,
@@ -346,7 +489,7 @@
}, },
"_enabled": true, "_enabled": true,
"__prefab": { "__prefab": {
"__id__": 17 "__id__": 23
}, },
"playOnLoad": true, "playOnLoad": true,
"_clips": [ "_clips": [

View File

@@ -35,10 +35,13 @@
}, },
{ {
"__id__": 14 "__id__": 14
},
{
"__id__": 16
} }
], ],
"_prefab": { "_prefab": {
"__id__": 16 "__id__": 18
}, },
"_lpos": { "_lpos": {
"__type__": "cc.Vec3", "__type__": "cc.Vec3",
@@ -92,8 +95,8 @@
}, },
"_lpos": { "_lpos": {
"__type__": "cc.Vec3", "__type__": "cc.Vec3",
"x": 6.77, "x": 0,
"y": 0, "y": -60,
"z": 0 "z": 0
}, },
"_lrot": { "_lrot": {
@@ -105,8 +108,8 @@
}, },
"_lscale": { "_lscale": {
"__type__": "cc.Vec3", "__type__": "cc.Vec3",
"x": 0.3, "x": 1.4,
"y": 0.3, "y": 2,
"z": 1 "z": 1
}, },
"_mobility": 0, "_mobility": 0,
@@ -133,13 +136,13 @@
}, },
"_contentSize": { "_contentSize": {
"__type__": "cc.Size", "__type__": "cc.Size",
"width": 90, "width": 128,
"height": 90 "height": 128
}, },
"_anchorPoint": { "_anchorPoint": {
"__type__": "cc.Vec2", "__type__": "cc.Vec2",
"x": 0.5, "x": 0.5,
"y": 0.5 "y": 0
}, },
"_id": "" "_id": ""
}, },
@@ -170,7 +173,7 @@
"a": 255 "a": 255
}, },
"_spriteFrame": { "_spriteFrame": {
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@4d4df", "__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@55402",
"__expectedType__": "cc.SpriteFrame" "__expectedType__": "cc.SpriteFrame"
}, },
"_type": 0, "_type": 0,
@@ -222,13 +225,13 @@
}, },
"_contentSize": { "_contentSize": {
"__type__": "cc.Size", "__type__": "cc.Size",
"width": 30, "width": 20,
"height": 40 "height": 100
}, },
"_anchorPoint": { "_anchorPoint": {
"__type__": "cc.Vec2", "__type__": "cc.Vec2",
"x": 0.5, "x": 0.5,
"y": 0.5 "y": 0
}, },
"_id": "" "_id": ""
}, },
@@ -248,13 +251,26 @@
"__prefab": { "__prefab": {
"__id__": 11 "__id__": 11
}, },
"atk_x": 10, "atk_x": 0,
"atk_y": 15, "atk_y": 0,
"runType": 3,
"endType": 0,
"speed": 720,
"time": 0,
"distance": 0,
"forceStartX": -1,
"forceStartY": -1,
"summon_count": 1,
"summon_target_mode": 0,
"summon_x_offset": 0,
"summon_y_offset": 0,
"summon_interval": 0,
"height_offset": 0,
"_id": "" "_id": ""
}, },
{ {
"__type__": "cc.CompPrefabInfo", "__type__": "cc.CompPrefabInfo",
"fileId": "60LInmZXxDtKu79AshRG9j" "fileId": "35nW0iQNBH2bqkWAr3MVkQ"
}, },
{ {
"__type__": "cc.RigidBody2D", "__type__": "cc.RigidBody2D",
@@ -288,7 +304,7 @@
}, },
{ {
"__type__": "cc.CompPrefabInfo", "__type__": "cc.CompPrefabInfo",
"fileId": "e1yBA625RLwLhzo6bLYW7j" "fileId": "57cr7S0YpK4oEZCavwXtIX"
}, },
{ {
"__type__": "cc.BoxCollider2D", "__type__": "cc.BoxCollider2D",
@@ -315,14 +331,43 @@
}, },
"_size": { "_size": {
"__type__": "cc.Size", "__type__": "cc.Size",
"width": 30, "width": 20,
"height": 40 "height": 100
}, },
"_id": "" "_id": ""
}, },
{ {
"__type__": "cc.CompPrefabInfo", "__type__": "cc.CompPrefabInfo",
"fileId": "43ZDJfXX9AX73gyytKQZWm" "fileId": "ebw5mObxNGGKxnJXDgX5gl"
},
{
"__type__": "cc.Animation",
"_name": "",
"_objFlags": 0,
"__editorExtras__": {},
"node": {
"__id__": 1
},
"_enabled": true,
"__prefab": {
"__id__": 17
},
"playOnLoad": true,
"_clips": [
{
"__uuid__": "45605d53-4dca-4529-819d-4a0d98c3a47c",
"__expectedType__": "cc.AnimationClip"
}
],
"_defaultClip": {
"__uuid__": "45605d53-4dca-4529-819d-4a0d98c3a47c",
"__expectedType__": "cc.AnimationClip"
},
"_id": ""
},
{
"__type__": "cc.CompPrefabInfo",
"fileId": "20U0hP/NZErJJXRCEib1lq"
}, },
{ {
"__type__": "cc.PrefabInfo", "__type__": "cc.PrefabInfo",

View File

@@ -2,7 +2,7 @@
"ver": "1.1.50", "ver": "1.1.50",
"importer": "prefab", "importer": "prefab",
"imported": true, "imported": true,
"uuid": "fc32700f-bf4a-47ce-b619-6497b7280fde", "uuid": "7edb8215-1344-4215-8172-7a50a72da8bb",
"files": [ "files": [
".json" ".json"
], ],

View File

@@ -35,10 +35,13 @@
}, },
{ {
"__id__": 14 "__id__": 14
},
{
"__id__": 16
} }
], ],
"_prefab": { "_prefab": {
"__id__": 16 "__id__": 18
}, },
"_lpos": { "_lpos": {
"__type__": "cc.Vec3", "__type__": "cc.Vec3",
@@ -92,7 +95,7 @@
}, },
"_lpos": { "_lpos": {
"__type__": "cc.Vec3", "__type__": "cc.Vec3",
"x": 6.77, "x": 0,
"y": 0, "y": 0,
"z": 0 "z": 0
}, },
@@ -100,13 +103,13 @@
"__type__": "cc.Quat", "__type__": "cc.Quat",
"x": 0, "x": 0,
"y": 0, "y": 0,
"z": 0, "z": 0.706489444943837,
"w": 1 "w": 0.7077235789366842
}, },
"_lscale": { "_lscale": {
"__type__": "cc.Vec3", "__type__": "cc.Vec3",
"x": 0.3, "x": -1,
"y": 0.3, "y": 1,
"z": 1 "z": 1
}, },
"_mobility": 0, "_mobility": 0,
@@ -115,7 +118,7 @@
"__type__": "cc.Vec3", "__type__": "cc.Vec3",
"x": 0, "x": 0,
"y": 0, "y": 0,
"z": 0 "z": 89.9
}, },
"_id": "" "_id": ""
}, },
@@ -133,8 +136,8 @@
}, },
"_contentSize": { "_contentSize": {
"__type__": "cc.Size", "__type__": "cc.Size",
"width": 90, "width": 85,
"height": 90 "height": 119
}, },
"_anchorPoint": { "_anchorPoint": {
"__type__": "cc.Vec2", "__type__": "cc.Vec2",
@@ -170,7 +173,7 @@
"a": 255 "a": 255
}, },
"_spriteFrame": { "_spriteFrame": {
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@179ff", "__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@59ec8",
"__expectedType__": "cc.SpriteFrame" "__expectedType__": "cc.SpriteFrame"
}, },
"_type": 0, "_type": 0,
@@ -222,8 +225,8 @@
}, },
"_contentSize": { "_contentSize": {
"__type__": "cc.Size", "__type__": "cc.Size",
"width": 30, "width": 50,
"height": 40 "height": 50
}, },
"_anchorPoint": { "_anchorPoint": {
"__type__": "cc.Vec2", "__type__": "cc.Vec2",
@@ -248,13 +251,25 @@
"__prefab": { "__prefab": {
"__id__": 11 "__id__": 11
}, },
"atk_x": 10, "atk_x": 20,
"atk_y": 15, "atk_y": 20,
"runType": 0,
"endType": 2,
"speed": 720,
"time": 0,
"distance": 0,
"forceStartX": -1,
"forceStartY": -1,
"summon_count": 1,
"summon_x_offset": 0,
"summon_y_offset": 0,
"summon_interval": 0,
"height_offset": 100,
"_id": "" "_id": ""
}, },
{ {
"__type__": "cc.CompPrefabInfo", "__type__": "cc.CompPrefabInfo",
"fileId": "60LInmZXxDtKu79AshRG9j" "fileId": "35nW0iQNBH2bqkWAr3MVkQ"
}, },
{ {
"__type__": "cc.RigidBody2D", "__type__": "cc.RigidBody2D",
@@ -288,7 +303,7 @@
}, },
{ {
"__type__": "cc.CompPrefabInfo", "__type__": "cc.CompPrefabInfo",
"fileId": "e1yBA625RLwLhzo6bLYW7j" "fileId": "57cr7S0YpK4oEZCavwXtIX"
}, },
{ {
"__type__": "cc.BoxCollider2D", "__type__": "cc.BoxCollider2D",
@@ -315,14 +330,43 @@
}, },
"_size": { "_size": {
"__type__": "cc.Size", "__type__": "cc.Size",
"width": 30, "width": 50,
"height": 40 "height": 150
}, },
"_id": "" "_id": ""
}, },
{ {
"__type__": "cc.CompPrefabInfo", "__type__": "cc.CompPrefabInfo",
"fileId": "43ZDJfXX9AX73gyytKQZWm" "fileId": "ebw5mObxNGGKxnJXDgX5gl"
},
{
"__type__": "cc.Animation",
"_name": "",
"_objFlags": 0,
"__editorExtras__": {},
"node": {
"__id__": 1
},
"_enabled": true,
"__prefab": {
"__id__": 17
},
"playOnLoad": true,
"_clips": [
{
"__uuid__": "45385cba-7334-4ff4-a548-578262417f58",
"__expectedType__": "cc.AnimationClip"
}
],
"_defaultClip": {
"__uuid__": "45385cba-7334-4ff4-a548-578262417f58",
"__expectedType__": "cc.AnimationClip"
},
"_id": ""
},
{
"__type__": "cc.CompPrefabInfo",
"fileId": "20U0hP/NZErJJXRCEib1lq"
}, },
{ {
"__type__": "cc.PrefabInfo", "__type__": "cc.PrefabInfo",

View File

@@ -2,7 +2,7 @@
"ver": "1.1.50", "ver": "1.1.50",
"importer": "prefab", "importer": "prefab",
"imported": true, "imported": true,
"uuid": "5a0c6727-c741-4a33-b6f2-b2c56e3fc540", "uuid": "7c7ff7a4-17d5-4c4a-8fee-68b73af250e5",
"files": [ "files": [
".json" ".json"
], ],

View File

@@ -0,0 +1,519 @@
[
{
"__type__": "cc.Prefab",
"_name": "m5",
"_objFlags": 0,
"__editorExtras__": {},
"_native": "",
"data": {
"__id__": 1
},
"optimizationPolicy": 0,
"persistent": false
},
{
"__type__": "cc.Node",
"_name": "m5",
"_objFlags": 0,
"__editorExtras__": {},
"_parent": null,
"_children": [
{
"__id__": 2
},
{
"__id__": 8
}
],
"_active": true,
"_components": [
{
"__id__": 14
},
{
"__id__": 16
},
{
"__id__": 18
},
{
"__id__": 20
},
{
"__id__": 22
}
],
"_prefab": {
"__id__": 24
},
"_lpos": {
"__type__": "cc.Vec3",
"x": 0,
"y": 0,
"z": 0
},
"_lrot": {
"__type__": "cc.Quat",
"x": 0,
"y": 0,
"z": 0,
"w": 1
},
"_lscale": {
"__type__": "cc.Vec3",
"x": 1,
"y": 1,
"z": 1
},
"_mobility": 0,
"_layer": 1073741824,
"_euler": {
"__type__": "cc.Vec3",
"x": 0,
"y": 0,
"z": 0
},
"_id": ""
},
{
"__type__": "cc.Node",
"_name": "Node",
"_objFlags": 0,
"__editorExtras__": {},
"_parent": {
"__id__": 1
},
"_children": [],
"_active": true,
"_components": [
{
"__id__": 3
},
{
"__id__": 5
}
],
"_prefab": {
"__id__": 7
},
"_lpos": {
"__type__": "cc.Vec3",
"x": 0,
"y": 0,
"z": 0
},
"_lrot": {
"__type__": "cc.Quat",
"x": 0,
"y": 0,
"z": 0,
"w": 1
},
"_lscale": {
"__type__": "cc.Vec3",
"x": -0.5,
"y": 0.5,
"z": 1
},
"_mobility": 0,
"_layer": 1073741824,
"_euler": {
"__type__": "cc.Vec3",
"x": 0,
"y": 0,
"z": 0
},
"_id": ""
},
{
"__type__": "cc.UITransform",
"_name": "",
"_objFlags": 0,
"__editorExtras__": {},
"node": {
"__id__": 2
},
"_enabled": true,
"__prefab": {
"__id__": 4
},
"_contentSize": {
"__type__": "cc.Size",
"width": 277,
"height": 250
},
"_anchorPoint": {
"__type__": "cc.Vec2",
"x": 0.5,
"y": 0
},
"_id": ""
},
{
"__type__": "cc.CompPrefabInfo",
"fileId": "93pNmvtQlLSqtTgIepyEmA"
},
{
"__type__": "cc.Sprite",
"_name": "",
"_objFlags": 0,
"__editorExtras__": {},
"node": {
"__id__": 2
},
"_enabled": true,
"__prefab": {
"__id__": 6
},
"_customMaterial": null,
"_srcBlendFactor": 2,
"_dstBlendFactor": 4,
"_color": {
"__type__": "cc.Color",
"r": 255,
"g": 255,
"b": 255,
"a": 255
},
"_spriteFrame": {
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@260b5",
"__expectedType__": "cc.SpriteFrame"
},
"_type": 0,
"_fillType": 0,
"_sizeMode": 0,
"_fillCenter": {
"__type__": "cc.Vec2",
"x": 0,
"y": 0
},
"_fillStart": 0,
"_fillRange": 0,
"_isTrimmedMode": true,
"_useGrayscale": false,
"_atlas": {
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20",
"__expectedType__": "cc.SpriteAtlas"
},
"_id": ""
},
{
"__type__": "cc.CompPrefabInfo",
"fileId": "12eKc8gltBz50frJCS5+ww"
},
{
"__type__": "cc.PrefabInfo",
"root": {
"__id__": 1
},
"asset": {
"__id__": 0
},
"fileId": "3arqAMBz1MvoXBzeDaL5M/",
"instance": null,
"targetOverrides": null,
"nestedPrefabInstanceRoots": null
},
{
"__type__": "cc.Node",
"_name": "Node-001",
"_objFlags": 0,
"__editorExtras__": {},
"_parent": {
"__id__": 1
},
"_children": [],
"_active": true,
"_components": [
{
"__id__": 9
},
{
"__id__": 11
}
],
"_prefab": {
"__id__": 13
},
"_lpos": {
"__type__": "cc.Vec3",
"x": 0,
"y": 0,
"z": 0
},
"_lrot": {
"__type__": "cc.Quat",
"x": 0,
"y": 0,
"z": 0,
"w": 1
},
"_lscale": {
"__type__": "cc.Vec3",
"x": -0.5,
"y": 0.5,
"z": 1
},
"_mobility": 0,
"_layer": 1073741824,
"_euler": {
"__type__": "cc.Vec3",
"x": 0,
"y": 0,
"z": 0
},
"_id": ""
},
{
"__type__": "cc.UITransform",
"_name": "",
"_objFlags": 0,
"__editorExtras__": {},
"node": {
"__id__": 8
},
"_enabled": true,
"__prefab": {
"__id__": 10
},
"_contentSize": {
"__type__": "cc.Size",
"width": 122,
"height": 68
},
"_anchorPoint": {
"__type__": "cc.Vec2",
"x": 0.5,
"y": 0
},
"_id": ""
},
{
"__type__": "cc.CompPrefabInfo",
"fileId": "4blcTDlixIRI3qtyERLs2E"
},
{
"__type__": "cc.Sprite",
"_name": "",
"_objFlags": 0,
"__editorExtras__": {},
"node": {
"__id__": 8
},
"_enabled": true,
"__prefab": {
"__id__": 12
},
"_customMaterial": null,
"_srcBlendFactor": 2,
"_dstBlendFactor": 4,
"_color": {
"__type__": "cc.Color",
"r": 255,
"g": 255,
"b": 255,
"a": 255
},
"_spriteFrame": null,
"_type": 0,
"_fillType": 0,
"_sizeMode": 1,
"_fillCenter": {
"__type__": "cc.Vec2",
"x": 0,
"y": 0
},
"_fillStart": 0,
"_fillRange": 0,
"_isTrimmedMode": true,
"_useGrayscale": false,
"_atlas": null,
"_id": ""
},
{
"__type__": "cc.CompPrefabInfo",
"fileId": "e6QtagQwZA/50lsdWvOjb0"
},
{
"__type__": "cc.PrefabInfo",
"root": {
"__id__": 1
},
"asset": {
"__id__": 0
},
"fileId": "ed54OCubBD853t6+5pUPLQ",
"instance": null,
"targetOverrides": null,
"nestedPrefabInstanceRoots": null
},
{
"__type__": "cc.UITransform",
"_name": "",
"_objFlags": 0,
"__editorExtras__": {},
"node": {
"__id__": 1
},
"_enabled": true,
"__prefab": {
"__id__": 15
},
"_contentSize": {
"__type__": "cc.Size",
"width": 50,
"height": 100
},
"_anchorPoint": {
"__type__": "cc.Vec2",
"x": 0.5,
"y": 0
},
"_id": ""
},
{
"__type__": "cc.CompPrefabInfo",
"fileId": "63NP9yq3hEUKD/OZZZ5t7x"
},
{
"__type__": "57aabs7TE1J5obTAZczc+64",
"_name": "",
"_objFlags": 0,
"__editorExtras__": {},
"node": {
"__id__": 1
},
"_enabled": true,
"__prefab": {
"__id__": 17
},
"atk_x": 0,
"atk_y": 0,
"runType": 0,
"endType": 2,
"speed": 720,
"time": 0,
"distance": 0,
"forceStartX": -1,
"forceStartY": -1,
"summon_count": 1,
"summon_x_offset": 0,
"summon_y_offset": 0,
"summon_interval": 0,
"height_offset": 0,
"_id": ""
},
{
"__type__": "cc.CompPrefabInfo",
"fileId": "35nW0iQNBH2bqkWAr3MVkQ"
},
{
"__type__": "cc.RigidBody2D",
"_name": "",
"_objFlags": 0,
"__editorExtras__": {},
"node": {
"__id__": 1
},
"_enabled": true,
"__prefab": {
"__id__": 19
},
"enabledContactListener": true,
"bullet": false,
"awakeOnLoad": true,
"_group": 1,
"_type": 1,
"_allowSleep": false,
"_gravityScale": 1,
"_linearDamping": 0,
"_angularDamping": 0,
"_linearVelocity": {
"__type__": "cc.Vec2",
"x": 0,
"y": 0
},
"_angularVelocity": 0,
"_fixedRotation": false,
"_id": ""
},
{
"__type__": "cc.CompPrefabInfo",
"fileId": "57cr7S0YpK4oEZCavwXtIX"
},
{
"__type__": "cc.BoxCollider2D",
"_name": "",
"_objFlags": 0,
"__editorExtras__": {},
"node": {
"__id__": 1
},
"_enabled": true,
"__prefab": {
"__id__": 21
},
"tag": 0,
"_group": 1,
"_density": 1,
"_sensor": true,
"_friction": 0.2,
"_restitution": 0,
"_offset": {
"__type__": "cc.Vec2",
"x": 0,
"y": 50
},
"_size": {
"__type__": "cc.Size",
"width": 50,
"height": 100
},
"_id": ""
},
{
"__type__": "cc.CompPrefabInfo",
"fileId": "ebw5mObxNGGKxnJXDgX5gl"
},
{
"__type__": "cc.Animation",
"_name": "",
"_objFlags": 0,
"__editorExtras__": {},
"node": {
"__id__": 1
},
"_enabled": true,
"__prefab": {
"__id__": 23
},
"playOnLoad": true,
"_clips": [
{
"__uuid__": "a71379d4-b14d-4070-96ee-e7c889f25bbd",
"__expectedType__": "cc.AnimationClip"
}
],
"_defaultClip": {
"__uuid__": "a71379d4-b14d-4070-96ee-e7c889f25bbd",
"__expectedType__": "cc.AnimationClip"
},
"_id": ""
},
{
"__type__": "cc.CompPrefabInfo",
"fileId": "20U0hP/NZErJJXRCEib1lq"
},
{
"__type__": "cc.PrefabInfo",
"root": {
"__id__": 1
},
"asset": {
"__id__": 0
},
"fileId": "c46/YsCPVOJYA4mWEpNYRx",
"instance": null,
"targetOverrides": null
}
]

View File

@@ -0,0 +1,13 @@
{
"ver": "1.1.50",
"importer": "prefab",
"imported": true,
"uuid": "8dc65122-222f-4bd3-b89c-62e7f8eefe78",
"files": [
".json"
],
"subMetas": {},
"userData": {
"syncNodeName": "m5"
}
}

View File

@@ -293,6 +293,10 @@
"forceStartX": -1, "forceStartX": -1,
"forceStartY": -1, "forceStartY": -1,
"summon_count": 4, "summon_count": 4,
"summon_target_mode": 2,
"summon_x_offset": 0,
"summon_y_offset": 0,
"summon_interval": 0,
"height_offset": 100, "height_offset": 100,
"_id": "" "_id": ""
}, },

View File

@@ -293,6 +293,10 @@
"forceStartX": -1, "forceStartX": -1,
"forceStartY": -1, "forceStartY": -1,
"summon_count": 6, "summon_count": 6,
"summon_target_mode": 2,
"summon_x_offset": 0,
"summon_y_offset": 0,
"summon_interval": 0,
"height_offset": 100, "height_offset": 100,
"_id": "" "_id": ""
}, },

View File

@@ -261,6 +261,10 @@
"forceStartX": -1, "forceStartX": -1,
"forceStartY": -1, "forceStartY": -1,
"summon_count": 3, "summon_count": 3,
"summon_target_mode": 2,
"summon_x_offset": 0,
"summon_y_offset": 0,
"summon_interval": 0,
"height_offset": 100, "height_offset": 100,
"_id": "" "_id": ""
}, },

View File

@@ -397,6 +397,10 @@
"forceStartX": -1, "forceStartX": -1,
"forceStartY": -1, "forceStartY": -1,
"summon_count": 3, "summon_count": 3,
"summon_target_mode": 0,
"summon_x_offset": 0,
"summon_y_offset": 0,
"summon_interval": 0.2,
"height_offset": 0, "height_offset": 0,
"_id": "" "_id": ""
}, },

View File

@@ -96,7 +96,7 @@
"_lpos": { "_lpos": {
"__type__": "cc.Vec3", "__type__": "cc.Vec3",
"x": 0, "x": 0,
"y": -30, "y": -90,
"z": 0 "z": 0
}, },
"_lrot": { "_lrot": {
@@ -108,7 +108,7 @@
}, },
"_lscale": { "_lscale": {
"__type__": "cc.Vec3", "__type__": "cc.Vec3",
"x": 1, "x": 1.5,
"y": 2, "y": 2,
"z": 1 "z": 1
}, },
@@ -261,6 +261,10 @@
"forceStartX": -1, "forceStartX": -1,
"forceStartY": -1, "forceStartY": -1,
"summon_count": 5, "summon_count": 5,
"summon_target_mode": 2,
"summon_x_offset": 0,
"summon_y_offset": 0,
"summon_interval": 0,
"height_offset": 0, "height_offset": 0,
"_id": "" "_id": ""
}, },

View File

@@ -261,6 +261,10 @@
"forceStartX": -1, "forceStartX": -1,
"forceStartY": -1, "forceStartY": -1,
"summon_count": 3, "summon_count": 3,
"summon_target_mode": 2,
"summon_x_offset": 0,
"summon_y_offset": 0,
"summon_interval": 0.5,
"height_offset": 100, "height_offset": 100,
"_id": "" "_id": ""
}, },

View File

@@ -261,6 +261,10 @@
"forceStartX": -1, "forceStartX": -1,
"forceStartY": -1, "forceStartY": -1,
"summon_count": 3, "summon_count": 3,
"summon_target_mode": 2,
"summon_x_offset": 0,
"summon_y_offset": 0,
"summon_interval": 0,
"height_offset": 100, "height_offset": 100,
"_id": "" "_id": ""
}, },

View File

@@ -261,6 +261,10 @@
"forceStartX": -1, "forceStartX": -1,
"forceStartY": -1, "forceStartY": -1,
"summon_count": 3, "summon_count": 3,
"summon_target_mode": 2,
"summon_x_offset": 0,
"summon_y_offset": 0,
"summon_interval": 0,
"height_offset": 100, "height_offset": 100,
"_id": "" "_id": ""
}, },

View File

@@ -0,0 +1,526 @@
[
{
"__type__": "cc.Prefab",
"_name": "maxm7",
"_objFlags": 0,
"__editorExtras__": {},
"_native": "",
"data": {
"__id__": 1
},
"optimizationPolicy": 0,
"persistent": false
},
{
"__type__": "cc.Node",
"_name": "maxm7",
"_objFlags": 0,
"__editorExtras__": {},
"_parent": null,
"_children": [
{
"__id__": 2
},
{
"__id__": 8
}
],
"_active": true,
"_components": [
{
"__id__": 14
},
{
"__id__": 16
},
{
"__id__": 18
},
{
"__id__": 20
},
{
"__id__": 22
}
],
"_prefab": {
"__id__": 24
},
"_lpos": {
"__type__": "cc.Vec3",
"x": 0,
"y": 0,
"z": 0
},
"_lrot": {
"__type__": "cc.Quat",
"x": 0,
"y": 0,
"z": 0,
"w": 1
},
"_lscale": {
"__type__": "cc.Vec3",
"x": 1,
"y": 1,
"z": 1
},
"_mobility": 0,
"_layer": 1073741824,
"_euler": {
"__type__": "cc.Vec3",
"x": 0,
"y": 0,
"z": 0
},
"_id": ""
},
{
"__type__": "cc.Node",
"_name": "Node",
"_objFlags": 0,
"__editorExtras__": {},
"_parent": {
"__id__": 1
},
"_children": [],
"_active": true,
"_components": [
{
"__id__": 3
},
{
"__id__": 5
}
],
"_prefab": {
"__id__": 7
},
"_lpos": {
"__type__": "cc.Vec3",
"x": 0,
"y": -30,
"z": 0
},
"_lrot": {
"__type__": "cc.Quat",
"x": 0,
"y": 0,
"z": 0,
"w": 1
},
"_lscale": {
"__type__": "cc.Vec3",
"x": 2,
"y": 2,
"z": 1
},
"_mobility": 0,
"_layer": 1073741824,
"_euler": {
"__type__": "cc.Vec3",
"x": 0,
"y": 0,
"z": 0
},
"_id": ""
},
{
"__type__": "cc.UITransform",
"_name": "",
"_objFlags": 0,
"__editorExtras__": {},
"node": {
"__id__": 2
},
"_enabled": true,
"__prefab": {
"__id__": 4
},
"_contentSize": {
"__type__": "cc.Size",
"width": 128,
"height": 128
},
"_anchorPoint": {
"__type__": "cc.Vec2",
"x": 0.5,
"y": 0
},
"_id": ""
},
{
"__type__": "cc.CompPrefabInfo",
"fileId": "93pNmvtQlLSqtTgIepyEmA"
},
{
"__type__": "cc.Sprite",
"_name": "",
"_objFlags": 0,
"__editorExtras__": {},
"node": {
"__id__": 2
},
"_enabled": true,
"__prefab": {
"__id__": 6
},
"_customMaterial": null,
"_srcBlendFactor": 2,
"_dstBlendFactor": 4,
"_color": {
"__type__": "cc.Color",
"r": 255,
"g": 255,
"b": 255,
"a": 255
},
"_spriteFrame": {
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@55402",
"__expectedType__": "cc.SpriteFrame"
},
"_type": 0,
"_fillType": 0,
"_sizeMode": 1,
"_fillCenter": {
"__type__": "cc.Vec2",
"x": 0,
"y": 0
},
"_fillStart": 0,
"_fillRange": 0,
"_isTrimmedMode": true,
"_useGrayscale": false,
"_atlas": {
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20",
"__expectedType__": "cc.SpriteAtlas"
},
"_id": ""
},
{
"__type__": "cc.CompPrefabInfo",
"fileId": "12eKc8gltBz50frJCS5+ww"
},
{
"__type__": "cc.PrefabInfo",
"root": {
"__id__": 1
},
"asset": {
"__id__": 0
},
"fileId": "3arqAMBz1MvoXBzeDaL5M/",
"instance": null,
"targetOverrides": null,
"nestedPrefabInstanceRoots": null
},
{
"__type__": "cc.Node",
"_name": "Node-001",
"_objFlags": 0,
"__editorExtras__": {},
"_parent": {
"__id__": 1
},
"_children": [],
"_active": true,
"_components": [
{
"__id__": 9
},
{
"__id__": 11
}
],
"_prefab": {
"__id__": 13
},
"_lpos": {
"__type__": "cc.Vec3",
"x": 0,
"y": -30,
"z": 0
},
"_lrot": {
"__type__": "cc.Quat",
"x": 0,
"y": 0,
"z": 0,
"w": 1
},
"_lscale": {
"__type__": "cc.Vec3",
"x": 2,
"y": 2,
"z": 1
},
"_mobility": 0,
"_layer": 1073741824,
"_euler": {
"__type__": "cc.Vec3",
"x": 0,
"y": 0,
"z": 0
},
"_id": ""
},
{
"__type__": "cc.UITransform",
"_name": "",
"_objFlags": 0,
"__editorExtras__": {},
"node": {
"__id__": 8
},
"_enabled": true,
"__prefab": {
"__id__": 10
},
"_contentSize": {
"__type__": "cc.Size",
"width": 128,
"height": 128
},
"_anchorPoint": {
"__type__": "cc.Vec2",
"x": 0.5,
"y": 0
},
"_id": ""
},
{
"__type__": "cc.CompPrefabInfo",
"fileId": "cbS/mBx7hFKK1RlGcpOgD1"
},
{
"__type__": "cc.Sprite",
"_name": "",
"_objFlags": 0,
"__editorExtras__": {},
"node": {
"__id__": 8
},
"_enabled": true,
"__prefab": {
"__id__": 12
},
"_customMaterial": null,
"_srcBlendFactor": 2,
"_dstBlendFactor": 4,
"_color": {
"__type__": "cc.Color",
"r": 255,
"g": 255,
"b": 255,
"a": 255
},
"_spriteFrame": {
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@55402",
"__expectedType__": "cc.SpriteFrame"
},
"_type": 0,
"_fillType": 0,
"_sizeMode": 1,
"_fillCenter": {
"__type__": "cc.Vec2",
"x": 0,
"y": 0
},
"_fillStart": 0,
"_fillRange": 0,
"_isTrimmedMode": true,
"_useGrayscale": false,
"_atlas": {
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20",
"__expectedType__": "cc.SpriteAtlas"
},
"_id": ""
},
{
"__type__": "cc.CompPrefabInfo",
"fileId": "eah7cf5S5FCrmP7CHX5e38"
},
{
"__type__": "cc.PrefabInfo",
"root": {
"__id__": 1
},
"asset": {
"__id__": 0
},
"fileId": "f9cYdo2HdAp7KWposjmIcg",
"instance": null,
"targetOverrides": null,
"nestedPrefabInstanceRoots": null
},
{
"__type__": "cc.UITransform",
"_name": "",
"_objFlags": 0,
"__editorExtras__": {},
"node": {
"__id__": 1
},
"_enabled": true,
"__prefab": {
"__id__": 15
},
"_contentSize": {
"__type__": "cc.Size",
"width": 200,
"height": 100
},
"_anchorPoint": {
"__type__": "cc.Vec2",
"x": 0.5,
"y": 0.3
},
"_id": ""
},
{
"__type__": "cc.CompPrefabInfo",
"fileId": "63NP9yq3hEUKD/OZZZ5t7x"
},
{
"__type__": "57aabs7TE1J5obTAZczc+64",
"_name": "",
"_objFlags": 0,
"__editorExtras__": {},
"node": {
"__id__": 1
},
"_enabled": true,
"__prefab": {
"__id__": 17
},
"atk_x": 0,
"atk_y": 0,
"runType": 3,
"endType": 0,
"speed": 720,
"time": 0,
"distance": 0,
"forceStartX": -1,
"forceStartY": -1,
"summon_count": 1,
"summon_target_mode": 2,
"summon_x_offset": 0,
"summon_y_offset": 0,
"summon_interval": 0.5,
"height_offset": 0,
"_id": ""
},
{
"__type__": "cc.CompPrefabInfo",
"fileId": "35nW0iQNBH2bqkWAr3MVkQ"
},
{
"__type__": "cc.RigidBody2D",
"_name": "",
"_objFlags": 0,
"__editorExtras__": {},
"node": {
"__id__": 1
},
"_enabled": true,
"__prefab": {
"__id__": 19
},
"enabledContactListener": true,
"bullet": false,
"awakeOnLoad": true,
"_group": 1,
"_type": 1,
"_allowSleep": false,
"_gravityScale": 1,
"_linearDamping": 0,
"_angularDamping": 0,
"_linearVelocity": {
"__type__": "cc.Vec2",
"x": 0,
"y": 0
},
"_angularVelocity": 0,
"_fixedRotation": false,
"_id": ""
},
{
"__type__": "cc.CompPrefabInfo",
"fileId": "57cr7S0YpK4oEZCavwXtIX"
},
{
"__type__": "cc.BoxCollider2D",
"_name": "",
"_objFlags": 0,
"__editorExtras__": {},
"node": {
"__id__": 1
},
"_enabled": true,
"__prefab": {
"__id__": 21
},
"tag": 0,
"_group": 1,
"_density": 1,
"_sensor": true,
"_friction": 0.2,
"_restitution": 0,
"_offset": {
"__type__": "cc.Vec2",
"x": 0,
"y": 0
},
"_size": {
"__type__": "cc.Size",
"width": 200,
"height": 100
},
"_id": ""
},
{
"__type__": "cc.CompPrefabInfo",
"fileId": "ebw5mObxNGGKxnJXDgX5gl"
},
{
"__type__": "cc.Animation",
"_name": "",
"_objFlags": 0,
"__editorExtras__": {},
"node": {
"__id__": 1
},
"_enabled": true,
"__prefab": {
"__id__": 23
},
"playOnLoad": true,
"_clips": [
{
"__uuid__": "b0bec9a1-c3c7-412f-b6de-e27ec78dcc86",
"__expectedType__": "cc.AnimationClip"
}
],
"_defaultClip": {
"__uuid__": "b0bec9a1-c3c7-412f-b6de-e27ec78dcc86",
"__expectedType__": "cc.AnimationClip"
},
"_id": ""
},
{
"__type__": "cc.CompPrefabInfo",
"fileId": "20U0hP/NZErJJXRCEib1lq"
},
{
"__type__": "cc.PrefabInfo",
"root": {
"__id__": 1
},
"asset": {
"__id__": 0
},
"fileId": "c46/YsCPVOJYA4mWEpNYRx",
"instance": null,
"targetOverrides": null
}
]

View File

@@ -0,0 +1,13 @@
{
"ver": "1.1.50",
"importer": "prefab",
"imported": true,
"uuid": "2316d214-bb61-434e-a056-48793e72dcce",
"files": [
".json"
],
"subMetas": {},
"userData": {
"syncNodeName": "maxm7"
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -81,11 +81,13 @@ const PLACEHOLDER_PATTERN = /\{(\w+)\}/g;
* atking/atked 为周期循环触发(运行时按次数取模判定),拼为"每攻击N次"/"每受击N次" * atking/atked 为周期循环触发(运行时按次数取模判定),拼为"每攻击N次"/"每受击N次"
* 表达循环语义(N=1 时退化为"每次攻击"/"每次受击");其余类型直接用触发名(召唤/死亡后/回合开始)。 * 表达循环语义(N=1 时退化为"每次攻击"/"每次受击");其余类型直接用触发名(召唤/死亡后/回合开始)。
*/ */
function buildTriggerLabel(type: SkillTriggerType, tNum: number): string { function buildTriggerLabel(type: SkillTriggerType, tNum: number, chance?: number): string {
if (type === SkillTriggerType.Atking || type === SkillTriggerType.Atked) { if (type === SkillTriggerType.Atking || type === SkillTriggerType.Atked) {
// 配置了 t_chance 且 < 100 时追加概率说明(保底叠加为隐藏机制,不在文案展示)
const chanceSeg = chance !== undefined && chance < 100 ? `(${valueRich(Math.round(chance))}%概率)` : "";
return tNum <= 1 return tNum <= 1
? `每次${SkillTriggerName[type]}` ? `每次${SkillTriggerName[type]}${chanceSeg}`
: `每${SkillTriggerName[type]}${valueRich(tNum)}次`; : `每${SkillTriggerName[type]}${valueRich(tNum)}次${chanceSeg}`;
} }
return SkillTriggerName[type]; return SkillTriggerName[type];
} }
@@ -137,18 +139,25 @@ function getBuffValue(skill: SkillConfig): number {
* Why: 数值不写死在模板里,overrides 调整档位数值时文案自动同步。 * Why: 数值不写死在模板里,overrides 调整档位数值时文案自动同步。
* @param tmpl 描述模板(含占位符) * @param tmpl 描述模板(含占位符)
* @param skill mergeSkillParams 合并后的技能配置 * @param skill mergeSkillParams 合并后的技能配置
* @param extra 条目级参数占位符(触发技能的 t_chance/pity_add 不在 SkillConfig,由调用方透传;优先于技能字段)
*/ */
function renderDesc(tmpl: string, skill: SkillConfig): string { function renderDesc(tmpl: string, skill: SkillConfig, extra?: Record<string, number>): string {
return tmpl.replace(PLACEHOLDER_PATTERN, (raw, key: string) => { return tmpl.replace(PLACEHOLDER_PATTERN, (raw, key: string) => {
if (key === "target") return buildTargetDesc(skill); if (key === "target") return buildTargetDesc(skill);
if (key === "dur") return valueRich(getBuffDuration(skill)); if (key === "dur") return valueRich(getBuffDuration(skill));
if (key === "buff_value") return valueRich(getBuffValue(skill)); if (key === "buff_value") return valueRich(getBuffValue(skill));
if (extra && key in extra) return valueRich(String(extra[key]));
const v = (skill as unknown as Record<string, unknown>)[key]; const v = (skill as unknown as Record<string, unknown>)[key];
// 未定义数值字段按 0 渲染,避免面板出现 undefined(模板与配置不匹配的兜底) // 未定义数值字段按 0 渲染,避免面板出现 undefined(模板与配置不匹配的兜底)
return v === undefined ? valueRich(0) : valueRich(String(v)); return v === undefined ? valueRich(0) : valueRich(String(v));
}); });
} }
/** 触发档位的条目级占位符上下文(普攻/大招档位无此层参数,返回 undefined 走技能字段) */
function tierExtras(t: ISkillTierInfo): Record<string, number> | undefined {
return t.tChance === undefined ? undefined : { t_chance: t.tChance, pity_add: t.pityAdd ?? 0 };
}
/** 无模板时兜底:回退底座技能的 info 备注 */ /** 无模板时兜底:回退底座技能的 info 备注 */
function fallbackDesc(skill: SkillConfig): string { function fallbackDesc(skill: SkillConfig): string {
return String(skill.info ?? ""); return String(skill.info ?? "");
@@ -224,9 +233,12 @@ export function buildHeroSkillDesc(heroUuid: number, showName: boolean = true, s
if (e.lv <= lv && e.desc) tmpl = e.desc; if (e.lv <= lv && e.desc) tmpl = e.desc;
} }
tmpl = tmpl ?? entries[0]?.desc; tmpl = tmpl ?? entries[0]?.desc;
const text = tmpl ? renderDesc(tmpl, skill) : fallbackDesc(skill); const text = tmpl
? renderDesc(tmpl, skill, { t_chance: item.t_chance ?? 100, pity_add: item.pity_add ?? 0 })
: fallbackDesc(skill);
// 触发语境:"每攻击N次"循环语义(buildTriggerLabel),逗号衔接效果文本 // 触发语境:"每攻击N次"循环语义(buildTriggerLabel),逗号衔接效果文本
const trig = buildTriggerLabel(type, item.t_num); // 模板已显式使用 {t_chance} 时不再自动追加概率后缀,避免同一行重复展示
const trig = buildTriggerLabel(type, item.t_num, tmpl?.includes("{t_chance}") ? undefined : item.t_chance);
parts.push(`${trig}, ${text}`); parts.push(`${trig}, ${text}`);
} }
// dead 组内的复活效果(revive_hp / revive_count)并入同一行 // dead 组内的复活效果(revive_hp / revive_count)并入同一行
@@ -279,12 +291,17 @@ interface ISkillTierInfo {
ownDesc?: string; ownDesc?: string;
/** 触发技能档位的触发次数(普攻无) */ /** 触发技能档位的触发次数(普攻无) */
tNum: number; tNum: number;
/** 触发技能档位的触发概率百分点(普攻无;缺省 100 必触发) */
tChance?: number;
/** 触发技能档位的保底叠加百分点(普攻无;缺省 0) */
pityAdd?: number;
} }
/** 相邻档 diff 参与展示的字段(排除动画/弹道/特效等玩家无感字段),t_num 为触发技能专有 */ /** 相邻档 diff 参与展示的字段(排除动画/弹道/特效等玩家无感字段),t_num 为触发技能专有 */
const DIFF_KEYS: string[] = [ const DIFF_KEYS: string[] = [
"ap", "hit_count", "num", "summon_count", "crt", "frz", "stun", "para", "ap", "hit_count", "num", "summon_count", "crt", "frz", "stun", "para",
"bck", "bck_chance", "buff_duration", "buff_value", "t_num", "timed_buff_id", "bck", "bck_chance", "buff_duration", "buff_value", "t_num", "timed_buff_id",
"t_chance", "pity_add",
]; ];
/** diff 字段的称谓与单位("新增/漂移"描述共用) */ /** diff 字段的称谓与单位("新增/漂移"描述共用) */
@@ -302,11 +319,15 @@ const DIFF_META: Record<string, { label: string; unit: string }> = {
buff_duration: { label: "持续", unit: "秒" }, buff_duration: { label: "持续", unit: "秒" },
buff_value: { label: "增益强度", unit: "" }, buff_value: { label: "增益强度", unit: "" },
t_num: { label: "触发次数", unit: "次" }, t_num: { label: "触发次数", unit: "次" },
t_chance: { label: "触发概率", unit: "%" },
pity_add: { label: "保底叠加", unit: "%" },
}; };
/** 读取档位某展示字段的实时值(t_num/buff_value 走专用取值) */ /** 读取档位某展示字段的实时值(t_num/t_chance/pity_add/buff_value 走专用取值) */
function getTierValue(tier: ISkillTierInfo, key: string): number { function getTierValue(tier: ISkillTierInfo, key: string): number {
if (key === "t_num") return tier.tNum; if (key === "t_num") return tier.tNum;
if (key === "t_chance") return tier.tChance ?? 100;
if (key === "pity_add") return tier.pityAdd ?? 0;
if (key === "buff_value") return getBuffValue(tier.skill); if (key === "buff_value") return getBuffValue(tier.skill);
const v = (tier.skill as unknown as Record<string, unknown>)[key]; const v = (tier.skill as unknown as Record<string, unknown>)[key];
return typeof v === "number" ? v : 0; return typeof v === "number" ? v : 0;
@@ -497,9 +518,13 @@ function collectTriggerTiers(hero: heroInfo, type: SkillTriggerType, skillUuid:
desc: e.desc ?? inherit, desc: e.desc ?? inherit,
ownDesc: e.desc, ownDesc: e.desc,
tNum: e.t_num, tNum: e.t_num,
tChance: e.t_chance ?? 100,
pityAdd: e.pity_add ?? 0,
}; };
}); });
const label = buildTriggerLabel(type, sorted[0].t_num); // slv1 模板已显式使用 {t_chance} 时不再自动追加概率后缀,避免同一行重复展示
const firstTmpl = tiers[0]?.desc;
const label = buildTriggerLabel(type, sorted[0].t_num, firstTmpl?.includes("{t_chance}") ? undefined : sorted[0].t_chance);
return { tiers, label }; return { tiers, label };
} }
@@ -510,11 +535,11 @@ function buildTierLines(tiers: ISkillTierInfo[], triggerLabel: string): HeroSkil
const t = tiers[i]; const t = tiers[i];
if (i === 0) { if (i === 0) {
// 技能 1 级:完整能力 + 数值 // 技能 1 级:完整能力 + 数值
const text = t.desc ? renderDesc(t.desc, t.skill) : fallbackDesc(t.skill); const text = t.desc ? renderDesc(t.desc, t.skill, tierExtras(t)) : fallbackDesc(t.skill);
lines.push({ sLv: t.sLv, heroLv: t.heroLv, text: triggerLabel ? `${triggerLabel}, ${text}` : text }); lines.push({ sLv: t.sLv, heroLv: t.heroLv, text: triggerLabel ? `${triggerLabel}, ${text}` : text });
} else if (t.ownDesc) { } else if (t.ownDesc) {
// 提升档:该档显式配置了模板(如护盾/治疗等 diff 标签语义不达的技能),策划表述优先 // 提升档:该档显式配置了模板(如护盾/治疗等 diff 标签语义不达的技能),策划表述优先
lines.push({ sLv: t.sLv, heroLv: t.heroLv, text: renderDesc(t.ownDesc, t.skill) }); lines.push({ sLv: t.sLv, heroLv: t.heroLv, text: renderDesc(t.ownDesc, t.skill, tierExtras(t)) });
} else { } else {
// 提升档:未配置模板,给相对上一级的提升 // 提升档:未配置模板,给相对上一级的提升
const diff = buildTierDiff(tiers[i - 1], t); const diff = buildTierDiff(tiers[i - 1], t);

View File

@@ -48,11 +48,9 @@ export interface GameDate {
talent_lv?: number, talent_lv?: number,
/** 天赋当前等级已累计的经验值 */ /** 天赋当前等级已累计的经验值 */
talent_exp?: number, talent_exp?: number,
/** 关卡进度存档:当前章节-关-节 */ /** 关卡进度存档:当前关卡号(无限关模式只记关卡号,回合恒从 1 开始) */
stage_progress?: { stage_progress?: {
chapter: number,
stage: number, stage: number,
section: number,
}, },
/** 奖励领取状态:段位/闯关首达奖励的已领取标记(玩家点击领取) */ /** 奖励领取状态:段位/闯关首达奖励的已领取标记(玩家点击领取) */
reward_claimed?: { reward_claimed?: {
@@ -61,7 +59,7 @@ export interface GameDate {
/** 已领取的大关号 */ /** 已领取的大关号 */
stage: number[], stage: number[],
}, },
/** 已通关大关的显式标记(覆盖存档停留场景,如第 10 关通关后进度停留 1-10-10) */ /** 已通关大关的显式标记(历史遗留字段,无限关模式不再写入;仅用于兼容读取旧存档) */
passed_stages?: number[], passed_stages?: number[],
} }
export interface CloudData { export interface CloudData {
@@ -152,11 +150,9 @@ export class SingletonModuleComp extends ecs.Comp {
talent_lv: 0, talent_lv: 0,
/** 当前等级已累计经验 */ /** 当前等级已累计经验 */
talent_exp: 0, talent_exp: 0,
/** 关卡进度存档:默认从 1-1-1 开始 */ /** 关卡进度存档:默认从第 1 关开始 */
stage_progress: { stage_progress: {
chapter: 1,
stage: 1, stage: 1,
section: 1,
}, },
/** 奖励领取状态(玩家点击领取,跨局保留) */ /** 奖励领取状态(玩家点击领取,跨局保留) */
reward_claimed: { reward_claimed: {
@@ -238,9 +234,7 @@ export class SingletonModuleComp extends ecs.Comp {
switch_music: true, // 音乐开关(MVVM绑定字段) switch_music: true, // 音乐开关(MVVM绑定字段)
/** 关卡进度(MVVM绑定字段,镜像 data.stage_progress,供 HUD 实时显示) */ /** 关卡进度(MVVM绑定字段,镜像 data.stage_progress,供 HUD 实时显示) */
stage_progress: { stage_progress: {
chapter: 1,
stage: 1, stage: 1,
section: 1,
}, },
}; };
@@ -352,26 +346,26 @@ export class SingletonModuleComp extends ecs.Comp {
* 将 data 层的关卡进度镜像到 vmdata 视图层(MVVM 绑定字段)。 * 将 data 层的关卡进度镜像到 vmdata 视图层(MVVM 绑定字段)。
* Why: data.stage_progress 为云端持久权威源,vmdata.stage_progress 仅供 HUD 绑定展示; * Why: data.stage_progress 为云端持久权威源,vmdata.stage_progress 仅供 HUD 绑定展示;
* 登录覆盖、关卡推进后都必须调用本方法保持镜像一致。 * 登录覆盖、关卡推进后都必须调用本方法保持镜像一致。
* 旧版三段存档(chapter/stage/section)在同步时归一化为 stage 单字段。
*/ */
public syncStageProgressToView(): void { public syncStageProgressToView(): void {
const p = this.data.stage_progress; const p = this.data.stage_progress;
// 就地更新字段而非整体替换对象:oops VM(JsonOb)只通知被赋值属性的精确路径, // 旧存档归一化:兼容历史 chapter/stage/section 三段结构,仅提取 stage
// 整体替换仅派发 VC:data.stage_progress,不会触发 HUD 绑定的 const stage = Math.max(1, Math.floor(p?.stage ?? 1));
// data.stage_progress.section 等嵌套末端路径刷新,导致进度显示停留在老节 if (p && (p.stage !== stage || (p as any).chapter !== undefined || (p as any).section !== undefined)) {
const view = this.vmdata.stage_progress; this.data.stage_progress = { stage };
view.chapter = p?.chapter ?? 1; }
view.stage = p?.stage ?? 1; this.vmdata.stage_progress.stage = stage;
view.section = p?.section ?? 1;
} }
/** /**
* 更新关卡进度(权威源 data + 视图镜像 vmdata),并派发事件刷新 UI。 * 更新关卡进度(权威源 data + 视图镜像 vmdata),并派发事件刷新 UI。
* Why: 替代直接赋值 smc.data.stage_progress,保证视图层实时同步。 * Why: 替代直接赋值 smc.data.stage_progress,保证视图层实时同步。
* @param progress 新的关卡进度(章节/大关/小节均从 1 开始) * @param progress 新的关卡进度(仅关卡号,从 1 开始)
* @param is_sync 是否标记脏并触发云端/本地同步 * @param is_sync 是否标记脏并触发云端/本地同步
*/ */
public updateStageProgress(progress: { chapter: number; stage: number; section: number }, is_sync: boolean = true): void { public updateStageProgress(progress: { stage: number }, is_sync: boolean = true): void {
this.data.stage_progress = { ...progress }; this.data.stage_progress = { stage: Math.max(1, Math.floor(progress.stage)) };
this.syncStageProgressToView(); this.syncStageProgressToView();
if (is_sync) { if (is_sync) {
gameDataSync.markDataDirty(); gameDataSync.markDataDirty();
@@ -452,20 +446,18 @@ export class SingletonModuleComp extends ecs.Comp {
} }
/** /**
* 标记大关已通关(通关点调用,覆盖存档停留场景) * 标记大关已通关(历史遗留入口)
* Why: 第 10 关通关后存档停留 1-10-10,无法从 stage_progress 推导已通状态, * Why: 旧版本第 10 关通关后存档停留,无法从 stage_progress 推导已通状态,需显式标记;
* 需在通关时显式写入。 * 无限关模式存档永远推进,判定已通可直接由 stage_progress 推导,无需再写入。
* @param stage 大关号 * 保留空实现以避免破坏外部调用方(若有旧存档读取场景走 passed_stages 兼容)。
* @param _stage 大关号(未使用,保留签名兼容)
* @deprecated 无限关模式无需调用,保留仅为兼容旧代码引用
*/ */
public markStagePassed(stage: number): void { public markStagePassed(_stage: number): void {
if (!this.data.passed_stages) this.data.passed_stages = []; // 无限关模式不再写入 passed_stages
if (!this.data.passed_stages.includes(stage)) {
this.data.passed_stages.push(stage);
gameDataSync.markDataDirty();
}
} }
/** 判定大关是否已通关:显式标记优先,存档推进兜底(已进入后续关即已通关) */ /** 判定大关是否已通关:旧存档显式标记兼容,无限关以存档关卡号推导(已进入后续关即已通关) */
private isStagePassed(stage: number): boolean { private isStagePassed(stage: number): boolean {
if ((this.data.passed_stages ?? []).includes(stage)) return true; if ((this.data.passed_stages ?? []).includes(stage)) return true;
return (this.data.stage_progress?.stage ?? 1) > stage; return (this.data.stage_progress?.stage ?? 1) > stage;

View File

@@ -104,15 +104,15 @@ export enum GameEvent {
STAGE_PROGRESS_UPDATE = "STAGE_PROGRESS_UPDATE", STAGE_PROGRESS_UPDATE = "STAGE_PROGRESS_UPDATE",
/** 奖励领取完成(payload 为空,UI 刷新待领取列表/红点) */ /** 奖励领取完成(payload 为空,UI 刷新待领取列表/红点) */
REWARD_CLAIMED = "REWARD_CLAIMED", REWARD_CLAIMED = "REWARD_CLAIMED",
/** 小节开始(payload: { chapter, stage, section },MissionMonComp 据此生成怪物) */ /** 回合开始(payload: { stage, section },MissionMonComp 据此生成怪物) */
SectionStart = "SectionStart", SectionStart = "SectionStart",
/** 小节结束(payload: { chapter, stage, section },玩家点击"下一节"后推进) */ /** @deprecated 已废弃:无限关模式无节间结算,回合自动推进,勿再监听 */
SectionEnd = "SectionEnd", SectionEnd = "SectionEnd",
/** 大关结束(payload: { chapter, stage },10 节打完) */ /** @deprecated 已废弃:无限关模式无大关结算,勿再监听 */
StageEnd = "StageEnd", StageEnd = "StageEnd",
/** 章节结束(payload: { chapter },10 关打完) */ /** @deprecated 已废弃:无限关模式无章节概念,勿再监听 */
ChapterEnd = "ChapterEnd", ChapterEnd = "ChapterEnd",
/** 结算弹窗点击"下一节"(payload 为空,MissionComp 据此推进到下一小节) */ /** @deprecated 已废弃:无限关模式无"下一节"手动推进,勿再监听 */
NextSection = "NextSection", NextSection = "NextSection",
/** 结算弹窗点击"再来一次"(payload 为空,MissionComp 据此重开本关) */ /** 结算弹窗点击"再来一次"(payload 为空,MissionComp 据此重开本关) */
RestartMission = "RestartMission", RestartMission = "RestartMission",

View File

@@ -65,6 +65,16 @@ export enum EType {
timeEnd = 1, //碰撞够也不消失,时间到才消失 timeEnd = 1, //碰撞够也不消失,时间到才消失
collision = 2, //碰撞次数够就消失 collision = 2, //碰撞次数够就消失
} }
/**
* 召唤类技能(summon_count>1)多次施放的目标选择模式(由技能 prefab 上 SkillView 配置)。
* 仅对敌方目标技能生效;友方/自身技能不走该逻辑。
*/
export enum SummonTMode {
same = 0, // 同一敌人:所有召唤物锁定施法时选定的目标(默认,原行为)
random = 1, // 随机敌人:每次出手时从射程内敌人中随机锁定一个
unique = 2, // 避免相同敌人:优先锁定本轮尚未选过的敌人,一轮选完后重置再选
}
//debuff类型 //debuff类型
@@ -318,6 +328,21 @@ export const SkillSet: Record<number, SkillConfig> = {
DTType: DTType.single, ap: 100, hit_count: 1, hitcd: 0.2, speed: 720, with: 0, ready: 0.2, EAnm: 0, DAnm: "", IType: IType.Melee, is_accel: true, DTType: DTType.single, ap: 100, hit_count: 1, hitcd: 0.2, speed: 720, with: 0, ready: 0.2, EAnm: 0, DAnm: "", IType: IType.Melee, is_accel: true,
RType: RType.bezier, EType: EType.collision, info: "红瓶抛射物", RType: RType.bezier, EType: EType.collision, info: "红瓶抛射物",
}, },
6013: {
uuid: 6013, name: "闪电", sp_name: "m3", icon: "109-Red-Potion", TGroup: TGroup.Enemy, readyAnm: "", endAnm: "", act: "atk",
DTType: DTType.single, ap: 100, hit_count: 1, hitcd: 0.2, speed: 720, with: 0, ready: 0.2, EAnm: 0, DAnm: "", IType: IType.Melee, is_accel: true,
RType: RType.fixedEnd, EType: EType.collision, info: "闪电",
},
6014: {
uuid: 6014, name: "小火球", sp_name: "m4", icon: "109-Red-Potion", TGroup: TGroup.Enemy, readyAnm: "", endAnm: "", act: "atk",
DTType: DTType.single, ap: 100, hit_count: 1, hitcd: 0.2, speed: 720, with: 0, ready: 0.2, EAnm: 0, DAnm: "", IType: IType.Melee, is_accel: true,
RType: RType.fixedEnd, EType: EType.collision, info: "小火球",
},
6015: {
uuid: 6015, name: "小飓风", sp_name: "m5", icon: "109-Red-Potion", TGroup: TGroup.Enemy, readyAnm: "", endAnm: "", act: "atk",
DTType: DTType.single, ap: 100, hit_count: 1, hitcd: 0.2, speed: 720, with: 0, ready: 0.2, EAnm: 0, DAnm: "", IType: IType.Melee, is_accel: true,
RType: RType.fixedEnd, EType: EType.collision, info: "小飓风抛",
},
// ==================== 群体大招(按职业分段:6100-6149 坦克/战士、6150-6199 刺客/射手、6200-6249 法师/辅助) ==================== // ==================== 群体大招(按职业分段:6100-6149 坦克/战士、6150-6199 刺客/射手、6200-6249 法师/辅助) ====================
// 坦克/战士群体攻击大招 // 坦克/战士群体攻击大招
6100: { 6100: {
@@ -336,8 +361,8 @@ export const SkillSet: Record<number, SkillConfig> = {
RType: RType.bezier, EType: EType.collision, info: "火焰斩动画",//英雄配置技能的时候,可以叠加暴击debuff RType: RType.bezier, EType: EType.collision, info: "火焰斩动画",//英雄配置技能的时候,可以叠加暴击debuff
}, },
6103: { 6103: {
uuid: 6103, name: "闪电斩", sp_name: "atk5", icon: "100-Enchant-Magic", TGroup: TGroup.Enemy, readyAnm: "", endAnm: "", act: "max0", uuid: 6103, name: "闪电斩", sp_name: "atk6", icon: "100-Enchant-Magic", TGroup: TGroup.Enemy, readyAnm: "", endAnm: "", act: "max0",
DTType: DTType.single, para: 30, ap: 150, hit_count: 5, hitcd: 0.2, speed: 720, with: 0, ready: 0.2, EAnm: 0, DAnm: "", IType: IType.Melee, is_accel: true, DTType: DTType.single, ap: 150, hit_count: 5, hitcd: 0.2, speed: 720, with: 0, ready: 0.2, EAnm: 0, DAnm: "", IType: IType.Melee, is_accel: true,
RType: RType.bezier, EType: EType.collision, info: "闪电斩动画",//英雄配置技能的时候,可以疲惫触发闪电系追加技能 RType: RType.bezier, EType: EType.collision, info: "闪电斩动画",//英雄配置技能的时候,可以疲惫触发闪电系追加技能
}, },
6104: { 6104: {
@@ -364,22 +389,22 @@ export const SkillSet: Record<number, SkillConfig> = {
}, },
6201: { 6201: {
uuid: 6201, name: "飓风", sp_name: "maxm2", icon: "98-Enchant-Wind", TGroup: TGroup.Enemy, readyAnm: "", endAnm: "", act: "max1", uuid: 6201, name: "飓风", sp_name: "maxm2", icon: "98-Enchant-Wind", TGroup: TGroup.Enemy, readyAnm: "", endAnm: "", act: "max1",
DTType: DTType.single, ap: 100, hit_count: 2, hitcd: 0.3, speed: 720, with: 90, ready: 0.2, EAnm: 0, DAnm: "", IType: IType.remote, DTType: DTType.single, ap: 100, hit_count: 99, hitcd: 0.3, speed: 720, with: 90, ready: 0.2, EAnm: 0, DAnm: "", IType: IType.remote,
RType: RType.linear, EType: EType.collision, info: "一个飓风", RType: RType.linear, EType: EType.collision, info: "一个飓风",
}, },
6202: { 6202: {
uuid: 6202, name: "毒气弹", sp_name: "maxm4", icon: "o_warlock_hyzy_skill", TGroup: TGroup.Enemy, readyAnm: "", endAnm: "", act: "max1", uuid: 6202, name: "毒气弹", sp_name: "maxm4", icon: "o_warlock_hyzy_skill", TGroup: TGroup.Enemy, readyAnm: "", endAnm: "", act: "max1",
DTType: DTType.single, ap: 100, hit_count: 2, hitcd: 0.3, speed: 720, with: 90, ready: 0.2, EAnm: 0, DAnm: "", IType: IType.remote, DTType: DTType.single, ap: 100, hit_count: 1, hitcd: 0.3, speed: 720, with: 90, ready: 0.2, EAnm: 0, DAnm: "", IType: IType.remote,
RType: RType.linear, EType: EType.collision, bezier_start_y: 20, bezier_mid_y: 140, bezier_arc: 1.05, info: "一个大毒气弹", RType: RType.linear, EType: EType.collision, bezier_start_y: 20, bezier_mid_y: 140, bezier_arc: 1.05, info: "一个大毒气弹",
}, },
6203: { 6203: {
uuid: 6203, name: "能量波", sp_name: "maxm5", icon: "b_priest_kx_skill", TGroup: TGroup.Enemy, readyAnm: "", endAnm: "", act: "max1", uuid: 6203, name: "能量波", sp_name: "maxm5", icon: "b_priest_kx_skill", TGroup: TGroup.Enemy, readyAnm: "", endAnm: "", act: "max1",
DTType: DTType.single, ap: 100, hit_count: 2, hitcd: 0.3, speed: 720, with: 90, ready: 0.2, EAnm: 0, DAnm: "", IType: IType.remote, DTType: DTType.single, ap: 100, hit_count: 1, hitcd: 0.3, speed: 720, with: 90, ready: 0.2, EAnm: 0, DAnm: "", IType: IType.remote,
RType: RType.linear, EType: EType.collision, bezier_start_y: 20, bezier_mid_y: 140, bezier_arc: 1.05, info: "一个能量波", RType: RType.linear, EType: EType.collision, bezier_start_y: 20, bezier_mid_y: 140, bezier_arc: 1.05, info: "一个能量波",
}, },
6204: { 6204: {
uuid: 6204, name: "多毒气弹", sp_name: "maxm6", icon: "o_warlock_hyzy_skill", TGroup: TGroup.Enemy, readyAnm: "", endAnm: "", act: "max1", uuid: 6204, name: "雷暴", sp_name: "maxm7", icon: "o_warlock_hyzy_skill", TGroup: TGroup.Enemy, readyAnm: "", endAnm: "", act: "max1",
DTType: DTType.single, ap: 100, hit_count: 2, hitcd: 0.3, speed: 720, with: 90, ready: 0.2, EAnm: 0, DAnm: "", IType: IType.remote, DTType: DTType.single, ap: 100, hit_count: 99, hitcd: 0.3, speed: 720, with: 90, ready: 0.2, EAnm: 0, DAnm: "", IType: IType.remote,
RType: RType.linear, EType: EType.collision, bezier_start_y: 20, bezier_mid_y: 140, bezier_arc: 1.05, info: "一个大毒气弹", RType: RType.linear, EType: EType.collision, bezier_start_y: 20, bezier_mid_y: 140, bezier_arc: 1.05, info: "一个大毒气弹",
}, },

View File

@@ -1,17 +1,22 @@
/** /**
* @file StageSet.ts * @file StageSet.ts
* @description 关卡系统配置(章节-关-节三级结构) * @description 关卡系统配置(无限关卡·单线推进)
* *
* 设计要点: * 设计要点:
* - 1 章 = 10 关,每关 = 5 小节(一关一局,节间自动推进),共 50 个小节 * - 无限关卡:从第 1 关起无上限推进,每关 = 5 回合(一关一局,回合间自动推进)
* - 每关节点固定:1~3 节普通(3 小怪)、第 4 节精英(3 精英)、第 5 节 Boss(1 Boss + 2 小怪) * - 第 1~4 回合为普通怪,属性逐回合轻量增强(SECTION_RAMP_STEP)
* - 怪物等级 = 关卡号(1-1 的怪为 Lv1,1-5 的怪为 Lv5) * - 第 5 回合为单 Boss 回合(无护卫),Boss 采用超厚血量(BOSS_HP_MUL)
* - 怪物属性 = 基础 × 开局系数 × (1 + 成长斜率 × (lv-1)) × 类型倍率 * - 怪物等级 = 关卡号(第 N 关的怪为 LvN,随关卡无限成长)
* - 小节配置按需动态生成,不再依赖章节静态表
* *
* 数值基准: * 数值基准:
* - 开局系数 0.8(1 级小怪略弱于英雄) * - 开局系数 0.8(1 级小怪略弱于英雄)
* - 成长斜率 +5%/级(10 级 ≈ 1.45 倍) * - 成长斜率 +5%/级(无限线性成长,曲线平缓可控)
* - 精英倍率 × 1.5,Boss 倍率 × 3.0(精英 × 2) * - 回合增强 +12%/回合(第 4 回合 ≈ 1.36 倍)
* - Boss:HP × 12(超厚血量)/ AP × 2.0(攻击克制,避免 Boss 秒杀英雄)
*
* 核心公式:
* 怪物属性 = 基础 × MON_START_COEF × (1 + MON_GROW_SLOPE×(lv-1)) × 回合增强 × 类型倍率
*/ */
import { MonType } from "./heroSet"; import { MonType } from "./heroSet";
@@ -20,82 +25,54 @@ import { MonType } from "./heroSet";
/** 怪物开局系数:1 级小怪略弱于英雄(0.8 倍) */ /** 怪物开局系数:1 级小怪略弱于英雄(0.8 倍) */
export const MON_START_COEF = 0.8; export const MON_START_COEF = 0.8;
/** 怪物成长斜率:每级 +5% 基础属性 */ /** 怪物成长斜率:每级 +5% 基础属性(无限线性成长) */
export const MON_GROW_SLOPE = 0.05; export const MON_GROW_SLOPE = 0.05;
/** 精英属性倍率:同级普通怪的 1.5 倍 */ /** 回合内轻量增强步长:第 1→4 回合每回合 +12% 属性 */
export const ELITE_MUL = 1.5; export const SECTION_RAMP_STEP = 0.12;
/** Boss 属性倍率:同级普通怪的 3.0 倍(精英 × 2) */ /** Boss 血量倍率:同级普通怪的 12 倍(超厚血量,拖长 Boss 战节奏) */
export const BOSS_MUL = 3.0; export const BOSS_HP_MUL = 12;
/** 每关小节总数(一关一局,节间自动推进) */ /** Boss 攻击倍率:同级普通怪的 2.0 倍(显著低于血量倍率,避免 Boss 秒杀英雄) */
export const BOSS_AP_MUL = 2.0;
/** 每关回合总数(一关一局,回合间自动推进) */
export const SECTIONS_PER_STAGE = 5; export const SECTIONS_PER_STAGE = 5;
/** 精英节号(每关第 4 节为精英节) */ /** Boss 回合号(每关第 5 回合,即末回合) */
export const ELITE_SECTION = 4;
/** Boss 节号(每关第 5 节为 Boss 节,即末节) */
export const BOSS_SECTION = 5; export const BOSS_SECTION = 5;
/** 普通节小怪数量(一关一局压缩后单节 3 只) */ /** 普通回合小怪数量 */
export const NORMAL_MON_COUNT = 3; export const NORMAL_MON_COUNT = 3;
/** 普通节开局立即刷出数量(3 只全部立即刷出) */ /** 普通回合开局立即刷出数量(3 只全部立即刷出) */
export const NORMAL_FIRST_SPAWN = 3; export const NORMAL_FIRST_SPAWN = 3;
/** 普通节后续刷怪间隔(秒):保留配置位(3 只全立即刷,当前无后续批次) */ /** 普通回合后续刷怪间隔(秒):保留配置位(3 只全立即刷,当前无后续批次) */
export const NORMAL_SPAWN_INTERVAL = 2; export const NORMAL_SPAWN_INTERVAL = 2;
/** 精英节精英数量 */ /** Boss 回合 Boss 延迟刷出时间(秒) */
export const ELITE_COUNT = 3;
/** Boss 节护卫小怪数量 */
export const BOSS_ELITE_COUNT = 2;
/** Boss 节 Boss 延迟刷出时间(秒) */
export const BOSS_DELAY = 1; export const BOSS_DELAY = 1;
// ======================== 类型定义 ======================== // ======================== 类型定义 ========================
/** 小节类型 */ /** 回合类型 */
export enum SectionType { export enum SectionType {
Normal = 0, // 普通节:3 小怪 Normal = 0, // 普通回合:3 小怪(逐回合轻量增强)
Elite = 1, // 精英节:3 精英 Boss = 2, // Boss 回合:1 Boss(超厚血量,无护卫)
Boss = 2, // Boss 节:1 Boss + 2 小怪
} }
/** 小节配置 */ /** 回合配置 */
export interface SectionConfig { export interface SectionConfig {
/** 小节类型 */ /** 回合类型 */
type: SectionType; type: SectionType;
/** 怪物等级(驱动线性成长) */ /** 怪物等级(= 关卡号,驱动线性成长) */
monLv: number; monLv: number;
/** 精英数量(精英关/Boss 关用) */ /** 回合增强系数(第 n 回合 = 1 + SECTION_RAMP_STEP×(n-1),仅普通回合生效) */
eliteCount?: number; ramp: number;
/** Boss UUID(Boss 关用,可选,缺省随机) */ /** 怪物类型池(普通回合用,缺省随机) */
bossUuid?: number;
/** 怪物类型池(普通关用,缺省随机) */
monTypes?: MonType[]; monTypes?: MonType[];
} }
/** 大关配置(1-1 ~ 1-10),每关 SECTIONS_PER_STAGE 个小节 */
export interface StageConfig {
/** 章节号 */
chapter: number;
/** 关卡号 1~10 */
stage: number;
/** 小节列表(长度 = SECTIONS_PER_STAGE) */
sections: SectionConfig[];
}
/** 章节配置 */
export interface ChapterConfig {
/** 章节号 */
chapter: number;
/** 章节名称 */
name: string;
/** 10 个大关 */
stages: StageConfig[];
}
// ======================== 工具函数 ======================== // ======================== 工具函数 ========================
/** /**
* 计算怪物最终属性 * 计算怪物最终属性(Boss 血/攻倍率分离:超厚血 + 克制攻)
* @param baseHp 基础 HP * @param baseHp 基础 HP
* @param baseAp 基础 AP * @param baseAp 基础 AP
* @param lv 怪物等级 * @param lv 怪物等级
* @param isElite 是否精英
* @param isBoss 是否 Boss * @param isBoss 是否 Boss
* @returns 最终 HP/AP * @returns 最终 HP/AP
*/ */
@@ -103,159 +80,70 @@ export function calcMonsterAttrs(
baseHp: number, baseHp: number,
baseAp: number, baseAp: number,
lv: number, lv: number,
isElite: boolean = false,
isBoss: boolean = false isBoss: boolean = false
): { hp: number; ap: number } { ): { hp: number; ap: number } {
const growCoef = 1 + MON_GROW_SLOPE * (lv - 1); const growCoef = 1 + MON_GROW_SLOPE * (lv - 1);
let typeMul = 1; const hp = Math.max(1, Math.round(baseHp * MON_START_COEF * growCoef * (isBoss ? BOSS_HP_MUL : 1)));
if (isBoss) { const ap = Math.max(1, Math.round(baseAp * MON_START_COEF * growCoef * (isBoss ? BOSS_AP_MUL : 1)));
typeMul = BOSS_MUL;
} else if (isElite) {
typeMul = ELITE_MUL;
}
const hp = Math.max(1, Math.round(baseHp * MON_START_COEF * growCoef * typeMul));
const ap = Math.max(1, Math.round(baseAp * MON_START_COEF * growCoef * typeMul));
return { hp, ap }; return { hp, ap };
} }
/** /**
* 获取指定关卡的怪物等级 * 获取指定关卡的怪物等级(无限关:等级 = 关卡号,无上限)
* @param stage 关卡号(1~10) * @param stage 关卡号(1~∞)
* @returns 怪物等级 * @returns 怪物等级
*/ */
export function getMonsterLv(stage: number): number { export function getMonsterLv(stage: number): number {
return Math.max(1, Math.min(10, stage)); return Math.max(1, Math.floor(stage));
} }
/** /**
* 判断是否为精英节(每关第 ELITE_SECTION 节) * 判断是否为 Boss 回合(每关第 BOSS_SECTION 回合,即末回合)
* @param section 小节号(1~SECTIONS_PER_STAGE) * @param section 回合号(1~SECTIONS_PER_STAGE)
*/
export function isEliteSection(section: number): boolean {
return section === ELITE_SECTION;
}
/**
* 判断是否为 Boss 节(每关第 BOSS_SECTION 节,即末节)
* @param section 小节号(1~SECTIONS_PER_STAGE)
*/ */
export function isBossSection(section: number): boolean { export function isBossSection(section: number): boolean {
return section === BOSS_SECTION; return section === BOSS_SECTION;
} }
/** /**
* 获取小节类型(按节号区分:1~3 普通 / 4 精英 / 5 Boss) * 获取回合类型(按回合号区分:1~4 普通 / 5 Boss)
* @param section 小节号(1~SECTIONS_PER_STAGE) * @param section 回合号(1~SECTIONS_PER_STAGE)
*/ */
export function getSectionType(section: number): SectionType { export function getSectionType(section: number): SectionType {
if (isBossSection(section)) return SectionType.Boss; return isBossSection(section) ? SectionType.Boss : SectionType.Normal;
if (isEliteSection(section)) return SectionType.Elite;
return SectionType.Normal;
} }
// ======================== 第 1 章配置 ========================
/** 生成单个大关的 SECTIONS_PER_STAGE 个小节配置(1~3 普通 / 4 精英 / 5 Boss) */
function makeStageSections(stage: number): SectionConfig[] {
const monLv = getMonsterLv(stage);
const sections: SectionConfig[] = [];
for (let i = 1; i <= SECTIONS_PER_STAGE; i++) {
const type = getSectionType(i);
const section: SectionConfig = { type, monLv };
if (type === SectionType.Elite) {
section.eliteCount = ELITE_COUNT;
} else if (type === SectionType.Boss) {
section.eliteCount = BOSS_ELITE_COUNT;
// bossUuid 缺省随机,由生成引擎从 Boss 池抽取
} else {
// 普通节:近战为主,穿插远程/重型
section.monTypes = [MonType.Melee, MonType.Melee, MonType.Melee, MonType.Heavy, MonType.Long];
}
sections.push(section);
}
return sections;
}
/** 第 1 章配置 */
export const Chapter1: ChapterConfig = {
chapter: 1,
name: "兽人入侵",
stages: [],
};
// 初始化第 1 章 10 个大关
for (let stage = 1; stage <= 10; stage++) {
Chapter1.stages.push({
chapter: 1,
stage,
sections: makeStageSections(stage),
});
}
/** 所有章节配置表(当前仅第 1 章,后续扩展) */
export const ChapterSet: Record<number, ChapterConfig> = {
1: Chapter1,
};
// ======================== 查询接口 ======================== // ======================== 查询接口 ========================
/** /**
* 获取小节配置 * 获取回合配置(无限关:按需动态生成,不再依赖章节静态表)
* @param chapter 章节号 * @param stage 关卡号(1~∞)
* @param stage 关卡号 * @param section 回合号(1~SECTIONS_PER_STAGE)
* @param section 小节号(1~SECTIONS_PER_STAGE) * @returns 回合配置,回合号越界时返回 null
* @returns 小节配置,不存在时返回 null
*/ */
export function getSectionConfig(chapter: number, stage: number, section: number): SectionConfig | null { export function getSectionConfig(stage: number, section: number): SectionConfig | null {
const ch = ChapterSet[chapter]; if (section < 1 || section > SECTIONS_PER_STAGE) return null;
if (!ch) return null;
const st = ch.stages.find(s => s.stage === stage); const type = getSectionType(section);
if (!st) return null; const cfg: SectionConfig = {
if (section < 1 || section > st.sections.length) return null; type,
return st.sections[section - 1]; monLv: getMonsterLv(stage),
ramp: 1 + SECTION_RAMP_STEP * (section - 1),
};
if (type !== SectionType.Boss) {
// 普通回合:近战为主,穿插远程/重型
cfg.monTypes = [MonType.Melee, MonType.Melee, MonType.Melee, MonType.Heavy, MonType.Long];
}
return cfg;
} }
/** /**
* 获取大关配置 * 获取当前进度显示文本(无限关:只展示 关-回合)
* @param chapter 章节号
* @param stage 关卡号 * @param stage 关卡号
* @returns 大关配置,不存在时返回 null * @param section 回合号
* @returns 格式化文本,如 "5-3"
*/ */
export function getStageConfig(chapter: number, stage: number): StageConfig | null { export function getProgressText(stage: number, section: number): string {
const ch = ChapterSet[chapter]; return `${stage}-${section}`;
if (!ch) return null;
return ch.stages.find(s => s.stage === stage) ?? null;
}
/**
* 获取章节配置
* @param chapter 章节号
* @returns 章节配置,不存在时返回 null
*/
export function getChapterConfig(chapter: number): ChapterConfig | null {
return ChapterSet[chapter] ?? null;
}
/**
* 获取当前进度显示文本
* @param chapter 章节号
* @param stage 关卡号
* @param section 小节号
* @returns 格式化文本,如 "1-5-3"
*/
export function getProgressText(chapter: number, stage: number, section: number): string {
return `${chapter}-${stage}-${section}`;
}
/**
* 获取大关显示文本
* @param chapter 章节号
* @param stage 关卡号
* @returns 格式化文本,如 "1-5"
*/
export function getStageText(chapter: number, stage: number): string {
return `${chapter}-${stage}`;
} }

View File

@@ -1,6 +1,6 @@
import { v3 } from "cc" import { v3 } from "cc"
import { BoxSet, FacSet, FightSet } from "./GameSet" import { BoxSet, FacSet, FightSet } from "./GameSet"
import { SkillOverrides, TGroup, SkillSet, FieldSkillSet, SkillConfig, SkillKind, FieldSkillConfig, FieldSkillType, mergeSkillParams } from "./SkillSet" import { SkillOverrides, TGroup, SkillSet, FieldSkillSet, SkillConfig, SkillKind, FieldSkillConfig, FieldSkillType, mergeSkillParams, BuffTarget } from "./SkillSet"
import { BuffList, BuffConfig, ModOp } from "./BuffSet" import { BuffList, BuffConfig, ModOp } from "./BuffSet"
import { Attrs } from "./HeroAttrs" import { Attrs } from "./HeroAttrs"
@@ -424,8 +424,8 @@ export interface heroInfo {
[SkillTriggerType.FStart]?: TriggerGrouped; // 战斗开始时释放的技能配置 [SkillTriggerType.FStart]?: TriggerGrouped; // 战斗开始时释放的技能配置
[SkillTriggerType.FEnd]?: TriggerGrouped; // 回合结束时释放的技能配置 [SkillTriggerType.FEnd]?: TriggerGrouped; // 回合结束时释放的技能配置
[SkillTriggerType.Field]?: LvFieldEntry[]; // 驻场光环(按 lv 升序,运行时取 ≤英雄等级 的最大档) [SkillTriggerType.Field]?: LvFieldEntry[]; // 驻场光环(按 lv 升序,运行时取 ≤英雄等级 的最大档)
[SkillTriggerType.Atking]?: TriggerGrouped; // 普通攻击后触发的技能配置,s_uuid: 技能id, t_num: 触发所需的普攻次数 [SkillTriggerType.Atking]?: TriggerGrouped; // 普通攻击后触发的技能配置,s_uuid: 技能id, t_num: 触发所需的普攻次数, t_chance: 触发概率(%),pity_add: 未触发时下次概率增量
[SkillTriggerType.Atked]?: TriggerGrouped; // 受击后触发的技能配置,s_uuid: 技能id, t_num: 触发所需的受击次数 [SkillTriggerType.Atked]?: TriggerGrouped; // 受击后触发的技能配置,s_uuid: 技能id, t_num: 触发所需的受击次数, t_chance: 触发概率(%),pity_add: 未触发时下次概率增量
dis?: number; // 攻击距离(像素) dis?: number; // 攻击距离(像素)
speed?: number; // 移动速度(像素/秒) speed?: number; // 移动速度(像素/秒)
dodge?: number; // 闪避率(百分点,缺省由初始化处兜底为全局默认值) dodge?: number; // 闪避率(百分点,缺省由初始化处兜底为全局默认值)
@@ -504,6 +504,11 @@ export interface LvTriggerEntry {
s_lv?: SkillLv; // 此档对应的技能等级(标注用,便于面板显示"技能Lv.x") s_lv?: SkillLv; // 此档对应的技能等级(标注用,便于面板显示"技能Lv.x")
name?: string; // 该 s_uuid 触发技能组的对外展示名(写在第 1 档,作为组名) name?: string; // 该 s_uuid 触发技能组的对外展示名(写在第 1 档,作为组名)
t_num: number; t_num: number;
/** 触发概率(百分点 0~100,缺省 100 必触发;仅 Atking/Atked 攻受击触发生效) */
t_chance?: number;
/** 保底叠加:判定未触发时,为该 s_uuid 累积下次概率增量(百分点)。
* 缺省/0 = 不叠加;触发成功后清零,最终概率封顶 100 */
pity_add?: number;
overrides?: SkillOverrides; overrides?: SkillOverrides;
/** 此档描述模板:缺省回退该组第 1 档 desc;由 HeroSkillText 渲染合并后实时数值。 /** 此档描述模板:缺省回退该组第 1 档 desc;由 HeroSkillText 渲染合并后实时数值。
* 显式配置后弹窗提升档(slv2+)直接展示该模板渲染结果,优先于自动 diff */ * 显式配置后弹窗提升档(slv2+)直接展示该模板渲染结果,优先于自动 diff */
@@ -516,6 +521,20 @@ export interface LvTriggerEntry {
*/ */
export type TriggerGrouped = Record<number /*s_uuid*/, LvTriggerEntry[]>; export type TriggerGrouped = Record<number /*s_uuid*/, LvTriggerEntry[]>;
/**
* 运行时生效的触发条目(resolveTriggerByLv 产出):
* 每个 s_uuid 取 ≤lv 最大档的扁平结果,供触发器/评分/文案消费。
*/
export interface ResolvedTriggerEntry {
s_uuid: number;
t_num: number;
/** 触发概率(百分点,缺省 100 必触发;仅 Atking/Atked 生效) */
t_chance?: number;
/** 保底叠加:未触发时累积的下次概率增量(百分点,触发成功后清零) */
pity_add?: number;
overrides?: SkillOverrides;
}
/** /**
* 驻场光环词条:uuid 指向 FieldSkillSet 底座(类型/图标/元数据), * 驻场光环词条:uuid 指向 FieldSkillSet 底座(类型/图标/元数据),
* value 为该词条实际生效数值(由配置处按档位指定,不再随 uuid 分档)。 * value 为该词条实际生效数值(由配置处按档位指定,不再随 uuid 分档)。
@@ -585,40 +604,40 @@ export const HeroInfo: Record<number, heroInfo> = {
}, },
}, },
atked: { atked: {
6301: [ 6412: [
{ lv: 4, s_lv: SkillLv.Lv1, name: "全体圣盾", t_num: 3, overrides: {"TGroup":null,"ap":10,"icon":"Stat_UnitSummonIncrease_01"}, desc: "全队获得本英雄生命最大值{ap}%的护盾" }, { lv: 4, s_lv: SkillLv.Lv1, t_num: 3, t_chance: 50, pity_add: 20, overrides: {"ap":1} },
], ],
}, },
bonus: [ bonus: [
{ lv: 12, attrs: {"def":50}, name: "钢铁壁垒", icon: "46-Iron-Clad", }, { lv: 12, attrs: {"def":50}, name: "钢铁壁垒", icon: "46-Iron-Clad", },
], ],
info: "自身强护盾+群体小护盾,强生存", info: "自身强护盾+防御强化",
}, },
// 5002 易伤剑仙 — CSV导入:击退压场+易伤放大;复刻酒仙 // 5002 易伤剑仙 — CSV导入:击退压场+易伤放大;复刻酒仙
5002: { 5002: {
uuid: 5002, name: "易伤剑仙", path: "hk3", fac: FacSet.HERO, rarity: 1, lv: 1, type: HType.Melee, grow_type: HGrowType.Warrior, role: HRole.Warrior, hp: HERO_ROLE_BASE[HRole.Warrior].hp + 5, ap: HERO_ROLE_BASE[HRole.Warrior].ap + 20, def: HERO_ROLE_BASE[HRole.Warrior].def + 5, uuid: 5002, name: "易伤剑仙", path: "hk5", fac: FacSet.HERO, rarity: 1, lv: 1, type: HType.Melee, grow_type: HGrowType.Warrior, role: HRole.Warrior, hp: HERO_ROLE_BASE[HRole.Warrior].hp + 5, ap: HERO_ROLE_BASE[HRole.Warrior].ap + 20, def: HERO_ROLE_BASE[HRole.Warrior].def + 5,
skills: { skills: {
6004: { uuid: 6004, name: "强化普攻", lv: 1, cd: AtkSpeedSet[AtkSpeedLv.Slow].cd, ccd: 0, overrides: {"ap":100}, desc: "对{target}造成攻击力{ap}%伤害", 6004: { uuid: 6004, name: "强化普攻", lv: 1, cd: AtkSpeedSet[AtkSpeedLv.Slow].cd, ccd: 0, overrides: {"ap":100}, desc: "对{target}造成攻击力{ap}%伤害",
lv_entries: [ lv_entries: [
{ lv: 2, s_lv: SkillLv.Lv2, overrides: {"ap":120}, desc: "普通攻击造成 120% 攻击伤害" }, { lv: 2, s_lv: SkillLv.Lv2, overrides: {"ap":120}, desc: "普通攻击造成 120% 攻击伤害" },
], ],
}, },
6101: { uuid: 6101, name: "气斩", lv: 1, cd: UltCdSet[UltCdLv.Normal].cd, ccd: 0, overrides: {"ap":150,"timed_debuff_id":7002,"icon":"Stat_AttackSpeed_02"}, desc: "斩出气刃,对{target}造成攻击力{ap}%伤害,并使目标易伤(受到伤害加深,持续{dur}秒)", 6101: { uuid: 6101, name: "气斩", lv: 1, cd: UltCdSet[UltCdLv.Normal].cd, ccd: 0, overrides: {"ap":150,"timed_debuff_id":7002,"debuff_value":30,"debuff_chance":100,"debuff_duration":5}, desc: "斩出气刃,对{target}造成攻击力{ap}%伤害,并使目标易伤(受到伤害加深,持续{dur}秒)",
lv_entries: [ lv_entries: [
{ lv: 8, s_lv: SkillLv.Lv2, overrides: {"buff_value":20} }, { lv: 8, s_lv: SkillLv.Lv2, overrides: {"ap":200,"timed_debuff_id":7002,"debuff_value":70,"debuff_chance":100,"debuff_duration":5} },
{ lv: 16, s_lv: SkillLv.Lv3, overrides: {"ap":180,"bck":60,"buff_value":40}, desc: "斩出气刃,对{target}造成攻击力{ap}%伤害,击退{bck},并使目标易伤(持续{dur}秒)" }, { lv: 16, s_lv: SkillLv.Lv3, overrides: {"ap":250,"timed_debuff_id":7002,"debuff_value":150,"debuff_chance":100,"debuff_duration":7} },
], ],
}, },
}, },
atking: { atking: {
6004: [ 6001: [
{ lv: 4, s_lv: SkillLv.Lv1, name: "风暴打击", t_num: 3, overrides: {"ap":300,"icon":"Stat_AllUnitAttack"}, desc: "立刻打击{target},造成攻击力{ap}%伤害" }, { lv: 4, s_lv: SkillLv.Lv1, t_num: 3, t_chance: 50, pity_add: 20, overrides: {"timed_debuff_id":7002,"debuff_value":10,"debuff_chance":100,"debuff_duration":5} },
], ],
}, },
bonus: [ bonus: [
{ lv: 12, attrs: {"hp":50}, name: "不屈战意", icon: "29-Endure", }, { lv: 12, attrs: {"hp":50}, name: "不屈战意", icon: "29-Endure", },
], ],
info: "易伤+风怒,近战 dps", info: "易伤,近战 dps",
}, },
// 5003 眩晕暴击哥 — CSV导入:高爆发+击晕收割;复刻齐天大圣 // 5003 眩晕暴击哥 — CSV导入:高爆发+击晕收割;复刻齐天大圣
5003: { 5003: {
@@ -629,16 +648,18 @@ export const HeroInfo: Record<number, heroInfo> = {
{ lv: 2, s_lv: SkillLv.Lv2, overrides: {"stun":10}, desc: "普通攻击有{stun}%概率击晕敌人" }, { lv: 2, s_lv: SkillLv.Lv2, overrides: {"stun":10}, desc: "普通攻击有{stun}%概率击晕敌人" },
], ],
}, },
6104: { uuid: 6104, name: "开山斧", lv: 1, cd: UltCdSet[UltCdLv.Normal].cd, ccd: 0, overrides: {"ap":300,"stun":100}, desc: "劈出开山斧,对{target}造成攻击力{ap}%伤害,必定击晕", 6104: { uuid: 6104, name: "开山斧", lv: 1, cd: UltCdSet[UltCdLv.Normal].cd, ccd: 0, overrides: {"ap":250,"stun":100}, desc: "劈出开山斧,对{target}造成攻击力{ap}%伤害,必定击晕",
lv_entries: [ lv_entries: [
{ lv: 8, s_lv: SkillLv.Lv2, overrides: {"ap":450,"stun":100} }, { lv: 8, s_lv: SkillLv.Lv2, overrides: {"ap":300,"stun":100} },
{ lv: 16, s_lv: SkillLv.Lv3, overrides: {"ap":450,"stun":100} }, { lv: 16, s_lv: SkillLv.Lv3, overrides: {"ap":350,"stun":100} },
], ],
}, },
}, },
field: [ atking: {
{ lv: 4, uuids: [{ uuid: 7005, value: 0.25, name: "大圣神威" }] }, 6504: [
], { lv: 4, s_lv: SkillLv.Lv1, t_num: 3, t_chance: 50, pity_add: 20, overrides: {"buff_value":30}, desc: "{t_chance}% 概率提升普通攻击 30%暴击率5秒" },
],
},
bonus: [ bonus: [
{ lv: 12, attrs: {"hp":50}, name: "不屈战意", icon: "29-Endure", }, { lv: 12, attrs: {"hp":50}, name: "不屈战意", icon: "29-Endure", },
], ],
@@ -653,16 +674,18 @@ export const HeroInfo: Record<number, heroInfo> = {
{ lv: 2, s_lv: SkillLv.Lv2, overrides: {"crt":10}, desc: "普通攻击有{crt}%概率暴击" }, { lv: 2, s_lv: SkillLv.Lv2, overrides: {"crt":10}, desc: "普通攻击有{crt}%概率暴击" },
], ],
}, },
6100: { uuid: 6100, name: "光闪", lv: 1, cd: UltCdSet[UltCdLv.VeryFast].cd, ccd: 0, overrides: {"ap":150}, desc: "斩出光闪,对{target}造成攻击力{ap}%伤害", 6150: { uuid: 6150, name: "剑刃风暴", lv: 1, cd: UltCdSet[UltCdLv.VeryFast].cd, ccd: 0, overrides: {"ap":150,"crt":50}, desc: "对{target}造成攻击力{ap}%伤害,有50% 概率暴击",
lv_entries: [ lv_entries: [
{ lv: 8, s_lv: SkillLv.Lv2, overrides: {"ap":250} }, { lv: 8, s_lv: SkillLv.Lv2, overrides: {"ap":200,"crt":60} },
{ lv: 16, s_lv: SkillLv.Lv3, overrides: {"ap":350} }, { lv: 16, s_lv: SkillLv.Lv3, overrides: {"ap":250,"crt":70} },
], ],
}, },
}, },
field: [ atking: {
{ lv: 4, uuids: [{ uuid: 7004, value: 0.12, name: "剑刃风暴" }, { uuid: 7005, value: 0.2, name: "斩魂利刃" }] }, 6504: [
], { lv: 4, s_lv: SkillLv.Lv1, t_num: 3, t_chance: 50, pity_add: 20, overrides: {"timed_buff_id":7012,"buff_value":10,"buff_chance":100,"buff_duration":5}, desc: "{t_chance}% 概率,普通攻击获得 10% 的暴击率" },
],
},
bonus: [ bonus: [
{ lv: 12, attrs: {"ap":50}, name: "致命本能", icon: "36-Guardian-Stance", }, { lv: 12, attrs: {"ap":50}, name: "致命本能", icon: "36-Guardian-Stance", },
], ],
@@ -674,19 +697,21 @@ export const HeroInfo: Record<number, heroInfo> = {
skills: { skills: {
6002: { uuid: 6002, name: "强化普攻", lv: 1, cd: AtkSpeedSet[AtkSpeedLv.Fast].cd, ccd: 0, overrides: {"ap":100}, desc: "挥刀对{target}造成攻击力{ap}%伤害", 6002: { uuid: 6002, name: "强化普攻", lv: 1, cd: AtkSpeedSet[AtkSpeedLv.Fast].cd, ccd: 0, overrides: {"ap":100}, desc: "挥刀对{target}造成攻击力{ap}%伤害",
lv_entries: [ lv_entries: [
{ lv: 2, s_lv: SkillLv.Lv2, overrides: {"timed_debuff_id":7007,"debuff_value":30,"debuff_chance":30}, desc: "普通攻击有{debuff_chance}%概率使目标出血(每0.5秒受到{debuff_value}点伤害,持续{dur}秒)" }, { lv: 2, s_lv: SkillLv.Lv2, overrides: {"timed_debuff_id":7007,"debuff_value":-30,"debuff_chance":50}, desc: "普通攻击有{debuff_chance}%概率使目标出血(每0.5秒受到{debuff_value}点伤害,持续{dur}秒)" },
], ],
}, },
6103: { uuid: 6103, name: "闪电斩", lv: 1, cd: UltCdSet[UltCdLv.VeryFast].cd, ccd: 0, overrides: {"ap":150}, desc: "高速斩击{target},造成攻击力{ap}%伤害", 6150: { uuid: 6150, name: "血刃风暴", lv: 1, cd: UltCdSet[UltCdLv.VeryFast].cd, ccd: 0, overrides: {"ap":200,"timed_debuff_id":7007,"debuff_value":-20,"debuff_chance":100,"debuff_duration":5}, desc: "高速斩击{target},造成攻击力{ap}%伤害",
lv_entries: [ lv_entries: [
{ lv: 8, s_lv: SkillLv.Lv2, overrides: {"ap":250,"timed_debuff_id":7007,"debuff_value":40}, desc: "高速斩击{target},造成攻击力{ap}%,并使目标出血(每0.5秒受到{debuff_value}点伤害,持续{dur}秒)" }, { lv: 8, s_lv: SkillLv.Lv2, overrides: {"ap":250,"timed_debuff_id":7007,"debuff_value":-30,"debuff_chance":100,"debuff_duration":7}, desc: "高速斩击{target},造成攻击力{ap}%,并使目标出血(每0.5秒受到{debuff_value}点伤害,持续{dur}秒)" },
{ lv: 16, s_lv: SkillLv.Lv3, overrides: {"ap":350,"timed_debuff_id":7007,"debuff_value":60}, desc: "高速斩击{target},造成攻击力{ap}%,附带 50% 概率麻痹,并使目标出血(每0.5秒受到{debuff_value}点伤害,持续{dur}秒)" }, { lv: 16, s_lv: SkillLv.Lv3, overrides: {"ap":300,"timed_debuff_id":7007,"debuff_value":-50,"debuff_chance":100,"debuff_duration":9}, desc: "高速斩击{target},造成攻击力{ap}%,附带 50% 概率麻痹,并使目标出血(每0.5秒受到{debuff_value}点伤害,持续{dur}秒)" },
], ],
}, },
}, },
field: [ atking: {
{ lv: 4, uuids: [{ uuid: 7002, value: 10, name: "攻击光环" }] }, 6401: [
], { lv: 4, s_lv: SkillLv.Lv1, t_num: 3, t_chance: 50, pity_add: 20, overrides: {"buff_value":2} },
],
},
bonus: [ bonus: [
{ lv: 12, attrs: {"ap":50}, name: "致命本能", icon: "36-Guardian-Stance", }, { lv: 12, attrs: {"ap":50}, name: "致命本能", icon: "36-Guardian-Stance", },
], ],
@@ -701,16 +726,18 @@ export const HeroInfo: Record<number, heroInfo> = {
{ lv: 2, s_lv: SkillLv.Lv2, overrides: {"frz":10}, desc: "普通攻击有{frz}%概率 冰冻敌人" }, { lv: 2, s_lv: SkillLv.Lv2, overrides: {"frz":10}, desc: "普通攻击有{frz}%概率 冰冻敌人" },
], ],
}, },
6150: { uuid: 6150, name: "万箭齐发·冰", lv: 1, cd: UltCdSet[UltCdLv.Normal].cd, ccd: 0, overrides: {"ap":150,"frz":30,"icon":"Stat_AttackRangeIncrease_02"}, desc: "万箭齐发,对{target}造成攻击力{ap}%伤害,{frz}%概率冰冻", 6150: { uuid: 6150, name: "寒冰箭", lv: 1, cd: UltCdSet[UltCdLv.Normal].cd, ccd: 0, overrides: {"ap":150,"frz":30,"icon":"Stat_AttackRangeIncrease_02"}, desc: "射出 6 支寒冰箭,对{target}造成攻击力{ap}%伤害,每支箭有{frz}%概率冰冻敌人",
lv_entries: [ lv_entries: [
{ lv: 8, s_lv: SkillLv.Lv2, overrides: {"ap":200,"frz":50} }, { lv: 8, s_lv: SkillLv.Lv2, overrides: {"ap":200,"frz":30} },
{ lv: 16, s_lv: SkillLv.Lv3, overrides: {"ap":250,"frz":70} }, { lv: 16, s_lv: SkillLv.Lv3, overrides: {"ap":250,"frz":30} },
], ],
}, },
}, },
field: [ atking: {
{ lv: 4, uuids: [{ uuid: 7006, value: 0.15 }] }, 6401: [
], { lv: 4, s_lv: SkillLv.Lv1, t_num: 3, t_chance: 50, pity_add: 20, overrides: {"buff_value":2,"TGroup": TGroup.Ally}, desc: "{t_chance}%概率,永久提升全队 2% 攻击力" },
],
},
bonus: [ bonus: [
{ lv: 12, attrs: {"ap":50}, name: "鹰眼锁定", icon: "27-Hawkeye", }, { lv: 12, attrs: {"ap":50}, name: "鹰眼锁定", icon: "27-Hawkeye", },
], ],
@@ -725,15 +752,15 @@ export const HeroInfo: Record<number, heroInfo> = {
{ lv: 2, s_lv: SkillLv.Lv2, overrides: {"bck_chance":20}, desc: "普通攻击有{bck_chance}%概率击退敌人" }, { lv: 2, s_lv: SkillLv.Lv2, overrides: {"bck_chance":20}, desc: "普通攻击有{bck_chance}%概率击退敌人" },
], ],
}, },
6200: { uuid: 6200, name: "火焰喷射", lv: 1, cd: UltCdSet[UltCdLv.Normal].cd, ccd: 0, overrides: {"ap":250,"bck":100}, desc: "喷出烈焰风暴,对{target}造成攻击力{ap}%伤害,击退{bck}", 6200: { uuid: 6200, name: "火焰喷射", lv: 1, cd: UltCdSet[UltCdLv.Normal].cd, ccd: 0, overrides: {"ap":250,"crt":50}, desc: "喷出烈焰风暴,对{target}造成攻击力{ap}%伤害,击退{bck}",
lv_entries: [ lv_entries: [
{ lv: 8, s_lv: SkillLv.Lv2, overrides: {"ap":350,"bck":100} }, { lv: 8, s_lv: SkillLv.Lv2, overrides: {"ap":350,"crt":0} },
{ lv: 16, s_lv: SkillLv.Lv3, overrides: {"ap":450,"bck":100,"summon_count":2} }, { lv: 16, s_lv: SkillLv.Lv3, overrides: {"ap":450,"crt":0,"summon_count":4} },
], ],
}, },
}, },
field: [ field: [
{ lv: 4, uuids: [{ uuid: 7002, value: 0.15, name: "深渊威压" }] }, { lv: 4, uuids: [{ uuid: 7002, value: 0.15, name: "攻击光环" }] },
], ],
bonus: [ bonus: [
{ lv: 12, attrs: {"ap":50}, name: "奥术共鸣", icon: "100-Enchant-Magic", }, { lv: 12, attrs: {"ap":50}, name: "奥术共鸣", icon: "100-Enchant-Magic", },
@@ -749,18 +776,16 @@ export const HeroInfo: Record<number, heroInfo> = {
{ lv: 2, s_lv: SkillLv.Lv2, overrides: {"ap":120}, desc: "普通攻击造成 120% 攻击伤害" }, { lv: 2, s_lv: SkillLv.Lv2, overrides: {"ap":120}, desc: "普通攻击造成 120% 攻击伤害" },
], ],
}, },
6302: { uuid: 6302, name: "治疗", lv: 1, cd: UltCdSet[UltCdLv.VerySlow].cd, ccd: 0, overrides: {"ap":30}, desc: "为{target}回复攻击力{ap}%生命", 6302: { uuid: 6302, name: "治疗", lv: 1, cd: UltCdSet[UltCdLv.VerySlow].cd, ccd: 0, overrides: {"ap":30,"TGroup": TGroup.Ally}, desc: "为{target}回复攻击力{ap}%生命",
lv_entries: [ lv_entries: [
{ lv: 8, s_lv: SkillLv.Lv2, overrides: {"ap":40} }, { lv: 8, s_lv: SkillLv.Lv2, overrides: {"ap":40,"TGroup": TGroup.Ally} },
{ lv: 16, s_lv: SkillLv.Lv3, overrides: {"ap":50} }, { lv: 16, s_lv: SkillLv.Lv3, overrides: {"ap":50,"TGroup": TGroup.Ally,"timed_buff_id":7024,"buff_value":20,"buff_chance":100,"buff_duration":5} },
], ],
}, },
}, },
atking: { field: [
6301: [ { lv: 4, uuids: [{ uuid: 7001, value: 20 }], desc: "每回合结束 休整恢复的血量值提升 20%" },
{ lv: 4, s_lv: SkillLv.Lv1, name: "圣愈之盾", t_num: 3, overrides: {"ap":30}, desc: "{target}获得生命最大值{ap}%的护盾" }, ],
],
},
bonus: [ bonus: [
{ lv: 12, attrs: {"hp":50}, name: "守护之心", icon: "29-Endure", }, { lv: 12, attrs: {"hp":50}, name: "守护之心", icon: "29-Endure", },
], ],
@@ -768,23 +793,23 @@ export const HeroInfo: Record<number, heroInfo> = {
}, },
// 5009 甲虫领主 // 5009 甲虫领主
5009: { 5009: {
uuid: 5009, name: "甲虫领主", path: "hk2", fac: FacSet.HERO, rarity: 1, lv: 1, type: HType.Melee, grow_type: HGrowType.Tank, role: HRole.Tank, hp: HERO_ROLE_BASE[HRole.Tank].hp, ap: HERO_ROLE_BASE[HRole.Tank].ap, def: HERO_ROLE_BASE[HRole.Tank].def, uuid: 5009, name: "甲虫领主", path: "hk3", fac: FacSet.HERO, rarity: 1, lv: 1, type: HType.Melee, grow_type: HGrowType.Tank, role: HRole.Tank, hp: HERO_ROLE_BASE[HRole.Tank].hp, ap: HERO_ROLE_BASE[HRole.Tank].ap, def: HERO_ROLE_BASE[HRole.Tank].def,
skills: { skills: {
6004: { uuid: 6004, name: "普攻强化", lv: 1, cd: AtkSpeedSet[AtkSpeedLv.Slow].cd, ccd: 0, 6004: { uuid: 6004, name: "普攻强化", lv: 1, cd: AtkSpeedSet[AtkSpeedLv.Slow].cd, ccd: 0,
lv_entries: [ lv_entries: [
{ lv: 2, s_lv: SkillLv.Lv2, overrides: {"proc_skill":{"s_uuid":6502,"chance":10,"overrides":{"ap":5,"TGroup": TGroup.Self}}}, desc: "普通攻击有 10% 的概率为自己释放回春(5 秒恢复生命值的{ap}%)" }, { lv: 2, s_lv: SkillLv.Lv2, overrides: {"ap":120}, desc: "普通攻击造成的伤害提升 20%" },
], ],
}, },
6102: { uuid: 6102, lv: 1, cd: UltCdSet[UltCdLv.Normal].cd, ccd: 0, overrides: {"ap":250,"bck":30}, 6102: { uuid: 6102, lv: 1, cd: UltCdSet[UltCdLv.Normal].cd, ccd: 0, overrides: {"ap":250,"proc_skill":{"s_uuid":6302,"chance":100,"overrides":{"TGroup": TGroup.Self,"buff_value":10}}},
lv_entries: [ lv_entries: [
{ lv: 8, s_lv: SkillLv.Lv2, overrides: {"ap":300,"bck":50} }, { lv: 8, s_lv: SkillLv.Lv2, overrides: {"ap":300,"proc_skill":{"s_uuid":6302,"chance":100,"overrides":{"TGroup": TGroup.Self,"buff_value":15}}} },
{ lv: 16, s_lv: SkillLv.Lv3, overrides: {"ap":350,"bck":70} }, { lv: 16, s_lv: SkillLv.Lv3, overrides: {"ap":350,"proc_skill":{"s_uuid":6302,"chance":100,"overrides":{"TGroup": TGroup.Self,"buff_value":20}}} },
], ],
}, },
}, },
atked: { atked: {
6302: [ 6302: [
{ lv: 4, s_lv: SkillLv.Lv1, t_num: 3, overrides: {"ap":5}, desc: "为自己释放治疗,恢复生命值的{ap}%" }, { lv: 4, s_lv: SkillLv.Lv1, t_num: 3, t_chance: 30, pity_add: 20, overrides: {"ap":5}, desc: "{t_chance}%概率,恢复{ap}%生命值" },
], ],
}, },
bonus: [ bonus: [
@@ -798,45 +823,45 @@ export const HeroInfo: Record<number, heroInfo> = {
skills: { skills: {
6006: { uuid: 6006, name: "强化普攻", lv: 1, cd: AtkSpeedSet[AtkSpeedLv.Fast].cd, ccd: 0, 6006: { uuid: 6006, name: "强化普攻", lv: 1, cd: AtkSpeedSet[AtkSpeedLv.Fast].cd, ccd: 0,
lv_entries: [ lv_entries: [
{ lv: 2, s_lv: SkillLv.Lv2, overrides: {"ap":100,"bck_chance":10} }, { lv: 2, s_lv: SkillLv.Lv2, overrides: {"crt":10} },
], ],
}, },
6151: { uuid: 6151, lv: 1, cd: UltCdSet[UltCdLv.VeryFast].cd, ccd: 0, overrides: {"ap":70,"summon_count":5,"bck_chance":100}, 6151: { uuid: 6151, lv: 1, cd: UltCdSet[UltCdLv.VeryFast].cd, ccd: 0, overrides: {"ap":70,"summon_count":5,"timed_debuff_id":7006,"debuff_value":-10,"debuff_chance":100,"debuff_duration":5},
lv_entries: [ lv_entries: [
{ lv: 8, s_lv: SkillLv.Lv2, overrides: {"ap":80,"summon_count":5,"bck_chance":100} }, { lv: 8, s_lv: SkillLv.Lv2, overrides: {"ap":80,"timed_debuff_id":7006,"debuff_value":-20,"debuff_chance":100,"debuff_duration":5} },
{ lv: 16, s_lv: SkillLv.Lv3, overrides: {"bck_chance":100,"ap":100,"summon_count":6} }, { lv: 16, s_lv: SkillLv.Lv3, overrides: {"ap":100,"timed_debuff_id":7006,"debuff_value":-30,"debuff_chance":100,"debuff_duration":5} },
], ],
}, },
}, },
atking: { atking: {
6008: [ 6008: [
{ lv: 4, s_lv: SkillLv.Lv1, t_num: 3, overrides: {"ap":120,"bck_chance":50} }, { lv: 4, s_lv: SkillLv.Lv1, t_num: 3, t_chance: 50, pity_add: 20, overrides: {"ap":120} },
], ],
}, },
bonus: [ bonus: [
{ lv: 12, attrs: {"ap":50}, name: "鹰眼锁定", icon: "27-Hawkeye", }, { lv: 12, attrs: {"ap":50}, name: "鹰眼锁定", icon: "27-Hawkeye", },
], ],
info: "万箭齐射+高频击退,远程压制", info: "暴击",
}, },
// 5011 控血大师 // 5011 控血大师
5011: { 5011: {
uuid: 5011, name: "控血大师", path: "hk3", fac: FacSet.HERO, rarity: 1, lv: 1, type: HType.Melee, grow_type: HGrowType.Tank, role: HRole.Tank, hp: HERO_ROLE_BASE[HRole.Tank].hp, ap: HERO_ROLE_BASE[HRole.Tank].ap, def: HERO_ROLE_BASE[HRole.Tank].def, uuid: 5011, name: "控血大师", path: "hk2", fac: FacSet.HERO, rarity: 1, lv: 1, type: HType.Melee, grow_type: HGrowType.Tank, role: HRole.Tank, hp: HERO_ROLE_BASE[HRole.Tank].hp, ap: HERO_ROLE_BASE[HRole.Tank].ap, def: HERO_ROLE_BASE[HRole.Tank].def,
skills: { skills: {
6004: { uuid: 6004, name: "普攻强化", lv: 1, cd: AtkSpeedSet[AtkSpeedLv.Normal].cd, ccd: 0, 6004: { uuid: 6004, name: "普攻强化", lv: 1, cd: AtkSpeedSet[AtkSpeedLv.Normal].cd, ccd: 0,
lv_entries: [ lv_entries: [
{ lv: 2, s_lv: SkillLv.Lv2, overrides: {"proc_skill":{"s_uuid":6502,"chance":10,"overrides":{"ap":5}}}, desc: "普攻有 10% 概率,对自己释放回春(5 秒回复5% 生命)" }, { lv: 2, s_lv: SkillLv.Lv2, overrides: {"proc_skill":{"s_uuid":6502,"chance":10,"overrides":{"ap":5,"TGroup": TGroup.Self}}}, desc: "普攻有 10% 概率,对自己释放回春(5 秒回复5% 生命)" },
], ],
}, },
6517: { uuid: 6517, name: "生命爆发", lv: 1, cd: UltCdSet[UltCdLv.VerySlow].cd, ccd: 0, overrides: {"buff_value":30,"buff_duration":10}, desc: "全体友方最大生命值提升{buff_value}%,持续{dur}秒", 6103: { uuid: 6103, name: "闪电战", lv: 1, cd: UltCdSet[UltCdLv.VerySlow].cd, ccd: 0, overrides: {"ap":200,"timed_buff_id":7029,"buff_value":30,"buff_chance":100,"buff_duration":5,"buff_target": BuffTarget.Self}, desc: "对前方敌人造成攻击力{ap}%伤害,并提升自己最大生命值{buff_value}%,持续{dur}秒",
lv_entries: [ lv_entries: [
{ lv: 8, s_lv: SkillLv.Lv2, overrides: {"buff_value":40,"buff_duration":10}, desc: "全体友方最大生命值提升{buff_value}%,持续{dur}秒" }, { lv: 8, s_lv: SkillLv.Lv2, overrides: {"ap":250,"timed_buff_id":7029,"buff_value":40,"buff_chance":100,"buff_duration":5,"buff_target": BuffTarget.Self} },
{ lv: 16, s_lv: SkillLv.Lv3, overrides: {"buff_value":50,"buff_duration":15}, desc: "全体友方最大生命值提升{buff_value}%,持续{dur}秒" }, { lv: 16, s_lv: SkillLv.Lv3, overrides: {"ap":300,"timed_buff_id":7029,"buff_value":50,"buff_chance":100,"buff_duration":5,"buff_target": BuffTarget.Self} },
], ],
}, },
}, },
atked: { atked: {
6402: [ 6402: [
{ lv: 4, s_lv: SkillLv.Lv1, t_num: 5, overrides: {"ap":1,"TGroup": TGroup.Ally,"hit_count":3}, desc: "全队永久增加 1% 生命最大值" }, { lv: 4, s_lv: SkillLv.Lv1, t_num: 5, t_chance: 30, pity_add: 15, overrides: {"ap":1,"TGroup": TGroup.Ally,"hit_count":3}, desc: "全队永久增加 1% 生命最大值" },
], ],
}, },
bonus: [ bonus: [
@@ -853,10 +878,10 @@ export const HeroInfo: Record<number, heroInfo> = {
{ lv: 2, s_lv: SkillLv.Lv2, overrides: {"proc_skill":{"s_uuid":6507,"chance":10,"overrides":{"buff_value":30,"TGroup": TGroup.Self}}} }, { lv: 2, s_lv: SkillLv.Lv2, overrides: {"proc_skill":{"s_uuid":6507,"chance":10,"overrides":{"buff_value":30,"TGroup": TGroup.Self}}} },
], ],
}, },
6201: { uuid: 6201, name: "飓风", lv: 1, cd: UltCdSet[UltCdLv.Normal].cd, ccd: 0, overrides: {"ap":100,"summon_count":2,"proc_skill":{"s_uuid":6507,"chance":20,"overrides":{"buff_value":20}}}, desc: "召唤 {summon_count} 道飓风攻击前方敌人,每道飓风造成 {ap}%伤害,每道飓风释放时有<color=#3CE66E>20</color>% 概率增加全体队友<color=#3CE66E>20</color>% 攻速", 6201: { uuid: 6201, name: "飓风", lv: 1, cd: UltCdSet[UltCdLv.Normal].cd, ccd: 0, overrides: {"ap":100,"summon_count":2,"proc_skill":{"s_uuid":6507,"chance":20,"overrides":{"buff_value":20,"TGroup": TGroup.Ally}}}, desc: "召唤 {summon_count} 道飓风攻击前方敌人,每道飓风造成 {ap}%伤害,每道飓风释放时有<color=#3CE66E>20</color>% 概率增加全体队友<color=#3CE66E>20</color>% 攻速",
lv_entries: [ lv_entries: [
{ lv: 8, s_lv: SkillLv.Lv2, overrides: {"ap":100,"summon_count":3,"proc_skill":{"s_uuid":6507,"chance":20,"overrides":{"buff_value":20}}}, desc: "召唤 {summon_count} 道飓风攻击前方敌人,每道飓风造成 {ap}%伤害,每道飓风释放时有<color=#3CE66E>20</color>% 概率增加全体队友<color=#3CE66E>20</color>% 攻速" }, { lv: 8, s_lv: SkillLv.Lv2, overrides: {"ap":100,"summon_count":3,"proc_skill":{"s_uuid":6507,"chance":25,"overrides":{"buff_value":25,"TGroup": TGroup.Ally}}}, desc: "召唤 {summon_count} 道飓风攻击前方敌人,每道飓风造成 {ap}%伤害,每道飓风释放时有<color=#3CE66E>20</color>% 概率增加全体队友<color=#3CE66E>20</color>% 攻速" },
{ lv: 16, s_lv: SkillLv.Lv3, overrides: {"ap":100,"summon_count":4,"proc_skill":{"s_uuid":6507,"chance":20,"overrides":{"buff_value":20}}}, desc: "召唤 {summon_count} 道飓风攻击前方敌人,每道飓风造成 {ap}%伤害,每道飓风释放时有<color=#3CE66E>20</color>% 概率增加全体队友<color=#3CE66E>20</color>% 攻速" }, { lv: 16, s_lv: SkillLv.Lv3, overrides: {"ap":100,"summon_count":4,"proc_skill":{"s_uuid":6507,"chance":30,"overrides":{"buff_value":30,"TGroup": TGroup.Ally}}}, desc: "召唤 {summon_count} 道飓风攻击前方敌人,每道飓风造成 {ap}%伤害,每道飓风释放时有<color=#3CE66E>20</color>% 概率增加全体队友<color=#3CE66E>20</color>% 攻速" },
], ],
}, },
}, },
@@ -868,31 +893,31 @@ export const HeroInfo: Record<number, heroInfo> = {
], ],
info: "普攻 大招加速 buff+加速光环,加速大师", info: "普攻 大招加速 buff+加速光环,加速大师",
}, },
// 5013 反伤哥 // 5013 生命哥
5013: { 5013: {
uuid: 5013, name: "反伤哥", path: "hh2", fac: FacSet.HERO, rarity: 1, lv: 1, type: HType.Long, grow_type: HGrowType.Support, role: HRole.Support, hp: HERO_ROLE_BASE[HRole.Support].hp, ap: HERO_ROLE_BASE[HRole.Support].ap, def: HERO_ROLE_BASE[HRole.Support].def, uuid: 5013, name: "生命哥", path: "hh2", fac: FacSet.HERO, rarity: 1, lv: 1, type: HType.Long, grow_type: HGrowType.Support, role: HRole.Support, hp: HERO_ROLE_BASE[HRole.Support].hp, ap: HERO_ROLE_BASE[HRole.Support].ap, def: HERO_ROLE_BASE[HRole.Support].def,
skills: { skills: {
6004: { uuid: 6004, lv: 1, cd: AtkSpeedSet[AtkSpeedLv.Normal].cd, ccd: 0, 6004: { uuid: 6004, lv: 1, cd: AtkSpeedSet[AtkSpeedLv.Normal].cd, ccd: 0,
lv_entries: [ lv_entries: [
{ lv: 2, s_lv: SkillLv.Lv2, overrides: {"timed_buff_id":7029,"buff_value":10,"buff_chance":20} }, { lv: 2, s_lv: SkillLv.Lv2, overrides: {"ap":120} },
], ],
}, },
6515: { uuid: 6515, name: "荆棘护盾", lv: 1, cd: UltCdSet[UltCdLv.VerySlow].cd, ccd: 0, overrides: {"buff_value":20,"TGroup": TGroup.Ally,"hit_count":3,"buff_duration":5}, 6517: { uuid: 6517, name: "生命护盾", lv: 1, cd: UltCdSet[UltCdLv.VerySlow].cd, ccd: 0, overrides: {"buff_value":20,"TGroup": TGroup.Ally,"hit_count":3,"buff_duration":5},
lv_entries: [ lv_entries: [
{ lv: 8, s_lv: SkillLv.Lv2, overrides: {"buff_value":25,"TGroup": TGroup.Ally,"hit_count":3,"buff_duration":10} }, { lv: 8, s_lv: SkillLv.Lv2, overrides: {"buff_value":25,"TGroup": TGroup.Ally,"hit_count":3,"buff_duration":10} },
{ lv: 16, s_lv: SkillLv.Lv3, overrides: {"buff_value":30,"buff_duration":10,"hit_count":3,"TGroup": TGroup.Ally} }, { lv: 16, s_lv: SkillLv.Lv3, overrides: {"buff_value":30,"buff_duration":10,"hit_count":3,"TGroup": TGroup.Ally} },
], ],
}, },
}, },
fstart: { atking: {
6301: [ 6414: [
{ lv: 4, s_lv: SkillLv.Lv1, t_num: 1, overrides: {"ap":20} }, { lv: 4, s_lv: SkillLv.Lv1, t_num: 3, t_chance: 30, pity_add: 15, overrides: {"buff_value":10,"TGroup": TGroup.Ally} },
], ],
}, },
bonus: [ bonus: [
{ lv: 12, attrs: {"hp":50}, name: "守护之心", icon: "29-Endure", }, { lv: 12, attrs: {"hp":50}, name: "守护之心", icon: "29-Endure", },
], ],
info: "大招全体反伤 普攻暴击 暴击反伤辅助", info: "大招全体生命最大值+概率全体+反伤护盾",
}, },
// 5014 闪避哥 // 5014 闪避哥
5014: { 5014: {
@@ -900,7 +925,7 @@ export const HeroInfo: Record<number, heroInfo> = {
skills: { skills: {
6004: { uuid: 6004, name: "普攻强化", lv: 1, cd: AtkSpeedSet[AtkSpeedLv.Normal].cd, ccd: 0, 6004: { uuid: 6004, name: "普攻强化", lv: 1, cd: AtkSpeedSet[AtkSpeedLv.Normal].cd, ccd: 0,
lv_entries: [ lv_entries: [
{ lv: 2, s_lv: SkillLv.Lv2, overrides: {"timed_buff_id":7030,"buff_value":10,"buff_chance":20} }, { lv: 2, s_lv: SkillLv.Lv2, overrides: {"crt":10} },
], ],
}, },
6100: { uuid: 6100, name: "寒冰斩", lv: 1, cd: UltCdSet[UltCdLv.Normal].cd, ccd: 0, overrides: {"ap":200,"timed_buff_id":7030,"buff_value":50}, 6100: { uuid: 6100, name: "寒冰斩", lv: 1, cd: UltCdSet[UltCdLv.Normal].cd, ccd: 0, overrides: {"ap":200,"timed_buff_id":7030,"buff_value":50},
@@ -916,7 +941,7 @@ export const HeroInfo: Record<number, heroInfo> = {
bonus: [ bonus: [
{ lv: 12, attrs: {"hp":50}, name: "不屈战意", icon: "29-Endure", }, { lv: 12, attrs: {"hp":50}, name: "不屈战意", icon: "29-Endure", },
], ],
info: "", info: "强闪避",
}, },
// 5015 毒箭猎手 — 毒伤持续流:普攻淬毒叠层+毒雨铺DoT+攻击光环喂养毒伤 // 5015 毒箭猎手 — 毒伤持续流:普攻淬毒叠层+毒雨铺DoT+攻击光环喂养毒伤
5015: { 5015: {
@@ -924,24 +949,21 @@ export const HeroInfo: Record<number, heroInfo> = {
skills: { skills: {
6007: { uuid: 6007, name: "淬毒箭", lv: 1, cd: AtkSpeedSet[AtkSpeedLv.Normal].cd, ccd: 0, overrides: {"ap":100}, desc: "射出箭矢,对{target}造成攻击力{ap}%伤害", 6007: { uuid: 6007, name: "淬毒箭", lv: 1, cd: AtkSpeedSet[AtkSpeedLv.Normal].cd, ccd: 0, overrides: {"ap":100}, desc: "射出箭矢,对{target}造成攻击力{ap}%伤害",
lv_entries: [ lv_entries: [
{ lv: 2, s_lv: SkillLv.Lv2, overrides: {"timed_debuff_id":7005,"debuff_value":30,"debuff_chance":30}, desc: "普通攻击有{debuff_chance}%概率使目标中毒(每0.5秒受到{debuff_value}点伤害,持续{dur}秒)" }, { lv: 2, s_lv: SkillLv.Lv2, overrides: {"bck_chance":10}, desc: "普通攻击有{bck_chance}%概率击退敌人" },
], ],
}, },
6150: { uuid: 6150, name: "万箭齐发·毒", lv: 1, cd: UltCdSet[UltCdLv.Normal].cd, ccd: 0, overrides: {"ap":150,"timed_debuff_id":7005,"debuff_value":30,"debuff_chance":50,"icon":"4-Apply-Poison"}, desc: "毒箭如雨,对{target}造成攻击力{ap}%伤害,{debuff_chance}%概率使目标中毒(每0.5秒受到{debuff_value}点伤害,持续{dur}秒)", 6150: { uuid: 6150, name: "万箭齐发·毒", lv: 1, cd: UltCdSet[UltCdLv.Normal].cd, ccd: 0, overrides: {"ap":150,"timed_debuff_id":7005,"debuff_value":-30,"debuff_chance":50,"icon":"4-Apply-Poison"}, desc: "毒箭如雨,对{target}造成攻击力{ap}%伤害,{debuff_chance}%概率使目标中毒(每0.5秒受到{debuff_value}点伤害,持续{dur}秒)",
lv_entries: [ lv_entries: [
{ lv: 8, s_lv: SkillLv.Lv2, overrides: {"ap":200,"buff_value":40,"buff_chance":60} }, { lv: 8, s_lv: SkillLv.Lv2, overrides: {"ap":200,"timed_debuff_id":7005,"debuff_value":-60,"debuff_chance":100,"debuff_duration":5} },
{ lv: 16, s_lv: SkillLv.Lv3, overrides: {"ap":250,"buff_value":60,"buff_chance":80,"hit_count":2}, desc: "毒箭如雨,对{target}造成攻击力{ap}%伤害,{buff_chance}%概率使目标中毒(每0.5秒受到{buff_value}点伤害,持续{dur}秒),每支箭可命中{hit_count}个目标" }, { lv: 16, s_lv: SkillLv.Lv3, overrides: {"ap":250,"timed_debuff_id":7005,"debuff_value":-100,"debuff_chance":100,"debuff_duration":7} },
], ],
}, },
}, },
atking: { atking: {
6007: [ 6007: [
{ lv: 4, s_lv: SkillLv.Lv1, name: "蚀骨毒箭", t_num: 3, overrides: {"ap":80,"timed_debuff_id":7005,"debuff_value":40,"debuff_chance":100}, desc: "追加射出蚀骨毒箭,对{target}造成攻击力{ap}%伤害,必定使目标中毒(每0.5秒受到{debuff_value}点伤害,持续{dur}秒)" }, { lv: 4, s_lv: SkillLv.Lv1, name: "蚀骨毒箭", t_num: 3, t_chance: 50, pity_add: 20, overrides: {"ap":80,"timed_debuff_id":7005,"debuff_value":40,"debuff_chance":100}, desc: "追加射出蚀骨毒箭,对{target}造成攻击力{ap}%伤害,必定使目标中毒(每0.5秒受到{debuff_value}点伤害,持续{dur}秒)" },
], ],
}, },
field: [
{ lv: 4, uuids: [{ uuid: 7002, value: 0.1, name: "淬毒磨砺" }] },
],
bonus: [ bonus: [
{ lv: 12, attrs: {"ap":50}, name: "剧毒淬炼", icon: "27-Hawkeye", }, { lv: 12, attrs: {"ap":50}, name: "剧毒淬炼", icon: "27-Hawkeye", },
], ],
@@ -953,23 +975,18 @@ export const HeroInfo: Record<number, heroInfo> = {
skills: { skills: {
6008: { uuid: 6008, name: "连珠箭", lv: 1, cd: AtkSpeedSet[AtkSpeedLv.VeryFast].cd, ccd: 0, overrides: {"ap":100}, desc: "极速连射,对{target}造成攻击力{ap}%伤害", 6008: { uuid: 6008, name: "连珠箭", lv: 1, cd: AtkSpeedSet[AtkSpeedLv.VeryFast].cd, ccd: 0, overrides: {"ap":100}, desc: "极速连射,对{target}造成攻击力{ap}%伤害",
lv_entries: [ lv_entries: [
{ lv: 2, s_lv: SkillLv.Lv2, overrides: {"crt":20,"proc_skill":{"s_uuid":6007,"chance":20,"overrides":{"crt":100}}}, desc: "普通攻击暴击率提升{crt}%,并有概率触发连射追箭(必定暴击)" }, { lv: 2, s_lv: SkillLv.Lv2, overrides: {"proc_skill":{"s_uuid":6007,"chance":20,"overrides":{"TGroup": TGroup.Enemy,"ap":80}}}, desc: "有 20%额外射击,造成 80% 伤害" },
], ],
}, },
6151: { uuid: 6151, name: "裂空箭雨", lv: 1, cd: UltCdSet[UltCdLv.VeryFast].cd, ccd: 0, overrides: {"ap":150,"crt":30,"summon_count":5}, desc: "箭雨倾泻,对{target}造成攻击力{ap}%伤害,{crt}%概率暴击", 6151: { uuid: 6151, name: "裂空箭雨", lv: 1, cd: UltCdSet[UltCdLv.VeryFast].cd, ccd: 0, overrides: {"ap":150,"crt":30,"summon_count":5}, desc: "箭雨倾泻,对{target}造成攻击力{ap}%伤害,{crt}%概率暴击",
lv_entries: [ lv_entries: [
{ lv: 8, s_lv: SkillLv.Lv2, overrides: {"ap":200,"crt":50} }, { lv: 8, s_lv: SkillLv.Lv2, overrides: {"ap":200,"crt":50} },
{ lv: 16, s_lv: SkillLv.Lv3, overrides: {"ap":250,"crt":70,"summon_count":6,"hit_count":2}, desc: "箭雨倾泻,对{target}造成攻击力{ap}%伤害,{crt}%概率暴击,每支箭可命中{hit_count}个目标" }, { lv: 16, s_lv: SkillLv.Lv3, overrides: {"ap":250,"crt":70,"summon_count":6}, desc: "箭雨倾泻,对{target}造成攻击力{ap}%伤害,{crt}%概率暴击,每支箭可命中{hit_count}个目标" },
], ],
}, },
}, },
fstart: {
6504: [
{ lv: 4, s_lv: SkillLv.Lv1, name: "猎杀时刻", t_num: 1, overrides: {"buff_value":30}, desc: "战斗开始时释放暴击爆发,全体友方暴击率提升{buff_value}%,持续{dur}秒" },
],
},
field: [ field: [
{ lv: 4, uuids: [{ uuid: 7004, value: 0.15, name: "猎手集结" }] }, { lv: 4, uuids: [{ uuid: 7004, value: 0.1, name: "猎手集结" }] },
], ],
bonus: [ bonus: [
{ lv: 12, attrs: {"ap":50}, name: "猎杀直觉", icon: "27-Hawkeye", }, { lv: 12, attrs: {"ap":50}, name: "猎杀直觉", icon: "27-Hawkeye", },
@@ -985,18 +1002,13 @@ export const HeroInfo: Record<number, heroInfo> = {
{ lv: 2, s_lv: SkillLv.Lv2, overrides: {"timed_debuff_id":7008,"debuff_chance":30}, desc: "普通攻击有{debuff_chance}%概率使目标破甲(防御降低,持续{dur}秒)" }, { lv: 2, s_lv: SkillLv.Lv2, overrides: {"timed_debuff_id":7008,"debuff_chance":30}, desc: "普通攻击有{debuff_chance}%概率使目标破甲(防御降低,持续{dur}秒)" },
], ],
}, },
6203: { uuid: 6203, name: "碎甲能量波", lv: 1, cd: UltCdSet[UltCdLv.Normal].cd, ccd: 0, overrides: {"ap":150,"timed_debuff_id":7008}, desc: "释放碎甲能量波,对{target}造成攻击力{ap}%伤害,并使目标破甲(防御降低,持续{dur}秒)", 6203: { uuid: 6203, name: "碎甲能量波", lv: 1, cd: UltCdSet[UltCdLv.Normal].cd, ccd: 0, overrides: {"ap":150,"timed_debuff_id":7008,"debuff_value":-30,"debuff_chance":100,"debuff_duration":5}, desc: "释放碎甲能量波,对{target}造成攻击力{ap}%伤害,并使目标破甲(防御降低,持续{dur}秒)",
lv_entries: [ lv_entries: [
{ lv: 8, s_lv: SkillLv.Lv2, overrides: {"ap":200} }, { lv: 8, s_lv: SkillLv.Lv2, overrides: {"ap":200,"timed_debuff_id":7008,"debuff_value":-50,"debuff_chance":100,"debuff_duration":5} },
{ lv: 16, s_lv: SkillLv.Lv3, overrides: {"ap":250,"buff_value":-70}, desc: "释放碎甲能量波,对{target}造成攻击力{ap}%伤害,并使目标破甲加深(防御大幅降低,持续{dur}秒)" }, { lv: 16, s_lv: SkillLv.Lv3, overrides: {"ap":250,"timed_debuff_id":7008,"debuff_value":-70,"debuff_chance":100,"debuff_duration":7}, desc: "释放碎甲能量波,对{target}造成攻击力{ap}%伤害,并使目标破甲加深(防御大幅降低,持续{dur}秒)" },
], ],
}, },
}, },
fstart: {
6012: [
{ lv: 4, s_lv: SkillLv.Lv1, name: "先手蚀甲", t_num: 1, overrides: {"ap":150,"timed_debuff_id":7008}, desc: "战斗开始时掷出蚀甲酸瓶,对{target}造成攻击力{ap}%伤害,并必定使其破甲(防御降低,持续{dur}秒)" },
],
},
field: [ field: [
{ lv: 4, uuids: [{ uuid: 7009, value: 0.1, name: "锐矛之赐" }] }, { lv: 4, uuids: [{ uuid: 7009, value: 0.1, name: "锐矛之赐" }] },
], ],
@@ -1009,60 +1021,26 @@ export const HeroInfo: Record<number, heroInfo> = {
5018: { 5018: {
uuid: 5018, name: "雷暴领主", path: "hm4", fac: FacSet.HERO, rarity: 1, lv: 1, type: HType.Long, grow_type: HGrowType.Mage, role: HRole.Mage, hp: HERO_ROLE_BASE[HRole.Mage].hp - 10, ap: HERO_ROLE_BASE[HRole.Mage].ap + 20, def: HERO_ROLE_BASE[HRole.Mage].def, uuid: 5018, name: "雷暴领主", path: "hm4", fac: FacSet.HERO, rarity: 1, lv: 1, type: HType.Long, grow_type: HGrowType.Mage, role: HRole.Mage, hp: HERO_ROLE_BASE[HRole.Mage].hp - 10, ap: HERO_ROLE_BASE[HRole.Mage].ap + 20, def: HERO_ROLE_BASE[HRole.Mage].def,
skills: { skills: {
6009: { uuid: 6009, name: "雷霆弹", lv: 1, cd: AtkSpeedSet[AtkSpeedLv.Fast].cd, ccd: 0, overrides: {"ap":100}, desc: "掷出雷霆弹,对{target}造成攻击力{ap}%伤害", 6013: { uuid: 6013, name: "召唤闪电", lv: 1, cd: AtkSpeedSet[AtkSpeedLv.Fast].cd, ccd: 0, overrides: {"ap":100}, desc: "召唤闪电,对{target}造成攻击力{ap}%伤害",
lv_entries: [ lv_entries: [
{ lv: 2, s_lv: SkillLv.Lv2, overrides: {"para":15}, desc: "普通攻击有{para}%概率麻痹敌人,减缓其技能冷却恢复" }, { lv: 2, s_lv: SkillLv.Lv2, overrides: {"para":15}, desc: "普通攻击有{para}%概率麻痹敌人,减缓其技能冷却恢复" },
], ],
}, },
6203: { uuid: 6203, name: "雷霆裂空", lv: 1, cd: UltCdSet[UltCdLv.Normal].cd, ccd: 0, overrides: {"ap":200,"para":40}, desc: "释放雷霆裂空波,对{target}造成攻击力{ap}%伤害,{para}%概率麻痹敌人", 6204: { uuid: 6204, name: "雷霆裂空", lv: 1, cd: UltCdSet[UltCdLv.Normal].cd, ccd: 0, overrides: {"ap":150,"para":50}, desc: "释放多束闪电,对{target}造成攻击力{ap}%伤害,{para}%概率麻痹敌人",
lv_entries: [ lv_entries: [
{ lv: 8, s_lv: SkillLv.Lv2, overrides: {"ap":250,"para":60}, desc: "释放雷霆裂空波,对{target}造成攻击力{ap}%伤害,{para}%概率麻痹敌人" }, { lv: 8, s_lv: SkillLv.Lv2, overrides: {"ap":200,"para":70}, desc: "释放雷霆裂空波,对{target}造成攻击力{ap}%伤害,{para}%概率麻痹敌人" },
{ lv: 16, s_lv: SkillLv.Lv3, overrides: {"ap":300,"para":80,"hit_count":3}, desc: "释放雷霆裂空波,对{target}造成攻击力{ap}%伤害,可多次命中,{para}%概率麻痹敌人" }, { lv: 16, s_lv: SkillLv.Lv3, overrides: {"ap":250,"para":100}, desc: "释放雷霆裂空波,对{target}造成攻击力{ap}%伤害,可多次命中,{para}%概率麻痹敌人" },
], ],
}, },
}, },
fstart: {
6203: [
{ lv: 4, s_lv: SkillLv.Lv1, name: "雷击先手", t_num: 1, overrides: {"ap":150,"para":30,"icon":"100-Enchant-Magic"}, desc: "战斗开始释放雷击,对{target}造成攻击力{ap}%伤害,{para}%概率麻痹敌人" },
],
},
field: [ field: [
{ lv: 4, uuids: [{ uuid: 7003, value: 10, name: "雷云领域" }] }, { lv: 4, uuids: [{ uuid: 7024, value: 10, name: "雷电精准" }] },
], ],
bonus: [ bonus: [
{ lv: 12, attrs: {"ap":50}, name: "奥术共鸣", icon: "100-Enchant-Magic", }, { lv: 12, attrs: {"ap":50}, name: "奥术共鸣", icon: "100-Enchant-Magic", },
], ],
info: "雷暴爆发+麻痹控场,法系主C", info: "雷暴爆发+麻痹控场,法系主C",
}, },
// 5019 圣盾贤者 — 护盾反伤生存法:全队圣盾+荆棘反伤+受击荆棘
5019: {
uuid: 5019, name: "圣盾贤者", path: "hm5", fac: FacSet.HERO, rarity: 1, lv: 1, type: HType.Long, grow_type: HGrowType.Mage, role: HRole.Mage, hp: HERO_ROLE_BASE[HRole.Mage].hp + 20, ap: HERO_ROLE_BASE[HRole.Mage].ap - 5, def: HERO_ROLE_BASE[HRole.Mage].def + 5,
skills: {
6011: { uuid: 6011, name: "圣光飞瓶", lv: 1, cd: AtkSpeedSet[AtkSpeedLv.Normal].cd, ccd: 0, overrides: {"ap":100}, desc: "掷出圣光飞瓶,对{target}造成攻击力{ap}%伤害",
lv_entries: [
{ lv: 2, s_lv: SkillLv.Lv2, overrides: {"proc_skill":{"s_uuid":6516,"chance":20,"overrides":{"timed_buff_id":7028,"buff_value":10}}}, desc: "普通攻击概率凝聚荆棘护体(受击时反弹{buff_value}%所受伤害,持续{dur}秒)" },
],
},
6301: { uuid: 6301, name: "奥术圣壁", lv: 1, cd: UltCdSet[UltCdLv.VerySlow].cd, ccd: 0, overrides: {"TGroup": TGroup.Ally,"ap":20,"timed_buff_id":7027,"buff_value":10}, desc: "为全体友方施加生命最大值{ap}%的护盾,并附加荆棘(受击时反弹{buff_value}点伤害,持续{dur}秒)",
lv_entries: [
{ lv: 8, s_lv: SkillLv.Lv2, overrides: {"ap":30,"buff_value":15}, desc: "为全体友方施加生命最大值{ap}%的护盾,并附加荆棘(受击时反弹{buff_value}点伤害,持续{dur}秒)" },
{ lv: 16, s_lv: SkillLv.Lv3, overrides: {"ap":40,"buff_value":20}, desc: "为全体友方施加生命最大值{ap}%的护盾,并附加荆棘(受击时反弹{buff_value}点伤害,持续{dur}秒)" },
],
},
},
atked: {
6516: [
{ lv: 4, s_lv: SkillLv.Lv1, name: "荆棘回应", t_num: 3, overrides: {"timed_buff_id":7028,"buff_value":10,"icon":"75-Shield-Stun"}, desc: "凝聚荆棘护体,受击时反弹{buff_value}%所受伤害,持续{dur}秒" },
],
},
field: [
{ lv: 4, uuids: [{ uuid: 7022, value: 8, name: "荆棘领域" }] },
],
bonus: [
{ lv: 12, attrs: {"hp":50}, name: "守护之心", icon: "29-Endure", },
],
info: "全队护盾+荆棘反伤,生存反击法",
},
// @hero-setup:heroes-end // @hero-setup:heroes-end
/* /*
@@ -1142,9 +1120,9 @@ export const HeroInfo: Record<number, heroInfo> = {
}; };
export const HeroList: number[] = [ export const HeroList: number[] = [
// 编辑器导出自动同步(共 19 个) // 编辑器导出自动同步(共 18 个)
5001, 5002, 5003, 5004, 5005, 5006, 5007, 5008, 5009, 5010, 5001, 5002, 5003, 5004, 5005, 5006, 5007, 5008, 5009, 5010,
5011, 5012, 5013, 5014, 5015, 5016, 5017, 5018, 5019, 5011, 5012, 5013, 5014, 5015, 5016, 5017, 5018,
]; ];
// @hero-setup:region-end // @hero-setup:region-end
@@ -1164,48 +1142,48 @@ export interface HeroComboInfo {
} }
/** /**
* 推荐阵容表(几何王国复刻版 5001~5009)。 * 推荐阵容表(基于现役 5001~5018 英雄实际技能组)。
* 设计原则: * 设计原则:
* 1. 铁三角结构:1 前排(坦克)+ 1 增益(光环/先手)+ 1 主C * 1. 铁三角结构:heroes[0] 固定为近战前排(坦克/战士),其余按站位从近到远
* 2. 乘区分散:攻击/暴击/暴伤各占独立乘区,组合优先覆盖不同乘区避免稀释 * 2. 乘区分散:攻击/攻速/暴击/穿透各占独立乘区,组合优先覆盖不同乘区避免稀释
* 3. 发动机冗余:前排挨打/死亡触发增益,叠甲骑士(5005)死亡缠绕负责献祭点火 * 3. 主题唯一:每套阵容围绕一个流派关键词(暴击/控制/续航/破甲/光环/消耗)组队
*/ */
export const HeroComboSet: Record<number, HeroComboInfo> = { export const HeroComboSet: Record<number, HeroComboInfo> = {
// 8001 暴击爆发流 — 暴击率与暴伤双乘区互不稀释,成型最强 // 8001 暴击爆发流 — 连珠神射暴击光环喂养双物理C,成型最强
8001: { 8001: {
uuid: 8001, name: "暴击爆发流", uuid: 8001, name: "暴击爆发流",
heroes: [5005, 5008, 5002], heroes: [5001, 5016, 5004],
desc: "叠甲骑士前排抗伤叠甲,刀刀暴击的暴击光环与眩晕暴击哥的暴伤光环组成双乘区,双近战暴击爆发收割。", desc: "叠甲骑士前排抗伤+受击叠防,连珠神射暴击光环覆盖全队并以极速箭雨压场,刀刀暴击近战收割残局。",
}, },
// 8002 冰雷控制流 — 冰冻+击晕双控场,敌人出不了手 // 8002 冰雷控制流 — 击晕+冰冻+麻痹三控链,敌人出不了手
8002: { 8002: {
uuid: 8002, name: "冰雷控制流", uuid: 8002, name: "冰雷控制流",
heroes: [5007, 5004, 5001], heroes: [5003, 5006, 5018],
desc: "微醺战神前排击退压场,冻住不谢冰冻链配合紫电魔女能量波击退击晕,击晕光环叠加,全场控制。", desc: "眩晕暴击哥前排开山斧必晕压阵,冻箭哥寒冰箭冰冻链,雷暴领主雷霆麻痹迟滞技能,三控交替敌人难以出手。",
}, },
// 8003 铁桶续航流 — 双防御前排+双治疗保血,最稳 // 8003 铁桶续航流 — 双坦克承伤+治疗保血,最稳
8003: { 8003: {
uuid: 8003, name: "铁桶续航流", uuid: 8003, name: "铁桶续航流",
heroes: [5005, 5009, 5006], heroes: [5009, 5011, 5008],
desc: "叠甲骑士与铁壳斧弟双前排叠甲叠防,光明奶爸治疗+生命光环抬全队血线,专打持久消耗战。", desc: "甲虫领主受击自疗顶前排,控血大师受击全队永久生命成长+大招生命爆发,团疗奶爸全体治疗+战后回复光环,专打持久战。",
}, },
// 8004 先手爆发流 — 入场剑气先手+能量波跟进,短回合最强 // 8004 破甲压制流 — 破甲+减攻双减益,克制高防高攻阵容
8004: { 8004: {
uuid: 8004, name: "先手爆发流", uuid: 8004, name: "破甲压制流",
heroes: [5003, 5001, 5008], heroes: [5001, 5017, 5010],
desc: "格挡反杀入场500%剑气先手压血线,紫电魔女能量波击退跟进,眩晕暴击哥开山斧收割残局。", desc: "碎甲术士普攻/大招双通道破甲+穿透光环放大物理伤害,火箭哥五箭弹幕必挂减攻削弱敌方输出,叠甲骑士前排兜底。",
}, },
// 8005 破甲推进流 — 易伤放大全队伤害,克制高血Boss // 8005 光环覆盖流 — 闪避/攻击/攻速三光环全覆盖
8005: { 8005: {
uuid: 8005, name: "破甲推进流", uuid: 8005, name: "光环覆盖流",
heroes: [5007, 5006, 5002], heroes: [5014, 5007, 5012],
desc: "微醺战神气斩易伤放大全队伤害,光明奶爸治疗保前排,刀刀暴击吃满易伤与自身暴击完成推进。", desc: "闪避哥前排+闪避光环提升全队生存,击退火女攻击光环、疾风法师攻速光环持续放大全队输出,三光环增益拉满。",
}, },
// 8006 光环覆盖流 — 攻击/暴击/暴伤/生命光环全覆盖 // 8006 易伤消耗流 — 易伤放大出血DoT,磨血收割
8006: { 8006: {
uuid: 8006, name: "光环覆盖流", uuid: 8006, name: "易伤消耗流",
heroes: [5002, 5006, 5001], heroes: [5002, 5005, 5008],
desc: "刀刀暴击暴击+暴伤双光环、紫电魔女攻击光环、光明奶爸生命光环,四光环全覆盖持续放大全队输出。", desc: "易伤剑仙气斩+普攻双通道挂易伤放大全队伤害,出血贼普攻+大招叠出血磨血,团疗奶爸治疗保前排打消耗战。",
}, },
}; };
@@ -1280,9 +1258,9 @@ export const HERO_POWER_WEIGHTS = {
* 解析触发技能在目标等级下的有效条目列表。 * 解析触发技能在目标等级下的有效条目列表。
* 每个 s_uuid 取 ≤lv 的最大档;返回扁平数组供评分/触发器消费。 * 每个 s_uuid 取 ≤lv 的最大档;返回扁平数组供评分/触发器消费。
*/ */
export function resolveTriggerByLv(grouped: TriggerGrouped | undefined, lv: number): { s_uuid: number; t_num: number; overrides?: SkillOverrides }[] { export function resolveTriggerByLv(grouped: TriggerGrouped | undefined, lv: number): ResolvedTriggerEntry[] {
if (!grouped) return []; if (!grouped) return [];
const result: { s_uuid: number; t_num: number; overrides?: SkillOverrides }[] = []; const result: ResolvedTriggerEntry[] = [];
for (const key in grouped) { for (const key in grouped) {
const entries = grouped[key]; const entries = grouped[key];
if (!entries || entries.length === 0) continue; if (!entries || entries.length === 0) continue;
@@ -1290,7 +1268,7 @@ export function resolveTriggerByLv(grouped: TriggerGrouped | undefined, lv: numb
for (const e of entries) { for (const e of entries) {
if (e.lv <= lv && (!pick || e.lv > pick.lv)) pick = e; if (e.lv <= lv && (!pick || e.lv > pick.lv)) pick = e;
} }
if (pick) result.push({ s_uuid: Number(key), t_num: pick.t_num, overrides: pick.overrides }); if (pick) result.push({ s_uuid: Number(key), t_num: pick.t_num, t_chance: pick.t_chance, pity_add: pick.pity_add, overrides: pick.overrides });
} }
return result; return result;
} }
@@ -1595,7 +1573,7 @@ export interface HeroPowerDetailed {
/** 计算普通触发类技能(atking/atked/fstart/dead)的详细价值 */ /** 计算普通触发类技能(atking/atked/fstart/dead)的详细价值 */
function calcTriggerPowerDetailed( function calcTriggerPowerDetailed(
triggerConfigs: { s_uuid: number, t_num?: number, overrides?: SkillOverrides }[], triggerConfigs: ResolvedTriggerEntry[],
hero: heroInfo, hero: heroInfo,
targetLv: number, targetLv: number,
type: SkillTriggerType, type: SkillTriggerType,
@@ -1636,7 +1614,9 @@ function calcTriggerPowerDetailed(
} }
const triggerCount = getTriggerCount(type, tNum, hero, seconds); const triggerCount = getTriggerCount(type, tNum, hero, seconds);
const value = effectValue * triggerCount * scopeMul * weight; // 期望折算:按基础触发概率缩放(保底叠加提升的是方差体验,不影响长期期望)
const chanceMul = (trig.t_chance ?? 100) / 100;
const value = effectValue * triggerCount * scopeMul * weight * chanceMul;
total += value; total += value;
items.push({ type, s_uuid: trig.s_uuid, name: skill.name, t_num: tNum, value }); items.push({ type, s_uuid: trig.s_uuid, name: skill.name, t_num: tNum, value });
} }

View File

@@ -1,9 +1,23 @@
uuid,英雄名称,简化说明,rarity,类型,形态,ap,hp,def,skill[0]_lv1,skill[0]_lv2,skill[1]_lv1,skill[1]_lv8,skill[1]_lv16,atking[0]_lv4,atked[0]_lv4,fstart[0]_lv4,dead[0]_lv4,field[0]_lv4 字段,5001,5002,5003,5004,5005,5006,5007,5008,5009,5010,5011,5012,5013,5014,5015,5016,5017,5018,5019
5001,叠甲骑士,CSV导入:自身护盾+全体护盾,1,tank,近战,tank,tank+20,tank+10,6004 强化普攻(ap100;慢速1.20s;触发飞剑6001(100%)),ap120,6301 魔法盾(ap30),ap60,ap120,无,6301 全体圣盾(t_num3;ap10):全队获得本英雄生命最大值{ap}%的护盾,无,无,无 英雄名称,叠甲骑士,易伤剑仙,眩晕暴击哥,刀刀暴击,出血贼,冻箭哥,击退火女,团疗奶爸,甲虫领主,火箭哥,控血大师,疾风法师,反伤哥,闪避哥,毒箭猎手,连珠神射,碎甲术士,雷暴领主,圣盾贤者
5002,易伤剑仙,CSV导入:击退压场+易伤放大;复刻酒仙,1,warrior,近战,warrior+20,warrior+5,warrior+5,6004 强化普攻(ap100;慢速1.20s),ap120,6101 气斩(ap150;附加易伤7002),,ap180;bck60,6004 风暴打击(t_num3;ap300):立刻打击{target},造成攻击力{ap}%伤害,无,无,无,无 简化说明,CSV导入:自身护盾+全体护盾,CSV导入:击退压场+易伤放大;复刻酒仙,CSV导入:高爆发+击晕收割;复刻齐天大圣,CSV导入:暴击/暴伤双光环乘区;复刻剑圣,CSV导入:入场先手+受击格挡;复刻剑豪,CSV导入:多重单体箭,带冰冻,CSV导入:群体击退/麻痹压场;复刻深渊女王,CSV导入:全体治疗续航+自身护盾,,,,,,,毒伤持续流:普攻淬毒叠层+毒雨铺DoT+攻击光环喂养毒伤,暴击连射爆发流:VeryFast极速普攻+概率追射必暴箭+开局团队暴击爆发,破甲减防法师:fstart先手/普攻概率/大招必定三通道施加破甲7008+穿透光环,团队物理增伤位,雷暴AOE爆发+麻痹控场:先手雷击+高倍率能量波,护盾反伤生存法:全队圣盾+荆棘反伤+受击荆棘
5003,眩晕暴击哥,CSV导入:高爆发+击晕收割;复刻齐天大圣,1,warrior,近战,warrior+20,warrior+5,warrior+5,6004 强化普攻(ap100;慢速1.20s),stun10,6104 开山斧(ap300;stun100),ap450;stun100,ap450;stun100,无,无,无,无,7005 大圣神威0.25 rarity,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1
5004,刀刀暴击,CSV导入:暴击/暴伤双光环乘区;复刻剑圣,1,assassin,中程,assassin+30,assassin,assassin,6002 强化普攻(ap100;快速0.90s),crt10,6100 光闪(ap150),ap250,ap350,无,无,无,无,7004 剑刃风暴0.12+7005 斩魂利刃0.2 类型,tank,warrior,warrior,assassin,assassin,archer,mage,support,tank,archer,tank,mage,support,warrior,archer,archer,mage,mage,mage
5005,出血贼,CSV导入:入场先手+受击格挡;复刻剑豪,1,assassin,中程,assassin+30,assassin,assassin,6002 强化普攻(ap100;快速0.90s),附加30出血7007buff_chance30,6103 闪电斩(ap150),ap250;附加出血7007,ap350;para50;附加60出血7007,无,无,无,无,7018 连击光环1 形态,近战,近战,近战,中程,中程,远程,远程,远程,近战,中程,近战,远程,远程,近战,远程,中程,远程,远程,远程
5006,冻箭哥,CSV导入:多重单体箭,带冰冻,1,archer,远程,archer+30,archer,archer,6006 强化普攻(ap100;中速1.05s),bck10,6150 万箭齐发·冰(ap150;frz30),ap200;frz50,ap250;frz70,无,无,无,无,7006 攻速光环0.15 ap,tank,warrior+20,warrior+20,assassin+30,assassin+30,archer+30,mage+10,support+20,tank,archer,tank,mage,support,warrior,archer,archer+10,mage+10,mage+20,mage-5
5007,击退火女,CSV导入:群体击退/麻痹压场;复刻深渊女王,1,mage,远程,mage+10,mage-5,mage,6010 强化普攻(ap100;慢速1.20s;bck30),bck40,6200 火焰喷射(ap250;bck100),ap350;bck100,ap450;bck100;summon2,无,无,无,无,7002 深渊威压0.15 hp,tank+20,warrior+5,warrior+5,assassin,assassin,archer,mage-5,support+10,tank,archer,tank,mage,support,warrior,archer+10,archer,mage,mage-10,mage+20
5008,团疗奶爸,CSV导入:全体治疗续航+自身护盾,1,support,远程,support+20,support+10,support,6011 强化普攻(ap100;中速1.05s),bck10,6302 治疗(ap30),ap40,ap50,6301 圣愈之盾(t_num3;ap30):{target}获得生命最大值{ap}%的护盾,无,无,无,无 def,tank+10,warrior+5,warrior+5,assassin,assassin,archer,mage,support,tank,archer,tank,mage,support,warrior,archer,archer,mage,mage,mage+5
dodge,,,,,,,,,,,,,,,,,,,
accuracy,,,,,,,,,,,,,,,,,,,
skill[0]_lv1,6004 强化普攻(ap100;慢速1.20s),6004 强化普攻(ap100;慢速1.20s),6004 强化普攻(ap100;慢速1.20s),6002 强化普攻(ap100;快速0.90s),6002 强化普攻(ap100;快速0.90s),6006 强化普攻(ap100;中速1.05s),6010 强化普攻(ap100;慢速1.20s),6011 强化普攻(ap100;中速1.05s),6004 普攻强化(慢速1.20s),6006 强化普攻(快速0.90s),6004 普攻强化(中速1.05s),6009 普攻强化(中速1.05s),6004 攻击(中速1.05s),6004 普攻强化(中速1.05s),6007 淬毒箭(ap100;中速1.05s),6008 连珠箭(ap100;极速0.75s),6012 蚀甲酸瓶(ap100;中速1.05s),6009 雷霆弹(ap100;快速0.90s),6011 圣光飞瓶(ap100;中速1.05s)
skill[0]_lv2,ap120,ap120,stun10,crt10,命中附加30出血7007debuff_chance30,frz10,,ap120,施法触发计时回血6502(10%;ap5),ap100,施法触发计时回血6502(10%;ap5),施法触发攻速爆发6507(10%),附加10生命爆发7029buff_chance20,附加10闪避爆发7030buff_chance20,命中附加30中毒7005debuff_chance30,crt20;施法触发蓝箭6007(20%),命中附加破甲7008debuff_chance30,para15,施法触发次级反伤6516(20%)
skill[1]_lv1,6301 魔法盾(ap30),6101 气斩(ap150;命中附加易伤7002),6104 开山斧(ap300;stun100),6100 光闪(ap150),6103 闪电斩(ap150),6150 万箭齐发·冰(ap150;frz30),6200 火焰喷射(ap250;bck100),6302 治疗(ap30),6102 火焰斩(ap250;bck30),6151 万箭齐发.火(ap70;summon5),6517 生命爆发(),6201 飓风(ap100;summon2;施法触发攻速爆发6507(20%)),6515 荆棘护盾(),6100 寒冰斩(ap200;附加50闪避爆发7030),6150 万箭齐发·毒(ap150;命中附加30中毒7005debuff_chance50),6151 裂空箭雨(ap150;crt30;summon5),6203 碎甲能量波(ap150;命中附加破甲7008),6203 雷霆裂空(ap200;para40),6301 奥术圣壁(ap20;附加10荆棘7027)
skill[1]_lv8,ap60,,ap450;stun100,ap250,ap250;命中附加40出血7007,ap200;frz50,ap350;bck100,ap40,ap300;bck50,ap80;summon5,,ap100;summon3;施法触发攻速爆发6507(20%),,ap250;附加50闪避爆发7030,ap200,ap200;crt50,ap200,ap250;para60,ap30
skill[1]_lv16,ap120,ap180;bck60,ap450;stun100,ap350,ap350;命中附加60出血7007,ap250;frz70,ap450;bck100;summon2,ap50,ap350;bck70,ap100;summon6,,ap100;summon4;施法触发攻速爆发6507(20%),,ap350;附加80闪避爆发7030,ap250,ap250;crt70;summon6,ap250,ap300;para80,ap40
atking[0]_lv4,无,6004 风暴打击(t_num3;ap300):立刻打击{target},造成攻击力{ap}%伤害,无,无,无,无,无,6301 圣愈之盾(t_num3;ap30):{target}获得生命最大值{ap}%的护盾,无,6008 红箭(t_num3;ap120):,无,无,无,无,6007 蚀骨毒箭(t_num3;ap80):追加射出蚀骨毒箭,对{target}造成攻击力{ap}%伤害,必定使目标中毒(每0.5秒受到{debuff_value}点伤害,持续{dur}秒),无,无,无,无
atked[0]_lv4,6302 治疗(t_num3;概率50%;ap10):有 {t_chance}% 的概率,治疗自己 {ap}%生命最大值,无,无,无,无,无,无,无,6302 治疗(t_num3;ap5):为自己释放治疗,恢复生命值的{ap}%,无,6402 生命强化(t_num5;ap1):全队永久增加 1% 生命最大值,无,无,无,无,无,无,无,6516 荆棘回应(t_num3):凝聚荆棘护体,受击时反弹{buff_value}%所受伤害,持续{dur}秒
fstart[0]_lv4,无,无,无,无,无,无,无,无,无,无,无,无,6301 护盾(t_num1;ap20):,无,无,6504 猎杀时刻(t_num1):战斗开始时释放暴击爆发,全体友方暴击率提升{buff_value}%,持续{dur}秒,6012 先手蚀甲(t_num1;ap150):战斗开始时掷出蚀甲酸瓶,对{target}造成攻击力{ap}%伤害,并必定使其破甲(防御降低,持续{dur}秒),6203 雷击先手(t_num1;ap150):战斗开始释放雷击,对{target}造成攻击力{ap}%伤害,{para}%概率麻痹敌人,无
fend[0]_lv4,无,无,无,无,无,无,无,无,无,无,无,无,无,无,无,无,无,无,无
dead[0]_lv4,无,无,无,无,无,无,无,无,无,无,无,无,无,无,无,无,无,无,无
field[0]_lv4,无,无,7005 大圣神威0.25,7004 剑刃风暴0.12+7005 斩魂利刃0.2,7002 攻击光环10,7006 攻速光环0.15,7002 深渊威压0.15,无,无,无,无,7006 攻速光环10,无,7023 闪避光环10,7002 淬毒磨砺0.1,7004 猎手集结0.15,7009 锐矛之赐0.1,7003 雷云领域10,7022 荆棘领域8
bonus,lv12 def+50%,lv12 hp+50%,lv12 hp+50%,lv12 ap+50%,lv12 ap+50%,lv12 ap+50%,lv12 ap+50%,lv12 hp+50%,lv12 def+50%,lv12 ap+50%,lv12 def+50%,lv12 ap+50%,lv12 hp+50%,lv12 hp+50%,lv12 ap+50%,lv12 ap+50%,lv12 ap+50%,lv12 ap+50%,lv12 hp+50%
1 uuid 字段 英雄名称 5001 简化说明 5002 rarity 5003 类型 5004 形态 5005 ap 5006 hp 5007 def 5008 skill[0]_lv1 5009 skill[0]_lv2 5010 skill[1]_lv1 5011 skill[1]_lv8 5012 skill[1]_lv16 5013 atking[0]_lv4 5014 atked[0]_lv4 5015 fstart[0]_lv4 5016 dead[0]_lv4 5017 field[0]_lv4 5018 5019
2 5001 英雄名称 叠甲骑士 叠甲骑士 CSV导入:自身护盾+全体护盾 易伤剑仙 1 眩晕暴击哥 tank 刀刀暴击 近战 出血贼 tank 冻箭哥 tank+20 击退火女 tank+10 团疗奶爸 6004 强化普攻(ap100;慢速1.20s;触发飞剑6001(100%)) 甲虫领主 ap120 火箭哥 6301 魔法盾(ap30) 控血大师 ap60 疾风法师 ap120 反伤哥 无 闪避哥 6301 全体圣盾(t_num3;ap10):全队获得本英雄生命最大值{ap}%的护盾 毒箭猎手 无 连珠神射 无 碎甲术士 无 雷暴领主 圣盾贤者
3 5002 简化说明 易伤剑仙 CSV导入:自身护盾+全体护盾 CSV导入:击退压场+易伤放大;复刻酒仙 CSV导入:击退压场+易伤放大;复刻酒仙 1 CSV导入:高爆发+击晕收割;复刻齐天大圣 warrior CSV导入:暴击/暴伤双光环乘区;复刻剑圣 近战 CSV导入:入场先手+受击格挡;复刻剑豪 warrior+20 CSV导入:多重单体箭,带冰冻 warrior+5 CSV导入:群体击退/麻痹压场;复刻深渊女王 warrior+5 CSV导入:全体治疗续航+自身护盾 6004 强化普攻(ap100;慢速1.20s) ap120 6101 气斩(ap150;附加易伤7002) ap180;bck60 6004 风暴打击(t_num3;ap300):立刻打击{target},造成攻击力{ap}%伤害 无 毒伤持续流:普攻淬毒叠层+毒雨铺DoT+攻击光环喂养毒伤 无 暴击连射爆发流:VeryFast极速普攻+概率追射必暴箭+开局团队暴击爆发 无 破甲减防法师:fstart先手/普攻概率/大招必定三通道施加破甲7008+穿透光环,团队物理增伤位 无 雷暴AOE爆发+麻痹控场:先手雷击+高倍率能量波 护盾反伤生存法:全队圣盾+荆棘反伤+受击荆棘
4 5003 rarity 眩晕暴击哥 1 CSV导入:高爆发+击晕收割;复刻齐天大圣 1 1 1 warrior 1 近战 1 warrior+20 1 warrior+5 1 warrior+5 1 6004 强化普攻(ap100;慢速1.20s) 1 stun10 1 6104 开山斧(ap300;stun100) 1 ap450;stun100 1 ap450;stun100 1 无 1 无 1 无 1 无 1 7005 大圣神威0.25 1 1
5 5004 类型 刀刀暴击 tank CSV导入:暴击/暴伤双光环乘区;复刻剑圣 warrior 1 warrior assassin assassin 中程 assassin assassin+30 archer assassin mage assassin support 6002 强化普攻(ap100;快速0.90s) tank crt10 archer 6100 光闪(ap150) tank ap250 mage ap350 support 无 warrior 无 archer 无 archer 无 mage 7004 剑刃风暴0.12+7005 斩魂利刃0.2 mage mage
6 5005 形态 出血贼 近战 CSV导入:入场先手+受击格挡;复刻剑豪 近战 1 近战 assassin 中程 中程 中程 assassin+30 远程 assassin 远程 assassin 远程 6002 强化普攻(ap100;快速0.90s) 近战 附加30出血7007buff_chance30 中程 6103 闪电斩(ap150) 近战 ap250;附加出血7007 远程 ap350;para50;附加60出血7007 远程 无 近战 无 远程 无 中程 无 远程 7018 连击光环1 远程 远程
7 5006 ap 冻箭哥 tank CSV导入:多重单体箭,带冰冻 warrior+20 1 warrior+20 archer assassin+30 远程 assassin+30 archer+30 archer+30 archer mage+10 archer support+20 6006 强化普攻(ap100;中速1.05s) tank bck10 archer 6150 万箭齐发·冰(ap150;frz30) tank ap200;frz50 mage ap250;frz70 support 无 warrior 无 archer 无 archer+10 无 mage+10 7006 攻速光环0.15 mage+20 mage-5
8 5007 hp 击退火女 tank+20 CSV导入:群体击退/麻痹压场;复刻深渊女王 warrior+5 1 warrior+5 mage assassin 远程 assassin mage+10 archer mage-5 mage-5 mage support+10 6010 强化普攻(ap100;慢速1.20s;bck30) tank bck40 archer 6200 火焰喷射(ap250;bck100) tank ap350;bck100 mage ap450;bck100;summon2 support 无 warrior 无 archer+10 无 archer 无 mage 7002 深渊威压0.15 mage-10 mage+20
9 5008 def 团疗奶爸 tank+10 CSV导入:全体治疗续航+自身护盾 warrior+5 1 warrior+5 support assassin 远程 assassin support+20 archer support+10 mage support support 6011 强化普攻(ap100;中速1.05s) tank bck10 archer 6302 治疗(ap30) tank ap40 mage ap50 support 6301 圣愈之盾(t_num3;ap30):{target}获得生命最大值{ap}%的护盾 warrior 无 archer 无 archer 无 mage 无 mage mage+5
10 dodge
11 accuracy
12 skill[0]_lv1 6004 强化普攻(ap100;慢速1.20s) 6004 强化普攻(ap100;慢速1.20s) 6004 强化普攻(ap100;慢速1.20s) 6002 强化普攻(ap100;快速0.90s) 6002 强化普攻(ap100;快速0.90s) 6006 强化普攻(ap100;中速1.05s) 6010 强化普攻(ap100;慢速1.20s) 6011 强化普攻(ap100;中速1.05s) 6004 普攻强化(慢速1.20s) 6006 强化普攻(快速0.90s) 6004 普攻强化(中速1.05s) 6009 普攻强化(中速1.05s) 6004 攻击(中速1.05s) 6004 普攻强化(中速1.05s) 6007 淬毒箭(ap100;中速1.05s) 6008 连珠箭(ap100;极速0.75s) 6012 蚀甲酸瓶(ap100;中速1.05s) 6009 雷霆弹(ap100;快速0.90s) 6011 圣光飞瓶(ap100;中速1.05s)
13 skill[0]_lv2 ap120 ap120 stun10 crt10 命中附加30出血7007debuff_chance30 frz10 ap120 施法触发计时回血6502(10%;ap5) ap100 施法触发计时回血6502(10%;ap5) 施法触发攻速爆发6507(10%) 附加10生命爆发7029buff_chance20 附加10闪避爆发7030buff_chance20 命中附加30中毒7005debuff_chance30 crt20;施法触发蓝箭6007(20%) 命中附加破甲7008debuff_chance30 para15 施法触发次级反伤6516(20%)
14 skill[1]_lv1 6301 魔法盾(ap30) 6101 气斩(ap150;命中附加易伤7002) 6104 开山斧(ap300;stun100) 6100 光闪(ap150) 6103 闪电斩(ap150) 6150 万箭齐发·冰(ap150;frz30) 6200 火焰喷射(ap250;bck100) 6302 治疗(ap30) 6102 火焰斩(ap250;bck30) 6151 万箭齐发.火(ap70;summon5) 6517 生命爆发() 6201 飓风(ap100;summon2;施法触发攻速爆发6507(20%)) 6515 荆棘护盾() 6100 寒冰斩(ap200;附加50闪避爆发7030) 6150 万箭齐发·毒(ap150;命中附加30中毒7005debuff_chance50) 6151 裂空箭雨(ap150;crt30;summon5) 6203 碎甲能量波(ap150;命中附加破甲7008) 6203 雷霆裂空(ap200;para40) 6301 奥术圣壁(ap20;附加10荆棘7027)
15 skill[1]_lv8 ap60 ap450;stun100 ap250 ap250;命中附加40出血7007 ap200;frz50 ap350;bck100 ap40 ap300;bck50 ap80;summon5 ap100;summon3;施法触发攻速爆发6507(20%) ap250;附加50闪避爆发7030 ap200 ap200;crt50 ap200 ap250;para60 ap30
16 skill[1]_lv16 ap120 ap180;bck60 ap450;stun100 ap350 ap350;命中附加60出血7007 ap250;frz70 ap450;bck100;summon2 ap50 ap350;bck70 ap100;summon6 ap100;summon4;施法触发攻速爆发6507(20%) ap350;附加80闪避爆发7030 ap250 ap250;crt70;summon6 ap250 ap300;para80 ap40
17 atking[0]_lv4 无 6004 风暴打击(t_num3;ap300):立刻打击{target},造成攻击力{ap}%伤害 无 无 无 无 无 6301 圣愈之盾(t_num3;ap30):{target}获得生命最大值{ap}%的护盾 无 6008 红箭(t_num3;ap120): 无 无 无 无 6007 蚀骨毒箭(t_num3;ap80):追加射出蚀骨毒箭,对{target}造成攻击力{ap}%伤害,必定使目标中毒(每0.5秒受到{debuff_value}点伤害,持续{dur}秒) 无 无 无 无
18 atked[0]_lv4 6302 治疗(t_num3;概率50%;ap10):有 {t_chance}% 的概率,治疗自己 {ap}%生命最大值 无 无 无 无 无 无 无 6302 治疗(t_num3;ap5):为自己释放治疗,恢复生命值的{ap}% 无 6402 生命强化(t_num5;ap1):全队永久增加 1% 生命最大值 无 无 无 无 无 无 无 6516 荆棘回应(t_num3):凝聚荆棘护体,受击时反弹{buff_value}%所受伤害,持续{dur}秒
19 fstart[0]_lv4 无 无 无 无 无 无 无 无 无 无 无 无 6301 护盾(t_num1;ap20): 无 无 6504 猎杀时刻(t_num1):战斗开始时释放暴击爆发,全体友方暴击率提升{buff_value}%,持续{dur}秒 6012 先手蚀甲(t_num1;ap150):战斗开始时掷出蚀甲酸瓶,对{target}造成攻击力{ap}%伤害,并必定使其破甲(防御降低,持续{dur}秒) 6203 雷击先手(t_num1;ap150):战斗开始释放雷击,对{target}造成攻击力{ap}%伤害,{para}%概率麻痹敌人 无
20 fend[0]_lv4 无 无 无 无 无 无 无 无 无 无 无 无 无 无 无 无 无 无 无
21 dead[0]_lv4 无 无 无 无 无 无 无 无 无 无 无 无 无 无 无 无 无 无 无
22 field[0]_lv4 无 无 7005 大圣神威0.25 7004 剑刃风暴0.12+7005 斩魂利刃0.2 7002 攻击光环10 7006 攻速光环0.15 7002 深渊威压0.15 无 无 无 无 7006 攻速光环10 无 7023 闪避光环10 7002 淬毒磨砺0.1 7004 猎手集结0.15 7009 锐矛之赐0.1 7003 雷云领域10 7022 荆棘领域8
23 bonus lv12 def+50% lv12 hp+50% lv12 hp+50% lv12 ap+50% lv12 ap+50% lv12 ap+50% lv12 ap+50% lv12 hp+50% lv12 def+50% lv12 ap+50% lv12 def+50% lv12 ap+50% lv12 hp+50% lv12 hp+50% lv12 ap+50% lv12 ap+50% lv12 ap+50% lv12 ap+50% lv12 hp+50%

View File

@@ -1,5 +1,5 @@
import { ecs } from "../../../../extensions/oops-plugin-framework/assets/libs/ecs/ECS"; import { ecs } from "../../../../extensions/oops-plugin-framework/assets/libs/ecs/ECS";
import { HeroDisVal, HeroInfo, HSkillInfo, HType, SkillTriggerType, TriggerGrouped, LvFieldEntry, LvBonusAttrsEntry, FieldEntry, HRole } from "../common/config/heroSet"; import { HeroDisVal, HeroInfo, HSkillInfo, HType, SkillTriggerType, TriggerGrouped, LvFieldEntry, LvBonusAttrsEntry, FieldEntry, HRole, ResolvedTriggerEntry } from "../common/config/heroSet";
import { mLogger } from "../common/Logger"; import { mLogger } from "../common/Logger";
import { FacSet, FightSet } from "../common/config/GameSet"; import { FacSet, FightSet } from "../common/config/GameSet";
import { FieldSkillSet, FieldSkillType, SkillOverrides } from "../common/config/SkillSet"; import { FieldSkillSet, FieldSkillType, SkillOverrides } from "../common/config/SkillSet";
@@ -64,20 +64,26 @@ export class HeroAttrsComp extends ecs.Comp {
// ==================== 运行时解析缓存(按当前等级 resolve 后的有效列表) ==================== // ==================== 运行时解析缓存(按当前等级 resolve 后的有效列表) ====================
/** 当前等级下生效的攻击触发条目(供 SkillTriggerHelper 消费) */ /** 当前等级下生效的攻击触发条目(供 SkillTriggerHelper 消费) */
runtime_atking?: { s_uuid: number; t_num: number; overrides?: SkillOverrides }[]; runtime_atking?: ResolvedTriggerEntry[];
/** 当前等级下生效的受击触发条目 */ /** 当前等级下生效的受击触发条目 */
runtime_atked?: { s_uuid: number; t_num: number; overrides?: SkillOverrides }[]; runtime_atked?: ResolvedTriggerEntry[];
/** 当前等级下生效的召唤触发条目 */ /** 当前等级下生效的召唤触发条目 */
runtime_call?: { s_uuid: number; t_num: number; overrides?: SkillOverrides }[]; runtime_call?: ResolvedTriggerEntry[];
/** 当前等级下生效的死亡触发条目 */ /** 当前等级下生效的死亡触发条目 */
runtime_dead?: { s_uuid: number; t_num: number; overrides?: SkillOverrides }[]; runtime_dead?: ResolvedTriggerEntry[];
/** 当前等级下生效的战前触发条目 */ /** 当前等级下生效的战前触发条目 */
runtime_fstart?: { s_uuid: number; t_num: number; overrides?: SkillOverrides }[]; runtime_fstart?: ResolvedTriggerEntry[];
/** 当前等级下生效的回合结束触发条目 */ /** 当前等级下生效的回合结束触发条目 */
runtime_fend?: { s_uuid: number; t_num: number; overrides?: SkillOverrides }[]; runtime_fend?: ResolvedTriggerEntry[];
/** 当前等级下生效的驻场光环词条列表 */ /** 当前等级下生效的驻场光环词条列表 */
runtime_field?: FieldEntry[]; runtime_field?: FieldEntry[];
// ==================== 触发概率保底缓存(key: s_uuid, value: 已累积的概率增量百分点) ====================
/** 攻击触发未命中时累积的下次概率增量(pity_add 驱动,触发成功后清零) */
pity_atking: Record<number, number> = {};
/** 受击触发未命中时累积的下次概率增量(pity_add 驱动,触发成功后清零) */
pity_atked: Record<number, number> = {};
// ==================== 特殊属性 ==================== // ==================== 特殊属性 ====================
critical: number = 0; // 暴击率 critical: number = 0; // 暴击率
critical_res: number = 0; // 暴击抗性 critical_res: number = 0; // 暴击抗性
@@ -759,6 +765,9 @@ export class HeroAttrsComp extends ecs.Comp {
this.runtime_fstart = undefined; this.runtime_fstart = undefined;
this.runtime_fend = undefined; this.runtime_fend = undefined;
this.runtime_field = undefined; this.runtime_field = undefined;
// 清空触发概率保底叠加缓存
this.pity_atking = {};
this.pity_atked = {};
this.critical = 0; this.critical = 0;
this.critical_res = 0; this.critical_res = 0;
this.dodge = 0; this.dodge = 0;

View File

@@ -236,6 +236,21 @@ export class Monster extends ecs.Entity {
if (testSkills.fstart !== undefined) model.fstart = testSkills.fstart; if (testSkills.fstart !== undefined) model.fstart = testSkills.fstart;
if (testSkills.call !== undefined) model.call = testSkills.call; if (testSkills.call !== undefined) model.call = testSkills.call;
} }
// Boss 大招注入:在保留普攻的基础上追加(多个大招共存,由 SCastSystem 按 CD 轮转施放,
// 含镜头聚焦 + 技能名横幅表现,与英雄大招同一条施法链路)
const ults = (this as any)._testSkills?.ults;
if (ults && ults.length > 0) {
for (const ult of ults) {
if (!ult || !ult.s_uuid) continue;
model.skills[ult.s_uuid] = {
uuid: ult.s_uuid,
cd: ult.cd ?? 8,
lv: 1,
ccd: 0,
overrides: ult.overrides
};
}
}
// 按怪物等级 resolve 触发技能到运行时缓存(怪物无 lv 成长,恒用 mon_lv) // 按怪物等级 resolve 触发技能到运行时缓存(怪物无 lv 成长,恒用 mon_lv)
model.runtime_call = resolveTriggerByLv(model.call, mon_lv); model.runtime_call = resolveTriggerByLv(model.call, mon_lv);

View File

@@ -1,8 +1,8 @@
import { ecs } from "../../../../extensions/oops-plugin-framework/assets/libs/ecs/ECS"; import { ecs } from "../../../../extensions/oops-plugin-framework/assets/libs/ecs/ECS";
import { Vec3, Prefab, instantiate, tween, Node } from "cc"; import { Vec3, Prefab, instantiate, tween, Node, UITransform } from "cc";
import { HeroAttrsComp } from "./HeroAttrsComp"; import { HeroAttrsComp } from "./HeroAttrsComp";
import { HeroViewComp } from "./HeroViewComp"; import { HeroViewComp } from "./HeroViewComp";
import { DTType, RType, SkillConfig, SkillKind, SkillSet, TGroup, SkillOverrides, mergeSkillParams } from "../common/config/SkillSet"; import { DTType, RType, SkillConfig, SkillKind, SkillSet, SummonTMode, TGroup, SkillOverrides, mergeSkillParams } from "../common/config/SkillSet";
import { Skill } from "../skill/Skill"; import { Skill } from "../skill/Skill";
import { SkillView } from "../skill/SkillView"; import { SkillView } from "../skill/SkillView";
import { smc } from "../common/SingletonModuleComp"; import { smc } from "../common/SingletonModuleComp";
@@ -20,12 +20,14 @@ import { BuffList } from "../common/config/BuffSet";
import { CameraFX } from "../common/CameraFX"; import { CameraFX } from "../common/CameraFX";
import { ScreenShake } from "../common/ScreenShake"; import { ScreenShake } from "../common/ScreenShake";
/** 召唤参数:数量 / XY 步进偏移 / 生成间隔,均由技能 prefab 上的 SkillView 配置 */ /** 召唤参数:数量 / XY 步进偏移 / 生成间隔 / 目标选择模式,均由技能 prefab 上的 SkillView 配置 */
export interface SummonParams { export interface SummonParams {
count: number; count: number;
x_offset: number; x_offset: number;
y_offset: number; y_offset: number;
interval: number; interval: number;
/** 多次施放的目标选择模式(同一敌人/随机敌人/避免相同敌人) */
target_mode: SummonTMode;
} }
/** /**
@@ -137,12 +139,12 @@ export class SCastSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate
mockAttrs.type = HType.Long; // 假定为远程,拥有较长索敌范围 mockAttrs.type = HType.Long; // 假定为远程,拥有较长索敌范围
mockAttrs.dis = 2000; // 给予全屏以上的索敌范围 mockAttrs.dis = 2000; // 给予全屏以上的索敌范围
// 伪造一个 view 供找敌逻辑使用,位置为 spawnPos(random/unique 模式实时索敌也复用)
const mockView = {
node: { position: spawnPos }
} as any;
let targetPos: Vec3 | null = null; let targetPos: Vec3 | null = null;
if (!isFriendly) { if (!isFriendly) {
// 伪造一个 view 供找敌逻辑使用,位置为 spawnPos
const mockView = {
node: { position: spawnPos }
} as any;
// 获取全屏索敌范围 // 获取全屏索敌范围
const maxRange = this.resolveMaxCastRange(mockAttrs, mockAttrs.type as HType); const maxRange = this.resolveMaxCastRange(mockAttrs, mockAttrs.type as HType);
const target = this.findNearestEnemyInRange(mockAttrs, mockView, maxRange); const target = this.findNearestEnemyInRange(mockAttrs, mockView, maxRange);
@@ -157,6 +159,8 @@ export class SCastSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate
} }
mLogger.log(this.debugMode, "SCastSystem", `[卡牌施法] 释放技能「${config.name}」(s_uuid:${s_uuid}) rarity:${rarity} castTimes:${castTimes} targetPos:${targetPos ? `(${targetPos.x.toFixed(0)},${targetPos.y.toFixed(0)})` : "none"} isFriendly:${isFriendly}`); mLogger.log(this.debugMode, "SCastSystem", `[卡牌施法] 释放技能「${config.name}」(s_uuid:${s_uuid}) rarity:${rarity} castTimes:${castTimes} targetPos:${targetPos ? `(${targetPos.x.toFixed(0)},${targetPos.y.toFixed(0)})` : "none"} isFriendly:${isFriendly}`);
// unique 模式去重记录:本次施法序列内已锁定过的敌人 eid
const usedTargetEids = new Set<number>();
for (let i = 0; i < castTimes; i++) { for (let i = 0; i < castTimes; i++) {
// 多发/召唤按间隔错峰执行:i=0 立即,其余延迟 i*castInterval(召唤间隔由 prefab 配置) // 多发/召唤按间隔错峰执行:i=0 立即,其余延迟 i*castInterval(召唤间隔由 prefab 配置)
const exec = () => { const exec = () => {
@@ -167,7 +171,7 @@ export class SCastSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate
if (friendlyTargets.length === 0) return; if (friendlyTargets.length === 0) return;
this.applyFriendlySkillEffects(s_uuid, rarity, config, null as any, mockAttrs, friendlyTargets, spawnPos); this.applyFriendlySkillEffects(s_uuid, rarity, config, null as any, mockAttrs, friendlyTargets, spawnPos);
} else { } else {
const enemyTargetPos = this.resolveRepeatCastTargetPos(targetPos, i, summon); const enemyTargetPos = this.resolveSummonCastTargetPos(config, mockAttrs, mockView, targetPos, i, summon, usedTargetEids);
this.createSkillEntityForCard(s_uuid, rarity, mockAttrs, spawnPos, enemyTargetPos, i, overrides, summon); this.createSkillEntityForCard(s_uuid, rarity, mockAttrs, spawnPos, enemyTargetPos, i, overrides, summon);
} }
}; };
@@ -214,14 +218,14 @@ export class SCastSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate
/** /**
* 解析单次施法的召唤参数。 * 解析单次施法的召唤参数。
* 数量优先级:合并后配置上的 summon_count(heroSet overrides 可覆写) > prefab 上 SkillView.summon_count; * 数量优先级:合并后配置上的 summon_count(heroSet overrides 可覆写) > prefab 上 SkillView.summon_count;
* XY 偏移与间隔仅由 prefab 配置。 * XY 偏移、间隔与目标选择模式仅由 prefab 配置。
*/ */
private resolveSummonParams(config: SkillConfig): SummonParams { private resolveSummonParams(config: SkillConfig): SummonParams {
const fromPrefab = this.readSummonParamsFromPrefab(config.sp_name); const fromPrefab = this.readSummonParamsFromPrefab(config.sp_name);
const count = typeof config.summon_count === "number" const count = typeof config.summon_count === "number"
? Math.max(1, Math.floor(config.summon_count)) ? Math.max(1, Math.floor(config.summon_count))
: fromPrefab.count; : fromPrefab.count;
return { count, x_offset: fromPrefab.x_offset, y_offset: fromPrefab.y_offset, interval: fromPrefab.interval }; return { count, x_offset: fromPrefab.x_offset, y_offset: fromPrefab.y_offset, interval: fromPrefab.interval, target_mode: fromPrefab.target_mode };
} }
/** /**
@@ -232,7 +236,7 @@ export class SCastSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate
const cached = this.summonParamsCache.get(sp_name); const cached = this.summonParamsCache.get(sp_name);
if (cached) return cached; if (cached) return cached;
const path = `game/skill/atk/${sp_name}`; const path = `game/skill/atk/${sp_name}`;
let params: SummonParams = { count: 1, x_offset: 0, y_offset: 0, interval: 0 }; let params: SummonParams = { count: 1, x_offset: 0, y_offset: 0, interval: 0, target_mode: SummonTMode.same };
const prefab = oops.res.get(path, Prefab) as Prefab | null; const prefab = oops.res.get(path, Prefab) as Prefab | null;
if (prefab) { if (prefab) {
const view = prefab.data?.getComponent(SkillView); const view = prefab.data?.getComponent(SkillView);
@@ -242,6 +246,7 @@ export class SCastSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate
x_offset: view.summon_x_offset, x_offset: view.summon_x_offset,
y_offset: view.summon_y_offset, y_offset: view.summon_y_offset,
interval: view.summon_interval, interval: view.summon_interval,
target_mode: view.summon_target_mode ?? SummonTMode.same,
}; };
} }
this.summonParamsCache.set(sp_name, params); this.summonParamsCache.set(sp_name, params);
@@ -355,6 +360,8 @@ export class SCastSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate
} }
heroView.skill_name(val, s_uuid) heroView.skill_name(val, s_uuid)
mLogger.log(this.debugMode, "SCastSystem", `[触发施法] ${heroAttrs.hero_name}(uuid:${heroAttrs.hero_uuid}) 触发类型:${triggerType ?? "none"} 释放技能「${config.name}」(s_uuid:${s_uuid}) lv:${skillLv} ${isFriendly ? "友方" : "对敌"} castTimes:${castTimes}`); mLogger.log(this.debugMode, "SCastSystem", `[触发施法] ${heroAttrs.hero_name}(uuid:${heroAttrs.hero_uuid}) 触发类型:${triggerType ?? "none"} 释放技能「${config.name}」(s_uuid:${s_uuid}) lv:${skillLv} ${isFriendly ? "友方" : "对敌"} castTimes:${castTimes}`);
// unique 模式去重记录:本次施法序列内已锁定过的敌人 eid
const usedTargetEids = new Set<number>();
for (let i = 0; i < castTimes; i++) { for (let i = 0; i < castTimes; i++) {
if (!heroView.node || !heroView.node.isValid) return; if (!heroView.node || !heroView.node.isValid) return;
// 多发/召唤按间隔错峰执行:i=0 立即,其余延迟 i*castInterval(召唤间隔由 prefab 配置) // 多发/召唤按间隔错峰执行:i=0 立即,其余延迟 i*castInterval(召唤间隔由 prefab 配置)
@@ -367,7 +374,7 @@ export class SCastSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate
this.applyFriendlySkillEffects(s_uuid, skillLv, config, heroView, heroAttrs, friendlyTargets, null); this.applyFriendlySkillEffects(s_uuid, skillLv, config, heroView, heroAttrs, friendlyTargets, null);
return; return;
} }
const enemyTargetPos = this.resolveRepeatCastTargetPos(targetPos, i, summon); const enemyTargetPos = this.resolveSummonCastTargetPos(config, heroAttrs, heroView, targetPos, i, summon, usedTargetEids);
this.applyEnemySkillEffects(s_uuid, skillLv, config, heroView, heroAttrs, enemyTargetPos, i, overrides, summon); this.applyEnemySkillEffects(s_uuid, skillLv, config, heroView, heroAttrs, enemyTargetPos, i, overrides, summon);
}, i * castInterval); }, i * castInterval);
} }
@@ -469,6 +476,8 @@ export class SCastSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate
// 注意:这里仍然是基于时间的延迟,受帧率波动影响。 // 注意:这里仍然是基于时间的延迟,受帧率波动影响。
// 若需精确同步,建议在动画中添加帧事件并在 HeroViewComp 中监听。 // 若需精确同步,建议在动画中添加帧事件并在 HeroViewComp 中监听。
const delay = config.ready > 0 ? config.ready : FightSet.SKILL_CAST_DELAY; const delay = config.ready > 0 ? config.ready : FightSet.SKILL_CAST_DELAY;
// unique 模式去重记录:本次施法序列内已锁定过的敌人 eid
const usedTargetEids = new Set<number>();
heroView.scheduleOnce(() => { heroView.scheduleOnce(() => {
if (!smc.mission.play || smc.mission.pause || !smc.mission.in_fight) return; if (!smc.mission.play || smc.mission.pause || !smc.mission.in_fight) return;
@@ -484,7 +493,7 @@ export class SCastSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate
this.applyFriendlySkillEffects(s_uuid, skillLv, config, heroView, heroAttrs, friendlyTargets, null); this.applyFriendlySkillEffects(s_uuid, skillLv, config, heroView, heroAttrs, friendlyTargets, null);
return; return;
} }
const enemyTargetPos = this.resolveRepeatCastTargetPos(castPlan.targetPos, i, summon); const enemyTargetPos = this.resolveSummonCastTargetPos(config, heroAttrs, heroView, castPlan.targetPos, i, summon, usedTargetEids);
this.applyEnemySkillEffects(s_uuid, skillLv, config, heroView, heroAttrs, enemyTargetPos, i, overrides, summon); this.applyEnemySkillEffects(s_uuid, skillLv, config, heroView, heroAttrs, enemyTargetPos, i, overrides, summon);
}, i * castInterval); }, i * castInterval);
} }
@@ -537,6 +546,71 @@ export class SCastSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate
return new Vec3(targetPos.x + offset.x, targetPos.y + offset.y, targetPos.z); return new Vec3(targetPos.x + offset.x, targetPos.y + offset.y, targetPos.z);
} }
/**
* 解析第 castIndex 次施放的对敌目标点(召唤目标选择模式入口)。
* - same(默认):沿用施法时锁定的目标点并按召唤偏移对称铺开(原行为);
* - random:每次出手时从射程内敌人中随机锁定一个(错峰施放时实时索敌,目标状态最新鲜);
* - unique:优先锁定本轮未选过的敌人,敌人不足一轮时重置去重记录再来一轮;
* 实时索敌失败(敌人死亡/移动出射程)时回退施法时锁定的目标点,保证技能不落空。
*/
private resolveSummonCastTargetPos(config: SkillConfig, heroAttrs: HeroAttrsComp, heroView: HeroViewComp | null, baseTargetPos: Vec3 | null, castIndex: number, summon: SummonParams | undefined, usedEids: Set<number>): Vec3 | null {
if (!summon || summon.count <= 1 || summon.target_mode === SummonTMode.same) {
return this.resolveRepeatCastTargetPos(baseTargetPos, castIndex, summon);
}
const maxRange = this.resolveMaxCastRange(heroAttrs, heroAttrs.type as HType);
const enemies = this.collectEnemiesInRange(heroAttrs, heroView, maxRange);
const picked = enemies.length > 0 ? this.pickEnemyByTargetMode(enemies, summon.target_mode, usedEids) : null;
if (picked?.node) {
mLogger.log(this.debugMode, "SCastSystem", `[召唤索敌] 「${config.name}」第${castIndex + 1}个实体锁定目标 eid:${picked.ent?.eid} 模式:${SummonTMode[summon.target_mode]}`);
// 与 resolveEnemyCastTargetPos 保持一致:贝塞尔取脚底原始坐标,其余补半身高命中身体中心
const pos = config.RType === RType.bezier ? picked.node.position.clone() : this.buildEnemyCastTargetPos(picked);
// 召唤偏移铺开仍生效:random 模式重复锁定同一敌人时,避免实体完全重叠
const offset = this.resolveCastOffset(castIndex, summon);
pos.x += offset.x;
pos.y += offset.y;
return pos;
}
// 实时索敌失败:回退施法时锁定的目标点
return this.resolveRepeatCastTargetPos(baseTargetPos, castIndex, summon);
}
/** 按目标模式从射程内候选敌人中挑选本次施放的锁定目标,并写入去重记录 */
private pickEnemyByTargetMode(enemies: HeroViewComp[], mode: SummonTMode, usedEids: Set<number>): HeroViewComp | null {
let pool = enemies;
if (mode === SummonTMode.unique) {
const unused = enemies.filter(view => !view.ent || !usedEids.has(view.ent.eid));
if (unused.length > 0) {
pool = unused;
} else {
// 敌人不足一轮:重置已选记录,重新开始去重,保证尽量分散
usedEids.clear();
}
}
const picked = pool[Math.floor(Math.random() * pool.length)];
if (picked?.ent) usedEids.add(picked.ent.eid);
return picked ?? null;
}
/** 收集施法者射程内的全部敌方目标(随机/去重目标模式实时索敌用),网格遍历与 findNearestEnemyByGrid 同源 */
private collectEnemiesInRange(heroAttrs: HeroAttrsComp, heroView: HeroViewComp | null, maxRange: number): HeroViewComp[] {
const result: HeroViewComp[] = [];
if (!heroView?.node) return result;
const grid = heroAttrs.fac === FacSet.HERO ? smc.mission.monGrid : smc.mission.heroGrid;
const currentX = heroView.node.position.x;
for (const eid of grid) {
if (eid < 0) continue;
const entity = ecs.getEntityByEid(eid);
if (!entity) continue;
const model = entity.get(HeroAttrsComp);
const view = entity.get(HeroViewComp);
if (!model || model.is_dead || model.is_reviving || !view?.node) continue;
if (Math.abs(currentX - view.node.position.x) <= maxRange) {
result.push(view);
}
}
return result;
}
/** 解析第 castIndex 个实体的偏移:召唤技能按 prefab 配置对称交替铺开(0, +1, -1, +2, -2... 档 × 步进值);多发回落纵向扇形档位 */ /** 解析第 castIndex 个实体的偏移:召唤技能按 prefab 配置对称交替铺开(0, +1, -1, +2, -2... 档 × 步进值);多发回落纵向扇形档位 */
private resolveCastOffset(castIndex: number, summon?: SummonParams): { x: number; y: number } { private resolveCastOffset(castIndex: number, summon?: SummonParams): { x: number; y: number } {
if (summon && summon.count > 1) { if (summon && summon.count > 1) {
@@ -883,7 +957,7 @@ export class SCastSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate
return nearestEnemy.node?.position.clone() ?? null; return nearestEnemy.node?.position.clone() ?? null;
} }
if (config.DTType !== DTType.range) { if (config.DTType !== DTType.range) {
return this.buildEnemyCastTargetPos(heroView, nearestEnemy, maxRange); return this.buildEnemyCastTargetPos(nearestEnemy);
} }
const frontEnemy = this.findFrontEnemyInRange(heroAttrs, heroView, maxRange, nearestEnemy); const frontEnemy = this.findFrontEnemyInRange(heroAttrs, heroView, maxRange, nearestEnemy);
if (!frontEnemy?.node) return null; if (!frontEnemy?.node) return null;
@@ -897,19 +971,10 @@ export class SCastSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate
return heroAttrs.dis; return heroAttrs.dis;
} }
/** 生成沿目标方向的施法目标坐标 */ /** 生成对敌施法目标坐标:直接返回目标的真实坐标;y 为脚底(碰撞体底部),补半身高以命中身体中心 */
private buildEnemyCastTargetPos(caster: HeroViewComp, target: HeroViewComp, castRange: number): Vec3 { private buildEnemyCastTargetPos(target: HeroViewComp): Vec3 {
// 直接返回目标的真实坐标,保留其 Y 轴信息,确保能向目标真实所在位置发射 const transform = target.node?.getComponent(UITransform);
// 考虑到目前角色的 y 坐标都是脚底(碰撞体底部),为了命中身体中心,给目标 y 加上高度的一半 const halfHeight = transform ? transform.height / 2 : 40; // 无 UITransform 时给默认高度偏移
let halfHeight = 0;
if (target.node) {
const transform = target.node.getComponent('cc.UITransform') as any;
if (transform) {
halfHeight = transform.height / 2;
} else {
halfHeight = 40; // 如果没有 UITransform,给一个默认高度偏移
}
}
const pos = target.node.position.clone(); const pos = target.node.position.clone();
pos.y += halfHeight; pos.y += halfHeight;

View File

@@ -1,6 +1,6 @@
import { oops } from "db://oops-framework/core/Oops"; import { oops } from "db://oops-framework/core/Oops";
import { GameEvent } from "../common/config/GameEvent"; import { GameEvent } from "../common/config/GameEvent";
import { SkillTriggerType } from "../common/config/heroSet"; import { ResolvedTriggerEntry, SkillTriggerType } from "../common/config/heroSet";
import { HeroAttrsComp } from "./HeroAttrsComp"; import { HeroAttrsComp } from "./HeroAttrsComp";
import { HeroViewComp } from "./HeroViewComp"; import { HeroViewComp } from "./HeroViewComp";
import { FacSet } from "../common/config/GameSet"; import { FacSet } from "../common/config/GameSet";
@@ -118,7 +118,8 @@ export class SkillTriggerHelper {
model.runtime_atking.forEach(atkConfig => { model.runtime_atking.forEach(atkConfig => {
// atk_count 代表已进行的普攻次数。当其余数刚好整除配置阈值时触发。 // atk_count 代表已进行的普攻次数。当其余数刚好整除配置阈值时触发。
const tNum = Math.max(1, atkConfig.t_num - tNumReduce); const tNum = Math.max(1, atkConfig.t_num - tNumReduce);
if (model.atk_count > 0 && model.atk_count % tNum === 0) { if (model.atk_count > 0 && model.atk_count % tNum === 0
&& this.rollTriggerChance(model, SkillTriggerType.Atking, atkConfig)) {
for (let i = 0; i < triggerCount; i++) { for (let i = 0; i < triggerCount; i++) {
this.dispatchSingle(atkConfig.s_uuid, model, view, SkillTriggerType.Atking, atkConfig.overrides); this.dispatchSingle(atkConfig.s_uuid, model, view, SkillTriggerType.Atking, atkConfig.overrides);
} }
@@ -149,7 +150,8 @@ export class SkillTriggerHelper {
model.runtime_atked.forEach(atkConfig => { model.runtime_atked.forEach(atkConfig => {
// atked_count 代表已承受的受击次数。当其余数刚好整除配置阈值时触发。 // atked_count 代表已承受的受击次数。当其余数刚好整除配置阈值时触发。
const tNum = Math.max(1, atkConfig.t_num - tNumReduce); const tNum = Math.max(1, atkConfig.t_num - tNumReduce);
if (model.atked_count > 0 && model.atked_count % tNum === 0) { if (model.atked_count > 0 && model.atked_count % tNum === 0
&& this.rollTriggerChance(model, SkillTriggerType.Atked, atkConfig)) {
for (let i = 0; i < triggerCount; i++) { for (let i = 0; i < triggerCount; i++) {
this.dispatchSingle(atkConfig.s_uuid, model, view, SkillTriggerType.Atked, atkConfig.overrides); this.dispatchSingle(atkConfig.s_uuid, model, view, SkillTriggerType.Atked, atkConfig.overrides);
} }
@@ -157,6 +159,31 @@ export class SkillTriggerHelper {
}); });
} }
/**
* 触发概率判定 + 保底叠加(仅 Atking/Atked 消费)
* 次数条件达成后按 t_chance(缺省 100 必触发,兼容存量配置)掷骰;
* 未命中且配置 pity_add > 0 时,为该 s_uuid 累积下次概率增量,形成"越不触发越容易触发"的保底体验;
* 触发成功后清空叠加,最终概率封顶 100。
*
* @param model 施法者属性组件(保底缓存挂载于此)
* @param type 触发类型(决定读/写哪份保底缓存)
* @param config 当前生效的触发条目
* @returns 是否通过概率判定
*/
private static rollTriggerChance(model: HeroAttrsComp, type: SkillTriggerType, config: ResolvedTriggerEntry): boolean {
const pityMap = type === SkillTriggerType.Atking ? model.pity_atking : model.pity_atked;
const chance = Math.min(100, (config.t_chance ?? 100) + (pityMap[config.s_uuid] ?? 0));
if (chance >= 100 || Math.random() * 100 < chance) {
pityMap[config.s_uuid] = 0; // 触发成功:清空保底叠加
return true;
}
const pityAdd = config.pity_add ?? 0;
if (pityAdd > 0) {
pityMap[config.s_uuid] = (pityMap[config.s_uuid] ?? 0) + pityAdd;
}
return false;
}
/** /**
* 通用的数组型触发器处理(适用于 FStart 等无需额外判定的简单列表触发) * 通用的数组型触发器处理(适用于 FStart 等无需额外判定的简单列表触发)
*/ */

View File

@@ -247,11 +247,13 @@ export class HeroInfoComp extends CCComp {
* @param delta 1 下一个,-1 上一个 * @param delta 1 下一个,-1 上一个
*/ */
private switchHero(delta: 1 | -1) { private switchHero(delta: 1 | -1) {
// 与图鉴页面排序同源:仅按品质降序 → uuid 升序 // 与图鉴页面排序同源:按职业(HRole)升序 → uuid 升序
const sorted = [...HeroList].sort((a, b) => { const sorted = [...HeroList].sort((a, b) => {
const ra = HeroInfo[a]?.rarity ?? 1; const heroA = HeroInfo[a];
const rb = HeroInfo[b]?.rarity ?? 1; const heroB = HeroInfo[b];
if (ra !== rb) return rb - ra; const roleA = heroA?.role ?? 0;
const roleB = heroB?.role ?? 0;
if (roleA !== roleB) return roleA - roleB;
return a - b; return a - b;
}); });
if (sorted.length === 0) return; if (sorted.length === 0) return;

View File

@@ -113,11 +113,13 @@ export class HerosListComp extends CCComp {
this.cards_node.removeAllChildren() this.cards_node.removeAllChildren()
// 图鉴排序:仅按品质降序 → uuid 升序(与养成进度解耦,保持展示稳定) // 图鉴排序:按职业(HRole)升序 → uuid 升序(与养成进度解耦,保持展示稳定)
const sorted = [...HeroList].sort((a, b) => { const sorted = [...HeroList].sort((a, b) => {
const ra = HeroInfo[a]?.rarity ?? 1; const heroA = HeroInfo[a];
const rb = HeroInfo[b]?.rarity ?? 1; const heroB = HeroInfo[b];
if (ra !== rb) return rb - ra; const roleA = heroA?.role ?? 0;
const roleB = heroB?.role ?? 0;
if (roleA !== roleB) return roleA - roleB;
return a - b; return a - b;
}) })

View File

@@ -17,7 +17,7 @@
* - 第 5 节胜利 → open_Victory(final) 弹结算,确认退出并存档进下一关。 * - 第 5 节胜利 → open_Victory(final) 弹结算,确认退出并存档进下一关。
* - cleanComponents() / clearBattlePools() 仅在整关开始/结束时执行,节间不调用。 * - cleanComponents() / clearBattlePools() 仅在整关开始/结束时执行,节间不调用。
*/ */
import { _decorator, Vec3, Animation, instantiate, Prefab, Node, NodeEventType, ProgressBar, Label, CCInteger, tween, v3, Tween, Widget, UIOpacity } from "cc"; import { _decorator, Node, NodeEventType, Label, tween, v3, Tween, Widget, Color, Sprite, ProgressBar } from "cc";
import { ecs } from "../../../../extensions/oops-plugin-framework/assets/libs/ecs/ECS"; import { ecs } from "../../../../extensions/oops-plugin-framework/assets/libs/ecs/ECS";
import { CCComp } from "../../../../extensions/oops-plugin-framework/assets/module/common/CCComp"; import { CCComp } from "../../../../extensions/oops-plugin-framework/assets/module/common/CCComp";
import { smc } from "../common/SingletonModuleComp"; import { smc } from "../common/SingletonModuleComp";
@@ -31,7 +31,6 @@ import { SkillTriggerHelper } from "../hero/SkillTriggerHelper";
import { UIID } from "../common/config/GameUIConfig"; import { UIID } from "../common/config/GameUIConfig";
import { SkillView } from "../skill/SkillView"; import { SkillView } from "../skill/SkillView";
import { FacSet, FightSet } from "../common/config/GameSet"; import { FacSet, FightSet } from "../common/config/GameSet";
import { HeroInfo } from "../common/config/heroSet";
import { mLogger } from "../common/Logger"; import { mLogger } from "../common/Logger";
import { Monster } from "../hero/Mon"; import { Monster } from "../hero/Mon";
import { Skill } from "../skill/Skill"; import { Skill } from "../skill/Skill";
@@ -80,8 +79,6 @@ type SettleType = "defeat" | "final";
export class MissionComp extends CCComp { export class MissionComp extends CCComp {
@property({ tooltip: "是否启用调试日志" }) @property({ tooltip: "是否启用调试日志" })
private debugMode: boolean = true; private debugMode: boolean = true;
@property({ tooltip: "是否显示战斗内存观测面板" })
private showMemoryPanel: boolean = false;
// ======================== 配置参数 ======================== // ======================== 配置参数 ========================
@@ -97,6 +94,21 @@ export class MissionComp extends CCComp {
@property(Node) @property(Node)
tooltip: Node = null! tooltip: Node = null!
/** 回合指示节点(5 个,索引 0~4 对应回合 1~5),按回合进度染色 */
@property({ type: [Node], tooltip: "回合指示节点(按回合 1~5 顺序绑定)" })
round_nodes: Node[] = [];
/** 回合进度条:第 1 回合 0%,每推进一回合 +25%(第 5 回合满格) */
@property({ type: ProgressBar, tooltip: "回合进度条(第 1 回合 0%,每回合 +25%)" })
round_progress: ProgressBar = null!;
/** 回合指示:未激活(白色) */
private static readonly ROUND_INACTIVE = new Color(255, 255, 255, 255);
/** 回合指示:已激活(橙黄 #FFA300) */
private static readonly ROUND_ACTIVE = new Color(255, 163, 0, 255);
/** 回合指示:Boss 当前回合(红色) */
private static readonly ROUND_BOSS = new Color(230, 60, 60, 255);
/** 阶段名称映射表(用于 UI 显示) */ /** 阶段名称映射表(用于 UI 显示) */
private static readonly PhaseNameMap: Record<MissionPhase, string> = { private static readonly PhaseNameMap: Record<MissionPhase, string> = {
[MissionPhase.None]: "未开始", [MissionPhase.None]: "未开始",
@@ -133,26 +145,6 @@ export class MissionComp extends CCComp {
private lastTimeStr: string = ""; private lastTimeStr: string = "";
/** 上一次显示的秒数(避免重复计算) */ /** 上一次显示的秒数(避免重复计算) */
private lastTimeSecond: number = -1; private lastTimeSecond: number = -1;
/** 性能监控面板 Label 引用 */
private memoryLabel: Label | null = null;
/** 性能监控刷新计时器 */
private memoryRefreshTimer: number = 0;
/** 上一次性能文本(避免重复渲染) */
private lastMemoryText: string = "";
/** 帧间隔累加(用于计算平均 FPS) */
private perfDtAcc: number = 0;
/** 帧数计数 */
private perfFrameCount: number = 0;
/** 初始堆内存基准值(MB) */
private heapBaseMB: number = -1;
/** 堆内存峰值(MB) */
private heapPeakMB: number = 0;
/** 堆内存增长趋势(MB/分钟) */
private heapTrendPerMinMB: number = 0;
/** 趋势计算计时器 */
private heapTrendTimer: number = 0;
/** 趋势计算基准(MB) */
private heapTrendBaseMB: number = -1;
/** 怪物数量同步计时器(降低同步频率) */ /** 怪物数量同步计时器(降低同步频率) */
private monsterCountSyncTimer: number = 0; private monsterCountSyncTimer: number = 0;
/** 当前回合数(= 当前小节号,驱动 HUD 回合/进度显示) */ /** 当前回合数(= 当前小节号,驱动 HUD 回合/进度显示) */
@@ -161,8 +153,6 @@ export class MissionComp extends CCComp {
private isBossWave: boolean = false; private isBossWave: boolean = false;
/** 超时回合已在 onBattleTimeout 预扣留存分,BattleEnd 需跳过重复累加 */ /** 超时回合已在 onBattleTimeout 预扣留存分,BattleEnd 需跳过重复累加 */
private skipRemainScoreOnBattleEnd: boolean = false; private skipRemainScoreOnBattleEnd: boolean = false;
/** 上节清场时间快照(含清场加速还原,供评分统计) */
private lastWaveClearTime: number = 0;
/** 当前任务阶段 */ /** 当前任务阶段 */
public currentPhase: MissionPhase = MissionPhase.None; public currentPhase: MissionPhase = MissionPhase.None;
/** 是否处于回合间倒计时状态 */ /** 是否处于回合间倒计时状态 */
@@ -180,11 +170,9 @@ export class MissionComp extends CCComp {
// ======================== 关卡进度状态 ======================== // ======================== 关卡进度状态 ========================
/** 当前章节号 */ /** 当前关卡号(无限关,1~∞) */
public currentChapter: number = 1;
/** 当前关卡号(1~10) */
public currentStage: number = 1; public currentStage: number = 1;
/** 当前小节号(1~SECTIONS_PER_STAGE) */ /** 当前回合号(1~SECTIONS_PER_STAGE) */
public currentSection: number = 1; public currentSection: number = 1;
// ======================== ECS 查询匹配器(预缓存) ======================== // ======================== ECS 查询匹配器(预缓存) ========================
@@ -202,7 +190,6 @@ export class MissionComp extends CCComp {
this.heroViewMatcher = ecs.allOf(HeroViewComp); this.heroViewMatcher = ecs.allOf(HeroViewComp);
this.skillViewMatcher = ecs.allOf(SkillView); this.skillViewMatcher = ecs.allOf(SkillView);
this.heroAttrsMatcher = ecs.allOf(HeroAttrsComp); this.heroAttrsMatcher = ecs.allOf(HeroAttrsComp);
this.showMemoryPanel = false
// 注册生命周期事件 // 注册生命周期事件
this.on(GameEvent.MissionEnd, this.mission_end, this) this.on(GameEvent.MissionEnd, this.mission_end, this)
this.on(GameEvent.NewWave, this.onNewWave, this) this.on(GameEvent.NewWave, this.onNewWave, this)
@@ -212,10 +199,9 @@ export class MissionComp extends CCComp {
this.start_btn?.on(NodeEventType.TOUCH_END, this.onStartFightBtnClick, this) this.start_btn?.on(NodeEventType.TOUCH_END, this.onStartFightBtnClick, this)
// 开局免费三选一选完后自动进入战斗 // 开局免费三选一选完后自动进入战斗
oops.message.on("OpeningPicksDone", this.onOpeningPicksDone, this); oops.message.on("OpeningPicksDone", this.onOpeningPicksDone, this);
this.removeMemoryPanel()
} }
onAdded(args: any) { onAdded() {
// 使用 scheduleOnce 将事件推迟到下一帧执行, // 使用 scheduleOnce 将事件推迟到下一帧执行,
// 确保所有关联组件(如 MissionCardComp 等)都已经完成其 onLoad 生命周期。 // 确保所有关联组件(如 MissionCardComp 等)都已经完成其 onLoad 生命周期。
this.scheduleOnce(() => { this.scheduleOnce(() => {
@@ -370,7 +356,6 @@ export class MissionComp extends CCComp {
this.changePhase(MissionPhase.Prepare); this.changePhase(MissionPhase.Prepare);
// 派发首个 SectionStart,MissionMonComp 据此生成开局怪物 // 派发首个 SectionStart,MissionMonComp 据此生成开局怪物
oops.message.dispatchEvent(GameEvent.SectionStart, { oops.message.dispatchEvent(GameEvent.SectionStart, {
chapter: this.currentChapter,
stage: this.currentStage, stage: this.currentStage,
section: this.currentSection, section: this.currentSection,
}); });
@@ -455,7 +440,6 @@ export class MissionComp extends CCComp {
*/ */
private changePhase(targetPhase: MissionPhase) { private changePhase(targetPhase: MissionPhase) {
if (this.currentPhase === targetPhase) return; if (this.currentPhase === targetPhase) return;
const oldPhase = this.currentPhase;
this.currentPhase = targetPhase; this.currentPhase = targetPhase;
const phaseName = MissionComp.PhaseNameMap[targetPhase] || "未知"; const phaseName = MissionComp.PhaseNameMap[targetPhase] || "未知";
@@ -556,8 +540,6 @@ export class MissionComp extends CCComp {
// 英雄为真实死亡(实体已销毁),本节死亡数取死亡记录长度 // 英雄为真实死亡(实体已销毁),本节死亡数取死亡记录长度
const heroDeathCount = smc.mission.dead_heroes.length; const heroDeathCount = smc.mission.dead_heroes.length;
// 快照清场时间供评分统计(onNewWave 会清零 clearTime,必须提前快照)
this.lastWaveClearTime = this.clearTime;
// 【评分系统 - 战绩分】记录全员存活的胜利节数(额外加分) // 【评分系统 - 战绩分】记录全员存活的胜利节数(额外加分)
if (hasHero && heroDeathCount === 0) { if (hasHero && heroDeathCount === 0) {
smc.vmdata.scores.wave_all_alive_count++; smc.vmdata.scores.wave_all_alive_count++;
@@ -751,11 +733,11 @@ export class MissionComp extends CCComp {
* - 胜利即 final(通关),存档推进到下一关;失败即 defeat(进度不变,可复活/再来一次) * - 胜利即 final(通关),存档推进到下一关;失败即 defeat(进度不变,可复活/再来一次)
* - 切入 BattleEnd,2s 后由 autoNextPhase 自动弹出 VictoryComp * - 切入 BattleEnd,2s 后由 autoNextPhase 自动弹出 VictoryComp
* *
* @param e 事件对象(未使用) * @param _e 事件对象(未使用)
* @param is_hero_dead 是否因英雄全灭触发 * @param _is_hero_dead 是否因英雄全灭触发(当前未使用,保留签名以统一事件调用口径)
* @param victory 是否胜利(默认 false) * @param victory 是否胜利(默认 false)
*/ */
open_Victory(e: any, is_hero_dead: boolean = false, victory: boolean = false) { open_Victory(_e: any, _is_hero_dead: boolean = false, victory: boolean = false) {
// 战斗结束(通关/失败),标记暂停状态以切断节间流转逻辑 // 战斗结束(通关/失败),标记暂停状态以切断节间流转逻辑
smc.mission.pause = true; smc.mission.pause = true;
this._victory = victory; this._victory = victory;
@@ -765,23 +747,18 @@ export class MissionComp extends CCComp {
// 失败:进度不变,结算窗走复活/再来一次/退出流程 // 失败:进度不变,结算窗走复活/再来一次/退出流程
this._settleType = "defeat"; this._settleType = "defeat";
} else { } else {
// 通关(Boss 节胜利):结算窗显示通关标题,确认退出并存档进下一关 // 通关(Boss 回合胜利):无限关卡模式,存档永远推进到下一关第 1 节
// (仅写存档,内存进度保留用于本局结算显示)
this._settleType = "final"; this._settleType = "final";
this._settleTitle = this.currentStage >= 10 ? "本章通关" : "本关通关"; this._settleTitle = "本关通关";
// 存档推进到下一关第 1 节(仅写存档,内存进度保留用于本局结算显示); smc.updateStageProgress({
// 第 10 关通关即本章全通,存档停留等待后续章节扩展 stage: this.currentStage + 1,
if (this.currentStage < 10) { });
smc.updateStageProgress({ if ((smc as any).updateCloudData) {
chapter: this.currentChapter, (smc as any).updateCloudData();
stage: this.currentStage + 1,
section: 1,
});
if ((smc as any).updateCloudData) {
(smc as any).updateCloudData();
}
mLogger.log(this.debugMode, 'MissionComp',
`[StageProgress] 本关通关,存档推进: ${this.currentChapter}-${this.currentStage + 1}-1`);
} }
mLogger.log(this.debugMode, 'MissionComp',
`[StageProgress] 本关通关,存档推进: ${this.currentStage + 1}-1`);
} }
// 直接切入 BattleEnd,2s 后由 autoNextPhase 自动流转弹窗结算 // 直接切入 BattleEnd,2s 后由 autoNextPhase 自动流转弹窗结算
this.changePhase(MissionPhase.BattleEnd); this.changePhase(MissionPhase.BattleEnd);
@@ -836,20 +813,11 @@ export class MissionComp extends CCComp {
this.currentWave = 1; this.currentWave = 1;
this.isBossWave = false; this.isBossWave = false;
this.skipRemainScoreOnBattleEnd = false; this.skipRemainScoreOnBattleEnd = false;
this.lastWaveClearTime = 0; this.updateRoundNodes();
this.rewards = [] this.rewards = []
this.revive_times = 1; this.revive_times = 1;
this.lastTimeStr = ""; this.lastTimeStr = "";
this.lastTimeSecond = -1; this.lastTimeSecond = -1;
this.memoryRefreshTimer = 0;
this.lastMemoryText = "";
this.perfDtAcc = 0;
this.perfFrameCount = 0;
this.heapBaseMB = -1;
this.heapPeakMB = 0;
this.heapTrendPerMinMB = 0;
this.heapTrendTimer = 0;
this.heapTrendBaseMB = -1;
this.monsterCountSyncTimer = 0; this.monsterCountSyncTimer = 0;
spawningEngine.reset(); spawningEngine.reset();
@@ -868,57 +836,48 @@ export class MissionComp extends CCComp {
// ======================== 关卡进度管理 ======================== // ======================== 关卡进度管理 ========================
/** /**
* 加载关卡进度存档(一关一局:只恢复大关,节恒从 1 开始) * 加载关卡进度存档(一关一局:只恢复大关,回合恒从 1 开始)
* 从 smc.data.stage_progress 恢复章节/大关,缺省从 1-1-1 开始 * 从 smc.data.stage_progress 恢复关卡号,缺省从第 1 关开始
*/ */
private loadStageProgress() { private loadStageProgress() {
const progress = smc.data.stage_progress; const progress = smc.data.stage_progress;
if (progress && progress.chapter >= 1 && progress.stage >= 1) { this.currentStage = Math.max(1, Math.floor(progress?.stage ?? 1));
this.currentChapter = progress.chapter; // 一关一局:进入关卡始终从第 1 回合开打
this.currentStage = progress.stage;
} else {
this.currentChapter = 1;
this.currentStage = 1;
}
// 一关一局:进入关卡始终从第 1 节开打
this.currentSection = 1; this.currentSection = 1;
// 加载完成后将权威进度镜像到 vmdata,驱动 HUD 实时显示 // 加载完成后将权威进度镜像到 vmdata,驱动 HUD 实时显示
smc.syncStageProgressToView(); smc.syncStageProgressToView();
mLogger.log(this.debugMode, 'MissionComp', mLogger.log(this.debugMode, 'MissionComp',
`[StageProgress] 加载进度: ${getProgressText(this.currentChapter, this.currentStage, this.currentSection)}`); `[StageProgress] 加载进度: ${getProgressText(this.currentStage, this.currentSection)}`);
} }
/** /**
* 推进到下一小节(节间自动推进): * 推进到下一回合(回合间自动推进):
* 1. 节号 +1,派发 SectionStart 触发 MissionMonComp 生成下一节怪物(从右侧跑入)。 * 1. 回合号 +1,派发 SectionStart 触发 MissionMonComp 生成下一回合怪物(从右侧跑入)。
* 2. 不清理英雄/技能实体、不重置局内数据、不重新三选一——英雄保留并自动归位(编队排队)。 * 2. 不清理英雄/技能实体、不重置局内数据、不重新三选一——英雄保留并自动归位(编队排队)。
* 3. 进度实时镜像到 HUD,但不写持久存档(存档只在整关通关时推进到下一关)。 * 3. 进度实时镜像到 HUD,但不写持久存档(存档只在整关通关时推进到下一关)。
* *
* 调用时机:PrepareStart 过场倒计时结束(autoNextPhase)。 * 调用时机:PrepareStart 过场倒计时结束(autoNextPhase)。
* 保证:仅 1~4 节清场后触发,末节(BOSS_SECTION)已走 open_Victory 结算,不会推进。 * 保证:仅 1~4 回合清场后触发,末回合(BOSS_SECTION)已走 open_Victory 结算,不会推进。
*/ */
private advanceToNextSection() { private advanceToNextSection() {
this.currentSection++; this.currentSection++;
// 节号实时同步到 HUD(内存进度,不持久化;整关通关时才统一写大关存档)。 // 回合号实时同步到 HUD(内存进度,不持久化;整关通关时才统一写大关存档)。
// 直接写 vmdata 视图层而非走 syncStageProgressToView(后者从 data 读,而 data 仍停留在大关起点) // 直接写 vmdata 视图层而非走 syncStageProgressToView(后者从 data 读,而 data 仍停留在大关起点)
const view = smc.vmdata.stage_progress; const view = smc.vmdata.stage_progress;
view.chapter = this.currentChapter;
view.stage = this.currentStage; view.stage = this.currentStage;
view.section = this.currentSection;
oops.message.dispatchEvent(GameEvent.STAGE_PROGRESS_UPDATE); oops.message.dispatchEvent(GameEvent.STAGE_PROGRESS_UPDATE);
// 触发 SectionStart 事件,MissionMonComp 据此生成下一节怪物(从右侧跑入) // 触发 SectionStart 事件,MissionMonComp 据此生成下一回合怪物(从右侧跑入)
oops.message.dispatchEvent(GameEvent.SectionStart, { oops.message.dispatchEvent(GameEvent.SectionStart, {
chapter: this.currentChapter,
stage: this.currentStage, stage: this.currentStage,
section: this.currentSection, section: this.currentSection,
}); });
mLogger.log(this.debugMode, 'MissionComp', mLogger.log(this.debugMode, 'MissionComp',
`[StageProgress] 进入小节: ${getProgressText(this.currentChapter, this.currentStage, this.currentSection)}`); `[StageProgress] 进入回合: ${getProgressText(this.currentStage, this.currentSection)}`);
} }
/** /**
* 重开本关:清理战场并重置数据,从本关第 1 节重新开始 * 重开本关:清理战场并重置数据,从本关第 1 回合重新开始
* Why: 一关一局,失败"再来一次"即整关重打(节恒从 1 开始) * Why: 一关一局,失败"再来一次"即整关重打(回合恒从 1 开始)
*/ */
private restartCurrentMission() { private restartCurrentMission() {
// 清理战场与局内数据 // 清理战场与局内数据
@@ -929,21 +888,20 @@ export class MissionComp extends CCComp {
this._victory = false; this._victory = false;
this._settleType = "defeat"; this._settleType = "defeat";
this._settleTitle = ""; this._settleTitle = "";
// 一关一局:重开从第 1 节开始 // 一关一局:重开从第 1 回合开始
this.currentSection = 1; this.currentSection = 1;
// 进入准备阶段 // 进入准备阶段
this.changePhase(MissionPhase.Prepare); this.changePhase(MissionPhase.Prepare);
// 触发 MissionStart 重置开局免费抽卡 // 触发 MissionStart 重置开局免费抽卡
oops.message.dispatchEvent(GameEvent.MissionStart, {}); oops.message.dispatchEvent(GameEvent.MissionStart, {});
oops.message.dispatchEvent(GameEvent.FightReady); oops.message.dispatchEvent(GameEvent.FightReady);
// 触发 SectionStart 重新生成本关第 1 节怪物 // 触发 SectionStart 重新生成本关第 1 回合怪物
oops.message.dispatchEvent(GameEvent.SectionStart, { oops.message.dispatchEvent(GameEvent.SectionStart, {
chapter: this.currentChapter,
stage: this.currentStage, stage: this.currentStage,
section: this.currentSection, section: this.currentSection,
}); });
mLogger.log(this.debugMode, 'MissionComp', mLogger.log(this.debugMode, 'MissionComp',
`[StageProgress] 重开本关: ${getProgressText(this.currentChapter, this.currentStage, this.currentSection)}`); `[StageProgress] 重开本关: ${getProgressText(this.currentStage, this.currentSection)}`);
} }
// ======================== 回合管理 ======================== // ======================== 回合管理 ========================
@@ -959,7 +917,7 @@ export class MissionComp extends CCComp {
* @param event 事件名 * @param event 事件名
* @param data { wave: number, bossWave?: boolean } * @param data { wave: number, bossWave?: boolean }
*/ */
private onNewWave(event: string, data: any) { private onNewWave(_event: string, data: any) {
const wave = Number(data?.wave ?? 0); const wave = Number(data?.wave ?? 0);
if (wave <= 0) return; if (wave <= 0) return;
@@ -968,12 +926,46 @@ export class MissionComp extends CCComp {
this.currentWave = wave; this.currentWave = wave;
smc.vmdata.mission_data.level = wave; smc.vmdata.mission_data.level = wave;
this.updateRoundNodes();
// 金币改为怪物死亡掉落(见 HeroAtkSystem),不再每回合固定发放 // 金币改为怪物死亡掉落(见 HeroAtkSystem),不再每回合固定发放
this.lastTimeSecond = -1; this.lastTimeSecond = -1;
this.clearTime = 0; this.clearTime = 0;
this.update_time(); this.update_time();
} }
/**
* 刷新回合指示节点颜色:
* - 已激活(已完成 + 当前回合)→ 黄色;当前回合且为 Boss 节 → 红色;未激活 → 白色。
* Why: 回合推进时(onNewWave)与开局重置(data_init)调用,驱动 HUD 回合指示实时反馈。
*/
private updateRoundNodes() {
const len = Math.min(this.round_nodes.length, SECTIONS_PER_STAGE);
for (let i = 0; i < len; i++) {
const node = this.round_nodes[i];
if (!node || !node.isValid) continue;
const round = i + 1;
const color = round > this.currentWave
? MissionComp.ROUND_INACTIVE
: (round === this.currentWave && this.isBossWave)
? MissionComp.ROUND_BOSS
: MissionComp.ROUND_ACTIVE;
// 优先染色 Sprite(图标配色),无 Sprite 时退化到 Label,均无则跳过
const sprite = node.getComponent(Sprite);
if (sprite) {
sprite.color = color;
} else {
const label = node.getComponent(Label);
if (label) label.color = color;
}
}
// 进度条:第 1 回合 0%,每推进一回合 +25%(第 5 回合满格)
if (this.round_progress && this.round_progress.isValid) {
this.round_progress.progress =
Math.max(0, Math.min(SECTIONS_PER_STAGE, this.currentWave) - 1) / (SECTIONS_PER_STAGE - 1);
}
}
// ======================== 怪物数量管理 ======================== // ======================== 怪物数量管理 ========================
/** /**
@@ -1182,115 +1174,6 @@ export class MissionComp extends CCComp {
} }
} }
/** 获取战斗层的英雄和技能节点数量(用于性能监控) */
private getBattleLayerNodeCount() {
const scene = smc.map?.MapView?.scene;
const layer = scene?.entityLayer?.node;
if (!layer) return { heroNodes: 0, skillNodes: 0 };
const heroRoot = layer.getChildByName("HERO");
const skillRoot = layer.getChildByName("SKILL");
return {
heroNodes: heroRoot?.children.length || 0,
skillNodes: skillRoot?.children.length || 0
};
}
// ======================== 性能监控面板 ========================
/** 性能监控相关代码 */
/** 初始化性能监控面板:在本组件节点下创建 Label */
private initMemoryPanel() {
if (!this.showMemoryPanel) return;
let panel = this.node.getChildByName("mem_panel");
if (!panel) {
panel = new Node("mem_panel");
panel.parent = this.node;
panel.setPosition(0, -32, 0);
}
let label = panel.getComponent(Label);
if (!label) {
label = panel.addComponent(Label);
}
label.fontSize = 16;
label.lineHeight = 20;
this.memoryLabel = label;
}
/** 移除性能监控面板 */
private removeMemoryPanel() {
const panel = this.node?.getChildByName("mem_panel");
if (panel) {
panel.destroy();
}
this.memoryLabel = null;
this.lastMemoryText = "";
}
/**
* 更新性能监控面板内容(每 0.5 秒一次):
* 显示 堆内存 / 增长趋势 / 帧率 / 实体数量 / 对象池状态 等信息。
*/
private updateMemoryPanel(dt: number) {
if (!this.showMemoryPanel || !this.memoryLabel) return;
this.perfDtAcc += dt;
this.perfFrameCount += 1;
this.memoryRefreshTimer += dt;
if (this.memoryRefreshTimer < 0.5) return;
this.memoryRefreshTimer = 0;
let heroCount = 0;
ecs.query(this.heroViewMatcher).forEach(() => {
heroCount++;
});
let skillCount = 0;
ecs.query(this.skillViewMatcher).forEach(() => {
skillCount++;
});
const monPool = Monster.getPoolStats();
const skillPool = Skill.getPoolStats();
const tooltipPool = Tooltip.getPoolStats();
const layerNodes = this.getBattleLayerNodeCount();
const perf = (globalThis as any).performance;
const heapBytes = perf && perf.memory ? perf.memory.usedJSHeapSize : 0;
let heapMB = heapBytes > 0 ? heapBytes / 1024 / 1024 : -1;
if (heapMB > 0 && this.heapBaseMB < 0) {
this.heapBaseMB = heapMB;
this.heapPeakMB = heapMB;
this.heapTrendBaseMB = heapMB;
this.heapTrendTimer = 0;
}
if (heapMB > this.heapPeakMB) {
this.heapPeakMB = heapMB;
}
this.heapTrendTimer += 0.5;
if (heapMB > 0 && this.heapTrendBaseMB > 0 && this.heapTrendTimer >= 10) {
const deltaMB = heapMB - this.heapTrendBaseMB;
this.heapTrendPerMinMB = (deltaMB / this.heapTrendTimer) * 60;
this.heapTrendBaseMB = heapMB;
this.heapTrendTimer = 0;
}
const heapText = heapMB > 0 ? heapMB.toFixed(1) : "N/A";
const heapDeltaText = this.heapBaseMB > 0 && heapMB > 0 ? (heapMB - this.heapBaseMB).toFixed(1) : "N/A";
const heapPeakText = this.heapPeakMB > 0 ? this.heapPeakMB.toFixed(1) : "N/A";
const avgDt = this.perfFrameCount > 0 ? this.perfDtAcc / this.perfFrameCount : 0;
const fps = avgDt > 0 ? 1 / avgDt : 0;
this.perfDtAcc = 0;
this.perfFrameCount = 0;
const text =
`Heap:${heapText}MB Δ:${heapDeltaText} Peak:${heapPeakText}\n` +
`Trend:${this.heapTrendPerMinMB.toFixed(2)}MB/min\n` +
`Perf dt:${(avgDt * 1000).toFixed(1)}ms fps:${fps.toFixed(1)}\n` +
`Ent H:${heroCount} S:${skillCount} N:${layerNodes.heroNodes}/${layerNodes.skillNodes}\n` +
`Pool M:${monPool.total}(${monPool.paths}) K:${skillPool.total}(${skillPool.paths}) T:${tooltipPool.total}`;
if (text === this.lastMemoryText) return;
this.lastMemoryText = text;
this.memoryLabel.string = text;
}
/** ECS 组件移除时销毁节点 */ /** ECS 组件移除时销毁节点 */
reset() { reset() {
this.PhaseTime = null as any; this.PhaseTime = null as any;

View File

@@ -124,12 +124,11 @@ export class MissionMonCompComp extends CCComp {
start() { } start() { }
/** /**
* 小节开始事件回调:生成怪物列表并按节奏刷出 * 回合开始事件回调:生成怪物列表并按节奏刷出
* @param event 事件名 * @param event 事件名
* @param data { chapter, stage, section } * @param data { stage, section }
*/ */
private onSectionStart(event: string, data: any) { private onSectionStart(event: string, data: any) {
const chapter = Number(data?.chapter ?? 1);
const stage = Number(data?.stage ?? 1); const stage = Number(data?.stage ?? 1);
const section = Number(data?.section ?? 1); const section = Number(data?.section ?? 1);
@@ -142,15 +141,15 @@ export class MissionMonCompComp extends CCComp {
smc.vmdata.mission_data.mon_num = 0; smc.vmdata.mission_data.mon_num = 0;
smc.vmdata.mission_data.pending_mon_num = 0; smc.vmdata.mission_data.pending_mon_num = 0;
// 从生成引擎获取本小节怪物列表 // 从生成引擎获取本回合怪物列表
const monsters = spawningEngine.generateSectionMonsters(chapter, stage, section); const monsters = spawningEngine.generateSectionMonsters(stage, section);
this.sectionTargetCount = monsters.length; this.sectionTargetCount = monsters.length;
if (TestModeConfig.enable) { if (TestModeConfig.enable) {
mLogger.log(this.debugMode, 'MissionMonComp', "[MissionMonComp] 测试模式已开启"); mLogger.log(this.debugMode, 'MissionMonComp', "[MissionMonComp] 测试模式已开启");
} }
mLogger.log(this.debugMode, 'MissionMonComp', mLogger.log(this.debugMode, 'MissionMonComp',
`[MissionMonComp] 小节 ${chapter}-${stage}-${section} 生成完成,怪物总数: ${this.sectionTargetCount}`); `[MissionMonComp] 回合 ${stage}-${section} 生成完成,怪物总数: ${this.sectionTargetCount}`);
// 按批次拆分:batch=0 立即刷,batch=1 进入待刷队列 // 按批次拆分:batch=0 立即刷,batch=1 进入待刷队列
const immediate: GeneratedMonster[] = []; const immediate: GeneratedMonster[] = [];

View File

@@ -1,30 +1,32 @@
/** /**
* @file RogueConfig.ts * @file RogueConfig.ts
* @description 关卡刷怪系统(章节-关-节三级推进) * @description 无限关卡刷怪系统(关-回合两级推进)
* *
* 游戏机制: * 游戏机制:
* - 玩家线性推进 1 章 10 关 × 每关 5 小节(一关一局,节间自动推进)。 * - 玩家单线无限推进:从第 1 关起无上限,每关 5 回合(一关一局,回合间自动推进)。
* - 每关节点固定:1~3 节普通(3 小怪,立即全刷)、第 4 节精英(3 精英同刷)、 * - 第 1~4 回合普通怪(3 小怪立即全刷),属性逐回合轻量增强(SECTION_RAMP_STEP)。
* 第 5 节 Boss(2 小怪先刷,Boss 延迟 1s 刷出)。 * - 第 5 回合单 Boss 登场(无护卫,延迟 1s 刷出),超厚血量(BOSS_HP_MUL)。
* - 怪物属性 = 基础 × 0.8 × (1 + 0.05×(lv-1)) × 类型倍率(精英1.5 / Boss3.0)。 * - Boss 加载时按攻击定位(近战/中程/远程)随机取型,并随机携带大招:
* 前期 1 个,随关卡解锁扩展至多个(BOSS_ULT_UNLOCK_EVERY / BOSS_ULT_MAX_COUNT)。
* *
* 设计层次: * 设计层次:
* 1. StageSet - 关卡配置(章节/关/节 + 数值公式) * 1. StageSet - 关卡数值公式(等级/成长/回合增强/Boss 血攻倍率)
* 2. MonSkillPool/BossSkillPool - 怪物技能池(atking / atked / dead 等全触发类型) * 2. BossPools - Boss 池(按攻击定位分组,动态从 HeroInfo 提取)
* 3. StageSpawningEngine - 生成引擎(按小节配置生成怪物列表) * 3. BossUltPools - Boss 大招池(按定位分组,引用 SkillSet 6100~6204 群体大招段)
* 4. StageSpawningEngine - 生成引擎(按回合配置生成怪物列表)
* *
* 核心公式: * 核心公式:
* 最终属性 = HeroInfo 基础属性 × MON_START_COEF × (1 + MON_GROW_SLOPE×(lv-1)) × 类型倍率 * 小怪属性 = HeroInfo 基础属性 × MON_START_COEF × (1 + MON_GROW_SLOPE×(lv-1)) × 回合增强
* 1 级小怪 ≈ 英雄 × 0.8,10 级小怪 ≈ 英雄 × 1.16,保持平缓成长。 * Boss 属性 = 同上 × BOSS_HP_MUL(血)/ BOSS_AP_MUL(攻),等级 = 关卡号无限成长
*/ */
import { HeroInfo, MonType, MonTypeName, TriggerGrouped } from "../common/config/heroSet"; import { HeroInfo, HType, MonType, TriggerGrouped, UltCdLv, UltCdSet } from "../common/config/heroSet";
import { SkillOverrides } from "../common/config/SkillSet"; import { SkillOverrides, SkillSet } from "../common/config/SkillSet";
import { FacSet } from "../common/config/GameSet"; import { FacSet } from "../common/config/GameSet";
import { import {
SectionType, SectionConfig, getSectionConfig, calcMonsterAttrs, SectionType, SectionConfig, getSectionConfig, calcMonsterAttrs,
NORMAL_MON_COUNT, NORMAL_FIRST_SPAWN, ELITE_COUNT, BOSS_ELITE_COUNT, BOSS_DELAY, NORMAL_MON_COUNT, NORMAL_FIRST_SPAWN, BOSS_DELAY,
MON_START_COEF, MON_GROW_SLOPE, ELITE_MUL, BOSS_MUL, MON_START_COEF,
} from "../common/config/StageSet"; } from "../common/config/StageSet";
// ======================== 1. 战斗常量 ======================== // ======================== 1. 战斗常量 ========================
@@ -79,126 +81,114 @@ export function getMonsterGoldDrop(monType: number, isBoss: boolean): number {
return Math.max(0, Math.floor(isBoss ? cfg.boss : cfg.base)); return Math.max(0, Math.floor(isBoss ? cfg.boss : cfg.base));
} }
// ======================== 3. 怪物技能池 ======================== // ======================== 3. Boss 池(按攻击定位分组) ========================
/** /**
* 怪物技能套装(一套完整的触发技能配置) * Boss 池:按攻击定位(近战/中程/远程)分组,动态从 HeroInfo 提取。
* 覆盖触发时机:call / atking / atked / dead / fstart / revive * 加载时随机一个定位 → 从对应池随机 Boss;定位池为空时自动回退(如暂无中程 Boss 配置)。
*/ */
export interface MonSkillSet { export const BossPools: Record<HType, number[]> = {
id: string; [HType.Melee]: [],
[HType.Mid]: [],
[HType.Long]: [],
};
for (const key in HeroInfo) {
const info = HeroInfo[key];
if (info.fac !== FacSet.MON) continue;
if (info.monType !== MonType.MeleeBoss && info.monType !== MonType.LongBoss) continue;
const pool = BossPools[info.type as HType];
if (pool) pool.push(info.uuid);
}
// ======================== 4. Boss 大招池 ========================
/** 每解锁 1 个额外大招收紧的关卡间隔(每 5 关 +1 个大招位) */
export const BOSS_ULT_UNLOCK_EVERY = 5;
/** Boss 同时携带大招数量上限 */
export const BOSS_ULT_MAX_COUNT = 3;
/**
* 获取指定关卡的 Boss 携带大招数量(1 个起步,随关卡解锁扩展)
* @param stage 关卡号(1~∞)
* @returns 大招数量(1~BOSS_ULT_MAX_COUNT)
*/
export function getBossUltCount(stage: number): number {
const st = Math.max(1, Math.floor(stage));
return Math.min(BOSS_ULT_MAX_COUNT, 1 + Math.floor((st - 1) / BOSS_ULT_UNLOCK_EVERY));
}
/** Boss 大招条目(s_uuid 引用 SkillSet 6100~6204 群体大招段,按定位分组) */
export interface BossUltEntry {
s_uuid: number;
name: string; name: string;
/** 普攻技能覆盖(可选,不填则使用怪物默认普攻) */ /** 抽取权重 */
skill?: { s_uuid: number; cd?: number; overrides?: SkillOverrides };
/** 召唤触发 */
call?: TriggerGrouped;
/** 攻击触发 */
atking?: TriggerGrouped;
/** 受击触发 */
atked?: TriggerGrouped;
/** 死亡触发 */
dead?: TriggerGrouped;
/** 战斗开始触发 */
fstart?: TriggerGrouped;
/** 复活触发 */
revive?: TriggerGrouped;
/** 在技能池中的抽取权重 */
weight: number; weight: number;
/** 技能参数覆盖(伤害系数等) */
overrides?: SkillOverrides;
} }
/** /**
* 怪物技能池(硬编码) * Boss 大招池(按攻击定位分组)
* 技能 uuid 引用 SkillSet 中的 6000~6500 段触发技能。 * 大招注入 Boss 的 skills 表后由 SCastSystem 按 CD 自动施放(含镜头聚焦 + 技能名横幅)。
*/ */
export const MonSkillPool: Record<string, MonSkillSet> = { export const BossUltPools: Record<HType, BossUltEntry[]> = {
/** 狂暴:攻击触发自身攻击提升 */ // 近战系:战士群体斩击(6100~6104 段)
berserk: { [HType.Melee]: [
id: "berserk", name: "狂暴", weight: 10, { s_uuid: 6100, name: "寒冰斩", weight: 10, overrides: { ap: 180 } },
atking: { { s_uuid: 6101, name: "裂气斩", weight: 10, overrides: { ap: 180 } },
6401: [{ lv: 1, t_num: 5, overrides: { ap: 1 } }], { s_uuid: 6102, name: "火焰斩", weight: 10, overrides: { ap: 180 } },
}, { s_uuid: 6103, name: "闪电斩", weight: 8, overrides: { ap: 180 } },
}, { s_uuid: 6104, name: "开天斩", weight: 6, overrides: { ap: 220 } },
/** 坚韧:受击获得护盾 */ ],
tough: { // 中程系:射手箭雨 + 混合法术(6150~6151 / 6203~6204 段)
id: "tough", name: "坚韧", weight: 8, [HType.Mid]: [
atked: { { s_uuid: 6150, name: "万箭齐发", weight: 10, overrides: { ap: 150 } },
6301: [{ lv: 1, t_num: 3, overrides: { ap: 2 } }], { s_uuid: 6151, name: "火箭齐发", weight: 10, overrides: { ap: 150 } },
}, { s_uuid: 6203, name: "能量波", weight: 8, overrides: { ap: 150 } },
}, { s_uuid: 6204, name: "雷暴", weight: 8, overrides: { ap: 150 } },
/** 遗志:死亡时全队攻击提升 */ ],
legacy: { // 远程系:法师群体法术(6200~6204 段)
id: "legacy", name: "遗志", weight: 6, [HType.Long]: [
dead: { { s_uuid: 6200, name: "火球术", weight: 10, overrides: { ap: 160 } },
6401: [{ lv: 1, t_num: 1, overrides: { ap: 3 } }], { s_uuid: 6201, name: "飓风", weight: 10, overrides: { ap: 140 } },
}, { s_uuid: 6202, name: "毒气弹", weight: 8, overrides: { ap: 150 } },
}, { s_uuid: 6203, name: "能量波", weight: 8, overrides: { ap: 150 } },
/** 战吼:战斗开始时全队攻击提升 */ { s_uuid: 6204, name: "雷暴", weight: 8, overrides: { ap: 150 } },
warcry: { ],
id: "warcry", name: "战吼", weight: 5,
fstart: {
6401: [{ lv: 1, t_num: 1, overrides: { ap: 2 } }],
},
},
/** 吸血:攻击恢复生命 */
leech: {
id: "leech", name: "吸血", weight: 7,
atking: {
6302: [{ lv: 1, t_num: 4, overrides: { ap: 150 } }],
},
},
}; };
/** Boss 专属技能池 */ // ======================== 5. 配置校验 ========================
export const BossSkillPool: Record<string, MonSkillSet> = {
/** 狂暴领主:攻击触发全队攻击提升 */
boss_rage: {
id: "boss_rage", name: "狂暴领主", weight: 10,
atking: {
6401: [{ lv: 1, t_num: 3, overrides: { ap: 3 } }],
},
dead: {
6401: [{ lv: 1, t_num: 1, overrides: { ap: 5 } }],
},
},
/** 铁壁领主:受击获得高额护盾 */
boss_iron: {
id: "boss_iron", name: "铁壁领主", weight: 8,
atked: {
6301: [{ lv: 1, t_num: 2, overrides: { ap: 5 } }],
},
},
/** 毁灭领主:战斗开始时全队攻击大幅提升 */
boss_doom: {
id: "boss_doom", name: "毁灭领主", weight: 6,
fstart: {
6401: [{ lv: 1, t_num: 1, overrides: { ap: 8 } }],
},
atking: {
6401: [{ lv: 1, t_num: 5, overrides: { ap: 2 } }],
},
},
};
// ======================== 4. 配置校验 ========================
/** /**
* 校验 MonSkillPool / BossSkillPool 引用一致性 * 校验 Boss 池 / Boss 大招池引用一致性
* 建议在游戏启动时调用一次,便于发现配置错误 * 建议在游戏启动时调用一次,便于发现配置错误
* @returns 错误信息数组,空数组表示校验通过 * @returns 错误信息数组,空数组表示校验通过
*/ */
export function validateRogueConfig(): string[] { export function validateRogueConfig(): string[] {
const errors: string[] = []; const errors: string[] = [];
// 校验 Boss 类型在 MonList 中有怪 // 校验至少一个定位有可用 Boss
if ((!MonList[MonType.MeleeBoss] || MonList[MonType.MeleeBoss].length === 0) const hasBoss = (Object.keys(BossPools) as unknown as HType[]).some(t => BossPools[t].length > 0);
&& (!MonList[MonType.LongBoss] || MonList[MonType.LongBoss].length === 0)) { if (!hasBoss) {
errors.push("MonList 中无任何 Boss 类型(MeleeBoss/LongBoss)可用 uuid"); errors.push("BossPools 中无任何可用 Boss uuid(MeleeBoss/LongBoss 均缺失)");
}
// 校验大招池条目均存在于 SkillSet
for (const key in BossUltPools) {
const pool = BossPools[key as unknown as HType];
const ults = BossUltPools[key as unknown as HType];
if (!pool || pool.length === 0) continue; // 空定位池跳过(大招池无消费方)
for (const ult of ults) {
if (!SkillSet[ult.s_uuid]) {
errors.push(`BossUltPools[${key}] 大招 ${ult.s_uuid}(${ult.name}) 未在 SkillSet 中定义`);
}
}
} }
return errors; return errors;
} }
// ======================== 5. 生成结果接口 ======================== // ======================== 6. 生成结果接口 ========================
/** 生成结果(传递给 MissionMonComp 用于实例化怪物) */ /** 生成结果(传递给 MissionMonComp 用于实例化怪物) */
export interface GeneratedMonster { export interface GeneratedMonster {
@@ -207,10 +197,8 @@ export interface GeneratedMonster {
hp: number; hp: number;
ap: number; ap: number;
isBoss: boolean; isBoss: boolean;
/** 是否为精英(精英关/Boss 关的精英) */ /** 是否为精英(对象池复用实体需显式重置的标记位) */
isElite?: boolean; isElite?: boolean;
/** 是否为 Boss 护卫队成员(供 UI/统计识别) */
isBossGuard?: boolean;
/** 怪物等级(驱动技能等级增量,Mon.load 第 6 参) */ /** 怪物等级(驱动技能等级增量,Mon.load 第 6 参) */
lv: number; lv: number;
spawnIndex: number; spawnIndex: number;
@@ -220,11 +208,15 @@ export interface GeneratedMonster {
delay?: number; delay?: number;
/** /**
* 怪物技能套装(覆盖全部触发时机) * 怪物技能套装(技能注入通道,与 _testSkills 相同,在 Mon.load() 中写入 HeroAttrsComp)
* 注入方式与 _testSkills 相同,在 Mon.load() 中写入 HeroAttrsComp * - skill:替换普攻(会清空原技能表)
* - ults:追加 Boss 大招(保留普攻,多个大招共存,SCastSystem 按 CD 轮转施放)
* - 其余为触发技能组覆盖
*/ */
skills?: { skills?: {
skill?: { s_uuid: number; cd?: number; overrides?: SkillOverrides }; skill?: { s_uuid: number; cd?: number; overrides?: SkillOverrides };
/** Boss 大招列表(追加注入,不替换普攻) */
ults?: { s_uuid: number; cd?: number; overrides?: SkillOverrides }[];
call?: TriggerGrouped; call?: TriggerGrouped;
atking?: TriggerGrouped; atking?: TriggerGrouped;
atked?: TriggerGrouped; atked?: TriggerGrouped;
@@ -234,7 +226,7 @@ export interface GeneratedMonster {
}; };
} }
// ======================== 6. 测试模式配置 ======================== // ======================== 7. 测试模式配置 ========================
export const TestModeConfig = { export const TestModeConfig = {
enable: false, // 默认关闭测试模式 enable: false, // 默认关闭测试模式
@@ -245,48 +237,43 @@ export const TestModeConfig = {
spawnCount: 1, spawnCount: 1,
skill: undefined as { s_uuid: number; cd?: number; overrides?: SkillOverrides } | undefined, skill: undefined as { s_uuid: number; cd?: number; overrides?: SkillOverrides } | undefined,
/** 测试模式注入的大招列表(追加,不替换普攻) */
ults: undefined as { s_uuid: number; cd?: number; overrides?: SkillOverrides }[] | undefined,
atking: undefined as TriggerGrouped | undefined, atking: undefined as TriggerGrouped | undefined,
atked: undefined as TriggerGrouped | undefined, atked: undefined as TriggerGrouped | undefined,
dead: undefined as TriggerGrouped | undefined, dead: undefined as TriggerGrouped | undefined,
fstart: undefined as TriggerGrouped | undefined, fstart: undefined as TriggerGrouped | undefined,
}; };
// ======================== 7. 生成引擎 ======================== // ======================== 8. 生成引擎 ========================
/** /**
* 关卡刷怪生成引擎 * 无限关卡刷怪生成引擎
* 按章节-关-节配置生成怪物列表,属性走 StageSet 数值公式 * 按关-回合配置生成怪物列表,属性走 StageSet 数值公式
*/ */
export class StageSpawningEngine { export class StageSpawningEngine {
/** /**
* 生成指定小节的怪物列表 * 生成指定回合的怪物列表
* @param chapter 章节号 * @param stage 关卡号(1~∞)
* @param stage 关卡号 * @param section 回合号(1~SECTIONS_PER_STAGE)
* @param section 小节号(1~10)
* @returns 怪物列表(按刷出顺序排列) * @returns 怪物列表(按刷出顺序排列)
*/ */
generateSectionMonsters(chapter: number, stage: number, section: number): GeneratedMonster[] { generateSectionMonsters(stage: number, section: number): GeneratedMonster[] {
// 测试模式拦截:完全绕过生成引擎,直接返回硬编码测试怪 // 测试模式拦截:完全绕过生成引擎,直接返回硬编码测试怪
if (TestModeConfig.enable) { if (TestModeConfig.enable) {
return this.generateTestWave(); return this.generateTestWave();
} }
const cfg = getSectionConfig(chapter, stage, section); const cfg = getSectionConfig(stage, section);
if (!cfg) { if (!cfg) {
// 配置缺失兜底:生成 3 只 Lv1 近战小怪 // 配置缺失兜底:生成 3 只 Lv1 近战小怪
return this.makeFallbackMonsters(); return this.makeFallbackMonsters();
} }
switch (cfg.type) { return cfg.type === SectionType.Boss
case SectionType.Elite: ? this.generateBossSection(cfg, stage)
return this.generateEliteSection(cfg); : this.generateNormalSection(cfg);
case SectionType.Boss:
return this.generateBossSection(cfg);
case SectionType.Normal:
default:
return this.generateNormalSection(cfg);
}
} }
/** 重置引擎状态(每局开始时调用,预留) */ /** 重置引擎状态(每局开始时调用,预留) */
@@ -294,7 +281,8 @@ export class StageSpawningEngine {
} }
/** /**
* 普通节:NORMAL_MON_COUNT 只小怪全部立即刷出(batch=0) * 普通回合(1~4):NORMAL_MON_COUNT 只小怪全部立即刷出(batch=0),
* 属性乘回合增强系数(cfg.ramp)实现逐回合轻量增强
*/ */
private generateNormalSection(cfg: SectionConfig): GeneratedMonster[] { private generateNormalSection(cfg: SectionConfig): GeneratedMonster[] {
const monsters: GeneratedMonster[] = []; const monsters: GeneratedMonster[] = [];
@@ -304,64 +292,49 @@ export class StageSpawningEngine {
const type = types[i % types.length]; const type = types[i % types.length];
const mon = this.makeMonster(type, cfg.monLv, i); const mon = this.makeMonster(type, cfg.monLv, i);
mon.batch = i < NORMAL_FIRST_SPAWN ? 0 : 1; mon.batch = i < NORMAL_FIRST_SPAWN ? 0 : 1;
// 回合内轻量增强:第 n 回合 × (1 + SECTION_RAMP_STEP×(n-1))
mon.hp = Math.max(1, Math.round(mon.hp * cfg.ramp));
mon.ap = Math.max(1, Math.round(mon.ap * cfg.ramp));
monsters.push(mon); monsters.push(mon);
} }
return monsters; return monsters;
} }
/** /**
* 精英节:3 只精英同时刷出 * Boss 回合(5):单 Boss 登场(无护卫)
* Boss 延迟 BOSS_DELAY 秒刷出,属性由 makeBoss 按血/攻分离倍率计算(超厚血量)
*/ */
private generateEliteSection(cfg: SectionConfig): GeneratedMonster[] { private generateBossSection(cfg: SectionConfig, stage: number): GeneratedMonster[] {
const monsters: GeneratedMonster[] = []; const boss = this.makeBoss(cfg.monLv, stage, 0);
const count = cfg.eliteCount ?? ELITE_COUNT;
// 精英池:近战/重型/远程/刺客
const eliteTypes = [MonType.Melee, MonType.Heavy, MonType.Long, MonType.Assassin];
for (let i = 0; i < count; i++) {
const type = eliteTypes[i % eliteTypes.length];
const mon = this.makeMonster(type, cfg.monLv, i);
mon.isElite = true;
mon.batch = 0;
// 精英属性 = 普通 × ELITE_MUL
mon.hp = Math.max(1, Math.round(mon.hp * ELITE_MUL));
mon.ap = Math.max(1, Math.round(mon.ap * ELITE_MUL));
monsters.push(mon);
}
return monsters;
}
/**
* Boss 节:2 小怪护卫 + 1 Boss
* 小怪先刷(batch=0),Boss 延迟刷出(batch=0, delay=BOSS_DELAY)
*/
private generateBossSection(cfg: SectionConfig): GeneratedMonster[] {
const monsters: GeneratedMonster[] = [];
const eliteCount = cfg.eliteCount ?? BOSS_ELITE_COUNT;
const eliteTypes = [MonType.Melee, MonType.Heavy];
// 先刷精英
for (let i = 0; i < eliteCount; i++) {
const type = eliteTypes[i % eliteTypes.length];
const mon = this.makeMonster(type, cfg.monLv, i);
mon.isElite = true;
mon.isBossGuard = true;
mon.batch = 0;
mon.hp = Math.max(1, Math.round(mon.hp * ELITE_MUL));
mon.ap = Math.max(1, Math.round(mon.ap * ELITE_MUL));
monsters.push(mon);
}
// Boss 延迟刷出
const boss = this.makeBoss(cfg.monLv, monsters.length);
boss.batch = 0; boss.batch = 0;
boss.delay = BOSS_DELAY; boss.delay = BOSS_DELAY;
// Boss 属性 = 普通 × BOSS_MUL return [boss];
boss.hp = Math.max(1, Math.round(boss.hp * BOSS_MUL)); }
boss.ap = Math.max(1, Math.round(boss.ap * BOSS_MUL));
monsters.push(boss);
return monsters; /** 生成普通怪物(属性按 StageSet 公式计算) */
private makeMonster(type: MonType, monLv: number, spawnIndex: number): GeneratedMonster {
let uuids = MonList[type];
if (!uuids || uuids.length === 0) {
// 兜底 Melee
uuids = MonList[MonType.Melee] || [6001];
}
const uuid = uuids[Math.floor(Math.random() * uuids.length)];
const baseInfo = HeroInfo[uuid];
const baseHp = baseInfo ? baseInfo.hp : 100;
const baseAp = baseInfo ? baseInfo.ap : 10;
const attrs = calcMonsterAttrs(baseHp, baseAp, monLv, false);
return {
uuid,
type,
hp: attrs.hp,
ap: attrs.ap,
isBoss: false,
lv: monLv,
spawnIndex,
batch: 0,
};
} }
/** 配置缺失兜底:3 只 Lv1 近战小怪 */ /** 配置缺失兜底:3 只 Lv1 近战小怪 */
@@ -399,6 +372,7 @@ export class StageSpawningEngine {
batch: 0, batch: 0,
skills: { skills: {
skill: TestModeConfig.skill, skill: TestModeConfig.skill,
ults: TestModeConfig.ults,
atking: TestModeConfig.atking, atking: TestModeConfig.atking,
atked: TestModeConfig.atked, atked: TestModeConfig.atked,
dead: TestModeConfig.dead, dead: TestModeConfig.dead,
@@ -409,77 +383,74 @@ export class StageSpawningEngine {
return monsters; return monsters;
} }
/** 生成 Boss(基础面板按 StageSet 公式计算) */ /**
private makeBoss(monLv: number, spawnIndex: number): GeneratedMonster { * 生成 Boss:加载时随机攻击定位 → 从对应池随机 Boss 个体 → 随机携带大招
const isMeleeBoss = Math.random() < 0.5; * 属性走 calcMonsterAttrs(isBoss=true):HP × BOSS_HP_MUL(超厚血)/ AP × BOSS_AP_MUL
const type = isMeleeBoss ? MonType.MeleeBoss : MonType.LongBoss; */
private makeBoss(monLv: number, stage: number, spawnIndex: number): GeneratedMonster {
const range = this.pickBossRange();
const uuid = this.pickBossUuid(range);
// Boss 类型兜底:若 MonList 缺失则退回 MeleeBoss
let uuids = MonList[type];
if (!uuids || uuids.length === 0) {
uuids = MonList[MonType.MeleeBoss] || MonList[MonType.Melee] || [6001];
}
const uuid = uuids[Math.floor(Math.random() * uuids.length)];
// Boss 基础面板取 HeroInfo 基础值,属性由调用方乘 BOSS_MUL
const baseInfo = HeroInfo[uuid]; const baseInfo = HeroInfo[uuid];
const baseHp = baseInfo ? baseInfo.hp : 600; const baseHp = baseInfo ? baseInfo.hp : 600;
const baseAp = baseInfo ? baseInfo.ap : 30; const baseAp = baseInfo ? baseInfo.ap : 30;
const attrs = calcMonsterAttrs(baseHp, baseAp, monLv, false, false); const attrs = calcMonsterAttrs(baseHp, baseAp, monLv, true);
return { return {
uuid, uuid,
type, type: baseInfo?.monType ?? MonType.MeleeBoss,
hp: attrs.hp, hp: attrs.hp,
ap: attrs.ap, ap: attrs.ap,
isBoss: true, isBoss: true,
lv: monLv, lv: monLv,
spawnIndex, spawnIndex,
batch: 0, batch: 0,
skills: {
ults: this.pickBossUlts(range, stage),
},
}; };
} }
/** 生成普通怪物(属性按 StageSet 公式计算) */ /**
private makeMonster(type: MonType, monLv: number, spawnIndex: number): GeneratedMonster { * 随机 Boss 攻击定位(近战/中程/远程)
let uuids = MonList[type]; * 空池自动回退:中程暂无 Boss 配置时落到远程/近战,后续补配即自动生效
*/
private pickBossRange(): HType {
const all: HType[] = [HType.Melee, HType.Mid, HType.Long];
const first = all[Math.floor(Math.random() * all.length)];
if (BossPools[first].length > 0) return first;
// 回退链:随机定位空池时按剩余定位找非空池
const fallback = all.find(t => BossPools[t].length > 0);
return fallback ?? HType.Melee;
}
/** 从指定定位池随机取 Boss uuid(含全局兜底) */
private pickBossUuid(range: HType): number {
let uuids = BossPools[range];
if (!uuids || uuids.length === 0) { if (!uuids || uuids.length === 0) {
// 兜底 Melee uuids = MonList[MonType.MeleeBoss] || MonList[MonType.Melee] || [6001];
uuids = MonList[MonType.Melee] || [6001];
} }
const uuid = uuids[Math.floor(Math.random() * uuids.length)]; return uuids[Math.floor(Math.random() * uuids.length)];
const baseInfo = HeroInfo[uuid];
const baseHp = baseInfo ? baseInfo.hp : 100;
const baseAp = baseInfo ? baseInfo.ap : 10;
const attrs = calcMonsterAttrs(baseHp, baseAp, monLv, false, false);
return {
uuid,
type,
hp: attrs.hp,
ap: attrs.ap,
isBoss: false,
lv: monLv,
spawnIndex,
batch: 0,
};
} }
/** 从技能池中按权重抽取一套技能 */ /**
private pickSkillSet(pool: string[], library: Record<string, MonSkillSet>): GeneratedMonster["skills"] | undefined { * 按定位抽取 Boss 大招(不重复),数量由关卡进度决定(getBossUltCount)
const valid = pool.map(id => library[id]).filter(s => s); * @returns 大招配置列表;池空时返回 undefined
if (valid.length === 0) return undefined; */
const picked = this.pickWeighted(valid); private pickBossUlts(range: HType, stage: number): GeneratedMonster["skills"]["ults"] {
if (!picked) return undefined; const pool = [...(BossUltPools[range] ?? [])];
return { const count = Math.min(getBossUltCount(stage), pool.length);
skill: picked.skill, if (count <= 0) return undefined;
call: picked.call,
atking: picked.atking, const ults: { s_uuid: number; cd?: number; overrides?: SkillOverrides }[] = [];
atked: picked.atked, for (let i = 0; i < count; i++) {
dead: picked.dead, const picked = this.pickWeighted(pool);
fstart: picked.fstart, if (!picked) break;
revive: picked.revive, pool.splice(pool.indexOf(picked), 1);
}; // 大招 CD 取英雄同档标准档(8s),与英雄大招节奏对齐
ults.push({ s_uuid: picked.s_uuid, cd: UltCdSet[UltCdLv.Normal].cd, overrides: picked.overrides });
}
return ults.length > 0 ? ults : undefined;
} }
/** 通用加权随机抽取 */ /** 通用加权随机抽取 */
@@ -496,18 +467,6 @@ export class StageSpawningEngine {
} }
} }
// ======================== 8. 全局单例 ======================== // ======================== 9. 全局单例 ========================
export const spawningEngine = new StageSpawningEngine(); export const spawningEngine = new StageSpawningEngine();
// 保留旧接口兼容(逐步迁移期使用)
/** @deprecated 请使用 StageSpawningEngine.generateSectionMonsters */
export class RogueSpawningEngine extends StageSpawningEngine {
/** @deprecated 请使用 generateSectionMonsters */
generateBossCombo(): GeneratedMonster[] {
return this.generateSectionMonsters(1, 1, 1);
}
}
/** @deprecated 请使用 spawningEngine */
export const rogueSpawningEngine = new RogueSpawningEngine();

View File

@@ -2,7 +2,7 @@ import { _decorator, Animation, CCFloat, CCInteger, Collider2D, Contact2DType, E
import { ecs } from "../../../../extensions/oops-plugin-framework/assets/libs/ecs/ECS"; import { ecs } from "../../../../extensions/oops-plugin-framework/assets/libs/ecs/ECS";
import { CCComp } from "../../../../extensions/oops-plugin-framework/assets/module/common/CCComp"; import { CCComp } from "../../../../extensions/oops-plugin-framework/assets/module/common/CCComp";
import { HeroViewComp } from "../hero/HeroViewComp"; import { HeroViewComp } from "../hero/HeroViewComp";
import { DTType, EType, RType, SkillConfig, SkillSet } from "../common/config/SkillSet"; import { DTType, EType, RType, SkillConfig, SkillSet, SummonTMode } from "../common/config/SkillSet";
import { SDataCom } from "./SDataCom"; import { SDataCom } from "./SDataCom";
import { HeroAttrsComp } from "../hero/HeroAttrsComp"; import { HeroAttrsComp } from "../hero/HeroAttrsComp";
import { DamageQueueHelper } from "../hero/DamageQueueComp"; import { DamageQueueHelper } from "../hero/DamageQueueComp";
@@ -54,6 +54,10 @@ export class SkillView extends CCComp {
@property({ type: CCInteger, slide: true, range: [1, 8, 1], tooltip: "单次施法召唤的技能实体个数" }) @property({ type: CCInteger, slide: true, range: [1, 8, 1], tooltip: "单次施法召唤的技能实体个数" })
summon_count: number = 1; summon_count: number = 1;
/** 召唤目标选择模式:same=锁定同一敌人(默认);random=每次出手随机敌人;unique=避免重复敌人(一轮选完重置) */
@property({ type: Enum(SummonTMode), tooltip: "召唤目标选择:同一敌人/随机敌人/避免相同敌人" })
summon_target_mode: SummonTMode = SummonTMode.same;
/** 召唤物 X 轴步进偏移(像素):summon_count>1 时以出生点/目标点为中心对称交替铺开(第1个=0,之后按 +1,-1,+2,-2... 档 × 该值,正=右) */ /** 召唤物 X 轴步进偏移(像素):summon_count>1 时以出生点/目标点为中心对称交替铺开(第1个=0,之后按 +1,-1,+2,-2... 档 × 该值,正=右) */
@property({ type: CCFloat, slide: true, range: [-200, 200, 5], tooltip: "召唤物X轴步进偏移:以中心对称交替铺开(0,+1,-1,+2,-2...档×该值)" }) @property({ type: CCFloat, slide: true, range: [-200, 200, 5], tooltip: "召唤物X轴步进偏移:以中心对称交替铺开(0,+1,-1,+2,-2...档×该值)" })
summon_x_offset: number = 0; summon_x_offset: number = 0;

File diff suppressed because it is too large Load Diff

View File

@@ -70,9 +70,12 @@
## 4. 触发组规范(atking / atked / fstart / fend / dead) ## 4. 触发组规范(atking / atked / fstart / fend / dead)
- 结构:`{ "<技能uuid字符串>": [条目, ...] }`,一个组可挂多个技能 uuid; - 结构:`{ "<技能uuid字符串>": [条目, ...] }`,一个组可挂多个技能 uuid;
- 条目:`{lv, s_lv, name, t_num, overrides, desc}`; - 条目:`{lv, s_lv, name, t_num, t_chance?, pity_add?, overrides, desc}`;
- 解锁等级惯例 **lv4**(`lv:4, s_lv:1`;heroSet.ts 头部注释写的 lv6 已过时,现有英雄与编辑器默认值均为 lv4); - 解锁等级惯例 **lv4**(`lv:4, s_lv:1`;heroSet.ts 头部注释写的 lv6 已过时,现有英雄与编辑器默认值均为 lv4);
- `t_num`:每 n 次普攻(atking)/受击(atked)触发一次;fstart/fend 为每回合开始/结束固定触发 1 次,`t_num` 恒填 1; - `t_num`:每 n 次普攻(atking)/受击(atked)触发一次;fstart/fend 为每回合开始/结束固定触发 1 次,`t_num` 恒填 1;
- `t_chance`:触发概率(百分点 0~100,**仅 atking/atked 生效**,其余组忽略);缺省/100 = 必触发。示例 30 表示次数条件达成后掷骰 30%;
- `pity_add`:保底叠加(百分点,仅 atking/atked 生效);未触发时为该技能累积下次概率增量,触发成功后清零、封顶 100。示例 `t_chance:30, pity_add:20` → 30/50/70/90/100 递进;
- 触发组 `desc` 模板可额外使用 `{t_chance}`(触发概率,缺省渲染 100)与 `{pity_add}`(保底叠加,缺省渲染 0)占位符;模板显式使用 `{t_chance}` 时触发语境不再自动追加"(N%概率)"后缀,避免重复;
- `name` 为组对外展示名(写在该组首档),留空回退底座名; - `name` 为组对外展示名(写在该组首档),留空回退底座名;
- 复活:在 `dead` 某条目 `overrides` 配 `revive_hp`(回血%)+ `revive_count`(次数上限); - 复活:在 `dead` 某条目 `overrides` 配 `revive_hp`(回血%)+ `revive_count`(次数上限);
- 无触发组时写空对象 `{}`,**不要省略字段**。 - 无触发组时写空对象 `{}`,**不要省略字段**。

View File

@@ -215,6 +215,9 @@ function renderSingleHero(h) {
if (e.s_lv) eparts.push(`s_lv: SkillLv.Lv${e.s_lv}`) if (e.s_lv) eparts.push(`s_lv: SkillLv.Lv${e.s_lv}`)
if (e.name) eparts.push(`name: ${JSON.stringify(e.name)}`) if (e.name) eparts.push(`name: ${JSON.stringify(e.name)}`)
eparts.push(`t_num: ${e.t_num}`) eparts.push(`t_num: ${e.t_num}`)
// 概率参数:仅攻/受击触发消费;缺省(100/0)不输出,保持生成 TS 干净
if (e.t_chance != null && e.t_chance < 100) eparts.push(`t_chance: ${e.t_chance}`)
if (e.pity_add != null && e.pity_add > 0) eparts.push(`pity_add: ${e.pity_add}`)
if (e.overrides && Object.keys(e.overrides).length) eparts.push(`overrides: ${serializeOverrides(e.overrides)}`) if (e.overrides && Object.keys(e.overrides).length) eparts.push(`overrides: ${serializeOverrides(e.overrides)}`)
if (e.desc) eparts.push(`desc: ${JSON.stringify(e.desc)}`) if (e.desc) eparts.push(`desc: ${JSON.stringify(e.desc)}`)
push(` { ${eparts.join(', ')} },`) push(` { ${eparts.join(', ')} },`)
@@ -351,6 +354,8 @@ function csvTrigger(grp) {
const name = e.name || base?.name || '' const name = e.name || base?.name || ''
const ov = e.overrides || {} const ov = e.overrides || {}
const parts = [`t_num${e.t_num}`] const parts = [`t_num${e.t_num}`]
// 攻/受击组附带概率信息(缺省 100 不展示)
if (e.t_chance != null && e.t_chance < 100) parts.push(`概率${e.t_chance}%`)
if (ov.ap != null) parts.push(`ap${ov.ap}`) if (ov.ap != null) parts.push(`ap${ov.ap}`)
const desc = e.desc || '' const desc = e.desc || ''
return `${sid} ${name}(${parts.join(';')}):${desc}` return `${sid} ${name}(${parts.join(';')}):${desc}`

View File

@@ -165,11 +165,11 @@
<div class="panel"> <div class="panel">
<h3>触发技能(lv4 激活)</h3> <h3>触发技能(lv4 激活)</h3>
<el-tabs> <el-tabs>
<el-tab-pane label="atking 攻击后"><TriggerGroupEditor :model="current.atking" :skill-options="allSkills" :skill-map="skillMap" :buff-options="buffOptions" /></el-tab-pane> <el-tab-pane label="atking 攻击后"><TriggerGroupEditor group="atking" :model="current.atking" :skill-options="allSkills" :skill-map="skillMap" :buff-options="buffOptions" /></el-tab-pane>
<el-tab-pane label="atked 受击后"><TriggerGroupEditor :model="current.atked" :skill-options="allSkills" :skill-map="skillMap" :buff-options="buffOptions" /></el-tab-pane> <el-tab-pane label="atked 受击后"><TriggerGroupEditor group="atked" :model="current.atked" :skill-options="allSkills" :skill-map="skillMap" :buff-options="buffOptions" /></el-tab-pane>
<el-tab-pane label="fstart 战斗开始"><TriggerGroupEditor :model="current.fstart" :skill-options="allSkills" :skill-map="skillMap" :buff-options="buffOptions" /></el-tab-pane> <el-tab-pane label="fstart 战斗开始"><TriggerGroupEditor group="fstart" :model="current.fstart" :skill-options="allSkills" :skill-map="skillMap" :buff-options="buffOptions" /></el-tab-pane>
<el-tab-pane label="fend 回合结束"><TriggerGroupEditor :model="current.fend" :skill-options="allSkills" :skill-map="skillMap" :buff-options="buffOptions" /></el-tab-pane> <el-tab-pane label="fend 回合结束"><TriggerGroupEditor group="fend" :model="current.fend" :skill-options="allSkills" :skill-map="skillMap" :buff-options="buffOptions" /></el-tab-pane>
<el-tab-pane label="dead 死亡后"><TriggerGroupEditor :model="current.dead" :skill-options="allSkills" :skill-map="skillMap" :buff-options="buffOptions" /></el-tab-pane> <el-tab-pane label="dead 死亡后"><TriggerGroupEditor group="dead" :model="current.dead" :skill-options="allSkills" :skill-map="skillMap" :buff-options="buffOptions" /></el-tab-pane>
</el-tabs> </el-tabs>
</div> </div>
@@ -380,7 +380,15 @@ function triggerSummary(h) {
const name = entries[0]?.name || skillMap.value[sid]?.name || '' const name = entries[0]?.name || skillMap.value[sid]?.name || ''
const e = entries[0] const e = entries[0]
const ov = e?.overrides || {} const ov = e?.overrides || {}
const parts = [`t_num${e?.t_num}`, ...overrideParts(ov)] const parts = [`t_num${e?.t_num}`]
// 攻/受击组附带概率与保底信息(缺省 100%/0 不展示)
if (tk === 'atking' || tk === 'atked') {
if (e?.t_chance != null && e.t_chance < 100) {
parts.push(`概率${e.t_chance}%`)
if (e.pity_add > 0) parts.push(`保底+${e.pity_add}%`)
}
}
parts.push(...overrideParts(ov))
lines.push(`${tk}: ${sid} ${name} lv${minLv} ${parts.join(' ')}`) lines.push(`${tk}: ${sid} ${name} lv${minLv} ${parts.join(' ')}`)
} }
} }

View File

@@ -32,6 +32,8 @@
<span class="tpl-meta-item">{{ p.uuid }} {{ skillName(p.uuid) }}</span> <span class="tpl-meta-item">{{ p.uuid }} {{ skillName(p.uuid) }}</span>
<span class="tpl-meta-sep">·</span> <span class="tpl-meta-sep">·</span>
<span class="tpl-meta-item">t_num {{ p.entry.t_num }}</span> <span class="tpl-meta-item">t_num {{ p.entry.t_num }}</span>
<span class="tpl-meta-sep" v-if="p.entry.t_chance != null && p.entry.t_chance < 100">·</span>
<span class="tpl-meta-item" v-if="p.entry.t_chance != null && p.entry.t_chance < 100">概率 {{ p.entry.t_chance }}%</span>
<span class="tpl-meta-sep">·</span> <span class="tpl-meta-sep">·</span>
<span class="tpl-meta-item">lv{{ p.entry.lv }}</span> <span class="tpl-meta-item">lv{{ p.entry.lv }}</span>
</div> </div>
@@ -129,6 +131,14 @@
<el-form-item label="t_num"> <el-form-item label="t_num">
<el-input-number v-model="currentTrigger.entry.t_num" :min="1" :controls="false" style="width: 100%" /> <el-input-number v-model="currentTrigger.entry.t_num" :min="1" :controls="false" style="width: 100%" />
</el-form-item> </el-form-item>
<template v-if="currentTrigger.group === 'atking' || currentTrigger.group === 'atked'">
<el-form-item label="t_chance 触发概率%(空=100)">
<el-input-number v-model="currentTrigger.entry.t_chance" :min="0" :max="100" :controls="false" style="width: 100%" />
</el-form-item>
<el-form-item label="pity_add 保底叠加%(空=0)">
<el-input-number v-model="currentTrigger.entry.pity_add" :min="0" :max="100" :controls="false" style="width: 100%" />
</el-form-item>
</template>
<el-form-item label="组名 name"> <el-form-item label="组名 name">
<el-input v-model="currentTrigger.entry.name" placeholder="留空回退底座名" /> <el-input v-model="currentTrigger.entry.name" placeholder="留空回退底座名" />
</el-form-item> </el-form-item>

View File

@@ -15,9 +15,17 @@
<el-option v-for="n in 5" :key="n" :label="`Lv${n}`" :value="n" /> <el-option v-for="n in 5" :key="n" :label="`Lv${n}`" :value="n" />
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="t_num (1=每次,3≈33%,4≈25%)"> <el-form-item label="t_num 次数阈值(1=每次)">
<el-input-number v-model="entry.t_num" :min="1" :controls="false" style="width: 100%" /> <el-input-number v-model="entry.t_num" :min="1" :controls="false" style="width: 100%" />
</el-form-item> </el-form-item>
<template v-if="chanceVisible">
<el-form-item label="t_chance 触发概率%(空=100)">
<el-input-number v-model="entry.t_chance" :min="0" :max="100" :controls="false" style="width: 100%" placeholder="缺省必触发" />
</el-form-item>
<el-form-item label="pity_add 保底叠加%(空=0)">
<el-input-number v-model="entry.pity_add" :min="0" :max="100" :controls="false" style="width: 100%" placeholder="未触发时下次概率增量" />
</el-form-item>
</template>
<el-form-item label="组名(仅第1档)" v-if="idx === 0"> <el-form-item label="组名(仅第1档)" v-if="idx === 0">
<el-input v-model="entry.name" /> <el-input v-model="entry.name" />
</el-form-item> </el-form-item>
@@ -42,18 +50,22 @@
</template> </template>
<script setup> <script setup>
import { ref } from 'vue' import { computed, ref } from 'vue'
import OverrideEditor from './OverrideEditor.vue' import OverrideEditor from './OverrideEditor.vue'
import { defaultTriggerEntry } from '../constants' import { defaultTriggerEntry } from '../constants'
const props = defineProps({ const props = defineProps({
model: { type: Object, required: true }, // TriggerGrouped model: { type: Object, required: true }, // TriggerGrouped
// 触发组 key(atking/atked/fstart/fend/dead),决定是否展示概率参数
group: { type: String, default: '' },
skillOptions: { type: Array, default: () => [] }, skillOptions: { type: Array, default: () => [] },
skillMap: { type: Object, default: () => ({}) }, skillMap: { type: Object, default: () => ({}) },
// 全部 buff 候选(timed_buff_id 下拉用),由 App 透传 // 全部 buff 候选(timed_buff_id 下拉用),由 App 透传
buffOptions: { type: Array, default: () => [] }, buffOptions: { type: Array, default: () => [] },
}) })
const newSid = ref(null) const newSid = ref(null)
// 概率参数仅攻/受击触发消费(fstart/fend/dead 固定触发)
const chanceVisible = computed(() => props.group === 'atking' || props.group === 'atked')
function skillName(sid) { function skillName(sid) {
return props.skillMap[sid]?.name || '' return props.skillMap[sid]?.name || ''
@@ -69,6 +81,13 @@ function removeGroup(sid) {
} }
function addEntry(group) { function addEntry(group) {
const lastLv = group.length ? group[group.length - 1].lv : 4 const lastLv = group.length ? group[group.length - 1].lv : 4
group.push({ lv: lastLv + 3, s_lv: 2, name: '', t_num: 3, overrides: {}, desc: '' }) const entry = { lv: lastLv + 3, s_lv: 2, name: '', t_num: 3, overrides: {}, desc: '' }
// 概率参数沿袭组内末档(攻/受击触发才生效)
if (chanceVisible.value && group.length) {
const last = group[group.length - 1]
entry.t_chance = last.t_chance ?? null
entry.pity_add = last.pity_add ?? null
}
group.push(entry)
} }
</script> </script>

View File

@@ -46,8 +46,8 @@ export const ROLE_ATK_SKILL = {
Warrior: [6004], Warrior: [6004],
Assassin: [6001, 6002, 6003, 6004], Assassin: [6001, 6002, 6003, 6004],
Archer: [6004, 6006, 6007, 6008], Archer: [6004, 6006, 6007, 6008],
Mage: [6009, 6010, 6011, 6012], Mage: [6009, 6010, 6011, 6012, 6013, 6014, 6015],
Support: [6004, 6009, 6010, 6011, 6012], Support: [6004, 6009, 6010, 6011, 6012, 6013, 6014, 6015],
} }
// 按职业映射大招底座 // 按职业映射大招底座
@@ -117,7 +117,7 @@ export function defaultHero() {
dodge: null, // 闪避率(null = 全局默认 15,填值覆盖) dodge: null, // 闪避率(null = 全局默认 15,填值覆盖)
accuracy: null, // 命中率(null = 全局默认 10,填值覆盖) accuracy: null, // 命中率(null = 全局默认 10,填值覆盖)
skills: [], // [{uuid,name,cd,cdExpr,overrides,desc,lv_entries:[{lv,s_lv,overrides,desc}]}] skills: [], // [{uuid,name,cd,cdExpr,overrides,desc,lv_entries:[{lv,s_lv,overrides,desc}]}]
atking: {}, // {uuid:[{lv,s_lv,name,t_num,overrides,desc}]} atking: {}, // {uuid:[{lv,s_lv,name,t_num,t_chance?,pity_add?,overrides,desc}]} t_chance/pity_add 仅攻/受击组生效
atked: {}, atked: {},
fstart: {}, fstart: {},
fend: {}, fend: {},