Compare commits
21 Commits
51256a2813
...
new2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4be5252cc4 | ||
|
|
04cea0fbb2 | ||
|
|
0db3404481 | ||
|
|
8c7748436b | ||
|
|
311b8ebb54 | ||
|
|
5d398d0a29 | ||
|
|
9c9cc99e64 | ||
|
|
1bb275607a | ||
|
|
95bf2a4e17 | ||
|
|
3f2989ab55 | ||
|
|
577a62193c | ||
|
|
8f89dd11fa | ||
|
|
c10e24709d | ||
|
|
f92502f4f5 | ||
|
|
fa58f699d9 | ||
|
|
90e8a4a284 | ||
|
|
39de30b9b4 | ||
|
|
8707316032 | ||
|
|
fdcd81c083 | ||
|
|
cd9e7296a1 | ||
|
|
be6d941b90 |
@@ -11,29 +11,32 @@
|
||||
"speed": 1,
|
||||
"wrapMode": 1,
|
||||
"enableTrsBlending": false,
|
||||
"_duration": 0.6,
|
||||
"_duration": 0.65,
|
||||
"_hash": 500763545,
|
||||
"_tracks": [
|
||||
{
|
||||
"__id__": 1
|
||||
},
|
||||
{
|
||||
"__id__": 7
|
||||
}
|
||||
],
|
||||
"_exoticAnimation": null,
|
||||
"_events": [
|
||||
{
|
||||
"frame": 0.2,
|
||||
"frame": 0.3,
|
||||
"func": "",
|
||||
"params": []
|
||||
},
|
||||
{
|
||||
"frame": 0.2,
|
||||
"frame": 0.3,
|
||||
"func": "atk",
|
||||
"params": []
|
||||
}
|
||||
],
|
||||
"_embeddedPlayers": [],
|
||||
"_additiveSettings": {
|
||||
"__id__": 7
|
||||
"__id__": 13
|
||||
},
|
||||
"_auxiliaryCurveEntries": []
|
||||
},
|
||||
@@ -90,7 +93,8 @@
|
||||
0.4,
|
||||
0.45,
|
||||
0.5,
|
||||
0.55
|
||||
0.55,
|
||||
0.6
|
||||
],
|
||||
"_values": [
|
||||
{
|
||||
@@ -140,7 +144,98 @@
|
||||
{
|
||||
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@5d13a",
|
||||
"__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
|
||||
]
|
||||
},
|
||||
{
|
||||
|
||||
@@ -11,29 +11,32 @@
|
||||
"speed": 1,
|
||||
"wrapMode": 1,
|
||||
"enableTrsBlending": false,
|
||||
"_duration": 0.4583333333333333,
|
||||
"_duration": 0.5833333333333334,
|
||||
"_hash": 500763545,
|
||||
"_tracks": [
|
||||
{
|
||||
"__id__": 1
|
||||
},
|
||||
{
|
||||
"__id__": 7
|
||||
}
|
||||
],
|
||||
"_exoticAnimation": null,
|
||||
"_events": [
|
||||
{
|
||||
"frame": 0.08333333333333333,
|
||||
"frame": 0.16666666666666666,
|
||||
"func": "",
|
||||
"params": []
|
||||
},
|
||||
{
|
||||
"frame": 0.08333333333333333,
|
||||
"frame": 0.16666666666666666,
|
||||
"func": "atk",
|
||||
"params": []
|
||||
}
|
||||
],
|
||||
"_embeddedPlayers": [],
|
||||
"_additiveSettings": {
|
||||
"__id__": 7
|
||||
"__id__": 13
|
||||
},
|
||||
"_auxiliaryCurveEntries": []
|
||||
},
|
||||
@@ -89,7 +92,8 @@
|
||||
0.2916666666666667,
|
||||
0.3333333333333333,
|
||||
0.375,
|
||||
0.4166666666666667
|
||||
0.4166666666666667,
|
||||
0.4583333333333333
|
||||
],
|
||||
"_values": [
|
||||
{
|
||||
@@ -135,7 +139,95 @@
|
||||
{
|
||||
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@21b99",
|
||||
"__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
|
||||
]
|
||||
},
|
||||
{
|
||||
|
||||
@@ -11,29 +11,32 @@
|
||||
"speed": 1,
|
||||
"wrapMode": 1,
|
||||
"enableTrsBlending": false,
|
||||
"_duration": 0.4166666666666667,
|
||||
"_duration": 0.7083333333333334,
|
||||
"_hash": 500763545,
|
||||
"_tracks": [
|
||||
{
|
||||
"__id__": 1
|
||||
},
|
||||
{
|
||||
"__id__": 7
|
||||
}
|
||||
],
|
||||
"_exoticAnimation": null,
|
||||
"_events": [
|
||||
{
|
||||
"frame": 0.08333333333333333,
|
||||
"frame": 0.16666666666666666,
|
||||
"func": "",
|
||||
"params": []
|
||||
},
|
||||
{
|
||||
"frame": 0.08333333333333333,
|
||||
"frame": 0.16666666666666666,
|
||||
"func": "atk",
|
||||
"params": []
|
||||
}
|
||||
],
|
||||
"_embeddedPlayers": [],
|
||||
"_additiveSettings": {
|
||||
"__id__": 7
|
||||
"__id__": 13
|
||||
},
|
||||
"_auxiliaryCurveEntries": []
|
||||
},
|
||||
@@ -88,7 +91,8 @@
|
||||
0.25,
|
||||
0.2916666666666667,
|
||||
0.3333333333333333,
|
||||
0.375
|
||||
0.375,
|
||||
0.4166666666666667
|
||||
],
|
||||
"_values": [
|
||||
{
|
||||
@@ -130,7 +134,115 @@
|
||||
{
|
||||
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@daa57",
|
||||
"__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
|
||||
]
|
||||
},
|
||||
{
|
||||
|
||||
@@ -11,39 +11,32 @@
|
||||
"speed": 1,
|
||||
"wrapMode": 1,
|
||||
"enableTrsBlending": false,
|
||||
"_duration": 0.625,
|
||||
"_duration": 0.75,
|
||||
"_hash": 500763545,
|
||||
"_tracks": [
|
||||
{
|
||||
"__id__": 1
|
||||
},
|
||||
{
|
||||
"__id__": 7
|
||||
}
|
||||
],
|
||||
"_exoticAnimation": null,
|
||||
"_events": [
|
||||
{
|
||||
"frame": 0.20833333333333334,
|
||||
"frame": 0.375,
|
||||
"func": "",
|
||||
"params": []
|
||||
},
|
||||
{
|
||||
"frame": 0.20833333333333334,
|
||||
"func": "atk",
|
||||
"params": []
|
||||
},
|
||||
{
|
||||
"frame": 0.4583333333333333,
|
||||
"func": "",
|
||||
"params": []
|
||||
},
|
||||
{
|
||||
"frame": 0.4583333333333333,
|
||||
"frame": 0.375,
|
||||
"func": "atk",
|
||||
"params": []
|
||||
}
|
||||
],
|
||||
"_embeddedPlayers": [],
|
||||
"_additiveSettings": {
|
||||
"__id__": 7
|
||||
"__id__": 13
|
||||
},
|
||||
"_auxiliaryCurveEntries": []
|
||||
},
|
||||
@@ -103,7 +96,8 @@
|
||||
0.4583333333333333,
|
||||
0.5,
|
||||
0.5416666666666666,
|
||||
0.5833333333333334
|
||||
0.5833333333333334,
|
||||
0.625
|
||||
],
|
||||
"_values": [
|
||||
{
|
||||
@@ -165,7 +159,115 @@
|
||||
{
|
||||
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@1b470",
|
||||
"__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
|
||||
]
|
||||
},
|
||||
{
|
||||
|
||||
921
assets/resources/game/skill/anm/atk/fb-8.anim
Normal file
921
assets/resources/game/skill/anm/atk/fb-8.anim
Normal 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
|
||||
}
|
||||
]
|
||||
13
assets/resources/game/skill/anm/atk/fb-8.anim.meta
Normal file
13
assets/resources/game/skill/anm/atk/fb-8.anim.meta
Normal 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"
|
||||
}
|
||||
}
|
||||
@@ -20,28 +20,31 @@
|
||||
"_children": [
|
||||
{
|
||||
"__id__": 2
|
||||
},
|
||||
{
|
||||
"__id__": 8
|
||||
}
|
||||
],
|
||||
"_active": true,
|
||||
"_components": [
|
||||
{
|
||||
"__id__": 8
|
||||
},
|
||||
{
|
||||
"__id__": 10
|
||||
},
|
||||
{
|
||||
"__id__": 12
|
||||
},
|
||||
{
|
||||
"__id__": 14
|
||||
},
|
||||
{
|
||||
"__id__": 16
|
||||
},
|
||||
{
|
||||
"__id__": 18
|
||||
},
|
||||
{
|
||||
"__id__": 20
|
||||
},
|
||||
{
|
||||
"__id__": 22
|
||||
}
|
||||
],
|
||||
"_prefab": {
|
||||
"__id__": 18
|
||||
"__id__": 24
|
||||
},
|
||||
"_lpos": {
|
||||
"__type__": "cc.Vec3",
|
||||
@@ -211,6 +214,139 @@
|
||||
"targetOverrides": 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",
|
||||
"_name": "",
|
||||
@@ -221,7 +357,7 @@
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 9
|
||||
"__id__": 15
|
||||
},
|
||||
"_contentSize": {
|
||||
"__type__": "cc.Size",
|
||||
@@ -249,7 +385,7 @@
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 11
|
||||
"__id__": 17
|
||||
},
|
||||
"atk_x": 20,
|
||||
"atk_y": 40,
|
||||
@@ -261,6 +397,10 @@
|
||||
"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": ""
|
||||
},
|
||||
@@ -278,7 +418,7 @@
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 13
|
||||
"__id__": 19
|
||||
},
|
||||
"enabledContactListener": true,
|
||||
"bullet": false,
|
||||
@@ -312,7 +452,7 @@
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 15
|
||||
"__id__": 21
|
||||
},
|
||||
"tag": 0,
|
||||
"_group": 1,
|
||||
@@ -346,7 +486,7 @@
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 17
|
||||
"__id__": 23
|
||||
},
|
||||
"playOnLoad": true,
|
||||
"_clips": [
|
||||
|
||||
@@ -20,28 +20,31 @@
|
||||
"_children": [
|
||||
{
|
||||
"__id__": 2
|
||||
},
|
||||
{
|
||||
"__id__": 8
|
||||
}
|
||||
],
|
||||
"_active": true,
|
||||
"_components": [
|
||||
{
|
||||
"__id__": 8
|
||||
},
|
||||
{
|
||||
"__id__": 10
|
||||
},
|
||||
{
|
||||
"__id__": 12
|
||||
},
|
||||
{
|
||||
"__id__": 14
|
||||
},
|
||||
{
|
||||
"__id__": 16
|
||||
},
|
||||
{
|
||||
"__id__": 18
|
||||
},
|
||||
{
|
||||
"__id__": 20
|
||||
},
|
||||
{
|
||||
"__id__": 22
|
||||
}
|
||||
],
|
||||
"_prefab": {
|
||||
"__id__": 18
|
||||
"__id__": 24
|
||||
},
|
||||
"_lpos": {
|
||||
"__type__": "cc.Vec3",
|
||||
@@ -211,6 +214,139 @@
|
||||
"targetOverrides": 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",
|
||||
"_name": "",
|
||||
@@ -221,7 +357,7 @@
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 9
|
||||
"__id__": 15
|
||||
},
|
||||
"_contentSize": {
|
||||
"__type__": "cc.Size",
|
||||
@@ -249,7 +385,7 @@
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 11
|
||||
"__id__": 17
|
||||
},
|
||||
"atk_x": 20,
|
||||
"atk_y": 40,
|
||||
@@ -261,6 +397,10 @@
|
||||
"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": ""
|
||||
},
|
||||
@@ -278,7 +418,7 @@
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 13
|
||||
"__id__": 19
|
||||
},
|
||||
"enabledContactListener": true,
|
||||
"bullet": false,
|
||||
@@ -312,7 +452,7 @@
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 15
|
||||
"__id__": 21
|
||||
},
|
||||
"tag": 0,
|
||||
"_group": 1,
|
||||
@@ -346,7 +486,7 @@
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 17
|
||||
"__id__": 23
|
||||
},
|
||||
"playOnLoad": true,
|
||||
"_clips": [
|
||||
|
||||
@@ -20,28 +20,31 @@
|
||||
"_children": [
|
||||
{
|
||||
"__id__": 2
|
||||
},
|
||||
{
|
||||
"__id__": 8
|
||||
}
|
||||
],
|
||||
"_active": true,
|
||||
"_components": [
|
||||
{
|
||||
"__id__": 8
|
||||
},
|
||||
{
|
||||
"__id__": 10
|
||||
},
|
||||
{
|
||||
"__id__": 12
|
||||
},
|
||||
{
|
||||
"__id__": 14
|
||||
},
|
||||
{
|
||||
"__id__": 16
|
||||
},
|
||||
{
|
||||
"__id__": 18
|
||||
},
|
||||
{
|
||||
"__id__": 20
|
||||
},
|
||||
{
|
||||
"__id__": 22
|
||||
}
|
||||
],
|
||||
"_prefab": {
|
||||
"__id__": 18
|
||||
"__id__": 24
|
||||
},
|
||||
"_lpos": {
|
||||
"__type__": "cc.Vec3",
|
||||
@@ -173,7 +176,7 @@
|
||||
"a": 255
|
||||
},
|
||||
"_spriteFrame": {
|
||||
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@13b06",
|
||||
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@7e6d7",
|
||||
"__expectedType__": "cc.SpriteFrame"
|
||||
},
|
||||
"_type": 0,
|
||||
@@ -211,6 +214,139 @@
|
||||
"targetOverrides": 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",
|
||||
"_name": "",
|
||||
@@ -221,7 +357,7 @@
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 9
|
||||
"__id__": 15
|
||||
},
|
||||
"_contentSize": {
|
||||
"__type__": "cc.Size",
|
||||
@@ -249,7 +385,7 @@
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 11
|
||||
"__id__": 17
|
||||
},
|
||||
"atk_x": 20,
|
||||
"atk_y": 40,
|
||||
@@ -261,6 +397,10 @@
|
||||
"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": ""
|
||||
},
|
||||
@@ -278,7 +418,7 @@
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 13
|
||||
"__id__": 19
|
||||
},
|
||||
"enabledContactListener": true,
|
||||
"bullet": false,
|
||||
@@ -312,7 +452,7 @@
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 15
|
||||
"__id__": 21
|
||||
},
|
||||
"tag": 0,
|
||||
"_group": 1,
|
||||
@@ -346,7 +486,7 @@
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 17
|
||||
"__id__": 23
|
||||
},
|
||||
"playOnLoad": true,
|
||||
"_clips": [
|
||||
|
||||
@@ -20,28 +20,31 @@
|
||||
"_children": [
|
||||
{
|
||||
"__id__": 2
|
||||
},
|
||||
{
|
||||
"__id__": 8
|
||||
}
|
||||
],
|
||||
"_active": true,
|
||||
"_components": [
|
||||
{
|
||||
"__id__": 8
|
||||
},
|
||||
{
|
||||
"__id__": 10
|
||||
},
|
||||
{
|
||||
"__id__": 12
|
||||
},
|
||||
{
|
||||
"__id__": 14
|
||||
},
|
||||
{
|
||||
"__id__": 16
|
||||
},
|
||||
{
|
||||
"__id__": 18
|
||||
},
|
||||
{
|
||||
"__id__": 20
|
||||
},
|
||||
{
|
||||
"__id__": 22
|
||||
}
|
||||
],
|
||||
"_prefab": {
|
||||
"__id__": 18
|
||||
"__id__": 24
|
||||
},
|
||||
"_lpos": {
|
||||
"__type__": "cc.Vec3",
|
||||
@@ -211,6 +214,142 @@
|
||||
"targetOverrides": 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",
|
||||
"_name": "",
|
||||
@@ -221,7 +360,7 @@
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 9
|
||||
"__id__": 15
|
||||
},
|
||||
"_contentSize": {
|
||||
"__type__": "cc.Size",
|
||||
@@ -249,7 +388,7 @@
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 11
|
||||
"__id__": 17
|
||||
},
|
||||
"atk_x": 20,
|
||||
"atk_y": 40,
|
||||
@@ -261,6 +400,10 @@
|
||||
"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": ""
|
||||
},
|
||||
@@ -278,7 +421,7 @@
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 13
|
||||
"__id__": 19
|
||||
},
|
||||
"enabledContactListener": true,
|
||||
"bullet": false,
|
||||
@@ -312,7 +455,7 @@
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 15
|
||||
"__id__": 21
|
||||
},
|
||||
"tag": 0,
|
||||
"_group": 1,
|
||||
@@ -346,7 +489,7 @@
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 17
|
||||
"__id__": 23
|
||||
},
|
||||
"playOnLoad": true,
|
||||
"_clips": [
|
||||
|
||||
@@ -35,10 +35,13 @@
|
||||
},
|
||||
{
|
||||
"__id__": 14
|
||||
},
|
||||
{
|
||||
"__id__": 16
|
||||
}
|
||||
],
|
||||
"_prefab": {
|
||||
"__id__": 16
|
||||
"__id__": 18
|
||||
},
|
||||
"_lpos": {
|
||||
"__type__": "cc.Vec3",
|
||||
@@ -92,8 +95,8 @@
|
||||
},
|
||||
"_lpos": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 6.77,
|
||||
"y": 0,
|
||||
"x": 0,
|
||||
"y": -60,
|
||||
"z": 0
|
||||
},
|
||||
"_lrot": {
|
||||
@@ -105,8 +108,8 @@
|
||||
},
|
||||
"_lscale": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 0.3,
|
||||
"y": 0.3,
|
||||
"x": 1.4,
|
||||
"y": 2,
|
||||
"z": 1
|
||||
},
|
||||
"_mobility": 0,
|
||||
@@ -133,13 +136,13 @@
|
||||
},
|
||||
"_contentSize": {
|
||||
"__type__": "cc.Size",
|
||||
"width": 90,
|
||||
"height": 90
|
||||
"width": 128,
|
||||
"height": 128
|
||||
},
|
||||
"_anchorPoint": {
|
||||
"__type__": "cc.Vec2",
|
||||
"x": 0.5,
|
||||
"y": 0.5
|
||||
"y": 0
|
||||
},
|
||||
"_id": ""
|
||||
},
|
||||
@@ -170,7 +173,7 @@
|
||||
"a": 255
|
||||
},
|
||||
"_spriteFrame": {
|
||||
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@4d4df",
|
||||
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@55402",
|
||||
"__expectedType__": "cc.SpriteFrame"
|
||||
},
|
||||
"_type": 0,
|
||||
@@ -222,13 +225,13 @@
|
||||
},
|
||||
"_contentSize": {
|
||||
"__type__": "cc.Size",
|
||||
"width": 30,
|
||||
"height": 40
|
||||
"width": 20,
|
||||
"height": 100
|
||||
},
|
||||
"_anchorPoint": {
|
||||
"__type__": "cc.Vec2",
|
||||
"x": 0.5,
|
||||
"y": 0.5
|
||||
"y": 0
|
||||
},
|
||||
"_id": ""
|
||||
},
|
||||
@@ -248,13 +251,26 @@
|
||||
"__prefab": {
|
||||
"__id__": 11
|
||||
},
|
||||
"atk_x": 10,
|
||||
"atk_y": 15,
|
||||
"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": 0,
|
||||
"summon_x_offset": 0,
|
||||
"summon_y_offset": 0,
|
||||
"summon_interval": 0,
|
||||
"height_offset": 0,
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "cc.CompPrefabInfo",
|
||||
"fileId": "60LInmZXxDtKu79AshRG9j"
|
||||
"fileId": "35nW0iQNBH2bqkWAr3MVkQ"
|
||||
},
|
||||
{
|
||||
"__type__": "cc.RigidBody2D",
|
||||
@@ -288,7 +304,7 @@
|
||||
},
|
||||
{
|
||||
"__type__": "cc.CompPrefabInfo",
|
||||
"fileId": "e1yBA625RLwLhzo6bLYW7j"
|
||||
"fileId": "57cr7S0YpK4oEZCavwXtIX"
|
||||
},
|
||||
{
|
||||
"__type__": "cc.BoxCollider2D",
|
||||
@@ -315,14 +331,43 @@
|
||||
},
|
||||
"_size": {
|
||||
"__type__": "cc.Size",
|
||||
"width": 30,
|
||||
"height": 40
|
||||
"width": 20,
|
||||
"height": 100
|
||||
},
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__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",
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"ver": "1.1.50",
|
||||
"importer": "prefab",
|
||||
"imported": true,
|
||||
"uuid": "fc32700f-bf4a-47ce-b619-6497b7280fde",
|
||||
"uuid": "7edb8215-1344-4215-8172-7a50a72da8bb",
|
||||
"files": [
|
||||
".json"
|
||||
],
|
||||
|
||||
@@ -35,10 +35,13 @@
|
||||
},
|
||||
{
|
||||
"__id__": 14
|
||||
},
|
||||
{
|
||||
"__id__": 16
|
||||
}
|
||||
],
|
||||
"_prefab": {
|
||||
"__id__": 16
|
||||
"__id__": 18
|
||||
},
|
||||
"_lpos": {
|
||||
"__type__": "cc.Vec3",
|
||||
@@ -92,7 +95,7 @@
|
||||
},
|
||||
"_lpos": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 6.77,
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
@@ -100,13 +103,13 @@
|
||||
"__type__": "cc.Quat",
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0,
|
||||
"w": 1
|
||||
"z": 0.706489444943837,
|
||||
"w": 0.7077235789366842
|
||||
},
|
||||
"_lscale": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 0.3,
|
||||
"y": 0.3,
|
||||
"x": -1,
|
||||
"y": 1,
|
||||
"z": 1
|
||||
},
|
||||
"_mobility": 0,
|
||||
@@ -115,7 +118,7 @@
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
"z": 89.9
|
||||
},
|
||||
"_id": ""
|
||||
},
|
||||
@@ -133,8 +136,8 @@
|
||||
},
|
||||
"_contentSize": {
|
||||
"__type__": "cc.Size",
|
||||
"width": 90,
|
||||
"height": 90
|
||||
"width": 85,
|
||||
"height": 119
|
||||
},
|
||||
"_anchorPoint": {
|
||||
"__type__": "cc.Vec2",
|
||||
@@ -170,7 +173,7 @@
|
||||
"a": 255
|
||||
},
|
||||
"_spriteFrame": {
|
||||
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@179ff",
|
||||
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@59ec8",
|
||||
"__expectedType__": "cc.SpriteFrame"
|
||||
},
|
||||
"_type": 0,
|
||||
@@ -222,8 +225,8 @@
|
||||
},
|
||||
"_contentSize": {
|
||||
"__type__": "cc.Size",
|
||||
"width": 30,
|
||||
"height": 40
|
||||
"width": 50,
|
||||
"height": 50
|
||||
},
|
||||
"_anchorPoint": {
|
||||
"__type__": "cc.Vec2",
|
||||
@@ -248,13 +251,25 @@
|
||||
"__prefab": {
|
||||
"__id__": 11
|
||||
},
|
||||
"atk_x": 10,
|
||||
"atk_y": 15,
|
||||
"atk_x": 20,
|
||||
"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": ""
|
||||
},
|
||||
{
|
||||
"__type__": "cc.CompPrefabInfo",
|
||||
"fileId": "60LInmZXxDtKu79AshRG9j"
|
||||
"fileId": "35nW0iQNBH2bqkWAr3MVkQ"
|
||||
},
|
||||
{
|
||||
"__type__": "cc.RigidBody2D",
|
||||
@@ -288,7 +303,7 @@
|
||||
},
|
||||
{
|
||||
"__type__": "cc.CompPrefabInfo",
|
||||
"fileId": "e1yBA625RLwLhzo6bLYW7j"
|
||||
"fileId": "57cr7S0YpK4oEZCavwXtIX"
|
||||
},
|
||||
{
|
||||
"__type__": "cc.BoxCollider2D",
|
||||
@@ -315,14 +330,43 @@
|
||||
},
|
||||
"_size": {
|
||||
"__type__": "cc.Size",
|
||||
"width": 30,
|
||||
"height": 40
|
||||
"width": 50,
|
||||
"height": 150
|
||||
},
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__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",
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"ver": "1.1.50",
|
||||
"importer": "prefab",
|
||||
"imported": true,
|
||||
"uuid": "5a0c6727-c741-4a33-b6f2-b2c56e3fc540",
|
||||
"uuid": "7c7ff7a4-17d5-4c4a-8fee-68b73af250e5",
|
||||
"files": [
|
||||
".json"
|
||||
],
|
||||
|
||||
519
assets/resources/game/skill/atk/m5.prefab
Normal file
519
assets/resources/game/skill/atk/m5.prefab
Normal 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
|
||||
}
|
||||
]
|
||||
13
assets/resources/game/skill/atk/m5.prefab.meta
Normal file
13
assets/resources/game/skill/atk/m5.prefab.meta
Normal 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"
|
||||
}
|
||||
}
|
||||
@@ -293,6 +293,10 @@
|
||||
"forceStartX": -1,
|
||||
"forceStartY": -1,
|
||||
"summon_count": 4,
|
||||
"summon_target_mode": 2,
|
||||
"summon_x_offset": 0,
|
||||
"summon_y_offset": 0,
|
||||
"summon_interval": 0,
|
||||
"height_offset": 100,
|
||||
"_id": ""
|
||||
},
|
||||
|
||||
@@ -293,6 +293,10 @@
|
||||
"forceStartX": -1,
|
||||
"forceStartY": -1,
|
||||
"summon_count": 6,
|
||||
"summon_target_mode": 2,
|
||||
"summon_x_offset": 0,
|
||||
"summon_y_offset": 0,
|
||||
"summon_interval": 0,
|
||||
"height_offset": 100,
|
||||
"_id": ""
|
||||
},
|
||||
|
||||
@@ -261,6 +261,10 @@
|
||||
"forceStartX": -1,
|
||||
"forceStartY": -1,
|
||||
"summon_count": 3,
|
||||
"summon_target_mode": 2,
|
||||
"summon_x_offset": 0,
|
||||
"summon_y_offset": 0,
|
||||
"summon_interval": 0,
|
||||
"height_offset": 100,
|
||||
"_id": ""
|
||||
},
|
||||
|
||||
@@ -397,6 +397,10 @@
|
||||
"forceStartX": -1,
|
||||
"forceStartY": -1,
|
||||
"summon_count": 3,
|
||||
"summon_target_mode": 0,
|
||||
"summon_x_offset": 0,
|
||||
"summon_y_offset": 0,
|
||||
"summon_interval": 0.2,
|
||||
"height_offset": 0,
|
||||
"_id": ""
|
||||
},
|
||||
|
||||
@@ -96,7 +96,7 @@
|
||||
"_lpos": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 0,
|
||||
"y": -30,
|
||||
"y": -90,
|
||||
"z": 0
|
||||
},
|
||||
"_lrot": {
|
||||
@@ -108,7 +108,7 @@
|
||||
},
|
||||
"_lscale": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 1,
|
||||
"x": 1.5,
|
||||
"y": 2,
|
||||
"z": 1
|
||||
},
|
||||
@@ -261,6 +261,10 @@
|
||||
"forceStartX": -1,
|
||||
"forceStartY": -1,
|
||||
"summon_count": 5,
|
||||
"summon_target_mode": 2,
|
||||
"summon_x_offset": 0,
|
||||
"summon_y_offset": 0,
|
||||
"summon_interval": 0,
|
||||
"height_offset": 0,
|
||||
"_id": ""
|
||||
},
|
||||
|
||||
@@ -261,6 +261,10 @@
|
||||
"forceStartX": -1,
|
||||
"forceStartY": -1,
|
||||
"summon_count": 3,
|
||||
"summon_target_mode": 2,
|
||||
"summon_x_offset": 0,
|
||||
"summon_y_offset": 0,
|
||||
"summon_interval": 0.5,
|
||||
"height_offset": 100,
|
||||
"_id": ""
|
||||
},
|
||||
|
||||
@@ -261,6 +261,10 @@
|
||||
"forceStartX": -1,
|
||||
"forceStartY": -1,
|
||||
"summon_count": 3,
|
||||
"summon_target_mode": 2,
|
||||
"summon_x_offset": 0,
|
||||
"summon_y_offset": 0,
|
||||
"summon_interval": 0,
|
||||
"height_offset": 100,
|
||||
"_id": ""
|
||||
},
|
||||
|
||||
@@ -261,6 +261,10 @@
|
||||
"forceStartX": -1,
|
||||
"forceStartY": -1,
|
||||
"summon_count": 3,
|
||||
"summon_target_mode": 2,
|
||||
"summon_x_offset": 0,
|
||||
"summon_y_offset": 0,
|
||||
"summon_interval": 0,
|
||||
"height_offset": 100,
|
||||
"_id": ""
|
||||
},
|
||||
|
||||
526
assets/resources/game/skill/atk/maxm7.prefab
Normal file
526
assets/resources/game/skill/atk/maxm7.prefab
Normal 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
|
||||
}
|
||||
]
|
||||
13
assets/resources/game/skill/atk/maxm7.prefab.meta
Normal file
13
assets/resources/game/skill/atk/maxm7.prefab.meta
Normal 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
@@ -34,7 +34,7 @@
|
||||
<key>spriteSourceSize</key>
|
||||
<string>{672,378}</string>
|
||||
<key>textureRect</key>
|
||||
<string>{{1349,1095},{616,182}}</string>
|
||||
<string>{{675,1669},{616,182}}</string>
|
||||
<key>textureRotated</key>
|
||||
<false/>
|
||||
</dict>
|
||||
@@ -51,7 +51,7 @@
|
||||
<key>spriteSourceSize</key>
|
||||
<string>{672,378}</string>
|
||||
<key>textureRect</key>
|
||||
<string>{{675,1775},{672,92}}</string>
|
||||
<string>{{675,1853},{672,92}}</string>
|
||||
<key>textureRotated</key>
|
||||
<false/>
|
||||
</dict>
|
||||
@@ -68,9 +68,9 @@
|
||||
<key>spriteSourceSize</key>
|
||||
<string>{672,378}</string>
|
||||
<key>textureRect</key>
|
||||
<string>{{675,1869},{672,76}}</string>
|
||||
<string>{{1931,675},{672,76}}</string>
|
||||
<key>textureRotated</key>
|
||||
<false/>
|
||||
<true/>
|
||||
</dict>
|
||||
<key>0l5_mountains.png</key>
|
||||
<dict>
|
||||
@@ -102,7 +102,7 @@
|
||||
<key>spriteSourceSize</key>
|
||||
<string>{672,378}</string>
|
||||
<key>textureRect</key>
|
||||
<string>{{1,1589},{672,162}}</string>
|
||||
<string>{{675,1193},{672,162}}</string>
|
||||
<key>textureRotated</key>
|
||||
<false/>
|
||||
</dict>
|
||||
@@ -119,9 +119,9 @@
|
||||
<key>spriteSourceSize</key>
|
||||
<string>{672,378}</string>
|
||||
<key>textureRect</key>
|
||||
<string>{{675,1507},{672,138}}</string>
|
||||
<string>{{1663,675},{672,138}}</string>
|
||||
<key>textureRotated</key>
|
||||
<false/>
|
||||
<true/>
|
||||
</dict>
|
||||
<key>0l8_ground.png</key>
|
||||
<dict>
|
||||
@@ -136,9 +136,9 @@
|
||||
<key>spriteSourceSize</key>
|
||||
<string>{672,378}</string>
|
||||
<key>textureRect</key>
|
||||
<string>{{1349,381},{672,216}}</string>
|
||||
<string>{{1729,1},{672,216}}</string>
|
||||
<key>textureRotated</key>
|
||||
<false/>
|
||||
<true/>
|
||||
</dict>
|
||||
<key>1l1_wall.png</key>
|
||||
<dict>
|
||||
@@ -221,9 +221,9 @@
|
||||
<key>spriteSourceSize</key>
|
||||
<string>{672,378}</string>
|
||||
<key>textureRect</key>
|
||||
<string>{{1349,1279},{662,90}}</string>
|
||||
<string>{{1349,1349},{662,90}}</string>
|
||||
<key>textureRotated</key>
|
||||
<true/>
|
||||
<false/>
|
||||
</dict>
|
||||
<key>1l6_ground.png</key>
|
||||
<dict>
|
||||
@@ -238,9 +238,9 @@
|
||||
<key>spriteSourceSize</key>
|
||||
<string>{672,378}</string>
|
||||
<key>textureRect</key>
|
||||
<string>{{1441,1279},{672,76}}</string>
|
||||
<string>{{1293,1699},{672,76}}</string>
|
||||
<key>textureRotated</key>
|
||||
<true/>
|
||||
<false/>
|
||||
</dict>
|
||||
<key>3l1_sky.png</key>
|
||||
<dict>
|
||||
@@ -272,9 +272,9 @@
|
||||
<key>spriteSourceSize</key>
|
||||
<string>{672,378}</string>
|
||||
<key>textureRect</key>
|
||||
<string>{{675,1353},{672,152}}</string>
|
||||
<string>{{1509,675},{672,152}}</string>
|
||||
<key>textureRotated</key>
|
||||
<false/>
|
||||
<true/>
|
||||
</dict>
|
||||
<key>3l3_pyramid.png</key>
|
||||
<dict>
|
||||
@@ -289,9 +289,9 @@
|
||||
<key>spriteSourceSize</key>
|
||||
<string>{672,378}</string>
|
||||
<key>textureRect</key>
|
||||
<string>{{1621,1279},{528,154}}</string>
|
||||
<string>{{1349,1543},{528,154}}</string>
|
||||
<key>textureRotated</key>
|
||||
<true/>
|
||||
<false/>
|
||||
</dict>
|
||||
<key>3l4_bg-ground01.png</key>
|
||||
<dict>
|
||||
@@ -306,7 +306,7 @@
|
||||
<key>spriteSourceSize</key>
|
||||
<string>{672,378}</string>
|
||||
<key>textureRect</key>
|
||||
<string>{{1,1753},{672,156}}</string>
|
||||
<string>{{675,1357},{672,156}}</string>
|
||||
<key>textureRotated</key>
|
||||
<false/>
|
||||
</dict>
|
||||
@@ -323,7 +323,7 @@
|
||||
<key>spriteSourceSize</key>
|
||||
<string>{672,378}</string>
|
||||
<key>textureRect</key>
|
||||
<string>{{1349,599},{672,180}}</string>
|
||||
<string>{{1,1589},{672,180}}</string>
|
||||
<key>textureRotated</key>
|
||||
<false/>
|
||||
</dict>
|
||||
@@ -340,9 +340,9 @@
|
||||
<key>spriteSourceSize</key>
|
||||
<string>{672,378}</string>
|
||||
<key>textureRect</key>
|
||||
<string>{{675,1647},{672,126}}</string>
|
||||
<string>{{1803,675},{672,126}}</string>
|
||||
<key>textureRotated</key>
|
||||
<false/>
|
||||
<true/>
|
||||
</dict>
|
||||
<key>3l7_ground.png</key>
|
||||
<dict>
|
||||
@@ -357,7 +357,24 @@
|
||||
<key>spriteSourceSize</key>
|
||||
<string>{672,378}</string>
|
||||
<key>textureRect</key>
|
||||
<string>{{1349,941},{672,152}}</string>
|
||||
<string>{{675,1515},{672,152}}</string>
|
||||
<key>textureRotated</key>
|
||||
<false/>
|
||||
</dict>
|
||||
<key>Icon_Battle.png</key>
|
||||
<dict>
|
||||
<key>aliases</key>
|
||||
<array/>
|
||||
<key>anchor</key>
|
||||
<string>{0.5,0.5}</string>
|
||||
<key>spriteOffset</key>
|
||||
<string>{0,0}</string>
|
||||
<key>spriteSize</key>
|
||||
<string>{64,57}</string>
|
||||
<key>spriteSourceSize</key>
|
||||
<string>{64,57}</string>
|
||||
<key>textureRect</key>
|
||||
<string>{{1349,1894},{64,57}}</string>
|
||||
<key>textureRotated</key>
|
||||
<false/>
|
||||
</dict>
|
||||
@@ -374,9 +391,9 @@
|
||||
<key>spriteSourceSize</key>
|
||||
<string>{68,51}</string>
|
||||
<key>textureRect</key>
|
||||
<string>{{1777,1626},{68,51}}</string>
|
||||
<string>{{1879,1629},{68,51}}</string>
|
||||
<key>textureRotated</key>
|
||||
<false/>
|
||||
<true/>
|
||||
</dict>
|
||||
<key>Stone_A_04.png</key>
|
||||
<dict>
|
||||
@@ -391,9 +408,9 @@
|
||||
<key>spriteSourceSize</key>
|
||||
<string>{60,51}</string>
|
||||
<key>textureRect</key>
|
||||
<string>{{1850,1562},{60,51}}</string>
|
||||
<string>{{1293,1777},{60,51}}</string>
|
||||
<key>textureRotated</key>
|
||||
<false/>
|
||||
<true/>
|
||||
</dict>
|
||||
<key>Stone_A_07.png</key>
|
||||
<dict>
|
||||
@@ -408,9 +425,9 @@
|
||||
<key>spriteSourceSize</key>
|
||||
<string>{107,51}</string>
|
||||
<key>textureRect</key>
|
||||
<string>{{1621,1809},{107,51}}</string>
|
||||
<string>{{1947,1},{107,51}}</string>
|
||||
<key>textureRotated</key>
|
||||
<false/>
|
||||
<true/>
|
||||
</dict>
|
||||
<key>Stone_B_01.png</key>
|
||||
<dict>
|
||||
@@ -425,7 +442,7 @@
|
||||
<key>spriteSourceSize</key>
|
||||
<string>{68,70}</string>
|
||||
<key>textureRect</key>
|
||||
<string>{{1519,1865},{68,70}}</string>
|
||||
<string>{{1935,1441},{68,70}}</string>
|
||||
<key>textureRotated</key>
|
||||
<false/>
|
||||
</dict>
|
||||
@@ -442,7 +459,7 @@
|
||||
<key>spriteSourceSize</key>
|
||||
<string>{66,45}</string>
|
||||
<key>textureRect</key>
|
||||
<string>{{1777,1679},{66,45}}</string>
|
||||
<string>{{1415,1894},{66,45}}</string>
|
||||
<key>textureRotated</key>
|
||||
<false/>
|
||||
</dict>
|
||||
@@ -459,7 +476,7 @@
|
||||
<key>spriteSourceSize</key>
|
||||
<string>{35,22}</string>
|
||||
<key>textureRect</key>
|
||||
<string>{{1730,1809},{35,22}}</string>
|
||||
<string>{{1293,1669},{35,22}}</string>
|
||||
<key>textureRotated</key>
|
||||
<false/>
|
||||
</dict>
|
||||
@@ -476,9 +493,9 @@
|
||||
<key>spriteSourceSize</key>
|
||||
<string>{71,62}</string>
|
||||
<key>textureRect</key>
|
||||
<string>{{1777,1562},{71,62}}</string>
|
||||
<string>{{1899,1777},{71,62}}</string>
|
||||
<key>textureRotated</key>
|
||||
<false/>
|
||||
<true/>
|
||||
</dict>
|
||||
<key>Stone_B_05.png</key>
|
||||
<dict>
|
||||
@@ -493,7 +510,7 @@
|
||||
<key>spriteSourceSize</key>
|
||||
<string>{84,43}</string>
|
||||
<key>textureRect</key>
|
||||
<string>{{1967,1095},{84,43}}</string>
|
||||
<string>{{1879,1543},{84,43}}</string>
|
||||
<key>textureRotated</key>
|
||||
<true/>
|
||||
</dict>
|
||||
@@ -510,7 +527,7 @@
|
||||
<key>spriteSourceSize</key>
|
||||
<string>{31,15}</string>
|
||||
<key>textureRect</key>
|
||||
<string>{{1519,1937},{31,15}}</string>
|
||||
<string>{{1947,110},{31,15}}</string>
|
||||
<key>textureRotated</key>
|
||||
<false/>
|
||||
</dict>
|
||||
@@ -527,7 +544,41 @@
|
||||
<key>spriteSourceSize</key>
|
||||
<string>{44,16}</string>
|
||||
<key>textureRect</key>
|
||||
<string>{{1,1911},{44,16}}</string>
|
||||
<string>{{1,1931},{44,16}}</string>
|
||||
<key>textureRotated</key>
|
||||
<false/>
|
||||
</dict>
|
||||
<key>Title_01_NoDeco_Orange.Png</key>
|
||||
<dict>
|
||||
<key>aliases</key>
|
||||
<array/>
|
||||
<key>anchor</key>
|
||||
<string>{0.5,0.5}</string>
|
||||
<key>spriteOffset</key>
|
||||
<string>{0,0}</string>
|
||||
<key>spriteSize</key>
|
||||
<string>{273,115}</string>
|
||||
<key>spriteSourceSize</key>
|
||||
<string>{273,115}</string>
|
||||
<key>textureRect</key>
|
||||
<string>{{1349,1777},{273,115}}</string>
|
||||
<key>textureRotated</key>
|
||||
<false/>
|
||||
</dict>
|
||||
<key>Title_01_NoDeco_Tangerine.Png</key>
|
||||
<dict>
|
||||
<key>aliases</key>
|
||||
<array/>
|
||||
<key>anchor</key>
|
||||
<string>{0.5,0.5}</string>
|
||||
<key>spriteOffset</key>
|
||||
<string>{0,0}</string>
|
||||
<key>spriteSize</key>
|
||||
<string>{273,115}</string>
|
||||
<key>spriteSourceSize</key>
|
||||
<string>{273,115}</string>
|
||||
<key>textureRect</key>
|
||||
<string>{{1624,1777},{273,115}}</string>
|
||||
<key>textureRotated</key>
|
||||
<false/>
|
||||
</dict>
|
||||
@@ -546,7 +597,7 @@
|
||||
<key>textureRect</key>
|
||||
<string>{{1349,1},{672,378}}</string>
|
||||
<key>textureRotated</key>
|
||||
<false/>
|
||||
<true/>
|
||||
</dict>
|
||||
<key>l2_mountains.png</key>
|
||||
<dict>
|
||||
@@ -578,9 +629,9 @@
|
||||
<key>spriteSourceSize</key>
|
||||
<string>{672,378}</string>
|
||||
<key>textureRect</key>
|
||||
<string>{{1519,1279},{584,100}}</string>
|
||||
<string>{{1349,1441},{584,100}}</string>
|
||||
<key>textureRotated</key>
|
||||
<true/>
|
||||
<false/>
|
||||
</dict>
|
||||
<key>l4_bg-ground01.png</key>
|
||||
<dict>
|
||||
@@ -595,9 +646,9 @@
|
||||
<key>spriteSourceSize</key>
|
||||
<string>{672,378}</string>
|
||||
<key>textureRect</key>
|
||||
<string>{{675,1193},{672,158}}</string>
|
||||
<string>{{1349,675},{672,158}}</string>
|
||||
<key>textureRotated</key>
|
||||
<false/>
|
||||
<true/>
|
||||
</dict>
|
||||
<key>l5_bg-ground02.png</key>
|
||||
<dict>
|
||||
@@ -612,7 +663,7 @@
|
||||
<key>spriteSourceSize</key>
|
||||
<string>{672,378}</string>
|
||||
<key>textureRect</key>
|
||||
<string>{{1349,781},{672,158}}</string>
|
||||
<string>{{1,1771},{672,158}}</string>
|
||||
<key>textureRotated</key>
|
||||
<false/>
|
||||
</dict>
|
||||
@@ -633,23 +684,6 @@
|
||||
<key>textureRotated</key>
|
||||
<false/>
|
||||
</dict>
|
||||
<key>logo2.png</key>
|
||||
<dict>
|
||||
<key>aliases</key>
|
||||
<array/>
|
||||
<key>anchor</key>
|
||||
<string>{0.5,0.5}</string>
|
||||
<key>spriteOffset</key>
|
||||
<string>{1,2}</string>
|
||||
<key>spriteSize</key>
|
||||
<string>{281,231}</string>
|
||||
<key>spriteSourceSize</key>
|
||||
<string>{307,307}</string>
|
||||
<key>textureRect</key>
|
||||
<string>{{1777,1279},{281,231}}</string>
|
||||
<key>textureRotated</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>metadata</key>
|
||||
<dict>
|
||||
@@ -662,9 +696,9 @@
|
||||
<key>realTextureFileName</key>
|
||||
<string>mps.png</string>
|
||||
<key>size</key>
|
||||
<string>{2022,1953}</string>
|
||||
<string>{2012,1952}</string>
|
||||
<key>smartupdate</key>
|
||||
<string>$TexturePacker:SmartUpdate:c995e79e2727f3d5b64d2e4345b903e7:ff13e6153e38a1ee043318ccbb0a835f:4c0e3901f0d5fcb2cf0cd4dcba1c7f8b$</string>
|
||||
<string>$TexturePacker:SmartUpdate:afc599cf42d3db8475edd4bf42d848d7:62891583945cafa92fc112c0ecd848ee:4c0e3901f0d5fcb2cf0cd4dcba1c7f8b$</string>
|
||||
<key>textureFileName</key>
|
||||
<string>mps.png</string>
|
||||
</dict>
|
||||
|
||||
@@ -7,6 +7,52 @@
|
||||
".json"
|
||||
],
|
||||
"subMetas": {
|
||||
"57674": {
|
||||
"importer": "sprite-frame",
|
||||
"uuid": "81af97ed-7940-45e6-91a1-21bd0df1a343@57674",
|
||||
"displayName": "",
|
||||
"id": "57674",
|
||||
"name": "Icon_Battle",
|
||||
"userData": {
|
||||
"trimThreshold": 1,
|
||||
"rotated": false,
|
||||
"offsetX": 0,
|
||||
"offsetY": 0,
|
||||
"trimX": 1349,
|
||||
"trimY": 1894,
|
||||
"width": 64,
|
||||
"height": 57,
|
||||
"rawWidth": 64,
|
||||
"rawHeight": 57,
|
||||
"borderTop": 0,
|
||||
"borderBottom": 0,
|
||||
"borderLeft": 0,
|
||||
"borderRight": 0,
|
||||
"packable": true,
|
||||
"pixelsToUnit": 100,
|
||||
"pivotX": 0.5,
|
||||
"pivotY": 0.5,
|
||||
"meshType": 0,
|
||||
"vertices": {
|
||||
"rawPosition": [],
|
||||
"indexes": [],
|
||||
"uv": [],
|
||||
"nuv": [],
|
||||
"minPos": [],
|
||||
"maxPos": []
|
||||
},
|
||||
"isUuid": true,
|
||||
"imageUuidOrDatabaseUri": "ca2b26a5-8d54-49ec-bdaf-e9f777afc9cb@6c48a",
|
||||
"atlasUuid": "81af97ed-7940-45e6-91a1-21bd0df1a343",
|
||||
"trimType": "auto"
|
||||
},
|
||||
"ver": "1.0.12",
|
||||
"imported": true,
|
||||
"files": [
|
||||
".json"
|
||||
],
|
||||
"subMetas": {}
|
||||
},
|
||||
"58094": {
|
||||
"importer": "sprite-frame",
|
||||
"uuid": "81af97ed-7940-45e6-91a1-21bd0df1a343@58094",
|
||||
@@ -53,6 +99,98 @@
|
||||
],
|
||||
"subMetas": {}
|
||||
},
|
||||
"63222": {
|
||||
"importer": "sprite-frame",
|
||||
"uuid": "81af97ed-7940-45e6-91a1-21bd0df1a343@63222",
|
||||
"displayName": "",
|
||||
"id": "63222",
|
||||
"name": "Title_01_NoDeco_Tangerine",
|
||||
"userData": {
|
||||
"trimThreshold": 1,
|
||||
"rotated": false,
|
||||
"offsetX": 0,
|
||||
"offsetY": 0,
|
||||
"trimX": 1624,
|
||||
"trimY": 1777,
|
||||
"width": 273,
|
||||
"height": 115,
|
||||
"rawWidth": 273,
|
||||
"rawHeight": 115,
|
||||
"borderTop": 0,
|
||||
"borderBottom": 0,
|
||||
"borderLeft": 0,
|
||||
"borderRight": 0,
|
||||
"packable": true,
|
||||
"pixelsToUnit": 100,
|
||||
"pivotX": 0.5,
|
||||
"pivotY": 0.5,
|
||||
"meshType": 0,
|
||||
"vertices": {
|
||||
"rawPosition": [],
|
||||
"indexes": [],
|
||||
"uv": [],
|
||||
"nuv": [],
|
||||
"minPos": [],
|
||||
"maxPos": []
|
||||
},
|
||||
"isUuid": true,
|
||||
"imageUuidOrDatabaseUri": "ca2b26a5-8d54-49ec-bdaf-e9f777afc9cb@6c48a",
|
||||
"atlasUuid": "81af97ed-7940-45e6-91a1-21bd0df1a343",
|
||||
"trimType": "auto"
|
||||
},
|
||||
"ver": "1.0.12",
|
||||
"imported": true,
|
||||
"files": [
|
||||
".json"
|
||||
],
|
||||
"subMetas": {}
|
||||
},
|
||||
"86850": {
|
||||
"importer": "sprite-frame",
|
||||
"uuid": "81af97ed-7940-45e6-91a1-21bd0df1a343@86850",
|
||||
"displayName": "",
|
||||
"id": "86850",
|
||||
"name": "Title_01_NoDeco_Orange",
|
||||
"userData": {
|
||||
"trimThreshold": 1,
|
||||
"rotated": false,
|
||||
"offsetX": 0,
|
||||
"offsetY": 0,
|
||||
"trimX": 1349,
|
||||
"trimY": 1777,
|
||||
"width": 273,
|
||||
"height": 115,
|
||||
"rawWidth": 273,
|
||||
"rawHeight": 115,
|
||||
"borderTop": 0,
|
||||
"borderBottom": 0,
|
||||
"borderLeft": 135,
|
||||
"borderRight": 138,
|
||||
"packable": true,
|
||||
"pixelsToUnit": 100,
|
||||
"pivotX": 0.5,
|
||||
"pivotY": 0.5,
|
||||
"meshType": 0,
|
||||
"vertices": {
|
||||
"rawPosition": [],
|
||||
"indexes": [],
|
||||
"uv": [],
|
||||
"nuv": [],
|
||||
"minPos": [],
|
||||
"maxPos": []
|
||||
},
|
||||
"isUuid": true,
|
||||
"imageUuidOrDatabaseUri": "ca2b26a5-8d54-49ec-bdaf-e9f777afc9cb@6c48a",
|
||||
"atlasUuid": "81af97ed-7940-45e6-91a1-21bd0df1a343",
|
||||
"trimType": "auto"
|
||||
},
|
||||
"ver": "1.0.12",
|
||||
"imported": true,
|
||||
"files": [
|
||||
".json"
|
||||
],
|
||||
"subMetas": {}
|
||||
},
|
||||
"4f746": {
|
||||
"importer": "sprite-frame",
|
||||
"uuid": "81af97ed-7940-45e6-91a1-21bd0df1a343@4f746",
|
||||
@@ -110,8 +248,8 @@
|
||||
"rotated": false,
|
||||
"offsetX": -4,
|
||||
"offsetY": 82,
|
||||
"trimX": 1349,
|
||||
"trimY": 1095,
|
||||
"trimX": 675,
|
||||
"trimY": 1669,
|
||||
"width": 616,
|
||||
"height": 182,
|
||||
"rawWidth": 672,
|
||||
@@ -157,7 +295,7 @@
|
||||
"offsetX": 0,
|
||||
"offsetY": -3,
|
||||
"trimX": 675,
|
||||
"trimY": 1775,
|
||||
"trimY": 1853,
|
||||
"width": 672,
|
||||
"height": 92,
|
||||
"rawWidth": 672,
|
||||
@@ -199,11 +337,11 @@
|
||||
"name": "0l4_clouds02",
|
||||
"userData": {
|
||||
"trimThreshold": 1,
|
||||
"rotated": false,
|
||||
"rotated": true,
|
||||
"offsetX": 0,
|
||||
"offsetY": 122,
|
||||
"trimX": 675,
|
||||
"trimY": 1869,
|
||||
"trimX": 1931,
|
||||
"trimY": 675,
|
||||
"width": 672,
|
||||
"height": 76,
|
||||
"rawWidth": 672,
|
||||
@@ -294,8 +432,8 @@
|
||||
"rotated": false,
|
||||
"offsetX": 0,
|
||||
"offsetY": -108,
|
||||
"trimX": 1,
|
||||
"trimY": 1589,
|
||||
"trimX": 675,
|
||||
"trimY": 1193,
|
||||
"width": 672,
|
||||
"height": 162,
|
||||
"rawWidth": 672,
|
||||
@@ -337,11 +475,11 @@
|
||||
"name": "0l7_ground02",
|
||||
"userData": {
|
||||
"trimThreshold": 1,
|
||||
"rotated": false,
|
||||
"rotated": true,
|
||||
"offsetX": 0,
|
||||
"offsetY": -120,
|
||||
"trimX": 675,
|
||||
"trimY": 1507,
|
||||
"trimX": 1663,
|
||||
"trimY": 675,
|
||||
"width": 672,
|
||||
"height": 138,
|
||||
"rawWidth": 672,
|
||||
@@ -383,11 +521,11 @@
|
||||
"name": "0l8_ground",
|
||||
"userData": {
|
||||
"trimThreshold": 1,
|
||||
"rotated": false,
|
||||
"rotated": true,
|
||||
"offsetX": 0,
|
||||
"offsetY": -81,
|
||||
"trimX": 1349,
|
||||
"trimY": 381,
|
||||
"trimX": 1729,
|
||||
"trimY": 1,
|
||||
"width": 672,
|
||||
"height": 216,
|
||||
"rawWidth": 672,
|
||||
@@ -613,11 +751,11 @@
|
||||
"name": "1l5_crystals",
|
||||
"userData": {
|
||||
"trimThreshold": 1,
|
||||
"rotated": true,
|
||||
"rotated": false,
|
||||
"offsetX": -2,
|
||||
"offsetY": -85,
|
||||
"trimX": 1349,
|
||||
"trimY": 1279,
|
||||
"trimY": 1349,
|
||||
"width": 662,
|
||||
"height": 90,
|
||||
"rawWidth": 672,
|
||||
@@ -659,11 +797,11 @@
|
||||
"name": "1l6_ground",
|
||||
"userData": {
|
||||
"trimThreshold": 1,
|
||||
"rotated": true,
|
||||
"rotated": false,
|
||||
"offsetX": 0,
|
||||
"offsetY": -151,
|
||||
"trimX": 1441,
|
||||
"trimY": 1279,
|
||||
"trimX": 1293,
|
||||
"trimY": 1699,
|
||||
"width": 672,
|
||||
"height": 76,
|
||||
"rawWidth": 672,
|
||||
@@ -705,11 +843,11 @@
|
||||
"name": "3l2_clouds",
|
||||
"userData": {
|
||||
"trimThreshold": 1,
|
||||
"rotated": false,
|
||||
"rotated": true,
|
||||
"offsetX": 0,
|
||||
"offsetY": -48,
|
||||
"trimX": 675,
|
||||
"trimY": 1353,
|
||||
"trimX": 1509,
|
||||
"trimY": 675,
|
||||
"width": 672,
|
||||
"height": 152,
|
||||
"rawWidth": 672,
|
||||
@@ -751,11 +889,11 @@
|
||||
"name": "3l3_pyramid",
|
||||
"userData": {
|
||||
"trimThreshold": 1,
|
||||
"rotated": true,
|
||||
"rotated": false,
|
||||
"offsetX": 2,
|
||||
"offsetY": -7,
|
||||
"trimX": 1621,
|
||||
"trimY": 1279,
|
||||
"trimX": 1349,
|
||||
"trimY": 1543,
|
||||
"width": 528,
|
||||
"height": 154,
|
||||
"rawWidth": 672,
|
||||
@@ -800,8 +938,8 @@
|
||||
"rotated": false,
|
||||
"offsetX": 0,
|
||||
"offsetY": -111,
|
||||
"trimX": 1,
|
||||
"trimY": 1753,
|
||||
"trimX": 675,
|
||||
"trimY": 1357,
|
||||
"width": 672,
|
||||
"height": 156,
|
||||
"rawWidth": 672,
|
||||
@@ -846,8 +984,8 @@
|
||||
"rotated": false,
|
||||
"offsetX": 0,
|
||||
"offsetY": -99,
|
||||
"trimX": 1349,
|
||||
"trimY": 599,
|
||||
"trimX": 1,
|
||||
"trimY": 1589,
|
||||
"width": 672,
|
||||
"height": 180,
|
||||
"rawWidth": 672,
|
||||
@@ -889,11 +1027,11 @@
|
||||
"name": "3l6_bg-ground03",
|
||||
"userData": {
|
||||
"trimThreshold": 1,
|
||||
"rotated": false,
|
||||
"rotated": true,
|
||||
"offsetX": 0,
|
||||
"offsetY": -126,
|
||||
"trimX": 675,
|
||||
"trimY": 1647,
|
||||
"trimX": 1803,
|
||||
"trimY": 675,
|
||||
"width": 672,
|
||||
"height": 126,
|
||||
"rawWidth": 672,
|
||||
@@ -938,8 +1076,8 @@
|
||||
"rotated": false,
|
||||
"offsetX": 0,
|
||||
"offsetY": -113,
|
||||
"trimX": 1349,
|
||||
"trimY": 941,
|
||||
"trimX": 675,
|
||||
"trimY": 1515,
|
||||
"width": 672,
|
||||
"height": 152,
|
||||
"rawWidth": 672,
|
||||
@@ -981,11 +1119,11 @@
|
||||
"name": "Stone_A_01",
|
||||
"userData": {
|
||||
"trimThreshold": 1,
|
||||
"rotated": false,
|
||||
"rotated": true,
|
||||
"offsetX": 0,
|
||||
"offsetY": 0,
|
||||
"trimX": 1777,
|
||||
"trimY": 1626,
|
||||
"trimX": 1879,
|
||||
"trimY": 1629,
|
||||
"width": 68,
|
||||
"height": 51,
|
||||
"rawWidth": 68,
|
||||
@@ -1027,11 +1165,11 @@
|
||||
"name": "Stone_A_04",
|
||||
"userData": {
|
||||
"trimThreshold": 1,
|
||||
"rotated": false,
|
||||
"rotated": true,
|
||||
"offsetX": 0,
|
||||
"offsetY": 0,
|
||||
"trimX": 1850,
|
||||
"trimY": 1562,
|
||||
"trimX": 1293,
|
||||
"trimY": 1777,
|
||||
"width": 60,
|
||||
"height": 51,
|
||||
"rawWidth": 60,
|
||||
@@ -1073,11 +1211,11 @@
|
||||
"name": "Stone_A_07",
|
||||
"userData": {
|
||||
"trimThreshold": 1,
|
||||
"rotated": false,
|
||||
"rotated": true,
|
||||
"offsetX": 0,
|
||||
"offsetY": 0,
|
||||
"trimX": 1621,
|
||||
"trimY": 1809,
|
||||
"trimX": 1947,
|
||||
"trimY": 1,
|
||||
"width": 107,
|
||||
"height": 51,
|
||||
"rawWidth": 107,
|
||||
@@ -1122,8 +1260,8 @@
|
||||
"rotated": false,
|
||||
"offsetX": 0,
|
||||
"offsetY": 0,
|
||||
"trimX": 1519,
|
||||
"trimY": 1865,
|
||||
"trimX": 1935,
|
||||
"trimY": 1441,
|
||||
"width": 68,
|
||||
"height": 70,
|
||||
"rawWidth": 68,
|
||||
@@ -1168,8 +1306,8 @@
|
||||
"rotated": false,
|
||||
"offsetX": 0,
|
||||
"offsetY": 0,
|
||||
"trimX": 1777,
|
||||
"trimY": 1679,
|
||||
"trimX": 1415,
|
||||
"trimY": 1894,
|
||||
"width": 66,
|
||||
"height": 45,
|
||||
"rawWidth": 66,
|
||||
@@ -1214,8 +1352,8 @@
|
||||
"rotated": false,
|
||||
"offsetX": 0,
|
||||
"offsetY": 0,
|
||||
"trimX": 1730,
|
||||
"trimY": 1809,
|
||||
"trimX": 1293,
|
||||
"trimY": 1669,
|
||||
"width": 35,
|
||||
"height": 22,
|
||||
"rawWidth": 35,
|
||||
@@ -1257,11 +1395,11 @@
|
||||
"name": "Stone_B_04",
|
||||
"userData": {
|
||||
"trimThreshold": 1,
|
||||
"rotated": false,
|
||||
"rotated": true,
|
||||
"offsetX": 0,
|
||||
"offsetY": 0,
|
||||
"trimX": 1777,
|
||||
"trimY": 1562,
|
||||
"trimX": 1899,
|
||||
"trimY": 1777,
|
||||
"width": 71,
|
||||
"height": 62,
|
||||
"rawWidth": 71,
|
||||
@@ -1306,8 +1444,8 @@
|
||||
"rotated": true,
|
||||
"offsetX": 0,
|
||||
"offsetY": 0,
|
||||
"trimX": 1967,
|
||||
"trimY": 1095,
|
||||
"trimX": 1879,
|
||||
"trimY": 1543,
|
||||
"width": 84,
|
||||
"height": 43,
|
||||
"rawWidth": 84,
|
||||
@@ -1352,8 +1490,8 @@
|
||||
"rotated": false,
|
||||
"offsetX": 0,
|
||||
"offsetY": 0,
|
||||
"trimX": 1519,
|
||||
"trimY": 1937,
|
||||
"trimX": 1947,
|
||||
"trimY": 110,
|
||||
"width": 31,
|
||||
"height": 15,
|
||||
"rawWidth": 31,
|
||||
@@ -1399,7 +1537,7 @@
|
||||
"offsetX": 0,
|
||||
"offsetY": 0,
|
||||
"trimX": 1,
|
||||
"trimY": 1911,
|
||||
"trimY": 1931,
|
||||
"width": 44,
|
||||
"height": 16,
|
||||
"rawWidth": 44,
|
||||
@@ -1441,7 +1579,7 @@
|
||||
"name": "l1_sky",
|
||||
"userData": {
|
||||
"trimThreshold": 1,
|
||||
"rotated": false,
|
||||
"rotated": true,
|
||||
"offsetX": 0,
|
||||
"offsetY": 0,
|
||||
"trimX": 1349,
|
||||
@@ -1533,11 +1671,11 @@
|
||||
"name": "l3_clouds",
|
||||
"userData": {
|
||||
"trimThreshold": 1,
|
||||
"rotated": true,
|
||||
"rotated": false,
|
||||
"offsetX": -6,
|
||||
"offsetY": 89,
|
||||
"trimX": 1519,
|
||||
"trimY": 1279,
|
||||
"trimX": 1349,
|
||||
"trimY": 1441,
|
||||
"width": 584,
|
||||
"height": 100,
|
||||
"rawWidth": 672,
|
||||
@@ -1579,11 +1717,11 @@
|
||||
"name": "l4_bg-ground01",
|
||||
"userData": {
|
||||
"trimThreshold": 1,
|
||||
"rotated": false,
|
||||
"rotated": true,
|
||||
"offsetX": 0,
|
||||
"offsetY": -110,
|
||||
"trimX": 675,
|
||||
"trimY": 1193,
|
||||
"trimX": 1349,
|
||||
"trimY": 675,
|
||||
"width": 672,
|
||||
"height": 158,
|
||||
"rawWidth": 672,
|
||||
@@ -1628,8 +1766,8 @@
|
||||
"rotated": false,
|
||||
"offsetX": 0,
|
||||
"offsetY": -110,
|
||||
"trimX": 1349,
|
||||
"trimY": 781,
|
||||
"trimX": 1,
|
||||
"trimY": 1771,
|
||||
"width": 672,
|
||||
"height": 158,
|
||||
"rawWidth": 672,
|
||||
@@ -1708,52 +1846,6 @@
|
||||
".json"
|
||||
],
|
||||
"subMetas": {}
|
||||
},
|
||||
"14c74": {
|
||||
"importer": "sprite-frame",
|
||||
"uuid": "81af97ed-7940-45e6-91a1-21bd0df1a343@14c74",
|
||||
"displayName": "",
|
||||
"id": "14c74",
|
||||
"name": "logo2",
|
||||
"userData": {
|
||||
"trimThreshold": 1,
|
||||
"rotated": true,
|
||||
"offsetX": 1,
|
||||
"offsetY": 2,
|
||||
"trimX": 1777,
|
||||
"trimY": 1279,
|
||||
"width": 281,
|
||||
"height": 231,
|
||||
"rawWidth": 307,
|
||||
"rawHeight": 307,
|
||||
"borderTop": 0,
|
||||
"borderBottom": 0,
|
||||
"borderLeft": 0,
|
||||
"borderRight": 0,
|
||||
"packable": true,
|
||||
"pixelsToUnit": 100,
|
||||
"pivotX": 0.5,
|
||||
"pivotY": 0.5,
|
||||
"meshType": 0,
|
||||
"vertices": {
|
||||
"rawPosition": [],
|
||||
"indexes": [],
|
||||
"uv": [],
|
||||
"nuv": [],
|
||||
"minPos": [],
|
||||
"maxPos": []
|
||||
},
|
||||
"isUuid": true,
|
||||
"imageUuidOrDatabaseUri": "ca2b26a5-8d54-49ec-bdaf-e9f777afc9cb@6c48a",
|
||||
"atlasUuid": "81af97ed-7940-45e6-91a1-21bd0df1a343",
|
||||
"trimType": "auto"
|
||||
},
|
||||
"ver": "1.0.12",
|
||||
"imported": true,
|
||||
"files": [
|
||||
".json"
|
||||
],
|
||||
"subMetas": {}
|
||||
}
|
||||
},
|
||||
"userData": {
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 469 KiB After Width: | Height: | Size: 396 KiB |
File diff suppressed because it is too large
Load Diff
@@ -81,11 +81,13 @@ const PLACEHOLDER_PATTERN = /\{(\w+)\}/g;
|
||||
* atking/atked 为周期循环触发(运行时按次数取模判定),拼为"每攻击N次"/"每受击N次"
|
||||
* 表达循环语义(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) {
|
||||
// 配置了 t_chance 且 < 100 时追加概率说明(保底叠加为隐藏机制,不在文案展示)
|
||||
const chanceSeg = chance !== undefined && chance < 100 ? `(${valueRich(Math.round(chance))}%概率)` : "";
|
||||
return tNum <= 1
|
||||
? `每次${SkillTriggerName[type]}`
|
||||
: `每${SkillTriggerName[type]}${valueRich(tNum)}次`;
|
||||
? `每次${SkillTriggerName[type]}${chanceSeg}`
|
||||
: `每${SkillTriggerName[type]}${valueRich(tNum)}次${chanceSeg}`;
|
||||
}
|
||||
return SkillTriggerName[type];
|
||||
}
|
||||
@@ -137,18 +139,25 @@ function getBuffValue(skill: SkillConfig): number {
|
||||
* Why: 数值不写死在模板里,overrides 调整档位数值时文案自动同步。
|
||||
* @param tmpl 描述模板(含占位符)
|
||||
* @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) => {
|
||||
if (key === "target") return buildTargetDesc(skill);
|
||||
if (key === "dur") return valueRich(getBuffDuration(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];
|
||||
// 未定义数值字段按 0 渲染,避免面板出现 undefined(模板与配置不匹配的兜底)
|
||||
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 备注 */
|
||||
function fallbackDesc(skill: SkillConfig): string {
|
||||
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;
|
||||
}
|
||||
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),逗号衔接效果文本
|
||||
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}`);
|
||||
}
|
||||
// dead 组内的复活效果(revive_hp / revive_count)并入同一行
|
||||
@@ -279,12 +291,17 @@ interface ISkillTierInfo {
|
||||
ownDesc?: string;
|
||||
/** 触发技能档位的触发次数(普攻无) */
|
||||
tNum: number;
|
||||
/** 触发技能档位的触发概率百分点(普攻无;缺省 100 必触发) */
|
||||
tChance?: number;
|
||||
/** 触发技能档位的保底叠加百分点(普攻无;缺省 0) */
|
||||
pityAdd?: number;
|
||||
}
|
||||
|
||||
/** 相邻档 diff 参与展示的字段(排除动画/弹道/特效等玩家无感字段),t_num 为触发技能专有 */
|
||||
const DIFF_KEYS: string[] = [
|
||||
"ap", "hit_count", "num", "summon_count", "crt", "frz", "stun", "para",
|
||||
"bck", "bck_chance", "buff_duration", "buff_value", "t_num", "timed_buff_id",
|
||||
"t_chance", "pity_add",
|
||||
];
|
||||
|
||||
/** diff 字段的称谓与单位("新增/漂移"描述共用) */
|
||||
@@ -302,11 +319,15 @@ const DIFF_META: Record<string, { label: string; unit: string }> = {
|
||||
buff_duration: { label: "持续", unit: "秒" },
|
||||
buff_value: { 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 {
|
||||
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);
|
||||
const v = (tier.skill as unknown as Record<string, unknown>)[key];
|
||||
return typeof v === "number" ? v : 0;
|
||||
@@ -497,9 +518,13 @@ function collectTriggerTiers(hero: heroInfo, type: SkillTriggerType, skillUuid:
|
||||
desc: e.desc ?? inherit,
|
||||
ownDesc: e.desc,
|
||||
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 };
|
||||
}
|
||||
|
||||
@@ -510,11 +535,11 @@ function buildTierLines(tiers: ISkillTierInfo[], triggerLabel: string): HeroSkil
|
||||
const t = tiers[i];
|
||||
if (i === 0) {
|
||||
// 技能 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 });
|
||||
} else if (t.ownDesc) {
|
||||
// 提升档:该档显式配置了模板(如护盾/治疗等 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 {
|
||||
// 提升档:未配置模板,给相对上一级的提升
|
||||
const diff = buildTierDiff(tiers[i - 1], t);
|
||||
|
||||
@@ -48,11 +48,9 @@ export interface GameDate {
|
||||
talent_lv?: number,
|
||||
/** 天赋当前等级已累计的经验值 */
|
||||
talent_exp?: number,
|
||||
/** 关卡进度存档:当前章节-关-节 */
|
||||
/** 关卡进度存档:当前关卡号(无限关模式只记关卡号,回合恒从 1 开始) */
|
||||
stage_progress?: {
|
||||
chapter: number,
|
||||
stage: number,
|
||||
section: number,
|
||||
},
|
||||
/** 奖励领取状态:段位/闯关首达奖励的已领取标记(玩家点击领取) */
|
||||
reward_claimed?: {
|
||||
@@ -61,7 +59,7 @@ export interface GameDate {
|
||||
/** 已领取的大关号 */
|
||||
stage: number[],
|
||||
},
|
||||
/** 已通关大关的显式标记(覆盖存档停留场景,如第 10 关通关后进度停留 1-10-10) */
|
||||
/** 已通关大关的显式标记(历史遗留字段,无限关模式不再写入;仅用于兼容读取旧存档) */
|
||||
passed_stages?: number[],
|
||||
}
|
||||
export interface CloudData {
|
||||
@@ -152,11 +150,9 @@ export class SingletonModuleComp extends ecs.Comp {
|
||||
talent_lv: 0,
|
||||
/** 当前等级已累计经验 */
|
||||
talent_exp: 0,
|
||||
/** 关卡进度存档:默认从 1-1-1 开始 */
|
||||
/** 关卡进度存档:默认从第 1 关开始 */
|
||||
stage_progress: {
|
||||
chapter: 1,
|
||||
stage: 1,
|
||||
section: 1,
|
||||
},
|
||||
/** 奖励领取状态(玩家点击领取,跨局保留) */
|
||||
reward_claimed: {
|
||||
@@ -238,9 +234,7 @@ export class SingletonModuleComp extends ecs.Comp {
|
||||
switch_music: true, // 音乐开关(MVVM绑定字段)
|
||||
/** 关卡进度(MVVM绑定字段,镜像 data.stage_progress,供 HUD 实时显示) */
|
||||
stage_progress: {
|
||||
chapter: 1,
|
||||
stage: 1,
|
||||
section: 1,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -352,26 +346,26 @@ export class SingletonModuleComp extends ecs.Comp {
|
||||
* 将 data 层的关卡进度镜像到 vmdata 视图层(MVVM 绑定字段)。
|
||||
* Why: data.stage_progress 为云端持久权威源,vmdata.stage_progress 仅供 HUD 绑定展示;
|
||||
* 登录覆盖、关卡推进后都必须调用本方法保持镜像一致。
|
||||
* 旧版三段存档(chapter/stage/section)在同步时归一化为 stage 单字段。
|
||||
*/
|
||||
public syncStageProgressToView(): void {
|
||||
const p = this.data.stage_progress;
|
||||
// 就地更新字段而非整体替换对象:oops VM(JsonOb)只通知被赋值属性的精确路径,
|
||||
// 整体替换仅派发 VC:data.stage_progress,不会触发 HUD 绑定的
|
||||
// data.stage_progress.section 等嵌套末端路径刷新,导致进度显示停留在老节
|
||||
const view = this.vmdata.stage_progress;
|
||||
view.chapter = p?.chapter ?? 1;
|
||||
view.stage = p?.stage ?? 1;
|
||||
view.section = p?.section ?? 1;
|
||||
// 旧存档归一化:兼容历史 chapter/stage/section 三段结构,仅提取 stage
|
||||
const stage = Math.max(1, Math.floor(p?.stage ?? 1));
|
||||
if (p && (p.stage !== stage || (p as any).chapter !== undefined || (p as any).section !== undefined)) {
|
||||
this.data.stage_progress = { stage };
|
||||
}
|
||||
this.vmdata.stage_progress.stage = stage;
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新关卡进度(权威源 data + 视图镜像 vmdata),并派发事件刷新 UI。
|
||||
* Why: 替代直接赋值 smc.data.stage_progress,保证视图层实时同步。
|
||||
* @param progress 新的关卡进度(章节/大关/小节均从 1 开始)
|
||||
* @param progress 新的关卡进度(仅关卡号,从 1 开始)
|
||||
* @param is_sync 是否标记脏并触发云端/本地同步
|
||||
*/
|
||||
public updateStageProgress(progress: { chapter: number; stage: number; section: number }, is_sync: boolean = true): void {
|
||||
this.data.stage_progress = { ...progress };
|
||||
public updateStageProgress(progress: { stage: number }, is_sync: boolean = true): void {
|
||||
this.data.stage_progress = { stage: Math.max(1, Math.floor(progress.stage)) };
|
||||
this.syncStageProgressToView();
|
||||
if (is_sync) {
|
||||
gameDataSync.markDataDirty();
|
||||
@@ -452,20 +446,18 @@ export class SingletonModuleComp extends ecs.Comp {
|
||||
}
|
||||
|
||||
/**
|
||||
* 标记大关已通关(通关点调用,覆盖存档停留场景)
|
||||
* Why: 第 10 关通关后存档停留 1-10-10,无法从 stage_progress 推导已通状态,
|
||||
* 需在通关时显式写入。
|
||||
* @param stage 大关号
|
||||
* 标记大关已通关(历史遗留入口)
|
||||
* Why: 旧版本第 10 关通关后存档停留,无法从 stage_progress 推导已通状态,需显式标记;
|
||||
* 无限关模式存档永远推进,判定已通可直接由 stage_progress 推导,无需再写入。
|
||||
* 保留空实现以避免破坏外部调用方(若有旧存档读取场景走 passed_stages 兼容)。
|
||||
* @param _stage 大关号(未使用,保留签名兼容)
|
||||
* @deprecated 无限关模式无需调用,保留仅为兼容旧代码引用
|
||||
*/
|
||||
public markStagePassed(stage: number): void {
|
||||
if (!this.data.passed_stages) this.data.passed_stages = [];
|
||||
if (!this.data.passed_stages.includes(stage)) {
|
||||
this.data.passed_stages.push(stage);
|
||||
gameDataSync.markDataDirty();
|
||||
}
|
||||
public markStagePassed(_stage: number): void {
|
||||
// 无限关模式不再写入 passed_stages
|
||||
}
|
||||
|
||||
/** 判定大关是否已通关:显式标记优先,存档推进兜底(已进入后续关即已通关) */
|
||||
/** 判定大关是否已通关:旧存档显式标记兼容,无限关以存档关卡号推导(已进入后续关即已通关) */
|
||||
private isStagePassed(stage: number): boolean {
|
||||
if ((this.data.passed_stages ?? []).includes(stage)) return true;
|
||||
return (this.data.stage_progress?.stage ?? 1) > stage;
|
||||
|
||||
@@ -104,15 +104,15 @@ export enum GameEvent {
|
||||
STAGE_PROGRESS_UPDATE = "STAGE_PROGRESS_UPDATE",
|
||||
/** 奖励领取完成(payload 为空,UI 刷新待领取列表/红点) */
|
||||
REWARD_CLAIMED = "REWARD_CLAIMED",
|
||||
/** 小节开始(payload: { chapter, stage, section },MissionMonComp 据此生成怪物) */
|
||||
/** 回合开始(payload: { stage, section },MissionMonComp 据此生成怪物) */
|
||||
SectionStart = "SectionStart",
|
||||
/** 小节结束(payload: { chapter, stage, section },玩家点击"下一节"后推进) */
|
||||
/** @deprecated 已废弃:无限关模式无节间结算,回合自动推进,勿再监听 */
|
||||
SectionEnd = "SectionEnd",
|
||||
/** 大关结束(payload: { chapter, stage },10 节打完) */
|
||||
/** @deprecated 已废弃:无限关模式无大关结算,勿再监听 */
|
||||
StageEnd = "StageEnd",
|
||||
/** 章节结束(payload: { chapter },10 关打完) */
|
||||
/** @deprecated 已废弃:无限关模式无章节概念,勿再监听 */
|
||||
ChapterEnd = "ChapterEnd",
|
||||
/** 结算弹窗点击"下一节"(payload 为空,MissionComp 据此推进到下一小节) */
|
||||
/** @deprecated 已废弃:无限关模式无"下一节"手动推进,勿再监听 */
|
||||
NextSection = "NextSection",
|
||||
/** 结算弹窗点击"再来一次"(payload 为空,MissionComp 据此重开本关) */
|
||||
RestartMission = "RestartMission",
|
||||
|
||||
@@ -65,6 +65,16 @@ export enum EType {
|
||||
timeEnd = 1, //碰撞够也不消失,时间到才消失
|
||||
collision = 2, //碰撞次数够就消失
|
||||
}
|
||||
|
||||
/**
|
||||
* 召唤类技能(summon_count>1)多次施放的目标选择模式(由技能 prefab 上 SkillView 配置)。
|
||||
* 仅对敌方目标技能生效;友方/自身技能不走该逻辑。
|
||||
*/
|
||||
export enum SummonTMode {
|
||||
same = 0, // 同一敌人:所有召唤物锁定施法时选定的目标(默认,原行为)
|
||||
random = 1, // 随机敌人:每次出手时从射程内敌人中随机锁定一个
|
||||
unique = 2, // 避免相同敌人:优先锁定本轮尚未选过的敌人,一轮选完后重置再选
|
||||
}
|
||||
//debuff类型
|
||||
|
||||
|
||||
@@ -72,31 +82,40 @@ export enum EType {
|
||||
=== 技能配置系统使用说明 ===
|
||||
|
||||
1. 基础属性:
|
||||
- uuid: 技能唯一ID
|
||||
- name: 技能名称
|
||||
- uuid: 技能唯一ID(6001~6013 单体普攻、6100~6204 群体大招、6301~6302 治疗护盾、
|
||||
6401~6416 永久强化、6501~6519 计时强化/特殊、7001~7024 驻场光环)
|
||||
- name: 技能名称(内部底座代号;英雄语境对外名由 heroSet 侧 name 字段覆写)
|
||||
- sp_name: 特效名称
|
||||
- AtkedName: 攻击类型
|
||||
- path: 图片资源路径
|
||||
- icon: 图标ID
|
||||
|
||||
2. 目标和效果:
|
||||
- TGroup: 目标群体 (敌方、友方等)
|
||||
- SType: 技能类型 (伤害、治疗、护盾等)
|
||||
- TGroup: 目标群体(Self 自身 / Ally 全体友方含自己 / Team 全体友方 / Enemy 敌方 / All 全部)
|
||||
- kind: 主效果类型(Damage 伤害 / Heal 治疗 / Shield 护盾 / Support 强化)
|
||||
|
||||
3. 执行参数:
|
||||
- act: 角色执行的动画
|
||||
- DTType: 伤害类型 (单体、范围)
|
||||
- EType: 结束条件
|
||||
- fname: 特效文件名
|
||||
- act: 角色执行的动画
|
||||
- DTType: 伤害类型(single 单体 / range 范围)
|
||||
- EType: 结束条件(动画结束/时间结束/碰撞次数)
|
||||
- RType: 弹道类型(linear 直线 / bezier 贝塞尔 / fixed 固定起点 / fixedEnd 固定终点)
|
||||
- with: 暂时无用
|
||||
|
||||
4. 数值参数:
|
||||
- ap: 攻击力百分比
|
||||
- cd: 冷却时间
|
||||
- hit_count: 可命中次数
|
||||
- t_num: 目标数量
|
||||
- hitcd: 持续伤害的伤害间隔
|
||||
- speed: 移动速度
|
||||
- cost: 消耗值
|
||||
- ap: 伤害/治疗为攻击力百分比;护盾为生命最大值百分比;强化技能为修饰数值
|
||||
- cd: 冷却时间(普攻 cd 即攻击间隔)
|
||||
- hit_count: 可命中目标数(伤害技能=弹道穿透数;辅助技能=作用目标数)
|
||||
- hitcd: 持续伤害的伤害间隔(秒)
|
||||
- speed: 弹道移动速度
|
||||
- summon_count: 单次施法召唤的弹道/实体个数(>1 视为召唤类技能)
|
||||
|
||||
5. 增益/减益:
|
||||
- buff_type + ap: 永久强化(直接累加到属性,无时长)
|
||||
- timed_buff_id + buff_value/buff_duration/buff_chance/buff_target: 计时强化(走 BuffList)
|
||||
- timed_debuff_id + debuff_value/debuff_duration/debuff_chance: 命中敌方后挂的计时减益
|
||||
- proc_skill: 施法后概率触发额外技能(技能级触发器,无视 CD)
|
||||
|
||||
6. 文案约定:
|
||||
- info 仅作语义描述,禁止写死数值;数值由 heroSet/卡片 overrides 注入,
|
||||
UI 文案由 SkillDescSet / HeroSkillText 按合并后实时配置动态生成
|
||||
*/
|
||||
export enum DType {
|
||||
ATK = 0, // 物理
|
||||
@@ -140,8 +159,8 @@ export interface SkillConfig {
|
||||
TGroup: TGroup, // 目标群体(敌方/友方/自身等)
|
||||
act: string, // 角色执行的动画
|
||||
DTType: DTType, // 伤害类型(单体/范围)
|
||||
ap: number, // 伤害/治疗技能为攻击百分比,护盾技能为免疫次数
|
||||
hit_count: number, // 可命中次数
|
||||
ap: number, // 伤害/治疗为攻击力百分比;护盾为生命最大值百分比;永久强化为修饰数值
|
||||
hit_count: number, // 可命中目标数(伤害技能=弹道穿透数;辅助技能=作用目标数,>1 生效)
|
||||
hitcd: number, // 持续伤害的伤害间隔(秒)
|
||||
speed: number, // 移动速度
|
||||
with: number, // 宽度(暂时无用)
|
||||
@@ -318,6 +337,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,
|
||||
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: {
|
||||
@@ -336,8 +370,8 @@ export const SkillSet: Record<number, SkillConfig> = {
|
||||
RType: RType.bezier, EType: EType.collision, info: "火焰斩动画",//英雄配置技能的时候,可以叠加暴击debuff
|
||||
},
|
||||
6103: {
|
||||
uuid: 6103, name: "闪电斩", sp_name: "atk5", 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,
|
||||
uuid: 6103, name: "闪电斩", sp_name: "atk6", icon: "100-Enchant-Magic", TGroup: TGroup.Enemy, readyAnm: "", endAnm: "", act: "max0",
|
||||
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: "闪电斩动画",//英雄配置技能的时候,可以疲惫触发闪电系追加技能
|
||||
},
|
||||
6104: {
|
||||
@@ -364,46 +398,46 @@ export const SkillSet: Record<number, SkillConfig> = {
|
||||
},
|
||||
6201: {
|
||||
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: "一个飓风",
|
||||
},
|
||||
6202: {
|
||||
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: "一个大毒气弹",
|
||||
},
|
||||
6203: {
|
||||
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: "一个能量波",
|
||||
},
|
||||
6204: {
|
||||
uuid: 6204, name: "多毒气弹", sp_name: "maxm6", 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,
|
||||
RType: RType.linear, EType: EType.collision, bezier_start_y: 20, bezier_mid_y: 140, bezier_arc: 1.05, info: "一个大毒气弹",
|
||||
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: 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: "雷暴多段打击(hit_count=99 直线穿透),可附加麻痹",
|
||||
},
|
||||
|
||||
//============================= ====== 辅助技能 回合技能 ====== ==========================
|
||||
6301: {
|
||||
uuid: 6301, name: "护盾", sp_name: "buff_wind", icon: "28-Electric-Wave", TGroup: TGroup.Self, readyAnm: "up_blue", endAnm: "", act: "max1",
|
||||
DTType: DTType.single, kind: SkillKind.Shield, ap: 30, hit_count: 1, hitcd: 0.2, speed: 720, with: 0, ready: 0.2, EAnm: 0, DAnm: "", IType: IType.support, shield_duration: 7,
|
||||
RType: RType.fixed, EType: EType.animationEnd, info: "获得施法者最大生命30%的护盾, 持续7秒",
|
||||
RType: RType.fixed, EType: EType.animationEnd, info: "获得施法者最大生命一定比例的护盾,持续7秒(ap=百分比)",
|
||||
},
|
||||
6302: {
|
||||
uuid: 6302, name: "治疗", sp_name: "buff_wind", icon: "g_priest_zldy_skill", TGroup: TGroup.Team, readyAnm: "up_green", endAnm: "", act: "max1",
|
||||
DTType: DTType.single, kind: SkillKind.Heal, ap: 300, hit_count: 1, hitcd: 0.2, speed: 720, with: 0, ready: 0.2, EAnm: 0, DAnm: "", IType: IType.support,
|
||||
RType: RType.fixed, EType: EType.animationEnd, info: "治疗伙伴/自己",
|
||||
RType: RType.fixed, EType: EType.animationEnd, info: "治疗友方目标,回复量=目标最大生命×ap%",
|
||||
},
|
||||
//==========================buff 技能=====================
|
||||
6401: {
|
||||
uuid: 6401, name: "攻击强化", sp_name: "buff_wind", icon: "36-Guardian-Stance", TGroup: TGroup.Team, readyAnm: "up_ap", endAnm: "", act: "atk",
|
||||
DTType: DTType.single, kind: SkillKind.Support, ap: 5, hit_count: 1, hitcd: 0.2, speed: 720, with: 0, ready: 0.2, EAnm: 0, DAnm: "", IType: IType.support,
|
||||
RType: RType.fixed, EType: EType.animationEnd, buff_type: Attrs.ap, info: "全体友方攻击力提升5%, 持续1次",
|
||||
RType: RType.fixed, EType: EType.animationEnd, buff_type: Attrs.ap, info: "全体友方攻击力永久提升(ap=百分比,单次施加)",
|
||||
},
|
||||
6402: {
|
||||
uuid: 6402, name: "生命强化", sp_name: "buff_wind", icon: "29-Endure", TGroup: TGroup.Team, readyAnm: "up_hp", endAnm: "", act: "atk",
|
||||
DTType: DTType.single, kind: SkillKind.Support, ap: 20, hit_count: 1, hitcd: 0.2, speed: 720, with: 0, ready: 0.2, EAnm: 0, DAnm: "", IType: IType.support,
|
||||
RType: RType.fixed, EType: EType.animationEnd, buff_type: Attrs.hp_max, info: "全体友方最大生命值提升20%, 持续1次",
|
||||
RType: RType.fixed, EType: EType.animationEnd, buff_type: Attrs.hp_max, info: "全体友方最大生命值永久提升(ap=百分比,单次施加)",
|
||||
},
|
||||
6403: {
|
||||
uuid: 6403, name: "暴击强化", sp_name: "buff_wind", icon: "5-Apply-Burn", TGroup: TGroup.Team, readyAnm: "up_ap", endAnm: "", act: "atk",
|
||||
@@ -456,7 +490,7 @@ export const SkillSet: Record<number, SkillConfig> = {
|
||||
6412: {
|
||||
uuid: 6412, name: "防御强化", sp_name: "buff_wind", icon: "46-Iron-Clad", TGroup: TGroup.Team, readyAnm: "up_blue", endAnm: "", act: "atk",
|
||||
DTType: DTType.single, kind: SkillKind.Support, ap: 50, hit_count: 1, hitcd: 0.2, speed: 720, with: 0, ready: 0.2, EAnm: 0, DAnm: "", IType: IType.support,
|
||||
RType: RType.fixed, EType: EType.animationEnd, buff_type: Attrs.defense, info: "全体友方防御提升50点, 持续1次",
|
||||
RType: RType.fixed, EType: EType.animationEnd, buff_type: Attrs.defense, info: "全体友方防御永久提升(ap=固定点数,单次施加)",
|
||||
},
|
||||
6413: {
|
||||
uuid: 6413, name: "反伤强化", sp_name: "buff_wind", icon: "75-Shield-Stun", TGroup: TGroup.Team, readyAnm: "up_blue", endAnm: "", act: "atk",
|
||||
@@ -514,7 +548,7 @@ export const SkillSet: Record<number, SkillConfig> = {
|
||||
6507: {
|
||||
uuid: 6507, name: "攻速爆发", sp_name: "buff_wind", icon: "147-Chronomancy", TGroup: TGroup.Team, readyAnm: "up_ap", endAnm: "", act: "atk",
|
||||
DTType: DTType.single, kind: SkillKind.Support, ap: 0, hit_count: 3, hitcd: 0.2, speed: 720, with: 0, ready: 0.2, EAnm: 0, DAnm: "", IType: IType.support,
|
||||
RType: RType.fixed, EType: EType.animationEnd, buff_type: Attrs.speed, timed_buff_id: 7015, info: "全体友方攻击速度提升40%, 持续5秒",
|
||||
RType: RType.fixed, EType: EType.animationEnd, buff_type: Attrs.speed, timed_buff_id: 7015, info: "全体友方攻击速度提升(buff_value=百分比,默认5秒)",
|
||||
},
|
||||
// 风怒机制已停用: 6508 风怒爆发技能已移除
|
||||
/*
|
||||
@@ -568,7 +602,7 @@ export const SkillSet: Record<number, SkillConfig> = {
|
||||
6517: {
|
||||
uuid: 6517, name: "生命爆发", sp_name: "buff_wind", icon: "29-Endure", TGroup: TGroup.Team, readyAnm: "up_green", endAnm: "", act: "atk",
|
||||
DTType: DTType.single, kind: SkillKind.Support, ap: 0, hit_count: 3, hitcd: 0.2, speed: 720, with: 0, ready: 0.2, EAnm: 0, DAnm: "", IType: IType.support,
|
||||
RType: RType.fixed, EType: EType.animationEnd, buff_type: Attrs.hp_max, timed_buff_id: 7029, info: "全体友方最大生命值提升30%, 持续5秒",
|
||||
RType: RType.fixed, EType: EType.animationEnd, buff_type: Attrs.hp_max, timed_buff_id: 7029, info: "全体友方最大生命值提升(buff_value=百分比,默认5秒)",
|
||||
},
|
||||
6518: {
|
||||
uuid: 6518, name: "闪避爆发", sp_name: "buff_wind", icon: "98-Enchant-Wind", TGroup: TGroup.Team, readyAnm: "up_blue", endAnm: "", act: "atk",
|
||||
@@ -576,9 +610,9 @@ export const SkillSet: Record<number, SkillConfig> = {
|
||||
RType: RType.fixed, EType: EType.animationEnd, buff_type: Attrs.dodge, timed_buff_id: 7030, info: "全体友方闪避概率提升20%, 持续5秒",
|
||||
},
|
||||
6519: {
|
||||
uuid: 6519, name: "命中强化", sp_name: "buff_wind", icon: "27-Hawkeye", TGroup: TGroup.Team, readyAnm: "up_blue", endAnm: "", act: "atk",
|
||||
uuid: 6519, name: "命中爆发", sp_name: "buff_wind", icon: "27-Hawkeye", TGroup: TGroup.Team, readyAnm: "up_blue", endAnm: "", act: "atk",
|
||||
DTType: DTType.single, kind: SkillKind.Support, ap: 0, hit_count: 3, hitcd: 0.2, speed: 720, with: 0, ready: 0.2, EAnm: 0, DAnm: "", IType: IType.support,
|
||||
RType: RType.fixed, EType: EType.animationEnd, buff_type: Attrs.accuracy, timed_buff_id: 7031, info: "全体友方命中概率提升20%, 持续5秒",
|
||||
RType: RType.fixed, EType: EType.animationEnd, buff_type: Attrs.accuracy, timed_buff_id: 7031, info: "全体友方命中概率提升(buff_value=百分比,默认5秒)",
|
||||
}
|
||||
};
|
||||
//***************驻场技能配置***************
|
||||
|
||||
@@ -1,17 +1,22 @@
|
||||
/**
|
||||
* @file StageSet.ts
|
||||
* @description 关卡系统配置(章节-关-节三级结构)
|
||||
* @description 关卡系统配置(无限关卡·单线推进)
|
||||
*
|
||||
* 设计要点:
|
||||
* - 1 章 = 10 关,每关 = 5 小节(一关一局,节间自动推进),共 50 个小节
|
||||
* - 每关节点固定:1~3 节普通(3 小怪)、第 4 节精英(3 精英)、第 5 节 Boss(1 Boss + 2 小怪)
|
||||
* - 怪物等级 = 关卡号(1-1 的怪为 Lv1,1-5 的怪为 Lv5)
|
||||
* - 怪物属性 = 基础 × 开局系数 × (1 + 成长斜率 × (lv-1)) × 类型倍率
|
||||
* - 无限关卡:从第 1 关起无上限推进,每关 = 5 回合(一关一局,回合间自动推进)
|
||||
* - 第 1~4 回合为普通怪,属性逐回合轻量增强(SECTION_RAMP_STEP)
|
||||
* - 第 5 回合为单 Boss 回合(无护卫),Boss 采用超厚血量(BOSS_HP_MUL)
|
||||
* - 怪物等级 = 关卡号(第 N 关的怪为 LvN,随关卡无限成长)
|
||||
* - 小节配置按需动态生成,不再依赖章节静态表
|
||||
*
|
||||
* 数值基准:
|
||||
* - 开局系数 0.8(1 级小怪略弱于英雄)
|
||||
* - 成长斜率 +5%/级(10 级 ≈ 1.45 倍)
|
||||
* - 精英倍率 × 1.5,Boss 倍率 × 3.0(精英 × 2)
|
||||
* - 成长斜率 +5%/级(无限线性成长,曲线平缓可控)
|
||||
* - 回合增强 +12%/回合(第 4 回合 ≈ 1.36 倍)
|
||||
* - Boss:HP × 12(超厚血量)/ AP × 2.0(攻击克制,避免 Boss 秒杀英雄)
|
||||
*
|
||||
* 核心公式:
|
||||
* 怪物属性 = 基础 × MON_START_COEF × (1 + MON_GROW_SLOPE×(lv-1)) × 回合增强 × 类型倍率
|
||||
*/
|
||||
|
||||
import { MonType } from "./heroSet";
|
||||
@@ -20,82 +25,54 @@ import { MonType } from "./heroSet";
|
||||
|
||||
/** 怪物开局系数:1 级小怪略弱于英雄(0.8 倍) */
|
||||
export const MON_START_COEF = 0.8;
|
||||
/** 怪物成长斜率:每级 +5% 基础属性 */
|
||||
/** 怪物成长斜率:每级 +5% 基础属性(无限线性成长) */
|
||||
export const MON_GROW_SLOPE = 0.05;
|
||||
/** 精英属性倍率:同级普通怪的 1.5 倍 */
|
||||
export const ELITE_MUL = 1.5;
|
||||
/** Boss 属性倍率:同级普通怪的 3.0 倍(精英 × 2) */
|
||||
export const BOSS_MUL = 3.0;
|
||||
/** 每关小节总数(一关一局,节间自动推进) */
|
||||
/** 回合内轻量增强步长:第 1→4 回合每回合 +12% 属性 */
|
||||
export const SECTION_RAMP_STEP = 0.12;
|
||||
/** Boss 血量倍率:同级普通怪的 12 倍(超厚血量,拖长 Boss 战节奏) */
|
||||
export const BOSS_HP_MUL = 12;
|
||||
/** Boss 攻击倍率:同级普通怪的 2.0 倍(显著低于血量倍率,避免 Boss 秒杀英雄) */
|
||||
export const BOSS_AP_MUL = 2.0;
|
||||
/** 每关回合总数(一关一局,回合间自动推进) */
|
||||
export const SECTIONS_PER_STAGE = 5;
|
||||
/** 精英节号(每关第 4 节为精英节) */
|
||||
export const ELITE_SECTION = 4;
|
||||
/** Boss 节号(每关第 5 节为 Boss 节,即末节) */
|
||||
/** Boss 回合号(每关第 5 回合,即末回合) */
|
||||
export const BOSS_SECTION = 5;
|
||||
/** 普通节小怪数量(一关一局压缩后单节 3 只) */
|
||||
/** 普通回合小怪数量 */
|
||||
export const NORMAL_MON_COUNT = 3;
|
||||
/** 普通节开局立即刷出数量(3 只全部立即刷出) */
|
||||
/** 普通回合开局立即刷出数量(3 只全部立即刷出) */
|
||||
export const NORMAL_FIRST_SPAWN = 3;
|
||||
/** 普通节后续刷怪间隔(秒):保留配置位(3 只全立即刷,当前无后续批次) */
|
||||
/** 普通回合后续刷怪间隔(秒):保留配置位(3 只全立即刷,当前无后续批次) */
|
||||
export const NORMAL_SPAWN_INTERVAL = 2;
|
||||
/** 精英节精英数量 */
|
||||
export const ELITE_COUNT = 3;
|
||||
/** Boss 节护卫小怪数量 */
|
||||
export const BOSS_ELITE_COUNT = 2;
|
||||
/** Boss 节 Boss 延迟刷出时间(秒) */
|
||||
/** Boss 回合 Boss 延迟刷出时间(秒) */
|
||||
export const BOSS_DELAY = 1;
|
||||
|
||||
// ======================== 类型定义 ========================
|
||||
|
||||
/** 小节类型 */
|
||||
/** 回合类型 */
|
||||
export enum SectionType {
|
||||
Normal = 0, // 普通节:3 小怪
|
||||
Elite = 1, // 精英节:3 精英
|
||||
Boss = 2, // Boss 节:1 Boss + 2 小怪
|
||||
Normal = 0, // 普通回合:3 小怪(逐回合轻量增强)
|
||||
Boss = 2, // Boss 回合:1 Boss(超厚血量,无护卫)
|
||||
}
|
||||
|
||||
/** 小节配置 */
|
||||
/** 回合配置 */
|
||||
export interface SectionConfig {
|
||||
/** 小节类型 */
|
||||
/** 回合类型 */
|
||||
type: SectionType;
|
||||
/** 怪物等级(驱动线性成长) */
|
||||
/** 怪物等级(= 关卡号,驱动线性成长) */
|
||||
monLv: number;
|
||||
/** 精英数量(精英关/Boss 关用) */
|
||||
eliteCount?: number;
|
||||
/** Boss UUID(Boss 关用,可选,缺省随机) */
|
||||
bossUuid?: number;
|
||||
/** 怪物类型池(普通关用,缺省随机) */
|
||||
/** 回合增强系数(第 n 回合 = 1 + SECTION_RAMP_STEP×(n-1),仅普通回合生效) */
|
||||
ramp: number;
|
||||
/** 怪物类型池(普通回合用,缺省随机) */
|
||||
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 baseAp 基础 AP
|
||||
* @param lv 怪物等级
|
||||
* @param isElite 是否精英
|
||||
* @param isBoss 是否 Boss
|
||||
* @returns 最终 HP/AP
|
||||
*/
|
||||
@@ -103,159 +80,70 @@ export function calcMonsterAttrs(
|
||||
baseHp: number,
|
||||
baseAp: number,
|
||||
lv: number,
|
||||
isElite: boolean = false,
|
||||
isBoss: boolean = false
|
||||
): { hp: number; ap: number } {
|
||||
const growCoef = 1 + MON_GROW_SLOPE * (lv - 1);
|
||||
let typeMul = 1;
|
||||
if (isBoss) {
|
||||
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));
|
||||
const hp = Math.max(1, Math.round(baseHp * MON_START_COEF * growCoef * (isBoss ? BOSS_HP_MUL : 1)));
|
||||
const ap = Math.max(1, Math.round(baseAp * MON_START_COEF * growCoef * (isBoss ? BOSS_AP_MUL : 1)));
|
||||
return { hp, ap };
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定关卡的怪物等级
|
||||
* @param stage 关卡号(1~10)
|
||||
* 获取指定关卡的怪物等级(无限关:等级 = 关卡号,无上限)
|
||||
* @param stage 关卡号(1~∞)
|
||||
* @returns 怪物等级
|
||||
*/
|
||||
export function getMonsterLv(stage: number): number {
|
||||
return Math.max(1, Math.min(10, stage));
|
||||
return Math.max(1, Math.floor(stage));
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否为精英节(每关第 ELITE_SECTION 节)
|
||||
* @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)
|
||||
* 判断是否为 Boss 回合(每关第 BOSS_SECTION 回合,即末回合)
|
||||
* @param section 回合号(1~SECTIONS_PER_STAGE)
|
||||
*/
|
||||
export function isBossSection(section: number): boolean {
|
||||
return section === BOSS_SECTION;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取小节类型(按节号区分:1~3 普通 / 4 精英 / 5 Boss)
|
||||
* @param section 小节号(1~SECTIONS_PER_STAGE)
|
||||
* 获取回合类型(按回合号区分:1~4 普通 / 5 Boss)
|
||||
* @param section 回合号(1~SECTIONS_PER_STAGE)
|
||||
*/
|
||||
export function getSectionType(section: number): SectionType {
|
||||
if (isBossSection(section)) return SectionType.Boss;
|
||||
if (isEliteSection(section)) return SectionType.Elite;
|
||||
return SectionType.Normal;
|
||||
return isBossSection(section) ? SectionType.Boss : 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 关卡号
|
||||
* @param section 小节号(1~SECTIONS_PER_STAGE)
|
||||
* @returns 小节配置,不存在时返回 null
|
||||
* 获取回合配置(无限关:按需动态生成,不再依赖章节静态表)
|
||||
* @param stage 关卡号(1~∞)
|
||||
* @param section 回合号(1~SECTIONS_PER_STAGE)
|
||||
* @returns 回合配置,回合号越界时返回 null
|
||||
*/
|
||||
export function getSectionConfig(chapter: number, stage: number, section: number): SectionConfig | null {
|
||||
const ch = ChapterSet[chapter];
|
||||
if (!ch) return null;
|
||||
const st = ch.stages.find(s => s.stage === stage);
|
||||
if (!st) return null;
|
||||
if (section < 1 || section > st.sections.length) return null;
|
||||
return st.sections[section - 1];
|
||||
export function getSectionConfig(stage: number, section: number): SectionConfig | null {
|
||||
if (section < 1 || section > SECTIONS_PER_STAGE) return null;
|
||||
|
||||
const type = getSectionType(section);
|
||||
const cfg: SectionConfig = {
|
||||
type,
|
||||
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 关卡号
|
||||
* @returns 大关配置,不存在时返回 null
|
||||
* @param section 回合号
|
||||
* @returns 格式化文本,如 "5-3"
|
||||
*/
|
||||
export function getStageConfig(chapter: number, stage: number): StageConfig | null {
|
||||
const ch = ChapterSet[chapter];
|
||||
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}`;
|
||||
export function getProgressText(stage: number, section: number): string {
|
||||
return `${stage}-${section}`;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { v3 } from "cc"
|
||||
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 { Attrs } from "./HeroAttrs"
|
||||
|
||||
@@ -424,8 +424,8 @@ export interface heroInfo {
|
||||
[SkillTriggerType.FStart]?: TriggerGrouped; // 战斗开始时释放的技能配置
|
||||
[SkillTriggerType.FEnd]?: TriggerGrouped; // 回合结束时释放的技能配置
|
||||
[SkillTriggerType.Field]?: LvFieldEntry[]; // 驻场光环(按 lv 升序,运行时取 ≤英雄等级 的最大档)
|
||||
[SkillTriggerType.Atking]?: TriggerGrouped; // 普通攻击后触发的技能配置,s_uuid: 技能id, t_num: 触发所需的普攻次数
|
||||
[SkillTriggerType.Atked]?: 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: 触发所需的受击次数, t_chance: 触发概率(%),pity_add: 未触发时下次概率增量
|
||||
dis?: number; // 攻击距离(像素)
|
||||
speed?: number; // 移动速度(像素/秒)
|
||||
dodge?: number; // 闪避率(百分点,缺省由初始化处兜底为全局默认值)
|
||||
@@ -504,6 +504,11 @@ export interface LvTriggerEntry {
|
||||
s_lv?: SkillLv; // 此档对应的技能等级(标注用,便于面板显示"技能Lv.x")
|
||||
name?: string; // 该 s_uuid 触发技能组的对外展示名(写在第 1 档,作为组名)
|
||||
t_num: number;
|
||||
/** 触发概率(百分点 0~100,缺省 100 必触发;仅 Atking/Atked 攻受击触发生效) */
|
||||
t_chance?: number;
|
||||
/** 保底叠加:判定未触发时,为该 s_uuid 累积下次概率增量(百分点)。
|
||||
* 缺省/0 = 不叠加;触发成功后清零,最终概率封顶 100 */
|
||||
pity_add?: number;
|
||||
overrides?: SkillOverrides;
|
||||
/** 此档描述模板:缺省回退该组第 1 档 desc;由 HeroSkillText 渲染合并后实时数值。
|
||||
* 显式配置后弹窗提升档(slv2+)直接展示该模板渲染结果,优先于自动 diff */
|
||||
@@ -516,6 +521,20 @@ export interface 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 底座(类型/图标/元数据),
|
||||
* value 为该词条实际生效数值(由配置处按档位指定,不再随 uuid 分档)。
|
||||
@@ -558,11 +577,12 @@ export interface LvBonusAttrsEntry {
|
||||
*=============英雄配置列表================
|
||||
* 几何王国复刻版 — 依据 英雄设计指引.md(A/B 级复刻英雄)配置
|
||||
*
|
||||
* 规则:lv1 激活 skills[0]/skills[1],lv6 解锁 atking/atked/fstart/dead/field 触发技能(触发类统一 lv6 激活,无品质门槛),
|
||||
* 大招(skills[1])lv9/lv16 走 lv_entries 分档成长,lv12 按职业对单项基础属性 +50%(基数取 lv11 有效值),
|
||||
* revive[0] 与 skills[1] 互斥二选一(配置 revive 时按 lv1/lv9/lv16 走 lv_entries 3 级成长),
|
||||
* 品质(rarity)仅影响 lv1 初始基础属性(相邻差 5%,仅 lv1 初始 AP/HP/DEF),不影响 uuid 段位/光环/技能解锁/属性补偿
|
||||
* 编号:本批复刻英雄集中于 5001~5009,rarity 按配置(不遵循段位规则)
|
||||
* 规则:lv1 激活 skills[0]/skills[1],lv4 解锁 atking/atked/fstart/dead/field 触发技能(触发类统一 lv4 激活,无品质门槛),
|
||||
* 大招(skills[1])lv8/lv16 走 lv_entries 分档成长,lv12 按职业对单项基础属性 +50%(基数取"基础×品质+成长"快照),
|
||||
* revive[0] 与 skills[1] 互斥二选一(配置 revive 时按 lv1/lv8/lv16 走 lv_entries 3 级成长),
|
||||
* 品质(rarity)当前全部英雄统一为 1,不再区分品质;getHeroQualityCoef 保留但恒为 1.00,
|
||||
* 若未来重启品质体系,仅影响 lv1 初始基础属性(相邻差 5%),不影响 uuid 段位/光环/技能解锁/属性补偿
|
||||
* 编号:本批复刻英雄集中于 5001~5018,rarity 统一 1
|
||||
*/
|
||||
|
||||
// @hero-setup:region-begin
|
||||
@@ -585,40 +605,40 @@ export const HeroInfo: Record<number, heroInfo> = {
|
||||
},
|
||||
},
|
||||
atked: {
|
||||
6301: [
|
||||
{ lv: 4, s_lv: SkillLv.Lv1, name: "全体圣盾", t_num: 3, overrides: {"TGroup":null,"ap":10,"icon":"Stat_UnitSummonIncrease_01"}, desc: "全队获得本英雄生命最大值{ap}%的护盾" },
|
||||
6412: [
|
||||
{ lv: 4, s_lv: SkillLv.Lv1, t_num: 3, t_chance: 50, pity_add: 20, overrides: {"ap":1} },
|
||||
],
|
||||
},
|
||||
bonus: [
|
||||
{ lv: 12, attrs: {"def":50}, name: "钢铁壁垒", icon: "46-Iron-Clad", },
|
||||
],
|
||||
info: "自身强护盾+群体小护盾,强生存",
|
||||
info: "自身强护盾+防御强化",
|
||||
},
|
||||
// 5002 易伤剑仙 — CSV导入:击退压场+易伤放大;复刻酒仙
|
||||
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: {
|
||||
6004: { uuid: 6004, name: "强化普攻", lv: 1, cd: AtkSpeedSet[AtkSpeedLv.Slow].cd, ccd: 0, overrides: {"ap":100}, desc: "对{target}造成攻击力{ap}%伤害",
|
||||
lv_entries: [
|
||||
{ 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: 8, s_lv: SkillLv.Lv2, overrides: {"buff_value":20} },
|
||||
{ lv: 16, s_lv: SkillLv.Lv3, overrides: {"ap":180,"bck":60,"buff_value":40}, desc: "斩出气刃,对{target}造成攻击力{ap}%伤害,击退{bck},并使目标易伤(持续{dur}秒)" },
|
||||
{ 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":250,"timed_debuff_id":7002,"debuff_value":150,"debuff_chance":100,"debuff_duration":7} },
|
||||
],
|
||||
},
|
||||
},
|
||||
atking: {
|
||||
6004: [
|
||||
{ lv: 4, s_lv: SkillLv.Lv1, name: "风暴打击", t_num: 3, overrides: {"ap":300,"icon":"Stat_AllUnitAttack"}, desc: "立刻打击{target},造成攻击力{ap}%伤害" },
|
||||
6001: [
|
||||
{ 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: [
|
||||
{ lv: 12, attrs: {"hp":50}, name: "不屈战意", icon: "29-Endure", },
|
||||
],
|
||||
info: "易伤+风怒,近战 dps",
|
||||
info: "易伤,近战 dps",
|
||||
},
|
||||
// 5003 眩晕暴击哥 — CSV导入:高爆发+击晕收割;复刻齐天大圣
|
||||
5003: {
|
||||
@@ -629,16 +649,18 @@ export const HeroInfo: Record<number, heroInfo> = {
|
||||
{ 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: 8, s_lv: SkillLv.Lv2, overrides: {"ap":450,"stun":100} },
|
||||
{ lv: 16, s_lv: SkillLv.Lv3, overrides: {"ap":450,"stun":100} },
|
||||
{ lv: 8, s_lv: SkillLv.Lv2, overrides: {"ap":300,"stun":100} },
|
||||
{ lv: 16, s_lv: SkillLv.Lv3, overrides: {"ap":350,"stun":100} },
|
||||
],
|
||||
},
|
||||
},
|
||||
field: [
|
||||
{ lv: 4, uuids: [{ uuid: 7005, value: 0.25, name: "大圣神威" }] },
|
||||
],
|
||||
atking: {
|
||||
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: [
|
||||
{ lv: 12, attrs: {"hp":50}, name: "不屈战意", icon: "29-Endure", },
|
||||
],
|
||||
@@ -653,16 +675,18 @@ export const HeroInfo: Record<number, heroInfo> = {
|
||||
{ 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: 8, s_lv: SkillLv.Lv2, overrides: {"ap":250} },
|
||||
{ lv: 16, s_lv: SkillLv.Lv3, overrides: {"ap":350} },
|
||||
{ lv: 8, s_lv: SkillLv.Lv2, overrides: {"ap":200,"crt":60} },
|
||||
{ lv: 16, s_lv: SkillLv.Lv3, overrides: {"ap":250,"crt":70} },
|
||||
],
|
||||
},
|
||||
},
|
||||
field: [
|
||||
{ lv: 4, uuids: [{ uuid: 7004, value: 0.12, name: "剑刃风暴" }, { uuid: 7005, value: 0.2, name: "斩魂利刃" }] },
|
||||
],
|
||||
atking: {
|
||||
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: [
|
||||
{ lv: 12, attrs: {"ap":50}, name: "致命本能", icon: "36-Guardian-Stance", },
|
||||
],
|
||||
@@ -674,19 +698,21 @@ export const HeroInfo: Record<number, heroInfo> = {
|
||||
skills: {
|
||||
6002: { uuid: 6002, name: "强化普攻", lv: 1, cd: AtkSpeedSet[AtkSpeedLv.Fast].cd, ccd: 0, overrides: {"ap":100}, desc: "挥刀对{target}造成攻击力{ap}%伤害",
|
||||
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: 8, s_lv: SkillLv.Lv2, overrides: {"ap":250,"timed_debuff_id":7007,"debuff_value":40}, 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: 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":300,"timed_debuff_id":7007,"debuff_value":-50,"debuff_chance":100,"debuff_duration":9}, desc: "高速斩击{target},造成攻击力{ap}%,附带 50% 概率麻痹,并使目标出血(每0.5秒受到{debuff_value}点伤害,持续{dur}秒)" },
|
||||
],
|
||||
},
|
||||
},
|
||||
field: [
|
||||
{ lv: 4, uuids: [{ uuid: 7002, value: 10, name: "攻击光环" }] },
|
||||
],
|
||||
atking: {
|
||||
6401: [
|
||||
{ lv: 4, s_lv: SkillLv.Lv1, t_num: 3, t_chance: 50, pity_add: 20, overrides: {"buff_value":2} },
|
||||
],
|
||||
},
|
||||
bonus: [
|
||||
{ lv: 12, attrs: {"ap":50}, name: "致命本能", icon: "36-Guardian-Stance", },
|
||||
],
|
||||
@@ -701,16 +727,18 @@ export const HeroInfo: Record<number, heroInfo> = {
|
||||
{ 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: 8, s_lv: SkillLv.Lv2, overrides: {"ap":200,"frz":50} },
|
||||
{ lv: 16, s_lv: SkillLv.Lv3, overrides: {"ap":250,"frz":70} },
|
||||
{ lv: 8, s_lv: SkillLv.Lv2, overrides: {"ap":200,"frz":30} },
|
||||
{ lv: 16, s_lv: SkillLv.Lv3, overrides: {"ap":250,"frz":30} },
|
||||
],
|
||||
},
|
||||
},
|
||||
field: [
|
||||
{ lv: 4, uuids: [{ uuid: 7006, value: 0.15 }] },
|
||||
],
|
||||
atking: {
|
||||
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: [
|
||||
{ lv: 12, attrs: {"ap":50}, name: "鹰眼锁定", icon: "27-Hawkeye", },
|
||||
],
|
||||
@@ -725,15 +753,15 @@ export const HeroInfo: Record<number, heroInfo> = {
|
||||
{ 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: 8, s_lv: SkillLv.Lv2, overrides: {"ap":350,"bck":100} },
|
||||
{ lv: 16, s_lv: SkillLv.Lv3, overrides: {"ap":450,"bck":100,"summon_count":2} },
|
||||
{ lv: 8, s_lv: SkillLv.Lv2, overrides: {"ap":350,"crt":0} },
|
||||
{ lv: 16, s_lv: SkillLv.Lv3, overrides: {"ap":450,"crt":0,"summon_count":4} },
|
||||
],
|
||||
},
|
||||
},
|
||||
field: [
|
||||
{ lv: 4, uuids: [{ uuid: 7002, value: 0.15, name: "深渊威压" }] },
|
||||
{ lv: 4, uuids: [{ uuid: 7002, value: 0.15, name: "攻击光环" }] },
|
||||
],
|
||||
bonus: [
|
||||
{ lv: 12, attrs: {"ap":50}, name: "奥术共鸣", icon: "100-Enchant-Magic", },
|
||||
@@ -749,18 +777,16 @@ export const HeroInfo: Record<number, heroInfo> = {
|
||||
{ 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: 8, s_lv: SkillLv.Lv2, overrides: {"ap":40} },
|
||||
{ lv: 16, s_lv: SkillLv.Lv3, overrides: {"ap":50} },
|
||||
{ lv: 8, s_lv: SkillLv.Lv2, overrides: {"ap":40,"TGroup": TGroup.Ally} },
|
||||
{ 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: {
|
||||
6301: [
|
||||
{ lv: 4, s_lv: SkillLv.Lv1, name: "圣愈之盾", t_num: 3, overrides: {"ap":30}, desc: "{target}获得生命最大值{ap}%的护盾" },
|
||||
],
|
||||
},
|
||||
field: [
|
||||
{ lv: 4, uuids: [{ uuid: 7001, value: 20 }], desc: "每回合结束 休整恢复的血量值提升 20%" },
|
||||
],
|
||||
bonus: [
|
||||
{ lv: 12, attrs: {"hp":50}, name: "守护之心", icon: "29-Endure", },
|
||||
],
|
||||
@@ -768,23 +794,23 @@ export const HeroInfo: Record<number, heroInfo> = {
|
||||
},
|
||||
// 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: {
|
||||
6004: { uuid: 6004, name: "普攻强化", lv: 1, cd: AtkSpeedSet[AtkSpeedLv.Slow].cd, ccd: 0,
|
||||
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: 8, s_lv: SkillLv.Lv2, overrides: {"ap":300,"bck":50} },
|
||||
{ lv: 16, s_lv: SkillLv.Lv3, overrides: {"ap":350,"bck":70} },
|
||||
{ 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,"proc_skill":{"s_uuid":6302,"chance":100,"overrides":{"TGroup": TGroup.Self,"buff_value":20}}} },
|
||||
],
|
||||
},
|
||||
},
|
||||
atked: {
|
||||
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: [
|
||||
@@ -798,45 +824,45 @@ export const HeroInfo: Record<number, heroInfo> = {
|
||||
skills: {
|
||||
6006: { uuid: 6006, name: "强化普攻", lv: 1, cd: AtkSpeedSet[AtkSpeedLv.Fast].cd, ccd: 0,
|
||||
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: 8, s_lv: SkillLv.Lv2, overrides: {"ap":80,"summon_count":5,"bck_chance":100} },
|
||||
{ lv: 16, s_lv: SkillLv.Lv3, overrides: {"bck_chance":100,"ap":100,"summon_count":6} },
|
||||
{ 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: {"ap":100,"timed_debuff_id":7006,"debuff_value":-30,"debuff_chance":100,"debuff_duration":5} },
|
||||
],
|
||||
},
|
||||
},
|
||||
atking: {
|
||||
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: [
|
||||
{ lv: 12, attrs: {"ap":50}, name: "鹰眼锁定", icon: "27-Hawkeye", },
|
||||
],
|
||||
info: "万箭齐射+高频击退,远程压制",
|
||||
info: "暴击",
|
||||
},
|
||||
// 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: {
|
||||
6004: { uuid: 6004, name: "普攻强化", lv: 1, cd: AtkSpeedSet[AtkSpeedLv.Normal].cd, ccd: 0,
|
||||
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: 8, s_lv: SkillLv.Lv2, overrides: {"buff_value":40,"buff_duration":10}, desc: "全体友方最大生命值提升{buff_value}%,持续{dur}秒" },
|
||||
{ lv: 16, s_lv: SkillLv.Lv3, overrides: {"buff_value":50,"buff_duration":15}, 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: {"ap":300,"timed_buff_id":7029,"buff_value":50,"buff_chance":100,"buff_duration":5,"buff_target": BuffTarget.Self} },
|
||||
],
|
||||
},
|
||||
},
|
||||
atked: {
|
||||
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: [
|
||||
@@ -853,10 +879,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}}} },
|
||||
],
|
||||
},
|
||||
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: 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: 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: 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":30,"overrides":{"buff_value":30,"TGroup": TGroup.Ally}}}, desc: "召唤 {summon_count} 道飓风攻击前方敌人,每道飓风造成 {ap}%伤害,每道飓风释放时有<color=#3CE66E>20</color>% 概率增加全体队友<color=#3CE66E>20</color>% 攻速" },
|
||||
],
|
||||
},
|
||||
},
|
||||
@@ -868,31 +894,31 @@ export const HeroInfo: Record<number, heroInfo> = {
|
||||
],
|
||||
info: "普攻 大招加速 buff+加速光环,加速大师",
|
||||
},
|
||||
// 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: {
|
||||
6004: { uuid: 6004, lv: 1, cd: AtkSpeedSet[AtkSpeedLv.Normal].cd, ccd: 0,
|
||||
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: 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} },
|
||||
],
|
||||
},
|
||||
},
|
||||
fstart: {
|
||||
6301: [
|
||||
{ lv: 4, s_lv: SkillLv.Lv1, t_num: 1, overrides: {"ap":20} },
|
||||
atking: {
|
||||
6414: [
|
||||
{ lv: 4, s_lv: SkillLv.Lv1, t_num: 3, t_chance: 30, pity_add: 15, overrides: {"buff_value":10,"TGroup": TGroup.Ally} },
|
||||
],
|
||||
},
|
||||
bonus: [
|
||||
{ lv: 12, attrs: {"hp":50}, name: "守护之心", icon: "29-Endure", },
|
||||
],
|
||||
info: "大招全体反伤 普攻暴击 暴击反伤辅助",
|
||||
info: "大招全体生命最大值+概率全体+反伤护盾",
|
||||
},
|
||||
// 5014 闪避哥
|
||||
5014: {
|
||||
@@ -900,7 +926,7 @@ export const HeroInfo: Record<number, heroInfo> = {
|
||||
skills: {
|
||||
6004: { uuid: 6004, name: "普攻强化", lv: 1, cd: AtkSpeedSet[AtkSpeedLv.Normal].cd, ccd: 0,
|
||||
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},
|
||||
@@ -916,7 +942,7 @@ export const HeroInfo: Record<number, heroInfo> = {
|
||||
bonus: [
|
||||
{ lv: 12, attrs: {"hp":50}, name: "不屈战意", icon: "29-Endure", },
|
||||
],
|
||||
info: "",
|
||||
info: "强闪避",
|
||||
},
|
||||
// 5015 毒箭猎手 — 毒伤持续流:普攻淬毒叠层+毒雨铺DoT+攻击光环喂养毒伤
|
||||
5015: {
|
||||
@@ -924,24 +950,21 @@ export const HeroInfo: Record<number, heroInfo> = {
|
||||
skills: {
|
||||
6007: { uuid: 6007, 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: {"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: 8, s_lv: SkillLv.Lv2, overrides: {"ap":200,"buff_value":40,"buff_chance":60} },
|
||||
{ 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: 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,"timed_debuff_id":7005,"debuff_value":-100,"debuff_chance":100,"debuff_duration":7} },
|
||||
],
|
||||
},
|
||||
},
|
||||
atking: {
|
||||
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: [
|
||||
{ lv: 12, attrs: {"ap":50}, name: "剧毒淬炼", icon: "27-Hawkeye", },
|
||||
],
|
||||
@@ -953,23 +976,18 @@ export const HeroInfo: Record<number, heroInfo> = {
|
||||
skills: {
|
||||
6008: { uuid: 6008, name: "连珠箭", lv: 1, cd: AtkSpeedSet[AtkSpeedLv.VeryFast].cd, ccd: 0, overrides: {"ap":100}, desc: "极速连射,对{target}造成攻击力{ap}%伤害",
|
||||
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}%概率暴击",
|
||||
lv_entries: [
|
||||
{ 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: [
|
||||
{ lv: 4, uuids: [{ uuid: 7004, value: 0.15, name: "猎手集结" }] },
|
||||
{ lv: 4, uuids: [{ uuid: 7004, value: 0.1, name: "猎手集结" }] },
|
||||
],
|
||||
bonus: [
|
||||
{ lv: 12, attrs: {"ap":50}, name: "猎杀直觉", icon: "27-Hawkeye", },
|
||||
@@ -985,18 +1003,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}秒)" },
|
||||
],
|
||||
},
|
||||
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: 8, s_lv: SkillLv.Lv2, overrides: {"ap":200} },
|
||||
{ lv: 16, s_lv: SkillLv.Lv3, overrides: {"ap":250,"buff_value":-70}, desc: "释放碎甲能量波,对{target}造成攻击力{ap}%伤害,并使目标破甲加深(防御大幅降低,持续{dur}秒)" },
|
||||
{ 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,"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: [
|
||||
{ lv: 4, uuids: [{ uuid: 7009, value: 0.1, name: "锐矛之赐" }] },
|
||||
],
|
||||
@@ -1009,60 +1022,26 @@ export const HeroInfo: Record<number, heroInfo> = {
|
||||
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,
|
||||
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: 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: 8, s_lv: SkillLv.Lv2, overrides: {"ap":250,"para":60}, desc: "释放雷霆裂空波,对{target}造成攻击力{ap}%伤害,{para}%概率麻痹敌人" },
|
||||
{ lv: 16, s_lv: SkillLv.Lv3, overrides: {"ap":300,"para":80,"hit_count":3}, 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":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: [
|
||||
{ lv: 4, uuids: [{ uuid: 7003, value: 10, name: "雷云领域" }] },
|
||||
{ lv: 4, uuids: [{ uuid: 7024, value: 10, name: "雷电精准" }] },
|
||||
],
|
||||
bonus: [
|
||||
{ lv: 12, attrs: {"ap":50}, name: "奥术共鸣", icon: "100-Enchant-Magic", },
|
||||
],
|
||||
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
|
||||
|
||||
/*
|
||||
@@ -1142,9 +1121,9 @@ export const HeroInfo: Record<number, heroInfo> = {
|
||||
};
|
||||
|
||||
export const HeroList: number[] = [
|
||||
// 编辑器导出自动同步(共 19 个)
|
||||
// 编辑器导出自动同步(共 18 个)
|
||||
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
|
||||
|
||||
@@ -1164,48 +1143,48 @@ export interface HeroComboInfo {
|
||||
}
|
||||
|
||||
/**
|
||||
* 推荐阵容表(几何王国复刻版 5001~5009)。
|
||||
* 推荐阵容表(基于现役 5001~5018 英雄实际技能组)。
|
||||
* 设计原则:
|
||||
* 1. 铁三角结构:1 前排(坦克)+ 1 增益(光环/先手)+ 1 主C
|
||||
* 2. 乘区分散:攻击/暴击/暴伤各占独立乘区,组合优先覆盖不同乘区避免稀释
|
||||
* 3. 发动机冗余:前排挨打/死亡触发增益,叠甲骑士(5005)死亡缠绕负责献祭点火
|
||||
* 1. 铁三角结构:heroes[0] 固定为近战前排(坦克/战士),其余按站位从近到远
|
||||
* 2. 乘区分散:攻击/攻速/暴击/穿透各占独立乘区,组合优先覆盖不同乘区避免稀释
|
||||
* 3. 主题唯一:每套阵容围绕一个流派关键词(暴击/控制/续航/破甲/光环/消耗)组队
|
||||
*/
|
||||
export const HeroComboSet: Record<number, HeroComboInfo> = {
|
||||
// 8001 暴击爆发流 — 暴击率与暴伤双乘区互不稀释,成型最强
|
||||
// 8001 暴击爆发流 — 连珠神射暴击光环喂养双物理C,成型最强
|
||||
8001: {
|
||||
uuid: 8001, name: "暴击爆发流",
|
||||
heroes: [5005, 5008, 5002],
|
||||
desc: "叠甲骑士前排抗伤叠甲,刀刀暴击的暴击光环与眩晕暴击哥的暴伤光环组成双乘区,双近战暴击爆发收割。",
|
||||
heroes: [5001, 5016, 5004],
|
||||
desc: "叠甲骑士前排抗伤+受击叠防,连珠神射暴击光环覆盖全队并以极速箭雨压场,刀刀暴击近战收割残局。",
|
||||
},
|
||||
// 8002 冰雷控制流 — 冰冻+击晕双控场,敌人出不了手
|
||||
// 8002 冰雷控制流 — 击晕+冰冻+麻痹三控链,敌人出不了手
|
||||
8002: {
|
||||
uuid: 8002, name: "冰雷控制流",
|
||||
heroes: [5007, 5004, 5001],
|
||||
desc: "微醺战神前排击退压场,冻住不谢冰冻链配合紫电魔女能量波击退击晕,击晕光环叠加,全场控制。",
|
||||
heroes: [5003, 5006, 5018],
|
||||
desc: "眩晕暴击哥前排开山斧必晕压阵,冻箭哥寒冰箭冰冻链,雷暴领主雷霆麻痹迟滞技能,三控交替敌人难以出手。",
|
||||
},
|
||||
// 8003 铁桶续航流 — 双防御前排+双治疗保血,最稳
|
||||
// 8003 铁桶续航流 — 双坦克承伤+治疗保血,最稳
|
||||
8003: {
|
||||
uuid: 8003, name: "铁桶续航流",
|
||||
heroes: [5005, 5009, 5006],
|
||||
desc: "叠甲骑士与铁壳斧弟双前排叠甲叠防,光明奶爸治疗+生命光环抬全队血线,专打持久消耗战。",
|
||||
heroes: [5009, 5011, 5008],
|
||||
desc: "甲虫领主受击自疗顶前排,控血大师受击全队永久生命成长+大招生命爆发,团疗奶爸全体治疗+战后回复光环,专打持久战。",
|
||||
},
|
||||
// 8004 先手爆发流 — 入场剑气先手+能量波跟进,短回合最强
|
||||
// 8004 破甲压制流 — 破甲+减攻双减益,克制高防高攻阵容
|
||||
8004: {
|
||||
uuid: 8004, name: "先手爆发流",
|
||||
heroes: [5003, 5001, 5008],
|
||||
desc: "格挡反杀入场500%剑气先手压血线,紫电魔女能量波击退跟进,眩晕暴击哥开山斧收割残局。",
|
||||
uuid: 8004, name: "破甲压制流",
|
||||
heroes: [5001, 5017, 5010],
|
||||
desc: "碎甲术士普攻/大招双通道破甲+穿透光环放大物理伤害,火箭哥五箭弹幕必挂减攻削弱敌方输出,叠甲骑士前排兜底。",
|
||||
},
|
||||
// 8005 破甲推进流 — 易伤放大全队伤害,克制高血Boss
|
||||
// 8005 光环覆盖流 — 闪避/攻击/攻速三光环全覆盖
|
||||
8005: {
|
||||
uuid: 8005, name: "破甲推进流",
|
||||
heroes: [5007, 5006, 5002],
|
||||
desc: "微醺战神气斩易伤放大全队伤害,光明奶爸治疗保前排,刀刀暴击吃满易伤与自身暴击完成推进。",
|
||||
uuid: 8005, name: "光环覆盖流",
|
||||
heroes: [5014, 5007, 5012],
|
||||
desc: "闪避哥前排+闪避光环提升全队生存,击退火女攻击光环、疾风法师攻速光环持续放大全队输出,三光环增益拉满。",
|
||||
},
|
||||
// 8006 光环覆盖流 — 攻击/暴击/暴伤/生命光环全覆盖
|
||||
// 8006 易伤消耗流 — 易伤放大出血DoT,磨血收割
|
||||
8006: {
|
||||
uuid: 8006, name: "光环覆盖流",
|
||||
heroes: [5002, 5006, 5001],
|
||||
desc: "刀刀暴击暴击+暴伤双光环、紫电魔女攻击光环、光明奶爸生命光环,四光环全覆盖持续放大全队输出。",
|
||||
uuid: 8006, name: "易伤消耗流",
|
||||
heroes: [5002, 5005, 5008],
|
||||
desc: "易伤剑仙气斩+普攻双通道挂易伤放大全队伤害,出血贼普攻+大招叠出血磨血,团疗奶爸治疗保前排打消耗战。",
|
||||
},
|
||||
};
|
||||
|
||||
@@ -1280,9 +1259,9 @@ export const HERO_POWER_WEIGHTS = {
|
||||
* 解析触发技能在目标等级下的有效条目列表。
|
||||
* 每个 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 [];
|
||||
const result: { s_uuid: number; t_num: number; overrides?: SkillOverrides }[] = [];
|
||||
const result: ResolvedTriggerEntry[] = [];
|
||||
for (const key in grouped) {
|
||||
const entries = grouped[key];
|
||||
if (!entries || entries.length === 0) continue;
|
||||
@@ -1290,7 +1269,7 @@ export function resolveTriggerByLv(grouped: TriggerGrouped | undefined, lv: numb
|
||||
for (const e of entries) {
|
||||
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;
|
||||
}
|
||||
@@ -1595,7 +1574,7 @@ export interface HeroPowerDetailed {
|
||||
|
||||
/** 计算普通触发类技能(atking/atked/fstart/dead)的详细价值 */
|
||||
function calcTriggerPowerDetailed(
|
||||
triggerConfigs: { s_uuid: number, t_num?: number, overrides?: SkillOverrides }[],
|
||||
triggerConfigs: ResolvedTriggerEntry[],
|
||||
hero: heroInfo,
|
||||
targetLv: number,
|
||||
type: SkillTriggerType,
|
||||
@@ -1636,7 +1615,9 @@ function calcTriggerPowerDetailed(
|
||||
}
|
||||
|
||||
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;
|
||||
items.push({ type, s_uuid: trig.s_uuid, name: skill.name, t_num: tNum, value });
|
||||
}
|
||||
|
||||
@@ -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,叠甲骑士,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}%伤害,无,无,无,无
|
||||
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
|
||||
5004,刀刀暴击,CSV导入:暴击/暴伤双光环乘区;复刻剑圣,1,assassin,中程,assassin+30,assassin,assassin,6002 强化普攻(ap100;快速0.90s),crt10,6100 光闪(ap150),ap250,ap350,无,无,无,无,7004 剑刃风暴0.12+7005 斩魂利刃0.2
|
||||
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
|
||||
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
|
||||
5008,团疗奶爸,CSV导入:全体治疗续航+自身护盾,1,support,远程,support+20,support+10,support,6011 强化普攻(ap100;中速1.05s),bck10,6302 治疗(ap30),ap40,ap50,6301 圣愈之盾(t_num3;ap30):{target}获得生命最大值{ap}%的护盾,无,无,无,无
|
||||
字段,5001,5002,5003,5004,5005,5006,5007,5008,5009,5010,5011,5012,5013,5014,5015,5016,5017,5018,5019
|
||||
英雄名称,叠甲骑士,易伤剑仙,眩晕暴击哥,刀刀暴击,出血贼,冻箭哥,击退火女,团疗奶爸,甲虫领主,火箭哥,控血大师,疾风法师,反伤哥,闪避哥,毒箭猎手,连珠神射,碎甲术士,雷暴领主,圣盾贤者
|
||||
简化说明,CSV导入:自身护盾+全体护盾,CSV导入:击退压场+易伤放大;复刻酒仙,CSV导入:高爆发+击晕收割;复刻齐天大圣,CSV导入:暴击/暴伤双光环乘区;复刻剑圣,CSV导入:入场先手+受击格挡;复刻剑豪,CSV导入:多重单体箭,带冰冻,CSV导入:群体击退/麻痹压场;复刻深渊女王,CSV导入:全体治疗续航+自身护盾,,,,,,,毒伤持续流:普攻淬毒叠层+毒雨铺DoT+攻击光环喂养毒伤,暴击连射爆发流:VeryFast极速普攻+概率追射必暴箭+开局团队暴击爆发,破甲减防法师:fstart先手/普攻概率/大招必定三通道施加破甲7008+穿透光环,团队物理增伤位,雷暴AOE爆发+麻痹控场:先手雷击+高倍率能量波,护盾反伤生存法:全队圣盾+荆棘反伤+受击荆棘
|
||||
rarity,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1
|
||||
类型,tank,warrior,warrior,assassin,assassin,archer,mage,support,tank,archer,tank,mage,support,warrior,archer,archer,mage,mage,mage
|
||||
形态,近战,近战,近战,中程,中程,远程,远程,远程,近战,中程,近战,远程,远程,近战,远程,中程,远程,远程,远程
|
||||
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
|
||||
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
|
||||
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,5 +1,5 @@
|
||||
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 { FacSet, FightSet } from "../common/config/GameSet";
|
||||
import { FieldSkillSet, FieldSkillType, SkillOverrides } from "../common/config/SkillSet";
|
||||
@@ -64,20 +64,26 @@ export class HeroAttrsComp extends ecs.Comp {
|
||||
|
||||
// ==================== 运行时解析缓存(按当前等级 resolve 后的有效列表) ====================
|
||||
/** 当前等级下生效的攻击触发条目(供 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[];
|
||||
|
||||
// ==================== 触发概率保底缓存(key: s_uuid, value: 已累积的概率增量百分点) ====================
|
||||
/** 攻击触发未命中时累积的下次概率增量(pity_add 驱动,触发成功后清零) */
|
||||
pity_atking: Record<number, number> = {};
|
||||
/** 受击触发未命中时累积的下次概率增量(pity_add 驱动,触发成功后清零) */
|
||||
pity_atked: Record<number, number> = {};
|
||||
|
||||
// ==================== 特殊属性 ====================
|
||||
critical: number = 0; // 暴击率
|
||||
critical_res: number = 0; // 暴击抗性
|
||||
@@ -759,6 +765,9 @@ export class HeroAttrsComp extends ecs.Comp {
|
||||
this.runtime_fstart = undefined;
|
||||
this.runtime_fend = undefined;
|
||||
this.runtime_field = undefined;
|
||||
// 清空触发概率保底叠加缓存
|
||||
this.pity_atking = {};
|
||||
this.pity_atked = {};
|
||||
this.critical = 0;
|
||||
this.critical_res = 0;
|
||||
this.dodge = 0;
|
||||
|
||||
@@ -236,6 +236,21 @@ export class Monster extends ecs.Entity {
|
||||
if (testSkills.fstart !== undefined) model.fstart = testSkills.fstart;
|
||||
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)
|
||||
model.runtime_call = resolveTriggerByLv(model.call, mon_lv);
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
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 { 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 { SkillView } from "../skill/SkillView";
|
||||
import { smc } from "../common/SingletonModuleComp";
|
||||
@@ -20,12 +20,14 @@ import { BuffList } from "../common/config/BuffSet";
|
||||
import { CameraFX } from "../common/CameraFX";
|
||||
import { ScreenShake } from "../common/ScreenShake";
|
||||
|
||||
/** 召唤参数:数量 / XY 步进偏移 / 生成间隔,均由技能 prefab 上的 SkillView 配置 */
|
||||
/** 召唤参数:数量 / XY 步进偏移 / 生成间隔 / 目标选择模式,均由技能 prefab 上的 SkillView 配置 */
|
||||
export interface SummonParams {
|
||||
count: number;
|
||||
x_offset: number;
|
||||
y_offset: number;
|
||||
interval: number;
|
||||
/** 多次施放的目标选择模式(同一敌人/随机敌人/避免相同敌人) */
|
||||
target_mode: SummonTMode;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -137,12 +139,12 @@ export class SCastSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate
|
||||
mockAttrs.type = HType.Long; // 假定为远程,拥有较长索敌范围
|
||||
mockAttrs.dis = 2000; // 给予全屏以上的索敌范围
|
||||
|
||||
// 伪造一个 view 供找敌逻辑使用,位置为 spawnPos(random/unique 模式实时索敌也复用)
|
||||
const mockView = {
|
||||
node: { position: spawnPos }
|
||||
} as any;
|
||||
let targetPos: Vec3 | null = null;
|
||||
if (!isFriendly) {
|
||||
// 伪造一个 view 供找敌逻辑使用,位置为 spawnPos
|
||||
const mockView = {
|
||||
node: { position: spawnPos }
|
||||
} as any;
|
||||
// 获取全屏索敌范围
|
||||
const maxRange = this.resolveMaxCastRange(mockAttrs, mockAttrs.type as HType);
|
||||
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}`);
|
||||
// unique 模式去重记录:本次施法序列内已锁定过的敌人 eid
|
||||
const usedTargetEids = new Set<number>();
|
||||
for (let i = 0; i < castTimes; i++) {
|
||||
// 多发/召唤按间隔错峰执行:i=0 立即,其余延迟 i*castInterval(召唤间隔由 prefab 配置)
|
||||
const exec = () => {
|
||||
@@ -167,7 +171,7 @@ export class SCastSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate
|
||||
if (friendlyTargets.length === 0) return;
|
||||
this.applyFriendlySkillEffects(s_uuid, rarity, config, null as any, mockAttrs, friendlyTargets, spawnPos);
|
||||
} 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);
|
||||
}
|
||||
};
|
||||
@@ -214,14 +218,14 @@ export class SCastSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate
|
||||
/**
|
||||
* 解析单次施法的召唤参数。
|
||||
* 数量优先级:合并后配置上的 summon_count(heroSet overrides 可覆写) > prefab 上 SkillView.summon_count;
|
||||
* XY 偏移与间隔仅由 prefab 配置。
|
||||
* XY 偏移、间隔与目标选择模式仅由 prefab 配置。
|
||||
*/
|
||||
private resolveSummonParams(config: SkillConfig): SummonParams {
|
||||
const fromPrefab = this.readSummonParamsFromPrefab(config.sp_name);
|
||||
const count = typeof config.summon_count === "number"
|
||||
? Math.max(1, Math.floor(config.summon_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);
|
||||
if (cached) return cached;
|
||||
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;
|
||||
if (prefab) {
|
||||
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,
|
||||
y_offset: view.summon_y_offset,
|
||||
interval: view.summon_interval,
|
||||
target_mode: view.summon_target_mode ?? SummonTMode.same,
|
||||
};
|
||||
}
|
||||
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)
|
||||
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++) {
|
||||
if (!heroView.node || !heroView.node.isValid) return;
|
||||
// 多发/召唤按间隔错峰执行: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);
|
||||
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);
|
||||
}, i * castInterval);
|
||||
}
|
||||
@@ -469,6 +476,8 @@ export class SCastSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate
|
||||
// 注意:这里仍然是基于时间的延迟,受帧率波动影响。
|
||||
// 若需精确同步,建议在动画中添加帧事件并在 HeroViewComp 中监听。
|
||||
const delay = config.ready > 0 ? config.ready : FightSet.SKILL_CAST_DELAY;
|
||||
// unique 模式去重记录:本次施法序列内已锁定过的敌人 eid
|
||||
const usedTargetEids = new Set<number>();
|
||||
|
||||
heroView.scheduleOnce(() => {
|
||||
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);
|
||||
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);
|
||||
}, 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);
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析第 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... 档 × 步进值);多发回落纵向扇形档位 */
|
||||
private resolveCastOffset(castIndex: number, summon?: SummonParams): { x: number; y: number } {
|
||||
if (summon && summon.count > 1) {
|
||||
@@ -883,7 +957,7 @@ export class SCastSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate
|
||||
return nearestEnemy.node?.position.clone() ?? null;
|
||||
}
|
||||
if (config.DTType !== DTType.range) {
|
||||
return this.buildEnemyCastTargetPos(heroView, nearestEnemy, maxRange);
|
||||
return this.buildEnemyCastTargetPos(nearestEnemy);
|
||||
}
|
||||
const frontEnemy = this.findFrontEnemyInRange(heroAttrs, heroView, maxRange, nearestEnemy);
|
||||
if (!frontEnemy?.node) return null;
|
||||
@@ -897,19 +971,10 @@ export class SCastSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate
|
||||
return heroAttrs.dis;
|
||||
}
|
||||
|
||||
/** 生成沿目标方向的施法目标坐标 */
|
||||
private buildEnemyCastTargetPos(caster: HeroViewComp, target: HeroViewComp, castRange: number): Vec3 {
|
||||
// 直接返回目标的真实坐标,保留其 Y 轴信息,确保能向目标真实所在位置发射
|
||||
// 考虑到目前角色的 y 坐标都是脚底(碰撞体底部),为了命中身体中心,给目标 y 加上高度的一半
|
||||
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,给一个默认高度偏移
|
||||
}
|
||||
}
|
||||
/** 生成对敌施法目标坐标:直接返回目标的真实坐标;y 为脚底(碰撞体底部),补半身高以命中身体中心 */
|
||||
private buildEnemyCastTargetPos(target: HeroViewComp): Vec3 {
|
||||
const transform = target.node?.getComponent(UITransform);
|
||||
const halfHeight = transform ? transform.height / 2 : 40; // 无 UITransform 时给默认高度偏移
|
||||
|
||||
const pos = target.node.position.clone();
|
||||
pos.y += halfHeight;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { oops } from "db://oops-framework/core/Oops";
|
||||
import { GameEvent } from "../common/config/GameEvent";
|
||||
import { SkillTriggerType } from "../common/config/heroSet";
|
||||
import { ResolvedTriggerEntry, SkillTriggerType } from "../common/config/heroSet";
|
||||
import { HeroAttrsComp } from "./HeroAttrsComp";
|
||||
import { HeroViewComp } from "./HeroViewComp";
|
||||
import { FacSet } from "../common/config/GameSet";
|
||||
@@ -118,7 +118,8 @@ export class SkillTriggerHelper {
|
||||
model.runtime_atking.forEach(atkConfig => {
|
||||
// atk_count 代表已进行的普攻次数。当其余数刚好整除配置阈值时触发。
|
||||
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++) {
|
||||
this.dispatchSingle(atkConfig.s_uuid, model, view, SkillTriggerType.Atking, atkConfig.overrides);
|
||||
}
|
||||
@@ -149,7 +150,8 @@ export class SkillTriggerHelper {
|
||||
model.runtime_atked.forEach(atkConfig => {
|
||||
// atked_count 代表已承受的受击次数。当其余数刚好整除配置阈值时触发。
|
||||
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++) {
|
||||
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 等无需额外判定的简单列表触发)
|
||||
*/
|
||||
|
||||
@@ -247,11 +247,13 @@ export class HeroInfoComp extends CCComp {
|
||||
* @param delta 1 下一个,-1 上一个
|
||||
*/
|
||||
private switchHero(delta: 1 | -1) {
|
||||
// 与图鉴页面排序同源:仅按品质降序 → uuid 升序
|
||||
// 与图鉴页面排序同源:按职业(HRole)升序 → uuid 升序
|
||||
const sorted = [...HeroList].sort((a, b) => {
|
||||
const ra = HeroInfo[a]?.rarity ?? 1;
|
||||
const rb = HeroInfo[b]?.rarity ?? 1;
|
||||
if (ra !== rb) return rb - ra;
|
||||
const heroA = HeroInfo[a];
|
||||
const heroB = HeroInfo[b];
|
||||
const roleA = heroA?.role ?? 0;
|
||||
const roleB = heroB?.role ?? 0;
|
||||
if (roleA !== roleB) return roleA - roleB;
|
||||
return a - b;
|
||||
});
|
||||
if (sorted.length === 0) return;
|
||||
|
||||
@@ -113,11 +113,13 @@ export class HerosListComp extends CCComp {
|
||||
|
||||
this.cards_node.removeAllChildren()
|
||||
|
||||
// 图鉴排序:仅按品质降序 → uuid 升序(与养成进度解耦,保持展示稳定)
|
||||
// 图鉴排序:按职业(HRole)升序 → uuid 升序(与养成进度解耦,保持展示稳定)
|
||||
const sorted = [...HeroList].sort((a, b) => {
|
||||
const ra = HeroInfo[a]?.rarity ?? 1;
|
||||
const rb = HeroInfo[b]?.rarity ?? 1;
|
||||
if (ra !== rb) return rb - ra;
|
||||
const heroA = HeroInfo[a];
|
||||
const heroB = HeroInfo[b];
|
||||
const roleA = heroA?.role ?? 0;
|
||||
const roleB = heroB?.role ?? 0;
|
||||
if (roleA !== roleB) return roleA - roleB;
|
||||
return a - b;
|
||||
})
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
* - 第 5 节胜利 → open_Victory(final) 弹结算,确认退出并存档进下一关。
|
||||
* - 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 { CCComp } from "../../../../extensions/oops-plugin-framework/assets/module/common/CCComp";
|
||||
import { smc } from "../common/SingletonModuleComp";
|
||||
@@ -31,7 +31,6 @@ import { SkillTriggerHelper } from "../hero/SkillTriggerHelper";
|
||||
import { UIID } from "../common/config/GameUIConfig";
|
||||
import { SkillView } from "../skill/SkillView";
|
||||
import { FacSet, FightSet } from "../common/config/GameSet";
|
||||
import { HeroInfo } from "../common/config/heroSet";
|
||||
import { mLogger } from "../common/Logger";
|
||||
import { Monster } from "../hero/Mon";
|
||||
import { Skill } from "../skill/Skill";
|
||||
@@ -80,8 +79,6 @@ type SettleType = "defeat" | "final";
|
||||
export class MissionComp extends CCComp {
|
||||
@property({ tooltip: "是否启用调试日志" })
|
||||
private debugMode: boolean = true;
|
||||
@property({ tooltip: "是否显示战斗内存观测面板" })
|
||||
private showMemoryPanel: boolean = false;
|
||||
|
||||
|
||||
// ======================== 配置参数 ========================
|
||||
@@ -97,6 +94,21 @@ export class MissionComp extends CCComp {
|
||||
@property(Node)
|
||||
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 显示) */
|
||||
private static readonly PhaseNameMap: Record<MissionPhase, string> = {
|
||||
[MissionPhase.None]: "未开始",
|
||||
@@ -133,26 +145,6 @@ export class MissionComp extends CCComp {
|
||||
private lastTimeStr: string = "";
|
||||
/** 上一次显示的秒数(避免重复计算) */
|
||||
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;
|
||||
/** 当前回合数(= 当前小节号,驱动 HUD 回合/进度显示) */
|
||||
@@ -161,8 +153,6 @@ export class MissionComp extends CCComp {
|
||||
private isBossWave: boolean = false;
|
||||
/** 超时回合已在 onBattleTimeout 预扣留存分,BattleEnd 需跳过重复累加 */
|
||||
private skipRemainScoreOnBattleEnd: boolean = false;
|
||||
/** 上节清场时间快照(含清场加速还原,供评分统计) */
|
||||
private lastWaveClearTime: number = 0;
|
||||
/** 当前任务阶段 */
|
||||
public currentPhase: MissionPhase = MissionPhase.None;
|
||||
/** 是否处于回合间倒计时状态 */
|
||||
@@ -180,11 +170,9 @@ export class MissionComp extends CCComp {
|
||||
|
||||
// ======================== 关卡进度状态 ========================
|
||||
|
||||
/** 当前章节号 */
|
||||
public currentChapter: number = 1;
|
||||
/** 当前关卡号(1~10) */
|
||||
/** 当前关卡号(无限关,1~∞) */
|
||||
public currentStage: number = 1;
|
||||
/** 当前小节号(1~SECTIONS_PER_STAGE) */
|
||||
/** 当前回合号(1~SECTIONS_PER_STAGE) */
|
||||
public currentSection: number = 1;
|
||||
|
||||
// ======================== ECS 查询匹配器(预缓存) ========================
|
||||
@@ -202,7 +190,6 @@ export class MissionComp extends CCComp {
|
||||
this.heroViewMatcher = ecs.allOf(HeroViewComp);
|
||||
this.skillViewMatcher = ecs.allOf(SkillView);
|
||||
this.heroAttrsMatcher = ecs.allOf(HeroAttrsComp);
|
||||
this.showMemoryPanel = false
|
||||
// 注册生命周期事件
|
||||
this.on(GameEvent.MissionEnd, this.mission_end, 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)
|
||||
// 开局免费三选一选完后自动进入战斗
|
||||
oops.message.on("OpeningPicksDone", this.onOpeningPicksDone, this);
|
||||
this.removeMemoryPanel()
|
||||
}
|
||||
|
||||
onAdded(args: any) {
|
||||
onAdded() {
|
||||
// 使用 scheduleOnce 将事件推迟到下一帧执行,
|
||||
// 确保所有关联组件(如 MissionCardComp 等)都已经完成其 onLoad 生命周期。
|
||||
this.scheduleOnce(() => {
|
||||
@@ -370,7 +356,6 @@ export class MissionComp extends CCComp {
|
||||
this.changePhase(MissionPhase.Prepare);
|
||||
// 派发首个 SectionStart,MissionMonComp 据此生成开局怪物
|
||||
oops.message.dispatchEvent(GameEvent.SectionStart, {
|
||||
chapter: this.currentChapter,
|
||||
stage: this.currentStage,
|
||||
section: this.currentSection,
|
||||
});
|
||||
@@ -426,22 +411,20 @@ export class MissionComp extends CCComp {
|
||||
|
||||
Tween.stopAllByTarget(this.tooltip);
|
||||
|
||||
// 动感动画设计:右侧进入 -> 屏幕中央(带有轻微的弹跳和滑动) -> 左侧飞出
|
||||
// 假设屏幕宽度适配下,1200是一个足够的屏幕外距离,适配横竖屏
|
||||
const startPos = v3(1200, this.tooltip.position.y, this.tooltip.position.z);
|
||||
const centerPos = v3(0, this.tooltip.position.y, this.tooltip.position.z);
|
||||
const driftPos = v3(-50, this.tooltip.position.y, this.tooltip.position.z); // 在中央时的缓慢漂移
|
||||
const endPos = v3(-1200, this.tooltip.position.y, this.tooltip.position.z);
|
||||
|
||||
this.tooltip.setPosition(startPos);
|
||||
// 动感动画设计:原地缩放弹入(0 -> 1,带轻微回弹)-> 短暂停留 -> 收缩消失
|
||||
// 相比位移飞入飞出,缩放动画更轻快,避免横幅长时间占用屏幕
|
||||
this.tooltip.setPosition(0, this.tooltip.position.y, this.tooltip.position.z);
|
||||
this.tooltip.setScale(0, 0, 1);
|
||||
|
||||
tween(this.tooltip)
|
||||
// 1. 从右侧快速飞入并带回弹效果 (0.5秒)
|
||||
.to(0.5, { position: centerPos }, { easing: "backOut" })
|
||||
// 2. 在屏幕中央缓慢向左漂移,增强动感停留 (1.0秒)
|
||||
.to(1.0, { position: driftPos }, { easing: "sineInOut" })
|
||||
// 3. 快速向左飞出并消失 (0.4秒)
|
||||
.to(0.4, { position: endPos }, { easing: "backIn" })
|
||||
// 1. 缩放从 0 快速弹到 1.1,制造轻微"冲出来"的动感 (0.18秒)
|
||||
.to(0.18, { scale: v3(1.1, 1.1, 1) }, { easing: "sineOut" })
|
||||
// 2. 回弹收缩到标准大小 1.0 (0.1秒)
|
||||
.to(0.1, { scale: v3(1, 1, 1) }, { easing: "sineIn" })
|
||||
// 3. 停留展示 (0.5秒)
|
||||
.delay(0.5)
|
||||
// 4. 向上轻弹并收缩消失,带背入加速感 (0.2秒)
|
||||
.to(0.2, { scale: v3(0, 0, 1) }, { easing: "backIn" })
|
||||
.call(() => {
|
||||
this.tooltip.active = false;
|
||||
})
|
||||
@@ -455,7 +438,6 @@ export class MissionComp extends CCComp {
|
||||
*/
|
||||
private changePhase(targetPhase: MissionPhase) {
|
||||
if (this.currentPhase === targetPhase) return;
|
||||
const oldPhase = this.currentPhase;
|
||||
this.currentPhase = targetPhase;
|
||||
|
||||
const phaseName = MissionComp.PhaseNameMap[targetPhase] || "未知";
|
||||
@@ -556,8 +538,6 @@ export class MissionComp extends CCComp {
|
||||
// 英雄为真实死亡(实体已销毁),本节死亡数取死亡记录长度
|
||||
const heroDeathCount = smc.mission.dead_heroes.length;
|
||||
|
||||
// 快照清场时间供评分统计(onNewWave 会清零 clearTime,必须提前快照)
|
||||
this.lastWaveClearTime = this.clearTime;
|
||||
// 【评分系统 - 战绩分】记录全员存活的胜利节数(额外加分)
|
||||
if (hasHero && heroDeathCount === 0) {
|
||||
smc.vmdata.scores.wave_all_alive_count++;
|
||||
@@ -751,11 +731,11 @@ export class MissionComp extends CCComp {
|
||||
* - 胜利即 final(通关),存档推进到下一关;失败即 defeat(进度不变,可复活/再来一次)
|
||||
* - 切入 BattleEnd,2s 后由 autoNextPhase 自动弹出 VictoryComp
|
||||
*
|
||||
* @param e 事件对象(未使用)
|
||||
* @param is_hero_dead 是否因英雄全灭触发
|
||||
* @param _e 事件对象(未使用)
|
||||
* @param _is_hero_dead 是否因英雄全灭触发(当前未使用,保留签名以统一事件调用口径)
|
||||
* @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;
|
||||
this._victory = victory;
|
||||
@@ -765,23 +745,18 @@ export class MissionComp extends CCComp {
|
||||
// 失败:进度不变,结算窗走复活/再来一次/退出流程
|
||||
this._settleType = "defeat";
|
||||
} else {
|
||||
// 通关(Boss 节胜利):结算窗显示通关标题,确认退出并存档进下一关
|
||||
// 通关(Boss 回合胜利):无限关卡模式,存档永远推进到下一关第 1 节
|
||||
// (仅写存档,内存进度保留用于本局结算显示)
|
||||
this._settleType = "final";
|
||||
this._settleTitle = this.currentStage >= 10 ? "本章通关" : "本关通关";
|
||||
// 存档推进到下一关第 1 节(仅写存档,内存进度保留用于本局结算显示);
|
||||
// 第 10 关通关即本章全通,存档停留等待后续章节扩展
|
||||
if (this.currentStage < 10) {
|
||||
smc.updateStageProgress({
|
||||
chapter: this.currentChapter,
|
||||
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`);
|
||||
this._settleTitle = "本关通关";
|
||||
smc.updateStageProgress({
|
||||
stage: this.currentStage + 1,
|
||||
});
|
||||
if ((smc as any).updateCloudData) {
|
||||
(smc as any).updateCloudData();
|
||||
}
|
||||
mLogger.log(this.debugMode, 'MissionComp',
|
||||
`[StageProgress] 本关通关,存档推进: ${this.currentStage + 1}-1`);
|
||||
}
|
||||
// 直接切入 BattleEnd,2s 后由 autoNextPhase 自动流转弹窗结算
|
||||
this.changePhase(MissionPhase.BattleEnd);
|
||||
@@ -836,20 +811,11 @@ export class MissionComp extends CCComp {
|
||||
this.currentWave = 1;
|
||||
this.isBossWave = false;
|
||||
this.skipRemainScoreOnBattleEnd = false;
|
||||
this.lastWaveClearTime = 0;
|
||||
this.updateRoundNodes();
|
||||
this.rewards = []
|
||||
this.revive_times = 1;
|
||||
this.lastTimeStr = "";
|
||||
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;
|
||||
|
||||
spawningEngine.reset();
|
||||
@@ -868,57 +834,48 @@ export class MissionComp extends CCComp {
|
||||
// ======================== 关卡进度管理 ========================
|
||||
|
||||
/**
|
||||
* 加载关卡进度存档(一关一局:只恢复大关,节恒从 1 开始)
|
||||
* 从 smc.data.stage_progress 恢复章节/大关,缺省从 1-1-1 开始
|
||||
* 加载关卡进度存档(一关一局:只恢复大关,回合恒从 1 开始)
|
||||
* 从 smc.data.stage_progress 恢复关卡号,缺省从第 1 关开始
|
||||
*/
|
||||
private loadStageProgress() {
|
||||
const progress = smc.data.stage_progress;
|
||||
if (progress && progress.chapter >= 1 && progress.stage >= 1) {
|
||||
this.currentChapter = progress.chapter;
|
||||
this.currentStage = progress.stage;
|
||||
} else {
|
||||
this.currentChapter = 1;
|
||||
this.currentStage = 1;
|
||||
}
|
||||
// 一关一局:进入关卡始终从第 1 节开打
|
||||
this.currentStage = Math.max(1, Math.floor(progress?.stage ?? 1));
|
||||
// 一关一局:进入关卡始终从第 1 回合开打
|
||||
this.currentSection = 1;
|
||||
// 加载完成后将权威进度镜像到 vmdata,驱动 HUD 实时显示
|
||||
smc.syncStageProgressToView();
|
||||
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. 不清理英雄/技能实体、不重置局内数据、不重新三选一——英雄保留并自动归位(编队排队)。
|
||||
* 3. 进度实时镜像到 HUD,但不写持久存档(存档只在整关通关时推进到下一关)。
|
||||
*
|
||||
* 调用时机:PrepareStart 过场倒计时结束(autoNextPhase)。
|
||||
* 保证:仅 1~4 节清场后触发,末节(BOSS_SECTION)已走 open_Victory 结算,不会推进。
|
||||
* 保证:仅 1~4 回合清场后触发,末回合(BOSS_SECTION)已走 open_Victory 结算,不会推进。
|
||||
*/
|
||||
private advanceToNextSection() {
|
||||
this.currentSection++;
|
||||
// 节号实时同步到 HUD(内存进度,不持久化;整关通关时才统一写大关存档)。
|
||||
// 回合号实时同步到 HUD(内存进度,不持久化;整关通关时才统一写大关存档)。
|
||||
// 直接写 vmdata 视图层而非走 syncStageProgressToView(后者从 data 读,而 data 仍停留在大关起点)
|
||||
const view = smc.vmdata.stage_progress;
|
||||
view.chapter = this.currentChapter;
|
||||
view.stage = this.currentStage;
|
||||
view.section = this.currentSection;
|
||||
oops.message.dispatchEvent(GameEvent.STAGE_PROGRESS_UPDATE);
|
||||
// 触发 SectionStart 事件,MissionMonComp 据此生成下一节怪物(从右侧跑入)
|
||||
// 触发 SectionStart 事件,MissionMonComp 据此生成下一回合怪物(从右侧跑入)
|
||||
oops.message.dispatchEvent(GameEvent.SectionStart, {
|
||||
chapter: this.currentChapter,
|
||||
stage: this.currentStage,
|
||||
section: this.currentSection,
|
||||
});
|
||||
mLogger.log(this.debugMode, 'MissionComp',
|
||||
`[StageProgress] 进入小节: ${getProgressText(this.currentChapter, this.currentStage, this.currentSection)}`);
|
||||
`[StageProgress] 进入回合: ${getProgressText(this.currentStage, this.currentSection)}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* 重开本关:清理战场并重置数据,从本关第 1 节重新开始
|
||||
* Why: 一关一局,失败"再来一次"即整关重打(节恒从 1 开始)
|
||||
* 重开本关:清理战场并重置数据,从本关第 1 回合重新开始
|
||||
* Why: 一关一局,失败"再来一次"即整关重打(回合恒从 1 开始)
|
||||
*/
|
||||
private restartCurrentMission() {
|
||||
// 清理战场与局内数据
|
||||
@@ -929,21 +886,20 @@ export class MissionComp extends CCComp {
|
||||
this._victory = false;
|
||||
this._settleType = "defeat";
|
||||
this._settleTitle = "";
|
||||
// 一关一局:重开从第 1 节开始
|
||||
// 一关一局:重开从第 1 回合开始
|
||||
this.currentSection = 1;
|
||||
// 进入准备阶段
|
||||
this.changePhase(MissionPhase.Prepare);
|
||||
// 触发 MissionStart 重置开局免费抽卡
|
||||
oops.message.dispatchEvent(GameEvent.MissionStart, {});
|
||||
oops.message.dispatchEvent(GameEvent.FightReady);
|
||||
// 触发 SectionStart 重新生成本关第 1 节怪物
|
||||
// 触发 SectionStart 重新生成本关第 1 回合怪物
|
||||
oops.message.dispatchEvent(GameEvent.SectionStart, {
|
||||
chapter: this.currentChapter,
|
||||
stage: this.currentStage,
|
||||
section: this.currentSection,
|
||||
});
|
||||
mLogger.log(this.debugMode, 'MissionComp',
|
||||
`[StageProgress] 重开本关: ${getProgressText(this.currentChapter, this.currentStage, this.currentSection)}`);
|
||||
`[StageProgress] 重开本关: ${getProgressText(this.currentStage, this.currentSection)}`);
|
||||
}
|
||||
|
||||
// ======================== 回合管理 ========================
|
||||
@@ -959,7 +915,7 @@ export class MissionComp extends CCComp {
|
||||
* @param event 事件名
|
||||
* @param data { wave: number, bossWave?: boolean }
|
||||
*/
|
||||
private onNewWave(event: string, data: any) {
|
||||
private onNewWave(_event: string, data: any) {
|
||||
const wave = Number(data?.wave ?? 0);
|
||||
if (wave <= 0) return;
|
||||
|
||||
@@ -968,12 +924,46 @@ export class MissionComp extends CCComp {
|
||||
|
||||
this.currentWave = wave;
|
||||
smc.vmdata.mission_data.level = wave;
|
||||
this.updateRoundNodes();
|
||||
// 金币改为怪物死亡掉落(见 HeroAtkSystem),不再每回合固定发放
|
||||
this.lastTimeSecond = -1;
|
||||
this.clearTime = 0;
|
||||
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 +1172,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 组件移除时销毁节点 */
|
||||
reset() {
|
||||
this.PhaseTime = null as any;
|
||||
|
||||
@@ -124,12 +124,11 @@ export class MissionMonCompComp extends CCComp {
|
||||
start() { }
|
||||
|
||||
/**
|
||||
* 小节开始事件回调:生成怪物列表并按节奏刷出
|
||||
* 回合开始事件回调:生成怪物列表并按节奏刷出
|
||||
* @param event 事件名
|
||||
* @param data { chapter, stage, section }
|
||||
* @param data { stage, section }
|
||||
*/
|
||||
private onSectionStart(event: string, data: any) {
|
||||
const chapter = Number(data?.chapter ?? 1);
|
||||
const stage = Number(data?.stage ?? 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.pending_mon_num = 0;
|
||||
|
||||
// 从生成引擎获取本小节怪物列表
|
||||
const monsters = spawningEngine.generateSectionMonsters(chapter, stage, section);
|
||||
// 从生成引擎获取本回合怪物列表
|
||||
const monsters = spawningEngine.generateSectionMonsters(stage, section);
|
||||
this.sectionTargetCount = monsters.length;
|
||||
|
||||
if (TestModeConfig.enable) {
|
||||
mLogger.log(this.debugMode, 'MissionMonComp', "[MissionMonComp] 测试模式已开启");
|
||||
}
|
||||
mLogger.log(this.debugMode, 'MissionMonComp',
|
||||
`[MissionMonComp] 小节 ${chapter}-${stage}-${section} 生成完成,怪物总数: ${this.sectionTargetCount}`);
|
||||
`[MissionMonComp] 回合 ${stage}-${section} 生成完成,怪物总数: ${this.sectionTargetCount}`);
|
||||
|
||||
// 按批次拆分:batch=0 立即刷,batch=1 进入待刷队列
|
||||
const immediate: GeneratedMonster[] = [];
|
||||
|
||||
@@ -1,30 +1,32 @@
|
||||
/**
|
||||
* @file RogueConfig.ts
|
||||
* @description 关卡刷怪系统(章节-关-节三级推进)
|
||||
* @description 无限关卡刷怪系统(关-回合两级推进)
|
||||
*
|
||||
* 游戏机制:
|
||||
* - 玩家线性推进 1 章 10 关 × 每关 5 小节(一关一局,节间自动推进)。
|
||||
* - 每关节点固定:1~3 节普通(3 小怪,立即全刷)、第 4 节精英(3 精英同刷)、
|
||||
* 第 5 节 Boss(2 小怪先刷,Boss 延迟 1s 刷出)。
|
||||
* - 怪物属性 = 基础 × 0.8 × (1 + 0.05×(lv-1)) × 类型倍率(精英1.5 / Boss3.0)。
|
||||
* - 玩家单线无限推进:从第 1 关起无上限,每关 5 回合(一关一局,回合间自动推进)。
|
||||
* - 第 1~4 回合普通怪(3 小怪立即全刷),属性逐回合轻量增强(SECTION_RAMP_STEP)。
|
||||
* - 第 5 回合单 Boss 登场(无护卫,延迟 1s 刷出),超厚血量(BOSS_HP_MUL)。
|
||||
* - Boss 加载时按攻击定位(近战/中程/远程)随机取型,并随机携带大招:
|
||||
* 前期 1 个,随关卡解锁扩展至多个(BOSS_ULT_UNLOCK_EVERY / BOSS_ULT_MAX_COUNT)。
|
||||
*
|
||||
* 设计层次:
|
||||
* 1. StageSet - 关卡配置(章节/关/节 + 数值公式)
|
||||
* 2. MonSkillPool/BossSkillPool - 怪物技能池(atking / atked / dead 等全触发类型)
|
||||
* 3. StageSpawningEngine - 生成引擎(按小节配置生成怪物列表)
|
||||
* 1. StageSet - 关卡数值公式(等级/成长/回合增强/Boss 血攻倍率)
|
||||
* 2. BossPools - Boss 池(按攻击定位分组,动态从 HeroInfo 提取)
|
||||
* 3. BossUltPools - Boss 大招池(按定位分组,引用 SkillSet 6100~6204 群体大招段)
|
||||
* 4. StageSpawningEngine - 生成引擎(按回合配置生成怪物列表)
|
||||
*
|
||||
* 核心公式:
|
||||
* 最终属性 = HeroInfo 基础属性 × MON_START_COEF × (1 + MON_GROW_SLOPE×(lv-1)) × 类型倍率
|
||||
* 1 级小怪 ≈ 英雄 × 0.8,10 级小怪 ≈ 英雄 × 1.16,保持平缓成长。
|
||||
* 小怪属性 = HeroInfo 基础属性 × MON_START_COEF × (1 + MON_GROW_SLOPE×(lv-1)) × 回合增强
|
||||
* Boss 属性 = 同上 × BOSS_HP_MUL(血)/ BOSS_AP_MUL(攻),等级 = 关卡号无限成长
|
||||
*/
|
||||
|
||||
import { HeroInfo, MonType, MonTypeName, TriggerGrouped } from "../common/config/heroSet";
|
||||
import { SkillOverrides } from "../common/config/SkillSet";
|
||||
import { HeroInfo, HType, MonType, TriggerGrouped, UltCdLv, UltCdSet } from "../common/config/heroSet";
|
||||
import { SkillOverrides, SkillSet } from "../common/config/SkillSet";
|
||||
import { FacSet } from "../common/config/GameSet";
|
||||
import {
|
||||
SectionType, SectionConfig, getSectionConfig, calcMonsterAttrs,
|
||||
NORMAL_MON_COUNT, NORMAL_FIRST_SPAWN, ELITE_COUNT, BOSS_ELITE_COUNT, BOSS_DELAY,
|
||||
MON_START_COEF, MON_GROW_SLOPE, ELITE_MUL, BOSS_MUL,
|
||||
NORMAL_MON_COUNT, NORMAL_FIRST_SPAWN, BOSS_DELAY,
|
||||
MON_START_COEF,
|
||||
} from "../common/config/StageSet";
|
||||
|
||||
// ======================== 1. 战斗常量 ========================
|
||||
@@ -79,126 +81,114 @@ export function getMonsterGoldDrop(monType: number, isBoss: boolean): number {
|
||||
return Math.max(0, Math.floor(isBoss ? cfg.boss : cfg.base));
|
||||
}
|
||||
|
||||
// ======================== 3. 怪物技能池 ========================
|
||||
// ======================== 3. Boss 池(按攻击定位分组) ========================
|
||||
|
||||
/**
|
||||
* 怪物技能套装(一套完整的触发技能配置)
|
||||
* 覆盖触发时机:call / atking / atked / dead / fstart / revive
|
||||
* Boss 池:按攻击定位(近战/中程/远程)分组,动态从 HeroInfo 提取。
|
||||
* 加载时随机一个定位 → 从对应池随机 Boss;定位池为空时自动回退(如暂无中程 Boss 配置)。
|
||||
*/
|
||||
export interface MonSkillSet {
|
||||
id: string;
|
||||
export const BossPools: Record<HType, number[]> = {
|
||||
[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;
|
||||
/** 普攻技能覆盖(可选,不填则使用怪物默认普攻) */
|
||||
skill?: { s_uuid: number; cd?: number; overrides?: SkillOverrides };
|
||||
/** 召唤触发 */
|
||||
call?: TriggerGrouped;
|
||||
/** 攻击触发 */
|
||||
atking?: TriggerGrouped;
|
||||
/** 受击触发 */
|
||||
atked?: TriggerGrouped;
|
||||
/** 死亡触发 */
|
||||
dead?: TriggerGrouped;
|
||||
/** 战斗开始触发 */
|
||||
fstart?: TriggerGrouped;
|
||||
/** 复活触发 */
|
||||
revive?: TriggerGrouped;
|
||||
/** 在技能池中的抽取权重 */
|
||||
/** 抽取权重 */
|
||||
weight: number;
|
||||
/** 技能参数覆盖(伤害系数等) */
|
||||
overrides?: SkillOverrides;
|
||||
}
|
||||
|
||||
/**
|
||||
* 怪物技能池(硬编码)
|
||||
* 技能 uuid 引用 SkillSet 中的 6000~6500 段触发技能。
|
||||
* Boss 大招池(按攻击定位分组)
|
||||
* 大招注入 Boss 的 skills 表后由 SCastSystem 按 CD 自动施放(含镜头聚焦 + 技能名横幅)。
|
||||
*/
|
||||
export const MonSkillPool: Record<string, MonSkillSet> = {
|
||||
/** 狂暴:攻击触发自身攻击提升 */
|
||||
berserk: {
|
||||
id: "berserk", name: "狂暴", weight: 10,
|
||||
atking: {
|
||||
6401: [{ lv: 1, t_num: 5, overrides: { ap: 1 } }],
|
||||
},
|
||||
},
|
||||
/** 坚韧:受击获得护盾 */
|
||||
tough: {
|
||||
id: "tough", name: "坚韧", weight: 8,
|
||||
atked: {
|
||||
6301: [{ lv: 1, t_num: 3, overrides: { ap: 2 } }],
|
||||
},
|
||||
},
|
||||
/** 遗志:死亡时全队攻击提升 */
|
||||
legacy: {
|
||||
id: "legacy", name: "遗志", weight: 6,
|
||||
dead: {
|
||||
6401: [{ lv: 1, t_num: 1, overrides: { ap: 3 } }],
|
||||
},
|
||||
},
|
||||
/** 战吼:战斗开始时全队攻击提升 */
|
||||
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 } }],
|
||||
},
|
||||
},
|
||||
export const BossUltPools: Record<HType, BossUltEntry[]> = {
|
||||
// 近战系:战士群体斩击(6100~6104 段)
|
||||
[HType.Melee]: [
|
||||
{ s_uuid: 6100, name: "寒冰斩", weight: 10, overrides: { ap: 180 } },
|
||||
{ s_uuid: 6101, name: "裂气斩", weight: 10, overrides: { ap: 180 } },
|
||||
{ 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 } },
|
||||
],
|
||||
// 中程系:射手箭雨 + 混合法术(6150~6151 / 6203~6204 段)
|
||||
[HType.Mid]: [
|
||||
{ s_uuid: 6150, name: "万箭齐发", weight: 10, overrides: { ap: 150 } },
|
||||
{ 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 } },
|
||||
],
|
||||
// 远程系:法师群体法术(6200~6204 段)
|
||||
[HType.Long]: [
|
||||
{ s_uuid: 6200, name: "火球术", weight: 10, overrides: { ap: 160 } },
|
||||
{ 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 } },
|
||||
],
|
||||
};
|
||||
|
||||
/** Boss 专属技能池 */
|
||||
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. 配置校验 ========================
|
||||
// ======================== 5. 配置校验 ========================
|
||||
|
||||
/**
|
||||
* 校验 MonSkillPool / BossSkillPool 引用一致性
|
||||
* 校验 Boss 池 / Boss 大招池引用一致性
|
||||
* 建议在游戏启动时调用一次,便于发现配置错误
|
||||
* @returns 错误信息数组,空数组表示校验通过
|
||||
*/
|
||||
export function validateRogueConfig(): string[] {
|
||||
const errors: string[] = [];
|
||||
|
||||
// 校验 Boss 类型在 MonList 中有怪
|
||||
if ((!MonList[MonType.MeleeBoss] || MonList[MonType.MeleeBoss].length === 0)
|
||||
&& (!MonList[MonType.LongBoss] || MonList[MonType.LongBoss].length === 0)) {
|
||||
errors.push("MonList 中无任何 Boss 类型(MeleeBoss/LongBoss)可用 uuid");
|
||||
// 校验至少一个定位有可用 Boss
|
||||
const hasBoss = (Object.keys(BossPools) as unknown as HType[]).some(t => BossPools[t].length > 0);
|
||||
if (!hasBoss) {
|
||||
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;
|
||||
}
|
||||
|
||||
// ======================== 5. 生成结果接口 ========================
|
||||
// ======================== 6. 生成结果接口 ========================
|
||||
|
||||
/** 生成结果(传递给 MissionMonComp 用于实例化怪物) */
|
||||
export interface GeneratedMonster {
|
||||
@@ -207,10 +197,8 @@ export interface GeneratedMonster {
|
||||
hp: number;
|
||||
ap: number;
|
||||
isBoss: boolean;
|
||||
/** 是否为精英(精英关/Boss 关的精英) */
|
||||
/** 是否为精英(对象池复用实体需显式重置的标记位) */
|
||||
isElite?: boolean;
|
||||
/** 是否为 Boss 护卫队成员(供 UI/统计识别) */
|
||||
isBossGuard?: boolean;
|
||||
/** 怪物等级(驱动技能等级增量,Mon.load 第 6 参) */
|
||||
lv: number;
|
||||
spawnIndex: number;
|
||||
@@ -220,11 +208,15 @@ export interface GeneratedMonster {
|
||||
delay?: number;
|
||||
|
||||
/**
|
||||
* 怪物技能套装(覆盖全部触发时机)
|
||||
* 注入方式与 _testSkills 相同,在 Mon.load() 中写入 HeroAttrsComp
|
||||
* 怪物技能套装(技能注入通道,与 _testSkills 相同,在 Mon.load() 中写入 HeroAttrsComp)
|
||||
* - skill:替换普攻(会清空原技能表)
|
||||
* - ults:追加 Boss 大招(保留普攻,多个大招共存,SCastSystem 按 CD 轮转施放)
|
||||
* - 其余为触发技能组覆盖
|
||||
*/
|
||||
skills?: {
|
||||
skill?: { s_uuid: number; cd?: number; overrides?: SkillOverrides };
|
||||
/** Boss 大招列表(追加注入,不替换普攻) */
|
||||
ults?: { s_uuid: number; cd?: number; overrides?: SkillOverrides }[];
|
||||
call?: TriggerGrouped;
|
||||
atking?: TriggerGrouped;
|
||||
atked?: TriggerGrouped;
|
||||
@@ -234,7 +226,7 @@ export interface GeneratedMonster {
|
||||
};
|
||||
}
|
||||
|
||||
// ======================== 6. 测试模式配置 ========================
|
||||
// ======================== 7. 测试模式配置 ========================
|
||||
|
||||
export const TestModeConfig = {
|
||||
enable: false, // 默认关闭测试模式
|
||||
@@ -245,48 +237,43 @@ export const TestModeConfig = {
|
||||
spawnCount: 1,
|
||||
|
||||
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,
|
||||
atked: undefined as TriggerGrouped | undefined,
|
||||
dead: undefined as TriggerGrouped | undefined,
|
||||
fstart: undefined as TriggerGrouped | undefined,
|
||||
};
|
||||
|
||||
// ======================== 7. 生成引擎 ========================
|
||||
// ======================== 8. 生成引擎 ========================
|
||||
|
||||
/**
|
||||
* 关卡刷怪生成引擎
|
||||
* 按章节-关-节配置生成怪物列表,属性走 StageSet 数值公式
|
||||
* 无限关卡刷怪生成引擎
|
||||
* 按关-回合配置生成怪物列表,属性走 StageSet 数值公式
|
||||
*/
|
||||
export class StageSpawningEngine {
|
||||
|
||||
/**
|
||||
* 生成指定小节的怪物列表
|
||||
* @param chapter 章节号
|
||||
* @param stage 关卡号
|
||||
* @param section 小节号(1~10)
|
||||
* 生成指定回合的怪物列表
|
||||
* @param stage 关卡号(1~∞)
|
||||
* @param section 回合号(1~SECTIONS_PER_STAGE)
|
||||
* @returns 怪物列表(按刷出顺序排列)
|
||||
*/
|
||||
generateSectionMonsters(chapter: number, stage: number, section: number): GeneratedMonster[] {
|
||||
generateSectionMonsters(stage: number, section: number): GeneratedMonster[] {
|
||||
// 测试模式拦截:完全绕过生成引擎,直接返回硬编码测试怪
|
||||
if (TestModeConfig.enable) {
|
||||
return this.generateTestWave();
|
||||
}
|
||||
|
||||
const cfg = getSectionConfig(chapter, stage, section);
|
||||
const cfg = getSectionConfig(stage, section);
|
||||
if (!cfg) {
|
||||
// 配置缺失兜底:生成 3 只 Lv1 近战小怪
|
||||
return this.makeFallbackMonsters();
|
||||
}
|
||||
|
||||
switch (cfg.type) {
|
||||
case SectionType.Elite:
|
||||
return this.generateEliteSection(cfg);
|
||||
case SectionType.Boss:
|
||||
return this.generateBossSection(cfg);
|
||||
case SectionType.Normal:
|
||||
default:
|
||||
return this.generateNormalSection(cfg);
|
||||
}
|
||||
return cfg.type === SectionType.Boss
|
||||
? this.generateBossSection(cfg, stage)
|
||||
: 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[] {
|
||||
const monsters: GeneratedMonster[] = [];
|
||||
@@ -304,64 +292,49 @@ export class StageSpawningEngine {
|
||||
const type = types[i % types.length];
|
||||
const mon = this.makeMonster(type, cfg.monLv, i);
|
||||
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);
|
||||
}
|
||||
return monsters;
|
||||
}
|
||||
|
||||
/**
|
||||
* 精英节:3 只精英同时刷出
|
||||
* Boss 回合(5):单 Boss 登场(无护卫)
|
||||
* Boss 延迟 BOSS_DELAY 秒刷出,属性由 makeBoss 按血/攻分离倍率计算(超厚血量)
|
||||
*/
|
||||
private generateEliteSection(cfg: SectionConfig): GeneratedMonster[] {
|
||||
const monsters: GeneratedMonster[] = [];
|
||||
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);
|
||||
private generateBossSection(cfg: SectionConfig, stage: number): GeneratedMonster[] {
|
||||
const boss = this.makeBoss(cfg.monLv, stage, 0);
|
||||
boss.batch = 0;
|
||||
boss.delay = BOSS_DELAY;
|
||||
// Boss 属性 = 普通 × BOSS_MUL
|
||||
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 [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 近战小怪 */
|
||||
@@ -399,6 +372,7 @@ export class StageSpawningEngine {
|
||||
batch: 0,
|
||||
skills: {
|
||||
skill: TestModeConfig.skill,
|
||||
ults: TestModeConfig.ults,
|
||||
atking: TestModeConfig.atking,
|
||||
atked: TestModeConfig.atked,
|
||||
dead: TestModeConfig.dead,
|
||||
@@ -409,77 +383,74 @@ export class StageSpawningEngine {
|
||||
return monsters;
|
||||
}
|
||||
|
||||
/** 生成 Boss(基础面板按 StageSet 公式计算) */
|
||||
private makeBoss(monLv: number, spawnIndex: number): GeneratedMonster {
|
||||
const isMeleeBoss = Math.random() < 0.5;
|
||||
const type = isMeleeBoss ? MonType.MeleeBoss : MonType.LongBoss;
|
||||
/**
|
||||
* 生成 Boss:加载时随机攻击定位 → 从对应池随机 Boss 个体 → 随机携带大招
|
||||
* 属性走 calcMonsterAttrs(isBoss=true):HP × BOSS_HP_MUL(超厚血)/ AP × BOSS_AP_MUL
|
||||
*/
|
||||
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 baseHp = baseInfo ? baseInfo.hp : 600;
|
||||
const baseAp = baseInfo ? baseInfo.ap : 30;
|
||||
const attrs = calcMonsterAttrs(baseHp, baseAp, monLv, false, false);
|
||||
const attrs = calcMonsterAttrs(baseHp, baseAp, monLv, true);
|
||||
|
||||
return {
|
||||
uuid,
|
||||
type,
|
||||
type: baseInfo?.monType ?? MonType.MeleeBoss,
|
||||
hp: attrs.hp,
|
||||
ap: attrs.ap,
|
||||
isBoss: true,
|
||||
lv: monLv,
|
||||
spawnIndex,
|
||||
batch: 0,
|
||||
skills: {
|
||||
ults: this.pickBossUlts(range, stage),
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
/** 生成普通怪物(属性按 StageSet 公式计算) */
|
||||
private makeMonster(type: MonType, monLv: number, spawnIndex: number): GeneratedMonster {
|
||||
let uuids = MonList[type];
|
||||
/**
|
||||
* 随机 Boss 攻击定位(近战/中程/远程)
|
||||
* 空池自动回退:中程暂无 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) {
|
||||
// 兜底 Melee
|
||||
uuids = MonList[MonType.Melee] || [6001];
|
||||
uuids = MonList[MonType.MeleeBoss] || 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, false);
|
||||
|
||||
return {
|
||||
uuid,
|
||||
type,
|
||||
hp: attrs.hp,
|
||||
ap: attrs.ap,
|
||||
isBoss: false,
|
||||
lv: monLv,
|
||||
spawnIndex,
|
||||
batch: 0,
|
||||
};
|
||||
return uuids[Math.floor(Math.random() * uuids.length)];
|
||||
}
|
||||
|
||||
/** 从技能池中按权重抽取一套技能 */
|
||||
private pickSkillSet(pool: string[], library: Record<string, MonSkillSet>): GeneratedMonster["skills"] | undefined {
|
||||
const valid = pool.map(id => library[id]).filter(s => s);
|
||||
if (valid.length === 0) return undefined;
|
||||
const picked = this.pickWeighted(valid);
|
||||
if (!picked) return undefined;
|
||||
return {
|
||||
skill: picked.skill,
|
||||
call: picked.call,
|
||||
atking: picked.atking,
|
||||
atked: picked.atked,
|
||||
dead: picked.dead,
|
||||
fstart: picked.fstart,
|
||||
revive: picked.revive,
|
||||
};
|
||||
/**
|
||||
* 按定位抽取 Boss 大招(不重复),数量由关卡进度决定(getBossUltCount)
|
||||
* @returns 大招配置列表;池空时返回 undefined
|
||||
*/
|
||||
private pickBossUlts(range: HType, stage: number): GeneratedMonster["skills"]["ults"] {
|
||||
const pool = [...(BossUltPools[range] ?? [])];
|
||||
const count = Math.min(getBossUltCount(stage), pool.length);
|
||||
if (count <= 0) return undefined;
|
||||
|
||||
const ults: { s_uuid: number; cd?: number; overrides?: SkillOverrides }[] = [];
|
||||
for (let i = 0; i < count; i++) {
|
||||
const picked = this.pickWeighted(pool);
|
||||
if (!picked) break;
|
||||
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();
|
||||
|
||||
// 保留旧接口兼容(逐步迁移期使用)
|
||||
/** @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();
|
||||
|
||||
@@ -2,7 +2,7 @@ import { _decorator, Animation, CCFloat, CCInteger, Collider2D, Contact2DType, E
|
||||
import { ecs } from "../../../../extensions/oops-plugin-framework/assets/libs/ecs/ECS";
|
||||
import { CCComp } from "../../../../extensions/oops-plugin-framework/assets/module/common/CCComp";
|
||||
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 { HeroAttrsComp } from "../hero/HeroAttrsComp";
|
||||
import { DamageQueueHelper } from "../hero/DamageQueueComp";
|
||||
@@ -54,6 +54,10 @@ export class SkillView extends CCComp {
|
||||
@property({ type: CCInteger, slide: true, range: [1, 8, 1], tooltip: "单次施法召唤的技能实体个数" })
|
||||
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... 档 × 该值,正=右) */
|
||||
@property({ type: CCFloat, slide: true, range: [-200, 200, 5], tooltip: "召唤物X轴步进偏移:以中心对称交替铺开(0,+1,-1,+2,-2...档×该值)" })
|
||||
summon_x_offset: number = 0;
|
||||
|
||||
447
docs/hero-numerical-review.md
Normal file
447
docs/hero-numerical-review.md
Normal file
@@ -0,0 +1,447 @@
|
||||
# 全英雄基础属性与能力说明(数值评审稿)
|
||||
|
||||
> 数据来源:`assets/script/game/common/config/heroSet.ts`(英雄配置)、`SkillSet.ts`(技能底座)、`BuffSet.ts`(buff/debuff 底座)
|
||||
> 用途:交予数值设计师讨论分析。lv1 基础属性均已按 `HERO_ROLE_BASE + 手动增量` 实算。
|
||||
|
||||
---
|
||||
|
||||
## 〇、全局数值框架
|
||||
|
||||
### 职业基础模板 `HERO_ROLE_BASE`
|
||||
|
||||
英雄实际属性 = 模板 + 手动增量;品质(rarity)仅乘 lv1 基础值,相邻品质差 5%。
|
||||
|
||||
| 职业 | HP | AP | DEF | 成长系数 HP/AP/DEF |
|
||||
|---|---|---|---|---|
|
||||
| 坦克 Tank | 600 | 20 | 50 | 1.5 / 0.6 / 1.5 |
|
||||
| 战士 Warrior | 560 | 22 | 30 | 1.0 / 1.0 / 1.0 |
|
||||
| 刺客 Assassin | 560 | 22 | 10 | 0.7 / 1.4 / 0.5 |
|
||||
| 射手 Archer | 280 | 32 | 10 | 0.8 / 1.3 / 0.5 |
|
||||
| 法师 Mage | 280 | 32 | 10 | 0.9 / 1.3 / 0.5 |
|
||||
| 辅助 Support | 280 | 32 | 15 | 1.1 / 0.7 / 1.0 |
|
||||
|
||||
### 攻速档 `AtkSpeedSet`(攻击间隔,越小越快)
|
||||
|
||||
| 档位 | 名称 | 间隔 |
|
||||
|---|---|---|
|
||||
| VeryFast | 极速 | 0.75s |
|
||||
| Fast | 快速 | 0.90s |
|
||||
| Normal | 中速 | 1.05s |
|
||||
| Slow | 慢速 | 1.20s |
|
||||
| VerySlow | 极慢 | 1.50s |
|
||||
|
||||
### 大招 CD 档 `UltCdSet`
|
||||
|
||||
| 档位 | 名称 | CD | 适用类型 |
|
||||
|---|---|---|---|
|
||||
| VeryFast | 极频 | 6s | 单体爆发/高频压制 |
|
||||
| Fast | 高频 | 7s | 频繁压制(中间档) |
|
||||
| Normal | 标准 | 8s | 群体伤害/控制 |
|
||||
| Slow | 低频 | 9s | 中度团队增益(中间档) |
|
||||
| VerySlow | 稀有 | 10s | 全体增益/治疗/护盾 |
|
||||
|
||||
### 成长与解锁节奏
|
||||
|
||||
- lv1:激活普攻 + 大招
|
||||
- lv2:普攻强化档(lv_entries 第 1 档)
|
||||
- lv4:解锁触发技 / 光环(配置实际生效等级)
|
||||
- lv8 / lv16:大招升档(lv_entries)
|
||||
- lv12:专项 bonus(单项属性 +50%,基数取"基础×品质+成长"快照)
|
||||
|
||||
### 触发技概率模型
|
||||
|
||||
t_num 次行为后判定,t_chance% 概率触发;未触发则 pity_add 累加下次概率(封顶 100%,触发成功后清零)。
|
||||
|
||||
---
|
||||
|
||||
## 一、前排坦克 / 战士
|
||||
|
||||
### 5001 叠甲骑士(近战·坦克)
|
||||
|
||||
**lv1:HP 620 / AP 20 / DEF 60** | 攻速 1.20s(慢速)| 大招 CD 10s(稀有)
|
||||
> 定位:自身强护盾 + 防御强化
|
||||
|
||||
- **普攻 6004 强化普攻**:100% 攻击伤害 → lv2 提升至 120%
|
||||
- **大招 6301 魔法盾**:自身获得生命最大值 **30%** 护盾 → lv8 60% → lv16 120%
|
||||
- **受击触发 6412 防御强化**(lv4):受击 3 次后 50% 概率触发(保底 +20),全队防御 +50(单次)
|
||||
- **lv12 钢铁壁垒**:DEF +50%
|
||||
|
||||
### 5009 甲虫领主(近战·坦克)
|
||||
|
||||
**lv1:HP 600 / AP 20 / DEF 50** | 攻速 1.20s | 大招 CD 8s
|
||||
> 定位:受击自疗 + 击退,自愈坦克
|
||||
|
||||
- **普攻 6004 普攻强化** → lv2 伤害提升至 120%
|
||||
- **大招 6102 火焰斩**:250% 攻击伤害,并 100% 触发治疗(回复自身 10% 生命)→ lv8 300%/15% → lv16 350%/20%
|
||||
- **受击触发 6302 治疗**(lv4):受击 3 次后 30% 概率(保底 +20),回复自身 5% 生命
|
||||
- **lv12 钢铁壁垒**:DEF +50%
|
||||
|
||||
### 5011 控血大师(近战·坦克)
|
||||
|
||||
**lv1:HP 600 / AP 20 / DEF 50** | 攻速 1.05s(中速)| 大招 CD 10s(稀有)
|
||||
> 定位:永久 + 计时生命上限,控血流
|
||||
|
||||
- **普攻 6004 普攻强化** → lv2:10% 概率对自己释放回春(5s 回复 5% 生命)
|
||||
- **大招 6103 闪电战**:200% 攻击伤害,自身最大生命 +30% 持续 5s → lv8 250%/+40% → lv16 300%/+50%
|
||||
- **受击触发 6402 生命强化**(lv4):受击 5 次后 30% 概率(保底 +15),**全队永久最大生命 +1%**
|
||||
- **lv12 钢铁壁垒**:DEF +50%
|
||||
|
||||
### 5002 易伤剑仙(近战·战士)
|
||||
|
||||
**lv1:HP 565 / AP 42 / DEF 35** | 攻速 1.20s | 大招 CD 8s
|
||||
> 定位:易伤放大,近战 dps
|
||||
|
||||
- **普攻 6004 强化普攻** → lv2 提升至 120%
|
||||
- **大招 6101 气斩**:150% 伤害 + 易伤(每层附加 30 固定受伤,持续 5s,可叠 5 层)→ lv8 200%/70 → lv16 250%/150 持续 7s
|
||||
- **攻击触发 6001 飞剑**(lv4):普攻 3 次后 50% 概率(保底 +20),追加飞剑并挂易伤 10/5s
|
||||
- **lv12 不屈战意**:HP +50%
|
||||
|
||||
### 5003 眩晕暴击哥(近战·战士)
|
||||
|
||||
**lv1:HP 565 / AP 42 / DEF 35** | 攻速 1.20s | 大招 CD 8s
|
||||
> 定位:必晕爆发 + 暴击,近战收割
|
||||
|
||||
- **普攻 6004 强化普攻** → lv2:普攻 10% 概率击晕
|
||||
- **大招 6104 开山斧**:250% 伤害 **必定击晕** → lv8 300% → lv16 350%
|
||||
- **攻击触发 6504 暴击爆发**(lv4):普攻 3 次后 50% 概率(保底 +20),自身暴击率 +30% 持续 5s
|
||||
- **lv12 不屈战意**:HP +50%
|
||||
|
||||
### 5014 闪避哥(近战·战士)
|
||||
|
||||
**lv1:HP 560 / AP 22 / DEF 30** | 攻速 1.05s | 大招 CD 8s
|
||||
> 定位:强闪避
|
||||
|
||||
- **普攻 6004 普攻强化** → lv2:暴击率 +10%
|
||||
- **大招 6100 寒冰斩**:200% 伤害,自身闪避 +50%(7030 闪避爆发)→ lv8 250%/50% → lv16 350%/80%
|
||||
- **光环 7023(lv4)**:词条值 10(语义存疑,见待确认点 ①)
|
||||
- **lv12 不屈战意**:HP +50%
|
||||
|
||||
---
|
||||
|
||||
## 二、刺客 / 中程输出
|
||||
|
||||
### 5004 刀刀暴击(中程·刺客)
|
||||
|
||||
**lv1:HP 560 / AP 52 / DEF 10** | 攻速 0.90s(快速)| 大招 CD 6s(极频)
|
||||
> 定位:暴击流刺客主C
|
||||
|
||||
- **普攻 6002 匕首** → lv2:暴击率 +10%
|
||||
- **大招 6150 剑刃风暴**:150% 伤害,50% 暴击 → lv8 200%/60% → lv16 250%/70%
|
||||
- **攻击触发 6504 暴击爆发**(lv4):普攻 3 次后 50% 概率(保底 +20),自身暴击率 +10% 持续 5s
|
||||
- **lv12 致命本能**:AP +50%
|
||||
|
||||
### 5005 出血贼(中程·刺客)
|
||||
|
||||
**lv1:HP 560 / AP 52 / DEF 10** | 攻速 0.90s | 大招 CD 6s(极频)
|
||||
> 定位:出血 DoT 持续消耗
|
||||
|
||||
- **普攻 6002 强化普攻** → lv2:50% 概率使目标出血(每 0.5s 微量掉血,每层使目标被暴击率 +1%,可叠 5 层)
|
||||
- **大招 6150 血刃风暴**:200% 伤害 + 100% 出血(-20/5s)→ lv8 250%/-30/7s → lv16 300%/-50/9s(lv16 文案附带 50% 麻痹但配置未注入,见待确认点 ②)
|
||||
- **攻击触发 6401 攻击强化**(lv4):普攻 3 次后 50% 概率(保底 +20),全队攻击 +2%
|
||||
- **lv12 致命本能**:AP +50%
|
||||
|
||||
### 5010 火箭哥(中程·射手)
|
||||
|
||||
**lv1:HP 280 / AP 32 / DEF 10** | 攻速 0.90s | 大招 CD 6s(极频)
|
||||
> 定位:弹幕减攻
|
||||
|
||||
- **普攻 6006 射击** → lv2:暴击率 +10%
|
||||
- **大招 6151 万箭齐发·火**:5 支箭各 70% 伤害,必挂减攻 -10%/5s → lv8 80%/-20% → lv16 100%/-30%
|
||||
- **攻击触发 6008 红箭**(lv4):普攻 3 次后 50% 概率(保底 +20),追加 120% 伤害射击
|
||||
- **lv12 鹰眼锁定**:AP +50%
|
||||
|
||||
### 5016 连珠神射(中程·射手)
|
||||
|
||||
**lv1:HP 280 / AP 42 / DEF 10** | 攻速 **0.75s(极速,全英雄最快)** | 大招 CD 6s(极频)
|
||||
> 定位:极速连射暴击爆发主C
|
||||
|
||||
- **普攻 6008 连珠箭** → lv2:20% 概率额外射击,造成 80% 伤害
|
||||
- **大招 6151 裂空箭雨**:5 箭各 150% 伤害,30% 暴击 → lv8 200%/50% → lv16 250%/70%/6 箭
|
||||
- **光环 7004 暴击光环(lv4)**:全队暴击率提升(词条值 0.1)
|
||||
- **lv12 猎杀直觉**:AP +50%
|
||||
|
||||
---
|
||||
|
||||
## 三、远程法师 / 射手 / 辅助
|
||||
|
||||
### 5006 冻箭哥(远程·射手)
|
||||
|
||||
**lv1:HP 280 / AP 62 / DEF 10** | 攻速 1.05s | 大招 CD 8s
|
||||
> 定位:冰冻控场 + 多重箭
|
||||
|
||||
- **普攻 6006 强化普攻** → lv2:10% 概率冰冻
|
||||
- **大招 6150 寒冰箭**:6 支箭各 150% 伤害,每支 30% 概率冰冻 → lv8 200% → lv16 250%(冰冻率恒 30%)
|
||||
- **攻击触发 6401 攻击强化**(lv4):普攻 3 次后 50% 概率(保底 +20),**全队永久攻击 +2%**
|
||||
- **lv12 鹰眼锁定**:AP +50%
|
||||
- 备注:手动增量 ap+30,lv1 AP 62 为全英雄最高普攻基数(见待确认点 ③)
|
||||
|
||||
### 5015 毒箭猎手(远程·射手)
|
||||
|
||||
**lv1:HP 290 / AP 32 / DEF 10** | 攻速 1.05s | 大招 CD 8s
|
||||
> 定位:毒伤 DoT 持续消耗型远程C
|
||||
|
||||
- **普攻 6007 淬毒箭** → lv2:10% 概率击退
|
||||
- **大招 6150 万箭齐发·毒**:150% 伤害,50% 中毒(每 0.5s 30 伤害/5s,可叠 5 层)→ lv8 200%/100%/60/5s → lv16 250%/100%/100/7s
|
||||
- **攻击触发 6007 蚀骨毒箭**(lv4):普攻 3 次后 50% 概率(保底 +20),追加 80% 伤害且 **必定中毒**(40/跳)
|
||||
- **lv12 剧毒淬炼**:AP +50%
|
||||
|
||||
### 5007 击退火女(远程·法师)
|
||||
|
||||
**lv1:HP 275 / AP 42 / DEF 10** | 攻速 1.20s | 大招 CD 8s
|
||||
> 定位:烈焰击退 + 攻击光环,法系压场
|
||||
|
||||
- **普攻 6010 紫珠** → lv2:20% 概率击退
|
||||
- **大招 6200 火焰喷射**:250% 伤害 + 50% 暴击 + 击退 → lv8 350% → lv16 450%/4 个火球(升档后暴击加成降为 0,见待确认点 ④)
|
||||
- **光环 7002 攻击光环(lv4)**:全队攻击 +15%
|
||||
- **lv12 奥术共鸣**:AP +50%
|
||||
|
||||
### 5012 疾风法师(远程·法师)
|
||||
|
||||
**lv1:HP 280 / AP 32 / DEF 10** | 攻速 1.05s | 大招 CD 8s
|
||||
> 定位:攻速 buff + 攻速光环,加速大师
|
||||
|
||||
- **普攻 6009 蓝珠** → lv2:10% 概率自身攻速 +30%(6507 攻速爆发)
|
||||
- **大招 6201 飓风**:2 道飓风各 100% 伤害,每道 20% 概率全队攻速 +20% → lv8 3 道/25%/+25% → lv16 4 道/30%/+30%
|
||||
- **光环 7006 攻速光环(lv4)**:全队攻速 +10%
|
||||
- **lv12 奥术共鸣**:AP +50%
|
||||
|
||||
### 5017 碎甲术士(远程·法师)
|
||||
|
||||
**lv1:HP 280 / AP 42 / DEF 10** | 攻速 1.05s | 大招 CD 8s
|
||||
> 定位:破甲 + 穿透光环,物理队核心增伤位
|
||||
|
||||
- **普攻 6012 蚀甲酸瓶** → lv2:30% 概率破甲(防御 -50%/5s)
|
||||
- **大招 6203 碎甲能量波**:150% 伤害 + 必破甲 -30%/5s → lv8 200%/-50% → lv16 250%/-70%/7s
|
||||
- **光环 7009 穿透光环(lv4)**:全队穿透概率 +10%
|
||||
- **lv12 奥术共鸣**:AP +50%
|
||||
|
||||
### 5018 雷暴领主(远程·法师)
|
||||
|
||||
**lv1:HP 270 / AP 52 / DEF 10** | 攻速 0.90s(快速)| 大招 CD 8s
|
||||
> 定位:雷暴 AOE + 麻痹控场,法系主C
|
||||
|
||||
- **普攻 6013 召唤闪电** → lv2:15% 概率麻痹(技能 CD 增长减慢 50%,持续 5s)
|
||||
- **大招 6204 雷霆裂空**:150% 伤害,50% 麻痹 → lv8 200%/70% → lv16 250%/100% 可多次命中
|
||||
- **光环 7024 命中光环(lv4)**:全队命中 +10%
|
||||
- **lv12 奥术共鸣**:AP +50%
|
||||
|
||||
### 5008 团疗奶爸(远程·辅助)
|
||||
|
||||
**lv1:HP 290 / AP 52 / DEF 15** | 攻速 1.05s | 大招 CD 10s(稀有)
|
||||
> 定位:全体治疗 + 团队续航
|
||||
|
||||
- **普攻 6011 绿瓶** → lv2:120% 伤害
|
||||
- **大招 6302 治疗**:全队回复攻击 30% 生命 → lv8 40% → lv16 50% + 全队防御 +20/5s(7024 防御爆发词条)
|
||||
- **光环 7001 战后恢复(lv4)**:回合结束休整回血 +20%
|
||||
- **lv12 守护之心**:HP +50%
|
||||
|
||||
### 5013 生命哥(远程·辅助)
|
||||
|
||||
**lv1:HP 280 / AP 32 / DEF 15** | 攻速 1.05s | 大招 CD 10s(稀有)
|
||||
> 定位:全体生命上限 + 反伤护盾
|
||||
|
||||
- **普攻 6004** → lv2:120% 伤害
|
||||
- **大招 6517 生命护盾**:全队最大生命 +20%/5s(3 人)→ lv8 +25%/10s → lv16 +30%/10s
|
||||
- **攻击触发 6414 反伤比例**(lv4):普攻 3 次后 30% 概率(保底 +15),全队比例反伤 +10%
|
||||
- **lv12 守护之心**:HP +50%
|
||||
|
||||
---
|
||||
|
||||
## 四、英雄速查总表(lv1 基础值)
|
||||
|
||||
| UUID | 名称 | 定位 | 职业 | HP | AP | DEF | 普攻间隔 | 大招CD | 核心机制 |
|
||||
|---|---|---|---|---|---|---|---|---|---|
|
||||
| 5001 | 叠甲骑士 | 近战 | 坦克 | 620 | 20 | 60 | 1.20s | 10s | 自身护盾/受击叠防 |
|
||||
| 5002 | 易伤剑仙 | 近战 | 战士 | 565 | 42 | 35 | 1.20s | 8s | 易伤放大 |
|
||||
| 5003 | 眩晕暴击哥 | 近战 | 战士 | 565 | 42 | 35 | 1.20s | 8s | 必晕+暴击 |
|
||||
| 5004 | 刀刀暴击 | 中程 | 刺客 | 560 | 52 | 10 | 0.90s | 6s | 暴击流主C |
|
||||
| 5005 | 出血贼 | 中程 | 刺客 | 560 | 52 | 10 | 0.90s | 6s | 出血DoT |
|
||||
| 5006 | 冻箭哥 | 远程 | 射手 | 280 | 62 | 10 | 1.05s | 8s | 冰冻控场 |
|
||||
| 5007 | 击退火女 | 远程 | 法师 | 275 | 42 | 10 | 1.20s | 8s | 击退+攻击光环 |
|
||||
| 5008 | 团疗奶爸 | 远程 | 辅助 | 290 | 52 | 15 | 1.05s | 10s | 全体治疗 |
|
||||
| 5009 | 甲虫领主 | 近战 | 坦克 | 600 | 20 | 50 | 1.20s | 8s | 受击自疗 |
|
||||
| 5010 | 火箭哥 | 中程 | 射手 | 280 | 32 | 10 | 0.90s | 6s | 弹幕减攻 |
|
||||
| 5011 | 控血大师 | 近战 | 坦克 | 600 | 20 | 50 | 1.05s | 10s | 生命上限成长 |
|
||||
| 5012 | 疾风法师 | 远程 | 法师 | 280 | 32 | 10 | 1.05s | 8s | 攻速buff+光环 |
|
||||
| 5013 | 生命哥 | 远程 | 辅助 | 280 | 32 | 15 | 1.05s | 10s | 生命上限+反伤 |
|
||||
| 5014 | 闪避哥 | 近战 | 战士 | 560 | 22 | 30 | 1.05s | 8s | 强闪避 |
|
||||
| 5015 | 毒箭猎手 | 远程 | 射手 | 290 | 32 | 10 | 1.05s | 8s | 毒伤DoT |
|
||||
| 5016 | 连珠神射 | 中程 | 射手 | 280 | 42 | 10 | 0.75s | 6s | 极速暴击爆发 |
|
||||
| 5017 | 碎甲术士 | 远程 | 法师 | 280 | 42 | 10 | 1.05s | 8s | 破甲+穿透光环 |
|
||||
| 5018 | 雷暴领主 | 远程 | 法师 | 270 | 52 | 10 | 0.90s | 8s | 雷暴+麻痹 |
|
||||
|
||||
---
|
||||
|
||||
## 五、官方推荐阵容(HeroComboSet)
|
||||
|
||||
| ID | 阵容 | 英雄 | 配合思路 |
|
||||
|---|---|---|---|
|
||||
| 8001 | 暴击爆发流 | 5001 + 5016 + 5004 | 叠甲骑士前排抗伤,连珠神射暴击光环覆盖全队+极速箭雨压场,刀刀暴击近战收割 |
|
||||
| 8002 | 冰雷控制流 | 5003 + 5006 + 5018 | 开山斧必晕 + 寒冰箭冰冻链 + 雷霆麻痹,三控交替 |
|
||||
| 8003 | 铁桶续航流 | 5009 + 5011 + 5008 | 受击自疗前排 + 全队永久生命成长 + 全体治疗,持久战 |
|
||||
| 8004 | 破甲压制流 | 5001 + 5017 + 5010 | 双通道破甲+穿透光环放大物理伤害,五箭弹幕挂减攻 |
|
||||
| 8005 | 光环覆盖流 | 5014 + 5007 + 5012 | 闪避/攻击/攻速三光环全覆盖 |
|
||||
| 8006 | 易伤消耗流 | 5002 + 5005 + 5008 | 易伤放大出血 DoT,治疗保前排磨血 |
|
||||
|
||||
---
|
||||
|
||||
## 六、待数值设计师确认的配置口径疑问
|
||||
|
||||
1. **5014 光环语义不一致**:词条 uuid=7023,FieldSkillSet 7023 名称为"闪避光环",但 BuffSet 7023 为"防御强化"(防御 +50/10s)。需确认实际生效语义。
|
||||
2. **5005 大招 lv16 文案与配置不符**:desc 写"附带 50% 概率麻痹",但 overrides 未注入 `para` 字段。
|
||||
3. **5006 冻箭哥 AP 基数偏高**:手动增量 ap+30(lv1 AP 62),显著高于其他远程英雄(32~52),需确认是否刻意。
|
||||
4. **5007 大招升档暴击消失**:lv1 档 crt:50,lv8/lv16 档 crt:0,升档后暴击加成消失,需确认是否刻意。
|
||||
5. **触发技解锁等级**:统一 **lv4** 激活(atking/atked/fstart/dead/field 触发类无品质门槛)。heroSet 头注释原为 lv6,已修正为 lv4 与实际配置对齐。
|
||||
6. **品质体系已停用**:全部英雄 rarity 统一为 1,不再区分品质;`getHeroQualityCoef` 保留但恒为 1.00。卡池费用统一 5、抽卡权重统一 40。若未来重启品质体系,仅影响 lv1 初始基础属性(相邻差 5%),不影响技能解锁/光环/属性补偿。
|
||||
|
||||
---
|
||||
|
||||
## 附录 A、技能底座表(SkillSet)
|
||||
|
||||
> 数值说明:`ap` 对伤害/治疗技能为攻击力百分比,对护盾(6301)为生命最大值百分比,对永久强化(64xx)为修饰数值;`hit_count` 对伤害技能为弹道穿透数,对辅助技能为作用目标数。
|
||||
|
||||
### A1. 单体普攻底座(6001~6013)
|
||||
|
||||
| UUID | 名称 | 弹道 | ap% | 穿透 | 附加语义 | 使用英雄 |
|
||||
|---|---|---|---|---|---|---|
|
||||
| 6001 | 飞剑 | 近战贝塞尔 | 100 | 1 | 可附加易伤 | 5002(触发技) |
|
||||
| 6002 | 匕首 | 近战贝塞尔 | 100 | 1 | 可附加出血/暴击 | 5004、5005 |
|
||||
| 6004 | 攻击 | 近战碰撞 | 100 | 1 | 默认 100% 击退(bck_chance=100) | 5001/5002/5003/5009/5011/5013/5014 |
|
||||
| 6006 | 射击 | 远程箭 | 100 | 1 | 可附加冰冻/暴击 | 5006、5010 |
|
||||
| 6007 | 蓝箭 | 远程箭 | 100 | 1 | 可附加击退/中毒 | 5015 |
|
||||
| 6008 | 红箭 | 远程箭 | 100 | 1 | 可附加追射/暴击 | 5010(触发技)、5016 |
|
||||
| 6009 | 蓝珠 | 近战弹道 | 100 | 1 | 可附加攻速 proc | 5012 |
|
||||
| 6010 | 紫珠 | 近战弹道 | 100 | 1 | 可附加击退 | 5007 |
|
||||
| 6011 | 绿瓶 | 近战弹道 | 100 | 1 | — | 5008 |
|
||||
| 6012 | 红瓶 | 近战弹道 | 100 | 1 | 可附加破甲 | 5017 |
|
||||
| 6013 | 闪电 | 固定终点落雷 | 100 | 1 | 可附加麻痹 | 5018 |
|
||||
|
||||
### A2. 群体大招底座(6100~6204)
|
||||
|
||||
| UUID | 名称 | 类型 | ap% | 穿透/弹道 | 附加语义 | 使用英雄 |
|
||||
|---|---|---|---|---|---|---|
|
||||
| 6100 | 寒冰斩 | 近战 | 150 | 5 | 可叠出血、自增益 | 5014 |
|
||||
| 6101 | 裂气斩 | 近战 | 150 | 5 | 可叠击退、易伤 | 5002 |
|
||||
| 6102 | 火焰斩 | 近战 | 150 | 5 | 可叠暴击、proc 治疗 | 5009 |
|
||||
| 6103 | 闪电斩 | 近战 | 150 | 5 | 可叠自身增益 | 5011 |
|
||||
| 6104 | 开天斩 | 远程范围 | 300 | 6 | 可叠击晕增强 | 5003 |
|
||||
| 6150 | 万箭齐发·冰 | 远程箭 | 100 | 1 | 6 支蓝箭底座 | 5004/5005/5006/5015 |
|
||||
| 6151 | 万箭齐发·火 | 远程箭 | 100 | 1 | 6 支红箭底座 | 5010、5016 |
|
||||
| 6200 | 火球术 | 远程 | 100 | 1 | 单发大火球 | 5007 |
|
||||
| 6201 | 飓风 | 远程直线 | 100 | 99 | 穿透飓风,可挂攻速 proc | 5012 |
|
||||
| 6202 | 毒气弹 | 远程直线 | 100 | 1 | 穿透毒气 | 未启用 |
|
||||
| 6203 | 能量波 | 远程直线 | 100 | 1 | 穿透能量波 | 5017 |
|
||||
| 6204 | 雷暴 | 远程直线 | 100 | 99 | 雷暴多段穿透,可附加麻痹 | 5018 |
|
||||
|
||||
### A3. 治疗/护盾底座(6301~6302)
|
||||
|
||||
| UUID | 名称 | kind | ap 语义 | 默认数值 | 使用英雄 |
|
||||
|---|---|---|---|---|---|
|
||||
| 6301 | 护盾 | Shield | 生命最大值 % | 30%、持续 7s | 5001 |
|
||||
| 6302 | 治疗 | Heal | 目标最大生命 × ap% | 300%(底座值,实际由 overrides 覆写) | 5008(大招)、5009(proc/受击触发) |
|
||||
|
||||
### A4. 永久强化底座(6401~6416,buff_type + ap,单次施加)
|
||||
|
||||
| UUID | 名称 | buff_type | 底座 ap | 语义 | 使用英雄 |
|
||||
|---|---|---|---|---|---|
|
||||
| 6401 | 攻击强化 | ap | 5 | 全体攻击永久 +N% | 5005、5006(触发技) |
|
||||
| 6402 | 生命强化 | hp_max | 20 | 全体最大生命永久 +N% | 5011(触发技) |
|
||||
| 6403 | 暴击强化 | critical | 1 | 全体暴击率永久 +N% | 未启用 |
|
||||
| 6404 | 暴伤强化 | critical_damage | 1 | 全体暴伤永久 +N% | 未启用 |
|
||||
| 6405 | 击晕强化 | stun_chance | 1 | 全体击晕概率永久 +N% | 未启用 |
|
||||
| 6406 | 击退强化 | knockback_chance | 10 | 全体击退距离永久 +N% | 未启用 |
|
||||
| 6408 | 穿刺强化 | puncture_chance | 20 | 全体穿刺概率永久 +N% | 未启用 |
|
||||
| 6410 | 冰冻强化 | freeze_chance | 5 | 全体冰冻概率永久 +N% | 未启用 |
|
||||
| 6411 | 溅射强化 | puncture_dmg_bonus | 10 | 全体穿透伤害永久 +N% | 未启用 |
|
||||
| 6412 | 防御强化 | defense | 50 | 全体防御永久 +N 点 | 5001(触发技) |
|
||||
| 6413 | 反伤强化 | thorns_dmg | 10 | 全体固定反伤永久 +N 点 | 未启用 |
|
||||
| 6414 | 反伤比例强化 | thorns_rate | 10 | 全体比例反伤永久 +N% | 5013(触发技) |
|
||||
| 6415 | 闪避强化 | dodge | 5 | 全体闪避永久 +N% | 未启用 |
|
||||
| 6416 | 命中强化 | accuracy | 5 | 全体命中永久 +N% | 未启用 |
|
||||
|
||||
### A5. 计时强化底座(6501~6519,走 timed_buff_id → BuffList,默认 5s)
|
||||
|
||||
| UUID | 名称 | 关联 Buff | buff_type | 底座语义 | 使用英雄 |
|
||||
|---|---|---|---|---|---|
|
||||
| 6501 | 复活 | — | — | ap=复活生命百分比(dead 触发用) | 未启用 |
|
||||
| 6502 | 计时回血 | 7010 再生 | hp | 全体每秒回血 5s | 5011(普攻 proc) |
|
||||
| 6503 | 攻击爆发 | 7001 攻击强化 | ap | 全体攻击 +N% 5s | 未启用 |
|
||||
| 6504 | 暴击爆发 | 7012 暴击爆发 | critical | 全体暴击 +N% 5s | 5003、5004(触发技) |
|
||||
| 6505 | 击退爆发 | 7013 击退爆发 | knockback_chance | 全体击退距离 +N% 5s | 未启用 |
|
||||
| 6506 | 穿透爆发 | 7014 穿透爆发 | puncture_chance | 全体穿透 +N% 5s | 未启用 |
|
||||
| 6507 | 攻速爆发 | 7015 攻速爆发 | speed | 全体攻速 +N% 5s | 5012(普攻/大招 proc) |
|
||||
| 6509 | 击晕爆发 | 7017 击晕爆发 | stun_chance | 全体击晕概率 +N% 5s | 未启用 |
|
||||
| 6510 | 击晕抗性 | 7018 击晕抗性 | stun_res | 全体击晕抗性 +N% 5s | 未启用 |
|
||||
| 6511 | 冰冻抗性 | 7019 冰冻抗性 | freeze_res | 全体冰冻抗性 +N% 5s | 未启用 |
|
||||
| 6512 | 溅射爆发 | 7022 穿透伤害爆发 | puncture_dmg_bonus | 全体穿透伤害 +N% 5s | 未启用 |
|
||||
| 6513 | 防御爆发 | 7024 防御爆发 | defense | 全体防御 +N 点 5s | 未启用 |
|
||||
| 6514 | 反伤护盾 | 7027 荆棘 | thorns_dmg | 全体固定反伤 +N 点 5s | 未启用 |
|
||||
| 6515 | 反伤比例 | 7028 荆棘比例 | thorns_rate | 全体比例反伤 +N% 5s | 未启用 |
|
||||
| 6516 | 次级反伤 | — | — | 空底座,效果由引用处 overrides 注入 | 未启用 |
|
||||
| 6517 | 生命爆发 | 7029 生命爆发 | hp_max | 全体最大生命 +N% 5s | 5013(大招) |
|
||||
| 6518 | 闪避爆发 | 7030 闪避爆发 | dodge | 全体闪避 +N% 5s | 5014(大招经 7030) |
|
||||
| 6519 | 命中爆发 | 7031 命中强化 | accuracy | 全体命中 +N% 5s | 未启用 |
|
||||
|
||||
## 附录 B、Buff/Debuff 底座表(BuffList)
|
||||
|
||||
### B1. 敌方减益(Debuff/Control)
|
||||
|
||||
| ID | 名称 | 类别 | 默认效果 | 持续 | 叠层 | 使用英雄 |
|
||||
|---|---|---|---|---|---|---|
|
||||
| 7002 | 易伤 | Debuff | 受伤附加 10 点固定伤害 | 5s | 5 | 5002 |
|
||||
| 7003 | 冰冻 | Control | 无法行动 | 2s | 1 | 5006 |
|
||||
| 7004 | 击晕 | Control | 无法行动 1s,CD 削减 20% 并停滞 | 1s | 1 | 5003 |
|
||||
| 7005 | 中毒 | Debuff | 每 0.5s 10 点 + AP 30% 伤害 | 5s | 5 | 5015 |
|
||||
| 7006 | 减攻 | Debuff | 攻击 -10% | 5s | 1 | 5010 |
|
||||
| 7007 | 出血 | Debuff | 每 0.5s 微量伤害,每层被暴击率 +1% | 5s | 5 | 5005 |
|
||||
| 7008 | 破甲 | Debuff | 防御 -50% | 5s | 1 | 5017 |
|
||||
| 7025 | 麻痹 | Control | 技能 CD 增长减慢 50% | 5s | 1 | 5018 |
|
||||
|
||||
### B2. 友方增益(Buff,计时类默认 5s)
|
||||
|
||||
| ID | 名称 | 效果 | 使用英雄 |
|
||||
|---|---|---|---|
|
||||
| 7001 | 攻击强化 | 攻击 +5%,10s | 6503 底座 |
|
||||
| 7010 | 再生 | 每 0.5s 回 10 血,5s | 5011(6502) |
|
||||
| 7012 | 暴击爆发 | 暴击率 +30% | 5003/5004(6504) |
|
||||
| 7013 | 击退爆发 | 击退距离 +30% | 6505 底座 |
|
||||
| 7014 | 穿透爆发 | 穿透概率 +30% | 6506 底座 |
|
||||
| 7015 | 攻速爆发 | 攻速 +40% | 5012(6507) |
|
||||
| 7017 | 击晕爆发 | 击晕概率 +30% | 6509 底座 |
|
||||
| 7018 | 击晕抗性 | 击晕抗性 +50% | 6510 底座 |
|
||||
| 7019 | 冰冻抗性 | 冰冻抗性 +50% | 6511 底座 |
|
||||
| 7020 | 暴伤爆发 | 暴伤 +30% | 6404/未启用 |
|
||||
| 7021 | 冰冻概率爆发 | 冰冻概率 +5% | 未启用 |
|
||||
| 7022 | 穿透伤害爆发 | 穿透伤害 +30% | 6512 底座 |
|
||||
| 7023 | 防御强化 | 防御 +50,10s | 5014 光环词条(语义存疑①) |
|
||||
| 7024 | 防御爆发 | 防御 +100 | 5008 大招 lv16 |
|
||||
| 7027 | 荆棘 | 固定反伤 10 点,可叠 5 层 | 6514 底座 |
|
||||
| 7028 | 荆棘比例 | 比例反伤 10%,可叠 3 层 | 6515 底座 |
|
||||
| 7029 | 生命爆发 | 最大生命 +30% 并等量回血 | 5013(6517)、5011(6103) |
|
||||
| 7030 | 闪避爆发 | 闪避 +20% | 5014(6100) |
|
||||
| 7031 | 命中强化 | 命中 +20% | 6519 底座 |
|
||||
|
||||
## 附录 C、驻场光环底座表(FieldSkillSet)
|
||||
|
||||
| UUID | 名称 | 类型 | 数值口径 | 使用英雄 |
|
||||
|---|---|---|---|---|
|
||||
| 7001 | 战后恢复 | WaveHeal | 比例(0.2=+20%) | 5008 |
|
||||
| 7002 | 攻击光环 | HeroAtk | 比例(0.15=+15%) | 5007 |
|
||||
| 7003 | 击晕光环 | HeroStun | 比例 | 未启用 |
|
||||
| 7004 | 暴击光环 | HeroCrit | 比例(0.1=+10%) | 5016 |
|
||||
| 7005 | 暴伤光环 | HeroCritDamage | 比例 | 未启用 |
|
||||
| 7006 | 攻速光环 | HeroSpeed | 比例(0.1=+10%) | 5012 |
|
||||
| 7007 | 生命光环 | HeroHp | 比例 | 未启用 |
|
||||
| 7009 | 穿透光环 | HeroPuncture | 比例(0.1=+10%) | 5017 |
|
||||
| 7014 | 召唤光环 | SummonCount | 整数次数 | 未启用 |
|
||||
| 7015 | 死亡光环 | DeadCount | 整数次数 | 未启用 |
|
||||
| 7016 | 鼓舞光环 | StartCount | 整数次数 | 未启用 |
|
||||
| 7018 | 连击光环 | AtkCount | 整数次数 | 未启用 |
|
||||
| 7019 | 受击光环 | BeAtkCount | 整数次数 | 未启用 |
|
||||
| 7020 | 溅射光环 | HeroPunctureDmg | 百分点 | 未启用 |
|
||||
| 7021 | 反伤光环 | HeroThornsDmg | 整数 | 未启用 |
|
||||
| 7022 | 反伤比例光环 | HeroThornsRate | 百分点 | 未启用 |
|
||||
| 7023 | 闪避光环 | HeroDodge | 百分点(10=+10%) | 5014(语义存疑①) |
|
||||
| 7024 | 命中光环 | HeroHit | 百分点(10=+10%) | 5018 |
|
||||
|
||||
> 注:BuffList 与 FieldSkillSet 共用 7000 号段但语义独立——BuffList 是计时/战斗内修饰,FieldSkillSet 是驻场光环元数据;同一 uuid(如 7023/7024)在两表含义不同,配置时需按引用位置区分。
|
||||
6
put/.gitignore
vendored
6
put/.gitignore
vendored
@@ -1,4 +1,8 @@
|
||||
node_modules
|
||||
dist
|
||||
*.local
|
||||
.DS_Store
|
||||
# 环境变量含数据库连接串,禁止提交(参考 server/.env.example)
|
||||
.env
|
||||
# 线上设计版部署所需的产物需提交:web/dist、server/data/meta.json(勿忽略)
|
||||
!web/dist
|
||||
!web/dist/**
|
||||
|
||||
89
put/README.md
Normal file
89
put/README.md
Normal file
@@ -0,0 +1,89 @@
|
||||
# hero_set — 英雄配置编辑器
|
||||
|
||||
英雄数值/技能/触发/光环的可视化配置工具。数据存储在 **MongoDB**,编辑器产出可写回游戏工程的 `heroSet.ts` 与 `英雄设计表.csv`。
|
||||
|
||||
## 双版本架构
|
||||
|
||||
| | 项目开发版(local) | 线上设计版(remote) |
|
||||
|---|---|---|
|
||||
| 使用人 | 开发者 | 数值设计人员 |
|
||||
| 数据 | 同一个线上 MongoDB | 同一个线上 MongoDB |
|
||||
| meta 底座(技能/Buff) | 从游戏工程 TS 实时编译 | `server/data/meta.json` 快照(需随部署发布) |
|
||||
| 英雄/预设 增删改 | ✅ | ✅(库结构版本更高时只读) |
|
||||
| 写 heroSet.ts / 导出 CSV | ✅ | ❌(接口返回 403,按钮隐藏) |
|
||||
|
||||
**版本闸门**:库中 `meta` 集合存 `schemaVersion`(只升不降)。线上版启动版本低于库版本时,保存接口返回 409、前端禁用保存——防止旧结构覆盖新数据。结构有破坏性变更时:本地 `SCHEMA_VERSION` +1 → `npm run push-meta` → 重新部署线上版。
|
||||
|
||||
## 目录
|
||||
|
||||
```
|
||||
put/
|
||||
├── server/ # Express API(单服务托管 API + 前端静态页)
|
||||
│ ├── index.js # 接口与模式/版本闸门
|
||||
│ ├── db.js # MongoDB 存储层
|
||||
│ ├── data/ # meta.json 快照(remote 模式必需)
|
||||
│ ├── scripts/
|
||||
│ │ ├── migrate-to-mongo.js # 一次性:JSON 文件 → Mongo
|
||||
│ │ └── push-meta.js # 开发版:生成 meta 快照 + 抬升库版本
|
||||
│ └── .env.example
|
||||
└── web/ # Vue3 + Element Plus 前端
|
||||
└── dist/ # 构建产物(remote 模式由 server 托管,需提交)
|
||||
```
|
||||
|
||||
## 部署线上设计版(给 AI 部署智能体)
|
||||
|
||||
前置:Node.js ≥ 18;可访问的 MongoDB 连接串。
|
||||
|
||||
```bash
|
||||
# 1. 拉代码
|
||||
git clone git@git.eoxnet.com:pan/hero_set.git && cd hero_set
|
||||
|
||||
# 2. 配置环境变量
|
||||
cp server/.env.example server/.env
|
||||
# 编辑 server/.env:
|
||||
# MODE=remote
|
||||
# MONGO_URL=mongodb://user:pass@host:27017
|
||||
# MONGO_DB=heroconfig
|
||||
# PORT=3001
|
||||
|
||||
# 3. 构建前端
|
||||
cd web && npm ci && npm run build && cd ..
|
||||
# 注意:web/dist 与 server/data/meta.json 必须存在(均已随仓库提交,若仓库有更新请重新构建)
|
||||
|
||||
# 4. 启动(server 自动托管 web/dist,单服务即可)
|
||||
cd server && npm ci && npm start
|
||||
# 访问 http://<host>:3001
|
||||
```
|
||||
|
||||
进程守护(可选):`pm2 start index.js --name hero-set --cwd server`
|
||||
|
||||
## 开发版工作流(本地)
|
||||
|
||||
```bash
|
||||
# server/.env:MODE=local + 同一个 MONGO_URL
|
||||
cd server && npm ci && npm run dev # API :3001
|
||||
cd web && npm ci && npm run dev # 前端 :4004(已代理 /api → :3001)
|
||||
```
|
||||
|
||||
- **保存到数据库** → 全量覆盖 MongoDB(按 uuid upsert + 删除多余)
|
||||
- **写入 heroSet.ts** → 渲染进 `assets/script/game/common/config/heroSet.ts` 的 `@hero-setup:heroes-begin/end` 标记区域
|
||||
- **技能/底座结构变更后**:`SCHEMA_VERSION` +1 → `npm run push-meta`(需 dev 服务已启动)→ 提交并重新部署线上版
|
||||
|
||||
## 环境变量
|
||||
|
||||
| 变量 | 默认 | 说明 |
|
||||
|---|---|---|
|
||||
| `MODE` | `local` | `local` 开发版 / `remote` 线上设计版 |
|
||||
| `MONGO_URL` | — | 必填,MongoDB 连接串 |
|
||||
| `MONGO_DB` | `heroconfig` | 库名 |
|
||||
| `PORT` | `3001` | 服务端口 |
|
||||
| `HOST` | `0.0.0.0` | 监听地址;容器部署必须保持 0.0.0.0 并映射端口(如 `docker run -p 3001:3001`) |
|
||||
| `SCHEMA_VERSION` | `1` | 数据结构版本,破坏性变更时 +1 |
|
||||
|
||||
前端单独部署(不经 server 托管)时,`web/.env` 配 `VITE_API_BASE=http://<host>:3001`。
|
||||
|
||||
## 数据库结构(MongoDB · heroconfig)
|
||||
|
||||
- `heroes`:每个英雄一条文档,`uuid` 唯一索引
|
||||
- `templates`:`_id='presets'` 单文档(triggerPresets / fieldPresets)
|
||||
- `meta`:`_id='version'` 单文档(schemaVersion)
|
||||
166
put/package-lock.json
generated
166
put/package-lock.json
generated
@@ -527,6 +527,15 @@
|
||||
"integrity": "sha512-T7jf+5zgsZHwNJ4lvQ7/aezbyk0nNX+zJVWpmHA7VYsEx7a7qr5Rg5IbtJFqkgze5Y2sruq1RUY8Q837Od7iFw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@mongodb-js/saslprep": {
|
||||
"version": "1.5.5",
|
||||
"resolved": "https://registry.npmjs.org/@mongodb-js/saslprep/-/saslprep-1.5.5.tgz",
|
||||
"integrity": "sha512-0PV4mvjGd2Q2/viDvXuoSNzTjQngHvtuWUry1vqvcK4Q/CTeO1zEKMf9set01DMocJnogl/pyNAdvyk+Pe0kQA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"sparse-bitfield": "^3.0.3"
|
||||
}
|
||||
},
|
||||
"node_modules/@napi-rs/lzma-linux-x64-gnu": {
|
||||
"version": "1.5.1",
|
||||
"resolved": "https://registry.npmjs.org/@napi-rs/lzma-linux-x64-gnu/-/lzma-linux-x64-gnu-1.5.1.tgz",
|
||||
@@ -975,6 +984,21 @@
|
||||
"integrity": "sha512-oIQLCGWtcFZy2JW77j9k8nHzAOpqMHLQejDA48XXMWH6tjCQHz5RCFz1bzsmROyL6PUm+LLnUiI4BCn221inxA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/webidl-conversions": {
|
||||
"version": "7.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/webidl-conversions/-/webidl-conversions-7.0.3.tgz",
|
||||
"integrity": "sha512-CiJJvcRtIgzadHCYXw7dqEnMNRjhGZlYK05Mj9OyktqV8uVT8fD2BFOB7S1uwBE3Kj2Z+4UyPmFw/Ixgw/LAlA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/whatwg-url": {
|
||||
"version": "11.0.5",
|
||||
"resolved": "https://registry.npmjs.org/@types/whatwg-url/-/whatwg-url-11.0.5.tgz",
|
||||
"integrity": "sha512-coYR071JRaHa+xoEvvYqvnIHaVqaYrLPbsufM9BF63HkwI5Lgmy2QR8Q5K/lYDYo5AK82wOvSOS0UsLTpTG7uQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/webidl-conversions": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@vitejs/plugin-vue": {
|
||||
"version": "5.2.4",
|
||||
"resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-5.2.4.tgz",
|
||||
@@ -1253,6 +1277,15 @@
|
||||
"npm": "1.2.8000 || >= 1.4.16"
|
||||
}
|
||||
},
|
||||
"node_modules/bson": {
|
||||
"version": "6.10.4",
|
||||
"resolved": "https://registry.npmjs.org/bson/-/bson-6.10.4.tgz",
|
||||
"integrity": "sha512-WIsKqkSC0ABoBJuT1LEX+2HEvNmNKKgnTAyd0fL8qzK4SH2i9NXg+t08YtdZp/V9IZ33cxe3iV4yM0qg8lMQng==",
|
||||
"license": "Apache-2.0",
|
||||
"engines": {
|
||||
"node": ">=16.20.1"
|
||||
}
|
||||
},
|
||||
"node_modules/bytes": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
|
||||
@@ -1495,6 +1528,21 @@
|
||||
"npm": "1.2.8000 || >= 1.4.16"
|
||||
}
|
||||
},
|
||||
"node_modules/dotenv": {
|
||||
"version": "18.0.5",
|
||||
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-18.0.5.tgz",
|
||||
"integrity": "sha512-aBrGvt6KhjxbEnatqMWOMidftwsrCiCvqh1yNIGB9QyF0J+VcWkKDMsvYOEm7ZS82oiV+BT1sTOtIlAmUlTpwQ==",
|
||||
"license": "BSD-2-Clause",
|
||||
"bin": {
|
||||
"dotenv": "dist/index.cjs"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://dotenvx.com"
|
||||
}
|
||||
},
|
||||
"node_modules/dunder-proto": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
|
||||
@@ -2102,6 +2150,12 @@
|
||||
"integrity": "sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/memory-pager": {
|
||||
"version": "1.5.0",
|
||||
"resolved": "https://registry.npmjs.org/memory-pager/-/memory-pager-1.5.0.tgz",
|
||||
"integrity": "sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/merge-descriptors": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz",
|
||||
@@ -2153,6 +2207,62 @@
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/mongodb": {
|
||||
"version": "6.21.0",
|
||||
"resolved": "https://registry.npmjs.org/mongodb/-/mongodb-6.21.0.tgz",
|
||||
"integrity": "sha512-URyb/VXMjJ4da46OeSXg+puO39XH9DeQpWCslifrRn9JWugy0D+DvvBvkm2WxmHe61O/H19JM66p1z7RHVkZ6A==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@mongodb-js/saslprep": "^1.3.0",
|
||||
"bson": "^6.10.4",
|
||||
"mongodb-connection-string-url": "^3.0.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16.20.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@aws-sdk/credential-providers": "^3.188.0",
|
||||
"@mongodb-js/zstd": "^1.1.0 || ^2.0.0",
|
||||
"gcp-metadata": "^5.2.0",
|
||||
"kerberos": "^2.0.1",
|
||||
"mongodb-client-encryption": ">=6.0.0 <7",
|
||||
"snappy": "^7.3.2",
|
||||
"socks": "^2.7.1"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@aws-sdk/credential-providers": {
|
||||
"optional": true
|
||||
},
|
||||
"@mongodb-js/zstd": {
|
||||
"optional": true
|
||||
},
|
||||
"gcp-metadata": {
|
||||
"optional": true
|
||||
},
|
||||
"kerberos": {
|
||||
"optional": true
|
||||
},
|
||||
"mongodb-client-encryption": {
|
||||
"optional": true
|
||||
},
|
||||
"snappy": {
|
||||
"optional": true
|
||||
},
|
||||
"socks": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/mongodb-connection-string-url": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/mongodb-connection-string-url/-/mongodb-connection-string-url-3.0.2.tgz",
|
||||
"integrity": "sha512-rMO7CGo/9BFwyZABcKAWL8UJwH/Kc2x0g72uhDWzG48URRax5TCIcJ7Rc3RZqffZzO/Gwff/jyKwCU9TN8gehA==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@types/whatwg-url": "^11.0.2",
|
||||
"whatwg-url": "^14.1.0 || ^13.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/ms": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
|
||||
@@ -2309,6 +2419,15 @@
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/punycode": {
|
||||
"version": "2.3.1",
|
||||
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
|
||||
"integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/qs": {
|
||||
"version": "6.15.3",
|
||||
"resolved": "https://registry.npmjs.org/qs/-/qs-6.15.3.tgz",
|
||||
@@ -2590,6 +2709,15 @@
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/sparse-bitfield": {
|
||||
"version": "3.0.3",
|
||||
"resolved": "https://registry.npmjs.org/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz",
|
||||
"integrity": "sha512-kvzhi7vqKTfkh0PZU+2D2PIllw2ymqJKujUcyPMd9Y75Nv4nPbGJZXNhxsgdQab2BmlDct1YnfQCguEvHr7VsQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"memory-pager": "^1.0.2"
|
||||
}
|
||||
},
|
||||
"node_modules/statuses": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz",
|
||||
@@ -2669,6 +2797,18 @@
|
||||
"node": ">=0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/tr46": {
|
||||
"version": "5.1.1",
|
||||
"resolved": "https://registry.npmjs.org/tr46/-/tr46-5.1.1.tgz",
|
||||
"integrity": "sha512-hdF5ZgjTqgAntKkklYw0R03MG2x/bSzTtkxmIRw/sTNV8YXsCJ1tfLAX23lhxhHJlEf3CRCOCGGWw3vI3GaSPw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"punycode": "^2.3.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/tree-kill": {
|
||||
"version": "1.2.2",
|
||||
"resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz",
|
||||
@@ -3299,6 +3439,28 @@
|
||||
"resolved": "web",
|
||||
"link": true
|
||||
},
|
||||
"node_modules/webidl-conversions": {
|
||||
"version": "7.0.0",
|
||||
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz",
|
||||
"integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==",
|
||||
"license": "BSD-2-Clause",
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/whatwg-url": {
|
||||
"version": "14.2.0",
|
||||
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-14.2.0.tgz",
|
||||
"integrity": "sha512-De72GdQZzNTUBBChsXueQUnPKDkg/5A5zp7pFDuQAj5UFoENpiACU0wlCvzpAGnTkj++ihpKwKyYewn/XNUbKw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"tr46": "^5.1.0",
|
||||
"webidl-conversions": "^7.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/wrap-ansi": {
|
||||
"version": "7.0.0",
|
||||
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
|
||||
@@ -3360,8 +3522,10 @@
|
||||
"version": "1.0.0",
|
||||
"dependencies": {
|
||||
"cors": "^2.8.5",
|
||||
"dotenv": "^18.0.5",
|
||||
"esbuild": "^0.24.0",
|
||||
"express": "^4.21.2"
|
||||
"express": "^4.21.2",
|
||||
"mongodb": "^6.12.0"
|
||||
}
|
||||
},
|
||||
"web": {
|
||||
|
||||
24
put/server/.env.example
Normal file
24
put/server/.env.example
Normal file
@@ -0,0 +1,24 @@
|
||||
# ---- 运行模式 ----
|
||||
# local = 项目开发版(本地,全功能:写 heroSet.ts / 导出 CSV / push-meta)
|
||||
# remote = 线上设计版(VPS 部署,仅英雄/预设编辑,版本落后时只读)
|
||||
MODE=local
|
||||
|
||||
# ---- MongoDB(两边都要配置,连同一个库)----
|
||||
# 本地 MongoDB 示例:mongodb://127.0.0.1:27017
|
||||
# 带账号密码示例: mongodb://user:password@your-vps-ip:27017
|
||||
# Atlas 示例: mongodb+srv://user:password@cluster0.xxxx.mongodb.net
|
||||
MONGO_URL=mongodb://user:password@your-vps-ip:27017
|
||||
MONGO_DB=heroconfig
|
||||
|
||||
# ---- 服务端口 ----
|
||||
PORT=3001
|
||||
# 监听地址:默认 0.0.0.0(容器/局域网部署必须);仅本机访问可改 127.0.0.1
|
||||
HOST=0.0.0.0
|
||||
|
||||
# ---- 数据结构版本 ----
|
||||
# 英雄/底座结构有破坏性变更时 +1,并执行 npm run push-meta 推送到库中
|
||||
# 线上设计版低于库中版本时将进入只读,需更新部署
|
||||
SCHEMA_VERSION=1
|
||||
|
||||
# ---- 前端(web/.env,仅静态部署时需要;server 托管 dist 时不用配)----
|
||||
# VITE_API_BASE=http://your-vps-ip:3001
|
||||
314
put/server/data/api-skill-guide.md
Normal file
314
put/server/data/api-skill-guide.md
Normal file
@@ -0,0 +1,314 @@
|
||||
# 英雄配置 API 智能体调用规范
|
||||
|
||||
> 本文档面向 **Hermes / OpenClaw** 等智能体 Skill,说明如何通过 HTTP API 配置与修改英雄。
|
||||
> 数据源头为 `heroes.json` / MongoDB,技能/光环/buff 底座定义请阅读 `heroes.json编辑指引.md`。
|
||||
|
||||
---
|
||||
|
||||
## 1. 服务信息
|
||||
|
||||
| 项 | 值 |
|
||||
|---|---|
|
||||
| 开发版地址 | `http://localhost:3001`(`MODE=local`) |
|
||||
| 线上设计版地址 | 部署地址(`MODE=remote`,静态托管 `web/dist`) |
|
||||
| 内容类型 | `application/json` |
|
||||
| 认证 | 无(内网/本地环境) |
|
||||
|
||||
启动服务(在 `put` 目录):
|
||||
```bash
|
||||
npm run dev # 开发版
|
||||
npm run dev:remote # 线上设计版(本地模拟 remote)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2. 核心接口一览
|
||||
|
||||
| 方法 | 路径 | 说明 |
|
||||
|---|---|---|
|
||||
| `GET` | `/api/meta` | 获取底座快照(技能/光环/buff/职业模板/版本) |
|
||||
| `GET` | `/api/heroes` | 获取全部英雄列表 |
|
||||
| `GET` | `/api/heroes/:uuid` | 获取单个英雄完整配置 |
|
||||
| `POST` | `/api/heroes/:uuid` | **新增或覆盖**单个英雄(body 为完整英雄对象) |
|
||||
| `PUT` | `/api/heroes/:uuid` | **局部更新**单个英雄(body 为需修改的字段,顶层浅合并) |
|
||||
| `PATCH` | `/api/heroes/:uuid/skills/:skillUuid` | **技能级局部更新**:支持按 `lv` 合并 `lv_entries`,避免整表替换 `skills` |
|
||||
| `DELETE` | `/api/heroes/:uuid` | 删除单个英雄 |
|
||||
| `POST` | `/api/refresh` | 刷新底座缓存(修改 SkillSet.ts 等后调用) |
|
||||
|
||||
> **版本闸门**:线上设计版(remote)在库中 `schemaVersion` 高于服务内置版本时,写操作返回 `409`,需更新部署。
|
||||
|
||||
---
|
||||
|
||||
## 3. 英雄对象结构(Hero Schema)
|
||||
|
||||
智能体在构造或修改英雄时,必须遵循以下字段规范。
|
||||
|
||||
### 3.1 顶层字段
|
||||
|
||||
| 字段 | 类型 | 必填 | 说明 |
|
||||
|---|---|---|---|
|
||||
| `uuid` | number | 是 | 英雄唯一 ID,5000 段,新增从 5011 起(先 `GET /api/heroes` 查重) |
|
||||
| `name` | string | 是 | 显示名 |
|
||||
| `comment` | string | 否 | 设计说明/机制主题 |
|
||||
| `path` | string | 是 | 美术资源名,需存在 `assets/resources/game/heros/{path}.prefab` |
|
||||
| `rarity` | 1~5 | 是 | 稀有度,影响 lv1 基础属性缩放与卡池费用 |
|
||||
| `roleKey` | string | 是 | 职业:`Tank`/`Warrior`/`Assassin`/`Archer`/`Mage`/`Support` |
|
||||
| `growKey` | string | 是 | 成长曲线,通常与 `roleKey` 一致 |
|
||||
| `typeKey` | string | 是 | 攻击定位:`Melee`/`Mid`/`Long` |
|
||||
| `statBase` | `{hp,ap,def}` | 是 | 相对职业模板的偏移量,惯例 ±5/10/20/30 |
|
||||
| `dis` / `speed` / `dodge` / `accuracy` | number\|null | 否 | 英雄一般 `null`,走默认 |
|
||||
| `skills` | array | 是 | **恰好 2 个**:`[普攻, 大招]`,见 §3.2 |
|
||||
| `atking`/`atked`/`fstart`/`fend`/`dead` | object | 是 | 触发组,见 §3.3;无则写 `{}` |
|
||||
| `field` | array | 是 | 驻场光环档位,见 §3.4;无则写 `[]` |
|
||||
| `bonus` | array | 是 | 额外属性加成,见 §3.5;常规英雄写 `[]` |
|
||||
| `info` | string | 否 | 描述文案 |
|
||||
|
||||
### 3.2 skills 数组(恰好 2 项)
|
||||
|
||||
每项结构:`{uuid, name, cd, cdExpr, overrides, desc, lv_entries}`
|
||||
|
||||
| 字段 | 说明 |
|
||||
|---|---|
|
||||
| `uuid` | 技能底座 uuid,普攻必须 ∈ `ROLE_ATK_SKILL[roleKey]`,大招 ∈ `ROLE_ULT_SKILL[roleKey]` 或 `SUPPORT_ULT` |
|
||||
| `name` | 留空回退底座名;建议起特色名 |
|
||||
| `cd` | 数值冷却(普攻 0.75/0.9/1.05/1.2/1.5;大招 6/7/8/9/10) |
|
||||
| `cdExpr` | 表达式,普攻=`AtkSpeedSet[AtkSpeedLv.X].cd`,大招=`UltCdSet[UltCdLv.X].cd` |
|
||||
| `overrides` | 覆写键值对,见 §3.6 |
|
||||
| `desc` | 描述模板,支持 `{target}` `{ap}` `{dur}` 等占位符 |
|
||||
| `lv_entries` | 升级档位:普攻 1 档 `{lv:2,s_lv:2,...}`;大招 2 档 `{lv:8,s_lv:2,...}`、`{lv:16,s_lv:3,...}` |
|
||||
|
||||
### 3.3 触发组(atking / atked / fstart / fend / dead)
|
||||
|
||||
结构:`{ "<技能uuid字符串>": [条目, ...] }`
|
||||
|
||||
条目:`{lv, s_lv, name, t_num, t_chance?, pity_add?, overrides, desc}`
|
||||
|
||||
| 字段 | 说明 |
|
||||
|---|---|
|
||||
| `lv` | 解锁等级,惯例 **4** |
|
||||
| `s_lv` | 技能等级,惯例 **1** |
|
||||
| `t_num` | 触发间隔:atking/atked 为每 n 次;fstart/fend 固定 **1** |
|
||||
| `t_chance` | 触发概率(0~100),仅 atking/atked 生效,缺省=100 |
|
||||
| `pity_add` | 保底叠加,仅 atking/atked 生效,触发后清零 |
|
||||
| `overrides` | 同技能覆写 |
|
||||
| `desc` | 描述模板,支持 `{t_chance}` `{pity_add}` 占位符 |
|
||||
|
||||
**复活**:在 `dead` 组条目 `overrides` 中配置 `revive_hp`(回血%)+ `revive_count`(次数上限)。
|
||||
|
||||
### 3.4 field 光环
|
||||
|
||||
结构:`[{lv:4, uuids:[{uuid, value, name}], desc?}]`
|
||||
|
||||
- `uuid` 必须 ∈ `FieldSkillSet`(7001~7022 段)
|
||||
- `value` 按光环类型:比例类为小数(如 0.15),次数/固定值类为整数
|
||||
- 解锁等级惯例 **lv4**
|
||||
|
||||
### 3.5 bonus 额外属性
|
||||
|
||||
结构:`[{lv, attrs:{...}, name?, icon?, info?}]`
|
||||
|
||||
- `attrs` 键:`hp`/`ap`/`def`(百分比,基数=基础×品质+成长)、`crt`/`frz`/`stun`/`para`(固定百分点)
|
||||
- 运行时累加所有 `lv ≤ 英雄等级` 的档位
|
||||
- 配 `icon` 的档位在图鉴技能列表最末展示
|
||||
|
||||
### 3.6 overrides 白名单
|
||||
|
||||
可用键:
|
||||
`ap, hit_count, hitcd, crt, frz, stun, para, bck, bck_chance, TGroup, buff_type, timed_buff_id, buff_value, buff_duration, buff_chance, buff_target, timed_debuff_id, debuff_value, debuff_duration, debuff_chance, call_hero, summon_count, is_accel, num, revive_hp, revive_count, proc_skill, icon`
|
||||
|
||||
特殊格式:
|
||||
- `TGroup`:字符串 `"Self"`/`"Ally"`/`"Team"`/`"Enemy"`,导出还原枚举
|
||||
- `buff_target`:数字 0~3(Hit/Self/Ally/Enemy)
|
||||
- `proc_skill`:对象 `{s_uuid, chance?, overrides?}`
|
||||
- `icon`:字符串图标帧名
|
||||
|
||||
**buff/debuff 语义**:
|
||||
- `timed_buff_id`:增益,缺省挂施法者自身(伤害技能)或友方目标(辅助技能)
|
||||
- `timed_debuff_id`:减益,命中后挂被命中者,目标不可覆写
|
||||
- 对敌挂减益必须用 `timed_debuff_id`,误用 `timed_buff_id` 会把减益挂到自己身上
|
||||
|
||||
---
|
||||
|
||||
## 4. 调用示例
|
||||
|
||||
### 4.1 获取底座数据(修改前必读)
|
||||
|
||||
```http
|
||||
GET /api/meta
|
||||
```
|
||||
|
||||
返回包含 `SkillSet`、`FieldSkillSet`、`BuffList`、`HERO_ROLE_BASE`、`HERO_GROW_COEF`、`AtkSpeedSet`、`HeroDisVal` 等。
|
||||
|
||||
### 4.2 查询全部英雄
|
||||
|
||||
```http
|
||||
GET /api/heroes
|
||||
```
|
||||
|
||||
### 4.3 查询单个英雄
|
||||
|
||||
```http
|
||||
GET /api/heroes/5001
|
||||
```
|
||||
|
||||
### 4.4 新增英雄(完整对象)
|
||||
|
||||
```http
|
||||
POST /api/heroes/5011
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"uuid": 5011,
|
||||
"name": "烈焰法师",
|
||||
"comment": "群体火伤+燃烧",
|
||||
"path": "mage_fire",
|
||||
"rarity": 4,
|
||||
"roleKey": "Mage",
|
||||
"growKey": "Mage",
|
||||
"typeKey": "Long",
|
||||
"statBase": { "hp": -5, "ap": 30, "def": 0 },
|
||||
"dis": null,
|
||||
"speed": null,
|
||||
"dodge": null,
|
||||
"accuracy": null,
|
||||
"skills": [
|
||||
{
|
||||
"uuid": 6009,
|
||||
"name": "火球术",
|
||||
"cd": 1.2,
|
||||
"cdExpr": "AtkSpeedSet[AtkSpeedLv.Slow].cd",
|
||||
"overrides": { "ap": 120 },
|
||||
"desc": "对{target}造成{ap}%伤害",
|
||||
"lv_entries": [
|
||||
{ "lv": 2, "s_lv": 2, "overrides": { "ap": 150 }, "desc": "造成{ap}%伤害" }
|
||||
]
|
||||
},
|
||||
{
|
||||
"uuid": 6200,
|
||||
"name": "烈焰风暴",
|
||||
"cd": 8,
|
||||
"cdExpr": "UltCdSet[UltCdLv.Normal].cd",
|
||||
"overrides": { "ap": 200, "timed_debuff_id": 7002, "debuff_value": 30, "debuff_chance": 50 },
|
||||
"desc": "对全体敌人造成{ap}%伤害,{debuff_chance}%附加燃烧",
|
||||
"lv_entries": [
|
||||
{ "lv": 8, "s_lv": 2, "overrides": { "ap": 250 }, "desc": "造成{ap}%伤害" },
|
||||
{ "lv": 16, "s_lv": 3, "overrides": { "ap": 350 }, "desc": "造成{ap}%伤害" }
|
||||
]
|
||||
}
|
||||
],
|
||||
"atking": {},
|
||||
"atked": {},
|
||||
"fstart": {},
|
||||
"fend": {},
|
||||
"dead": {},
|
||||
"field": [],
|
||||
"bonus": [],
|
||||
"info": "掌控火焰的法师"
|
||||
}
|
||||
```
|
||||
|
||||
### 4.5 局部修改英雄(如只改大招数值)
|
||||
|
||||
```http
|
||||
PUT /api/heroes/5011
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"skills": [
|
||||
{ "uuid": 6009, "name": "火球术", "cd": 1.2, "cdExpr": "AtkSpeedSet[AtkSpeedLv.Slow].cd", "overrides": { "ap": 120 }, "desc": "对{target}造成{ap}%伤害", "lv_entries": [{ "lv": 2, "s_lv": 2, "overrides": { "ap": 150 }, "desc": "造成{ap}%伤害" }] },
|
||||
{ "uuid": 6200, "name": "烈焰风暴", "cd": 8, "cdExpr": "UltCdSet[UltCdLv.Normal].cd", "overrides": { "ap": 250, "timed_debuff_id": 7002, "debuff_value": 50, "debuff_chance": 80 }, "desc": "对全体敌人造成{ap}%伤害,{debuff_chance}%附加燃烧", "lv_entries": [{ "lv": 8, "s_lv": 2, "overrides": { "ap": 300 }, "desc": "造成{ap}%伤害" }, { "lv": 16, "s_lv": 3, "overrides": { "ap": 400 }, "desc": "造成{ap}%伤害" }] }
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
> **注意**:`PUT` 是**顶层字段浅合并**。若修改 `skills` 数组,必须传入**完整的新数组**(不能只传被修改的技能对象)。若只需改某个技能的局部字段,请用 `PATCH /api/heroes/:uuid/skills/:skillUuid`(见 §4.7)。
|
||||
|
||||
### 4.6 删除英雄
|
||||
|
||||
```http
|
||||
DELETE /api/heroes/5011
|
||||
```
|
||||
|
||||
### 4.7 技能级局部更新(推荐智能体使用)
|
||||
|
||||
当只需要修改某个技能的局部字段(如调整 lv8 档位的 ap 值)时,使用技能级 PATCH,避免整表替换 `skills` 数组。
|
||||
|
||||
**合并规则**:
|
||||
- `name`/`cd`/`cdExpr`/`desc`:存在则直接覆盖
|
||||
- `overrides`:与现有 `overrides` **浅合并**(不是替换)
|
||||
- `lv_entries`:按 `lv` 合并——同 `lv` 更新该档(`overrides` 浅合并),不同 `lv` 新增
|
||||
|
||||
```http
|
||||
PATCH /api/heroes/5011/skills/6200
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"overrides": { "ap": 280 },
|
||||
"lv_entries": [
|
||||
{ "lv": 8, "overrides": { "ap": 320 } },
|
||||
{ "lv": 20, "s_lv": 4, "overrides": { "ap": 500 }, "desc": "造成{ap}%伤害" }
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
**效果**:
|
||||
- 基础 `overrides.ap` 从 250 变为 280
|
||||
- `lv_entries` 中 `lv:8` 档的 `overrides.ap` 从 300 变为 320(其他字段保留)
|
||||
- `lv_entries` 中新增 `lv:20` 档
|
||||
|
||||
**对比:三种修改方式的选择**
|
||||
|
||||
| 场景 | 推荐接口 | 原因 |
|
||||
|---|---|---|
|
||||
| 只改英雄名/稀有度/statBase 等顶层字段 | `PUT /api/heroes/:uuid` | 简单直接,不涉及 skills |
|
||||
| 改某个技能的 name/cd/desc/overrides 或某一档 lv_entry | `PATCH /api/heroes/:uuid/skills/:skillUuid` | 避免整表替换 skills,最安全 |
|
||||
| 新增/删除技能、改技能 uuid、大规模重构 | `POST /api/heroes/:uuid`(全量覆盖) | 结构变动大,整表替换更清晰 |
|
||||
|
||||
---
|
||||
|
||||
## 5. 智能体操作流程(推荐)
|
||||
|
||||
1. **读取底座**:`GET /api/meta`,确认技能/光环/buff 可用值与职业模板
|
||||
2. **查询现有英雄**:`GET /api/heroes`,确定新 uuid 不冲突(当前已用 5001~5010)
|
||||
3. **构造英雄对象**:严格遵循 §3 结构,空组写 `{}`,空数组写 `[]`
|
||||
4. **提交**:
|
||||
- 新增/覆盖:`POST /api/heroes/:uuid`
|
||||
- 顶层字段局部修改:`PUT /api/heroes/:uuid`
|
||||
- 技能级局部修改:`PATCH /api/heroes/:uuid/skills/:skillUuid`
|
||||
5. **验证**:`GET /api/heroes/:uuid` 确认数据已写入
|
||||
6. **(开发版)应用**:`POST /api/apply` 将 heroes.json 渲染进 `heroSet.ts`(线上设计版无此权限)
|
||||
|
||||
---
|
||||
|
||||
## 6. 错误码与处理
|
||||
|
||||
| 状态码 | 场景 | 处理 |
|
||||
|---|---|---|
|
||||
| 400 | 参数错误(uuid 非数字、body 非对象/数组、heroes 为空等) | 检查请求格式 |
|
||||
| 403 | 线上设计版调用本地专属接口(如 `/api/apply`) | 切换至开发版或放弃该操作 |
|
||||
| 404 | 英雄不存在 | 先 `GET /api/heroes` 确认 uuid |
|
||||
| 409 | 线上设计版结构版本落后 | 更新部署后再试 |
|
||||
| 500 | 服务端错误(MongoDB 连接失败、文件读写失败等) | 查看服务日志 |
|
||||
|
||||
---
|
||||
|
||||
## 7. 常见陷阱(智能体必读)
|
||||
|
||||
- **不要手改 `heroSet.ts` 英雄区**:`POST /api/apply` 会整体覆盖标记区内容
|
||||
- **新增英雄后必须手动把 uuid 加入 `HeroList`**(`heroSet.ts` 标记区之外),否则英雄不进卡池
|
||||
- **触发组解锁等级是 lv4,大招档位是 lv8+lv16**,不要写 lv6/lv9
|
||||
- **普攻 cdExpr 用 `AtkSpeedSet`,大招 cdExpr 用 `UltCdSet`**,两套体系不可混用
|
||||
- **档位 overrides 与基础 overrides 浅合并**,档位只写变化键,不要全量复制
|
||||
- **desc 用占位符 `{ap}`**,不要硬编码数字,避免与 overrides 数值脱节
|
||||
- **对敌 debuff 用 `timed_debuff_id`,吸血/自强化用 `timed_buff_id`**,两者目标语义相反
|
||||
- **复活已废弃独立 `revive` 字段**,改在 `dead` 组 overrides 配 `revive_hp`/`revive_count`
|
||||
|
||||
---
|
||||
|
||||
## 8. 参考文档
|
||||
|
||||
- 详细字段规则与数据源:`put/server/data/heroes.json编辑指引.md`
|
||||
- 编辑器枚举与默认值:`put/web/src/constants.js`
|
||||
- 技能底座定义:`assets/script/game/common/config/SkillSet.ts`
|
||||
- Buff 底座定义:`assets/script/game/common/config/BuffSet.ts`
|
||||
- 职业模板与成长:`assets/script/game/common/config/heroSet.ts`
|
||||
File diff suppressed because it is too large
Load Diff
@@ -70,9 +70,12 @@
|
||||
## 4. 触发组规范(atking / atked / fstart / fend / dead)
|
||||
|
||||
- 结构:`{ "<技能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);
|
||||
- `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` 为组对外展示名(写在该组首档),留空回退底座名;
|
||||
- 复活:在 `dead` 某条目 `overrides` 配 `revive_hp`(回血%)+ `revive_count`(次数上限);
|
||||
- 无触发组时写空对象 `{}`,**不要省略字段**。
|
||||
|
||||
1
put/server/data/meta.json
Normal file
1
put/server/data/meta.json
Normal file
File diff suppressed because one or more lines are too long
75
put/server/db.js
Normal file
75
put/server/db.js
Normal file
@@ -0,0 +1,75 @@
|
||||
/**
|
||||
* 英雄/预设存储层:开发版与线上设计版统一读写线上 MongoDB。
|
||||
* - heroes 集合:每个英雄一条文档,uuid 唯一索引
|
||||
* - templates 集合:预设库(_id='presets' 单文档)
|
||||
* - meta 集合:版本闸门(_id='version' 单文档,schemaVersion 由开发版推送 meta 时写入)
|
||||
* 技能/Buff 底座不进数据库,开发版走 TS 编译,线上版走 meta.json 快照。
|
||||
*/
|
||||
import { MongoClient } from 'mongodb'
|
||||
|
||||
const MONGO_URL = process.env.MONGO_URL || ''
|
||||
const DB_NAME = process.env.MONGO_DB || 'heroconfig'
|
||||
|
||||
let client = null
|
||||
let db = null
|
||||
|
||||
/** 惰性连接 MongoDB(单例复用) */
|
||||
async function mongo() {
|
||||
if (db) return db
|
||||
if (!MONGO_URL) throw new Error('未配置 MONGO_URL 环境变量')
|
||||
client = new MongoClient(MONGO_URL)
|
||||
await client.connect()
|
||||
db = client.db(DB_NAME)
|
||||
// uuid 唯一索引:保证英雄按 uuid 幂等覆盖
|
||||
await db.collection('heroes').createIndex({ uuid: 1 }, { unique: true })
|
||||
return db
|
||||
}
|
||||
|
||||
/** 读取全部英雄(按 uuid 升序,剥离 Mongo 内部 _id) */
|
||||
export async function getHeroes() {
|
||||
const docs = await (await mongo()).collection('heroes').find().sort({ uuid: 1 }).toArray()
|
||||
return docs.map(({ _id, ...h }) => h)
|
||||
}
|
||||
|
||||
/** 全量覆盖:upsert 传入英雄,并删除库中多余的 uuid */
|
||||
export async function saveHeroes(heroes) {
|
||||
const col = (await mongo()).collection('heroes')
|
||||
for (const h of heroes) {
|
||||
await col.replaceOne({ uuid: h.uuid }, h, { upsert: true })
|
||||
}
|
||||
await col.deleteMany({ uuid: { $nin: heroes.map((h) => h.uuid) } })
|
||||
}
|
||||
|
||||
/** 读取预设库(无文档时返回空池) */
|
||||
export async function getTemplates() {
|
||||
const doc = await (await mongo()).collection('templates').findOne({ _id: 'presets' })
|
||||
return {
|
||||
triggerPresets: Array.isArray(doc?.triggerPresets) ? doc.triggerPresets : [],
|
||||
fieldPresets: Array.isArray(doc?.fieldPresets) ? doc.fieldPresets : [],
|
||||
}
|
||||
}
|
||||
|
||||
/** 全量覆盖预设库 */
|
||||
export async function saveTemplates(triggerPresets, fieldPresets) {
|
||||
await (await mongo())
|
||||
.collection('templates')
|
||||
.replaceOne({ _id: 'presets' }, { _id: 'presets', triggerPresets, fieldPresets }, { upsert: true })
|
||||
}
|
||||
|
||||
/** 读取库中数据结构版本(首次为 0) */
|
||||
export async function getSchemaVersion() {
|
||||
const doc = await (await mongo()).collection('meta').findOne({ _id: 'version' })
|
||||
return doc?.schemaVersion ?? 0
|
||||
}
|
||||
|
||||
/**
|
||||
* 推送数据结构版本:只允许升不允许降,避免旧部署误把版本刷低导致线上版解锁写入。
|
||||
* @returns {Promise<number>} 写入后的实际版本
|
||||
*/
|
||||
export async function bumpSchemaVersion(version) {
|
||||
const col = (await mongo()).collection('meta')
|
||||
const cur = await getSchemaVersion()
|
||||
const next = Math.max(cur, version)
|
||||
await col.replaceOne({ _id: 'version' }, { _id: 'version', schemaVersion: next, updatedAt: new Date() }, { upsert: true })
|
||||
return next
|
||||
}
|
||||
@@ -1,9 +1,17 @@
|
||||
/**
|
||||
* 英雄配置工具服务(双模式)
|
||||
* - 项目开发版(MODE=local):全功能,meta 从游戏工程 TS 编译,可写 heroSet.ts / 导出 CSV / 推送快照
|
||||
* - 线上设计版(MODE=remote):meta 从 data/meta.json 快照加载,仅英雄/预设的增删改查;
|
||||
* 库中 schemaVersion 高于本服务内置版本时进入只读(保存接口返回 409),需更新部署后才能修改
|
||||
*/
|
||||
import 'dotenv/config'
|
||||
import express from 'express'
|
||||
import cors from 'cors'
|
||||
import esbuild from 'esbuild'
|
||||
import fs from 'node:fs'
|
||||
import path from 'node:path'
|
||||
import url from 'node:url'
|
||||
import * as store from './db.js'
|
||||
|
||||
const __dirname = path.dirname(url.fileURLToPath(import.meta.url))
|
||||
const PROJECT_ROOT = path.resolve(__dirname, '..', '..')
|
||||
@@ -14,7 +22,11 @@ const CSV_PATH = path.join(CONFIG_DIR, '英雄设计表.csv')
|
||||
const HEROES_BEGIN = '// @hero-setup:heroes-begin'
|
||||
const HEROES_END = '// @hero-setup:heroes-end'
|
||||
const DATA_DIR = path.join(__dirname, 'data')
|
||||
const HEROES_PATH = path.join(DATA_DIR, 'heroes.json')
|
||||
const META_SNAPSHOT_PATH = path.join(DATA_DIR, 'meta.json')
|
||||
|
||||
const MODE = process.env.MODE || 'local'
|
||||
/** 数据结构版本:英雄/底座结构有破坏性变更时 +1,并随 push-meta 推送到库中 */
|
||||
const SCHEMA_VERSION = Number(process.env.SCHEMA_VERSION || 1)
|
||||
|
||||
const app = express()
|
||||
app.use(cors())
|
||||
@@ -43,6 +55,14 @@ async function loadConfigModule(file) {
|
||||
let cache = null
|
||||
|
||||
async function buildCache() {
|
||||
// 线上设计版:从快照文件加载(快照由开发版 scripts/push-meta.js 生成并随部署发布)
|
||||
if (MODE === 'remote') {
|
||||
if (!fs.existsSync(META_SNAPSHOT_PATH)) {
|
||||
throw new Error('缺少 data/meta.json 快照,请先在开发版执行 npm run push-meta 并重新部署')
|
||||
}
|
||||
cache = JSON.parse(fs.readFileSync(META_SNAPSHOT_PATH, 'utf8'))
|
||||
return cache
|
||||
}
|
||||
const [skill, buff, hero] = await Promise.all([
|
||||
loadConfigModule('SkillSet.ts'),
|
||||
loadConfigModule('BuffSet.ts'),
|
||||
@@ -63,7 +83,12 @@ async function buildCache() {
|
||||
app.get('/api/meta', async (_req, res) => {
|
||||
try {
|
||||
if (!cache) await buildCache()
|
||||
res.json(cache)
|
||||
res.json({
|
||||
...cache,
|
||||
mode: MODE,
|
||||
schemaVersion: SCHEMA_VERSION,
|
||||
dbSchemaVersion: await store.getSchemaVersion(),
|
||||
})
|
||||
} catch (e) {
|
||||
res.status(500).json({ error: String(e?.message || e) })
|
||||
}
|
||||
@@ -78,51 +103,209 @@ app.post('/api/refresh', async (_req, res) => {
|
||||
}
|
||||
})
|
||||
|
||||
/** 英雄数据持久化:GET 读取(无文件时返回空列表) */
|
||||
app.get('/api/heroes', (_req, res) => {
|
||||
/** 版本闸门:线上设计版落后于库中结构版本时,写操作返回 409 强制只读 */
|
||||
async function guardVersion(res) {
|
||||
if (MODE !== 'remote') return true
|
||||
const dbVer = await store.getSchemaVersion()
|
||||
if (dbVer > SCHEMA_VERSION) {
|
||||
res.status(409).json({
|
||||
error: `线上设计版结构版本(v${SCHEMA_VERSION})低于数据库(v${dbVer}),请更新部署后再修改`,
|
||||
dbSchemaVersion: dbVer,
|
||||
schemaVersion: SCHEMA_VERSION,
|
||||
})
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
/** 英雄数据:GET 从线上库读取 */
|
||||
app.get('/api/heroes', async (_req, res) => {
|
||||
try {
|
||||
if (!fs.existsSync(HEROES_PATH)) return res.json({ heroes: [] })
|
||||
res.json(JSON.parse(fs.readFileSync(HEROES_PATH, 'utf8')))
|
||||
res.json({ heroes: await store.getHeroes() })
|
||||
} catch (e) {
|
||||
res.status(500).json({ error: String(e?.message || e) })
|
||||
}
|
||||
})
|
||||
|
||||
/** 英雄数据持久化:POST 全量覆盖保存 */
|
||||
app.post('/api/heroes', (req, res) => {
|
||||
/** 英雄数据:POST 全量覆盖写入线上库 */
|
||||
app.post('/api/heroes', async (req, res) => {
|
||||
const heroes = req.body?.heroes
|
||||
if (!Array.isArray(heroes)) {
|
||||
return res.status(400).json({ error: 'heroes 必须为数组' })
|
||||
}
|
||||
try {
|
||||
fs.mkdirSync(DATA_DIR, { recursive: true })
|
||||
fs.writeFileSync(HEROES_PATH, JSON.stringify({ heroes }, null, 2), 'utf8')
|
||||
res.json({ ok: true, path: HEROES_PATH, count: heroes.length })
|
||||
if (!(await guardVersion(res))) return
|
||||
await store.saveHeroes(heroes)
|
||||
res.json({ ok: true, count: heroes.length })
|
||||
} catch (e) {
|
||||
res.status(500).json({ error: String(e?.message || e) })
|
||||
}
|
||||
})
|
||||
|
||||
const TEMPLATES_PATH = path.join(DATA_DIR, 'templates.json')
|
||||
|
||||
/** 预设库持久化:GET 读取(无文件时返回空池) */
|
||||
app.get('/api/templates', (_req, res) => {
|
||||
/** 单英雄读取:GET /api/heroes/:uuid */
|
||||
app.get('/api/heroes/:uuid', async (req, res) => {
|
||||
try {
|
||||
if (!fs.existsSync(TEMPLATES_PATH)) return res.json({ triggerPresets: [], fieldPresets: [] })
|
||||
const data = JSON.parse(fs.readFileSync(TEMPLATES_PATH, 'utf8'))
|
||||
// 兼容旧格式:若根上是 templates 数组,返回空池让前端走默认
|
||||
if (Array.isArray(data.templates)) return res.json({ triggerPresets: [], fieldPresets: [] })
|
||||
res.json({
|
||||
triggerPresets: Array.isArray(data.triggerPresets) ? data.triggerPresets : [],
|
||||
fieldPresets: Array.isArray(data.fieldPresets) ? data.fieldPresets : [],
|
||||
})
|
||||
const uuid = Number(req.params.uuid)
|
||||
if (Number.isNaN(uuid)) return res.status(400).json({ error: 'uuid 必须为数字' })
|
||||
const heroes = await store.getHeroes()
|
||||
const hero = heroes.find((h) => h.uuid === uuid)
|
||||
if (!hero) return res.status(404).json({ error: `英雄 ${uuid} 不存在` })
|
||||
res.json(hero)
|
||||
} catch (e) {
|
||||
res.status(500).json({ error: String(e?.message || e) })
|
||||
}
|
||||
})
|
||||
|
||||
/** 职业模板持久化:POST 全量覆盖保存(结构:{ triggerPresets: [], fieldPresets: [] }) */
|
||||
app.post('/api/templates', (req, res) => {
|
||||
/** 单英雄新增/覆盖:POST /api/heroes/:uuid(body 为完整英雄对象,uuid 以 URL 为准) */
|
||||
app.post('/api/heroes/:uuid', async (req, res) => {
|
||||
try {
|
||||
if (!(await guardVersion(res))) return
|
||||
const uuid = Number(req.params.uuid)
|
||||
if (Number.isNaN(uuid)) return res.status(400).json({ error: 'uuid 必须为数字' })
|
||||
const hero = req.body
|
||||
if (!hero || typeof hero !== 'object') return res.status(400).json({ error: 'body 必须为英雄对象' })
|
||||
hero.uuid = uuid
|
||||
const heroes = await store.getHeroes()
|
||||
const idx = heroes.findIndex((h) => h.uuid === uuid)
|
||||
if (idx >= 0) heroes[idx] = hero
|
||||
else heroes.push(hero)
|
||||
await store.saveHeroes(heroes)
|
||||
res.json({ ok: true, uuid, action: idx >= 0 ? 'updated' : 'created' })
|
||||
} catch (e) {
|
||||
res.status(500).json({ error: String(e?.message || e) })
|
||||
}
|
||||
})
|
||||
|
||||
/** 单英雄局部更新:PUT /api/heroes/:uuid(body 为部分字段,与现有英雄浅合并) */
|
||||
app.put('/api/heroes/:uuid', async (req, res) => {
|
||||
try {
|
||||
if (!(await guardVersion(res))) return
|
||||
const uuid = Number(req.params.uuid)
|
||||
if (Number.isNaN(uuid)) return res.status(400).json({ error: 'uuid 必须为数字' })
|
||||
const patch = req.body
|
||||
if (!patch || typeof patch !== 'object') return res.status(400).json({ error: 'body 必须为部分字段对象' })
|
||||
const heroes = await store.getHeroes()
|
||||
const idx = heroes.findIndex((h) => h.uuid === uuid)
|
||||
if (idx < 0) return res.status(404).json({ error: `英雄 ${uuid} 不存在` })
|
||||
// uuid 不可变,防止 patch 覆盖
|
||||
delete patch.uuid
|
||||
heroes[idx] = { ...heroes[idx], ...patch }
|
||||
await store.saveHeroes(heroes)
|
||||
res.json({ ok: true, uuid, action: 'patched' })
|
||||
} catch (e) {
|
||||
res.status(500).json({ error: String(e?.message || e) })
|
||||
}
|
||||
})
|
||||
|
||||
/** 单英雄删除:DELETE /api/heroes/:uuid */
|
||||
app.delete('/api/heroes/:uuid', async (req, res) => {
|
||||
try {
|
||||
if (!(await guardVersion(res))) return
|
||||
const uuid = Number(req.params.uuid)
|
||||
if (Number.isNaN(uuid)) return res.status(400).json({ error: 'uuid 必须为数字' })
|
||||
const heroes = await store.getHeroes()
|
||||
const idx = heroes.findIndex((h) => h.uuid === uuid)
|
||||
if (idx < 0) return res.status(404).json({ error: `英雄 ${uuid} 不存在` })
|
||||
heroes.splice(idx, 1)
|
||||
await store.saveHeroes(heroes)
|
||||
res.json({ ok: true, uuid, action: 'deleted' })
|
||||
} catch (e) {
|
||||
res.status(500).json({ error: String(e?.message || e) })
|
||||
}
|
||||
})
|
||||
|
||||
/**
|
||||
* 技能级局部更新:PATCH /api/heroes/:uuid/skills/:skillUuid
|
||||
* 支持对技能字段及 lv_entries 按 lv 合并,避免整表替换 skills 数组。
|
||||
*
|
||||
* body 格式:
|
||||
* {
|
||||
* name?, cd?, cdExpr?, desc?, // 技能基础字段,存在则覆盖
|
||||
* overrides?, // 与现有 overrides 浅合并(不是替换)
|
||||
* lv_entries?: [ // 按 lv 合并:存在则更新该档,不存在则新增
|
||||
* { lv, s_lv?, overrides?, desc? }
|
||||
* ]
|
||||
* }
|
||||
*/
|
||||
app.patch('/api/heroes/:uuid/skills/:skillUuid', async (req, res) => {
|
||||
try {
|
||||
if (!(await guardVersion(res))) return
|
||||
const uuid = Number(req.params.uuid)
|
||||
const skillUuid = Number(req.params.skillUuid)
|
||||
if (Number.isNaN(uuid) || Number.isNaN(skillUuid)) {
|
||||
return res.status(400).json({ error: 'uuid 与 skillUuid 必须为数字' })
|
||||
}
|
||||
const patch = req.body
|
||||
if (!patch || typeof patch !== 'object') {
|
||||
return res.status(400).json({ error: 'body 必须为技能补丁对象' })
|
||||
}
|
||||
|
||||
const heroes = await store.getHeroes()
|
||||
const hIdx = heroes.findIndex((h) => h.uuid === uuid)
|
||||
if (hIdx < 0) return res.status(404).json({ error: `英雄 ${uuid} 不存在` })
|
||||
|
||||
const hero = heroes[hIdx]
|
||||
const sIdx = hero.skills.findIndex((s) => s.uuid === skillUuid)
|
||||
if (sIdx < 0) return res.status(404).json({ error: `英雄 ${uuid} 不存在技能 ${skillUuid}` })
|
||||
|
||||
const skill = hero.skills[sIdx]
|
||||
|
||||
// 基础字段直接覆盖
|
||||
if (patch.name !== undefined) skill.name = patch.name
|
||||
if (patch.cd !== undefined) skill.cd = patch.cd
|
||||
if (patch.cdExpr !== undefined) skill.cdExpr = patch.cdExpr
|
||||
if (patch.desc !== undefined) skill.desc = patch.desc
|
||||
|
||||
// overrides 浅合并(不是替换)
|
||||
if (patch.overrides && typeof patch.overrides === 'object') {
|
||||
skill.overrides = { ...skill.overrides, ...patch.overrides }
|
||||
}
|
||||
|
||||
// lv_entries 按 lv 合并:同 lv 更新,不同 lv 新增
|
||||
if (Array.isArray(patch.lv_entries)) {
|
||||
if (!Array.isArray(skill.lv_entries)) skill.lv_entries = []
|
||||
for (const entry of patch.lv_entries) {
|
||||
if (!entry || typeof entry !== 'object') continue
|
||||
const lv = entry.lv
|
||||
if (lv === undefined) continue
|
||||
const eIdx = skill.lv_entries.findIndex((e) => e.lv === lv)
|
||||
if (eIdx >= 0) {
|
||||
// 同 lv:浅合并 overrides,覆盖其他字段
|
||||
const existing = skill.lv_entries[eIdx]
|
||||
skill.lv_entries[eIdx] = {
|
||||
...existing,
|
||||
...entry,
|
||||
overrides: entry.overrides
|
||||
? { ...existing.overrides, ...entry.overrides }
|
||||
: existing.overrides,
|
||||
}
|
||||
} else {
|
||||
// 新 lv:直接插入
|
||||
skill.lv_entries.push(entry)
|
||||
}
|
||||
}
|
||||
// 按 lv 升序排序,保持数据整洁
|
||||
skill.lv_entries.sort((a, b) => a.lv - b.lv)
|
||||
}
|
||||
|
||||
await store.saveHeroes(heroes)
|
||||
res.json({ ok: true, uuid, skillUuid, action: 'skill_patched' })
|
||||
} catch (e) {
|
||||
res.status(500).json({ error: String(e?.message || e) })
|
||||
}
|
||||
})
|
||||
|
||||
/** 预设库:GET 从线上库读取 */
|
||||
app.get('/api/templates', async (_req, res) => {
|
||||
try {
|
||||
res.json(await store.getTemplates())
|
||||
} catch (e) {
|
||||
res.status(500).json({ error: String(e?.message || e) })
|
||||
}
|
||||
})
|
||||
|
||||
/** 预设库:POST 全量覆盖写入线上库(结构:{ triggerPresets: [], fieldPresets: [] }) */
|
||||
app.post('/api/templates', async (req, res) => {
|
||||
const body = req.body || {}
|
||||
const triggerPresets = body.triggerPresets
|
||||
const fieldPresets = body.fieldPresets
|
||||
@@ -136,9 +319,9 @@ app.post('/api/templates', (req, res) => {
|
||||
return res.status(400).json({ error: `触发预设 ${bad.id || bad.label} 的 group 非法:${bad.group}` })
|
||||
}
|
||||
try {
|
||||
fs.mkdirSync(DATA_DIR, { recursive: true })
|
||||
fs.writeFileSync(TEMPLATES_PATH, JSON.stringify({ triggerPresets, fieldPresets }, null, 2), 'utf8')
|
||||
res.json({ ok: true, path: TEMPLATES_PATH, triggerCount: triggerPresets.length, fieldCount: fieldPresets.length })
|
||||
if (!(await guardVersion(res))) return
|
||||
await store.saveTemplates(triggerPresets, fieldPresets)
|
||||
res.json({ ok: true, triggerCount: triggerPresets.length, fieldCount: fieldPresets.length })
|
||||
} catch (e) {
|
||||
res.status(500).json({ error: String(e?.message || e) })
|
||||
}
|
||||
@@ -215,6 +398,9 @@ function renderSingleHero(h) {
|
||||
if (e.s_lv) eparts.push(`s_lv: SkillLv.Lv${e.s_lv}`)
|
||||
if (e.name) eparts.push(`name: ${JSON.stringify(e.name)}`)
|
||||
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.desc) eparts.push(`desc: ${JSON.stringify(e.desc)}`)
|
||||
push(` { ${eparts.join(', ')} },`)
|
||||
@@ -351,6 +537,8 @@ function csvTrigger(grp) {
|
||||
const name = e.name || base?.name || ''
|
||||
const ov = e.overrides || {}
|
||||
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}`)
|
||||
const desc = e.desc || ''
|
||||
return `${sid} ${name}(${parts.join(';')}):${desc}`
|
||||
@@ -420,8 +608,16 @@ function renderHeroCsv(heroes) {
|
||||
return rows.map((r) => r.map(csvCell).join(',')).join('\n') + '\n'
|
||||
}
|
||||
|
||||
/** 仅开发版可用的本地文件写操作(heroSet.ts / CSV),线上设计版调用返回 403 */
|
||||
function localOnly(res) {
|
||||
if (MODE === 'local') return true
|
||||
res.status(403).json({ error: '线上设计版不支持此操作(写 heroSet.ts / 导出 CSV 请在项目开发版执行)' })
|
||||
return false
|
||||
}
|
||||
|
||||
app.post('/api/export-csv', async (req, res) => {
|
||||
try {
|
||||
if (!localOnly(res)) return
|
||||
const heroes = req.body?.heroes
|
||||
if (!Array.isArray(heroes) || !heroes.length) {
|
||||
return res.status(400).json({ error: 'heroes 不能为空' })
|
||||
@@ -435,12 +631,25 @@ app.post('/api/export-csv', async (req, res) => {
|
||||
}
|
||||
})
|
||||
|
||||
app.get('/api/export-csv', (_req, res) => {
|
||||
app.get('/api/export-csv', (req, res) => {
|
||||
if (!localOnly(res)) return
|
||||
if (!fs.existsSync(CSV_PATH)) return res.status(404).json({ error: '尚未生成' })
|
||||
res.setHeader('Content-Type', 'text/csv; charset=utf-8')
|
||||
res.send(fs.readFileSync(CSV_PATH, 'utf8'))
|
||||
})
|
||||
|
||||
/** 导出 meta 快照(开发版专用):供 push-meta 脚本发布到线上设计版 */
|
||||
app.get('/api/meta-snapshot', async (_req, res) => {
|
||||
try {
|
||||
if (!localOnly(res)) return
|
||||
if (!cache) await buildCache()
|
||||
const { mode: _m, schemaVersion: _v, dbSchemaVersion: _d, ...snapshot } = cache
|
||||
res.json(snapshot)
|
||||
} catch (e) {
|
||||
res.status(500).json({ error: String(e?.message || e) })
|
||||
}
|
||||
})
|
||||
|
||||
/** HeroList 定义匹配(用于导出时同步图鉴/卡池数据源) */
|
||||
const HERO_LIST_RE = /export const HeroList: number\[\] = \[[\s\S]*?\n\];/
|
||||
|
||||
@@ -465,6 +674,7 @@ function syncHeroList(src, heroes) {
|
||||
|
||||
app.post('/api/apply', (req, res) => {
|
||||
try {
|
||||
if (!localOnly(res)) return
|
||||
const heroes = req.body?.heroes
|
||||
if (!Array.isArray(heroes) || !heroes.length) {
|
||||
return res.status(400).json({ error: 'heroes 不能为空' })
|
||||
@@ -486,7 +696,19 @@ app.post('/api/apply', (req, res) => {
|
||||
}
|
||||
})
|
||||
|
||||
const PORT = 3001
|
||||
app.listen(PORT, () => {
|
||||
console.log(`[hero-config-tool] server listening http://localhost:${PORT}`)
|
||||
const PORT = Number(process.env.PORT || 3001)
|
||||
// 默认监听所有网卡,保证容器/局域网端口映射可用;可用 HOST=127.0.0.1 限制为本机
|
||||
const HOST = process.env.HOST || '0.0.0.0'
|
||||
|
||||
// 线上设计版:托管前端构建产物(web/dist),单个服务即可对外提供完整站点
|
||||
if (MODE === 'remote') {
|
||||
const DIST_DIR = path.resolve(__dirname, '..', 'web', 'dist')
|
||||
if (fs.existsSync(DIST_DIR)) {
|
||||
app.use(express.static(DIST_DIR))
|
||||
app.get(/^\/(?!api\/).*/, (_req, res) => res.sendFile(path.join(DIST_DIR, 'index.html')))
|
||||
}
|
||||
}
|
||||
|
||||
app.listen(PORT, HOST, () => {
|
||||
console.log(`[hero-config-tool] mode=${MODE} schemaVersion=${SCHEMA_VERSION} listening http://${HOST}:${PORT}`)
|
||||
})
|
||||
|
||||
@@ -4,11 +4,15 @@
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "node --watch index.js"
|
||||
"dev": "node --watch index.js",
|
||||
"start": "node index.js",
|
||||
"push-meta": "node scripts/push-meta.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"cors": "^2.8.5",
|
||||
"dotenv": "^18.0.5",
|
||||
"esbuild": "^0.24.0",
|
||||
"express": "^4.21.2"
|
||||
"express": "^4.21.2",
|
||||
"mongodb": "^6.12.0"
|
||||
}
|
||||
}
|
||||
|
||||
35
put/server/scripts/migrate-to-mongo.js
Normal file
35
put/server/scripts/migrate-to-mongo.js
Normal file
@@ -0,0 +1,35 @@
|
||||
/**
|
||||
* 一次性迁移:把本地 data/heroes.json、data/templates.json 导入线上 MongoDB
|
||||
* 用法:配置 MONGO_URL 后执行 node scripts/migrate-to-mongo.js
|
||||
* 已在库中的数据会按 uuid 幂等覆盖,可重复执行。
|
||||
*/
|
||||
import fs from 'node:fs'
|
||||
import path from 'node:path'
|
||||
import url from 'node:url'
|
||||
import { saveHeroes, saveTemplates, getHeroes } from '../db.js'
|
||||
|
||||
const __dirname = path.dirname(url.fileURLToPath(import.meta.url))
|
||||
const DATA_DIR = path.join(__dirname, '..', 'data')
|
||||
|
||||
const readJson = (file, fallback) => {
|
||||
const p = path.join(DATA_DIR, file)
|
||||
return fs.existsSync(p) ? JSON.parse(fs.readFileSync(p, 'utf8')) : fallback
|
||||
}
|
||||
|
||||
const heroes = readJson('heroes.json', { heroes: [] }).heroes || []
|
||||
const tpl = readJson('templates.json', { triggerPresets: [], fieldPresets: [] })
|
||||
|
||||
if (heroes.length) {
|
||||
await saveHeroes(heroes)
|
||||
console.log(`[migrate] heroes 导入 ${heroes.length} 条`)
|
||||
} else {
|
||||
console.log('[migrate] 无本地 heroes.json 或为空,跳过英雄导入')
|
||||
}
|
||||
if ((tpl.triggerPresets?.length || 0) + (tpl.fieldPresets?.length || 0) > 0) {
|
||||
await saveTemplates(tpl.triggerPresets || [], tpl.fieldPresets || [])
|
||||
console.log(`[migrate] templates 导入 trigger=${tpl.triggerPresets?.length || 0} field=${tpl.fieldPresets?.length || 0}`)
|
||||
} else {
|
||||
console.log('[migrate] 无本地 templates.json 或为空,跳过预设导入')
|
||||
}
|
||||
console.log(`[migrate] 库中现有英雄 ${(await getHeroes()).length} 条`)
|
||||
process.exit(0)
|
||||
29
put/server/scripts/push-meta.js
Normal file
29
put/server/scripts/push-meta.js
Normal file
@@ -0,0 +1,29 @@
|
||||
/**
|
||||
* 推送 meta 快照 + 结构版本到线上(项目开发版使用)
|
||||
* 用法:先启动本地 dev 服务,再执行 npm run push-meta
|
||||
* 产物:server/data/meta.json —— 需随线上设计版一起部署(git 提交或拷贝到 VPS)
|
||||
*/
|
||||
import fs from 'node:fs'
|
||||
import path from 'node:path'
|
||||
import url from 'node:url'
|
||||
import { bumpSchemaVersion } from '../db.js'
|
||||
|
||||
const __dirname = path.dirname(url.fileURLToPath(import.meta.url))
|
||||
const SNAPSHOT_PATH = path.join(__dirname, '..', 'data', 'meta.json')
|
||||
const LOCAL_API = process.env.LOCAL_API || 'http://localhost:3001'
|
||||
const SCHEMA_VERSION = Number(process.env.SCHEMA_VERSION || 1)
|
||||
|
||||
const res = await fetch(`${LOCAL_API}/api/meta-snapshot`)
|
||||
if (!res.ok) {
|
||||
const body = await res.text().catch(() => '')
|
||||
throw new Error(`拉取 meta 快照失败(请确认本地 dev 服务已启动): ${res.status} ${body}`)
|
||||
}
|
||||
const snapshot = await res.json()
|
||||
fs.mkdirSync(path.dirname(SNAPSHOT_PATH), { recursive: true })
|
||||
fs.writeFileSync(SNAPSHOT_PATH, JSON.stringify(snapshot), 'utf8')
|
||||
|
||||
const dbVersion = await bumpSchemaVersion(SCHEMA_VERSION)
|
||||
console.log(`[push-meta] meta.json 已生成(${Buffer.byteLength(JSON.stringify(snapshot))} bytes)`)
|
||||
console.log(`[push-meta] 数据库结构版本: v${dbVersion}(本服务 v${SCHEMA_VERSION})`)
|
||||
console.log('[push-meta] 请将 meta.json 与最新代码一起部署到线上设计版')
|
||||
process.exit(0)
|
||||
88
put/web/dist/assets/index-CZTxENXL.js
vendored
Normal file
88
put/web/dist/assets/index-CZTxENXL.js
vendored
Normal file
File diff suppressed because one or more lines are too long
1
put/web/dist/assets/index-Dzv_EDk3.css
vendored
Normal file
1
put/web/dist/assets/index-Dzv_EDk3.css
vendored
Normal file
File diff suppressed because one or more lines are too long
13
put/web/dist/index.html
vendored
Normal file
13
put/web/dist/index.html
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>英雄配置编辑器</title>
|
||||
<script type="module" crossorigin src="/assets/index-CZTxENXL.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/assets/index-Dzv_EDk3.css">
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,18 +1,33 @@
|
||||
<template>
|
||||
<div class="hero-app">
|
||||
<header class="hero-header">
|
||||
<h1>英雄配置编辑器</h1>
|
||||
<h1>
|
||||
英雄配置编辑器
|
||||
<el-tag size="small" :type="isDev ? 'success' : 'warning'" effect="plain">
|
||||
{{ isDev ? '项目开发版' : '线上设计版' }} v{{ meta?.schemaVersion ?? '-' }}
|
||||
</el-tag>
|
||||
</h1>
|
||||
<div class="actions">
|
||||
<el-radio-group v-model="view" size="small">
|
||||
<el-radio-button value="heroes">英雄列表</el-radio-button>
|
||||
<el-radio-button value="templates">预设库</el-radio-button>
|
||||
</el-radio-group>
|
||||
<el-button size="small" @click="refreshMeta" :loading="loadingMeta">刷新配置数据</el-button>
|
||||
<el-button size="small" type="success" @click="doSave" :disabled="!heroes.length">保存到服务器</el-button>
|
||||
<el-button size="small" type="primary" @click="doApply" :disabled="!heroes.length">写入 heroSet.ts</el-button>
|
||||
<el-button size="small" type="danger" @click="doExportCsv" :disabled="!heroes.length">导出英雄设计表.csv</el-button>
|
||||
<el-button size="small" type="success" @click="doSave" :disabled="!heroes.length || outdated">保存到数据库</el-button>
|
||||
<template v-if="isDev">
|
||||
<el-button size="small" type="primary" @click="doApply" :disabled="!heroes.length">写入 heroSet.ts</el-button>
|
||||
<el-button size="small" type="danger" @click="doExportCsv" :disabled="!heroes.length">导出英雄设计表.csv</el-button>
|
||||
</template>
|
||||
</div>
|
||||
</header>
|
||||
<el-alert
|
||||
v-if="outdated"
|
||||
type="error"
|
||||
:closable="false"
|
||||
show-icon
|
||||
:title="`数据库结构已升级到 v${meta.dbSchemaVersion},当前线上设计版(v${meta.schemaVersion})已切换为只读,请更新部署后再修改`"
|
||||
style="margin-bottom: 8px"
|
||||
/>
|
||||
<div class="hero-main">
|
||||
<!-- 预设库视图 -->
|
||||
<TemplateManager
|
||||
@@ -165,11 +180,11 @@
|
||||
<div class="panel">
|
||||
<h3>触发技能(lv4 激活)</h3>
|
||||
<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="atked 受击后"><TriggerGroupEditor :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="fend 回合结束"><TriggerGroupEditor :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="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 group="atked" :model="current.atked" :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 group="fend" :model="current.fend" :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>
|
||||
</div>
|
||||
|
||||
@@ -252,6 +267,10 @@ const editVisible = ref(false)
|
||||
|
||||
const current = computed(() => heroes.value[activeIdx.value])
|
||||
|
||||
// 版本/模式:isDev 区分开发版全功能;outdated 时线上设计版只读
|
||||
const isDev = computed(() => meta.value?.mode === 'local')
|
||||
const outdated = computed(() => (meta.value?.dbSchemaVersion ?? 0) > (meta.value?.schemaVersion ?? 0))
|
||||
|
||||
// 首页列表排序:none 原始顺序 / role 按职业枚举序(坦克→辅助)/ rarity 按星级
|
||||
const sortKey = ref('none')
|
||||
const sortOrder = ref('desc')
|
||||
@@ -380,7 +399,15 @@ function triggerSummary(h) {
|
||||
const name = entries[0]?.name || skillMap.value[sid]?.name || ''
|
||||
const e = entries[0]
|
||||
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(' ')}`)
|
||||
}
|
||||
}
|
||||
@@ -502,7 +529,7 @@ async function loadTemplates() {
|
||||
async function doSave() {
|
||||
try {
|
||||
const r = await api.saveHeroes(heroes.value)
|
||||
ElMessage.success(`已保存 ${r.count} 个英雄 → ${r.path}`)
|
||||
ElMessage.success(`已保存 ${r.count} 个英雄到数据库`)
|
||||
} catch (e) {
|
||||
ElMessage.error('保存失败: ' + (e?.response?.data?.error || e.message))
|
||||
}
|
||||
|
||||
@@ -1,12 +1,16 @@
|
||||
import axios from 'axios'
|
||||
|
||||
// 开发环境走 vite 代理(留空即可);部署静态站点时用 VITE_API_BASE 指向后端服务
|
||||
const baseURL = import.meta.env.VITE_API_BASE || ''
|
||||
const http = axios.create({ baseURL })
|
||||
|
||||
export const api = {
|
||||
meta: () => axios.get('/api/meta').then((r) => r.data),
|
||||
refresh: () => axios.post('/api/refresh').then((r) => r.data),
|
||||
fetchHeroes: () => axios.get('/api/heroes').then((r) => r.data),
|
||||
saveHeroes: (heroes) => axios.post('/api/heroes', { heroes }).then((r) => r.data),
|
||||
applyHeroes: (heroes) => axios.post('/api/apply', { heroes }).then((r) => r.data),
|
||||
exportCsv: (heroes) => axios.post('/api/export-csv', { heroes }).then((r) => r.data),
|
||||
fetchTemplates: () => axios.get('/api/templates').then((r) => r.data),
|
||||
saveTemplates: (templates) => axios.post('/api/templates', { templates }).then((r) => r.data),
|
||||
meta: () => http.get('/api/meta').then((r) => r.data),
|
||||
refresh: () => http.post('/api/refresh').then((r) => r.data),
|
||||
fetchHeroes: () => http.get('/api/heroes').then((r) => r.data),
|
||||
saveHeroes: (heroes) => http.post('/api/heroes', { heroes }).then((r) => r.data),
|
||||
applyHeroes: (heroes) => http.post('/api/apply', { heroes }).then((r) => r.data),
|
||||
exportCsv: (heroes) => http.post('/api/export-csv', { heroes }).then((r) => r.data),
|
||||
fetchTemplates: () => http.get('/api/templates').then((r) => r.data),
|
||||
saveTemplates: (templates) => http.post('/api/templates', { templates }).then((r) => r.data),
|
||||
}
|
||||
|
||||
@@ -32,6 +32,8 @@
|
||||
<span class="tpl-meta-item">{{ p.uuid }} {{ skillName(p.uuid) }}</span>
|
||||
<span class="tpl-meta-sep">·</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-item">lv{{ p.entry.lv }}</span>
|
||||
</div>
|
||||
@@ -129,6 +131,14 @@
|
||||
<el-form-item label="t_num">
|
||||
<el-input-number v-model="currentTrigger.entry.t_num" :min="1" :controls="false" style="width: 100%" />
|
||||
</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-input v-model="currentTrigger.entry.name" placeholder="留空回退底座名" />
|
||||
</el-form-item>
|
||||
|
||||
@@ -15,9 +15,17 @@
|
||||
<el-option v-for="n in 5" :key="n" :label="`Lv${n}`" :value="n" />
|
||||
</el-select>
|
||||
</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-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-input v-model="entry.name" />
|
||||
</el-form-item>
|
||||
@@ -42,18 +50,22 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
import { computed, ref } from 'vue'
|
||||
import OverrideEditor from './OverrideEditor.vue'
|
||||
import { defaultTriggerEntry } from '../constants'
|
||||
|
||||
const props = defineProps({
|
||||
model: { type: Object, required: true }, // TriggerGrouped
|
||||
// 触发组 key(atking/atked/fstart/fend/dead),决定是否展示概率参数
|
||||
group: { type: String, default: '' },
|
||||
skillOptions: { type: Array, default: () => [] },
|
||||
skillMap: { type: Object, default: () => ({}) },
|
||||
// 全部 buff 候选(timed_buff_id 下拉用),由 App 透传
|
||||
buffOptions: { type: Array, default: () => [] },
|
||||
})
|
||||
const newSid = ref(null)
|
||||
// 概率参数仅攻/受击触发消费(fstart/fend/dead 固定触发)
|
||||
const chanceVisible = computed(() => props.group === 'atking' || props.group === 'atked')
|
||||
|
||||
function skillName(sid) {
|
||||
return props.skillMap[sid]?.name || ''
|
||||
@@ -69,6 +81,13 @@ function removeGroup(sid) {
|
||||
}
|
||||
function addEntry(group) {
|
||||
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>
|
||||
|
||||
@@ -46,8 +46,8 @@ export const ROLE_ATK_SKILL = {
|
||||
Warrior: [6004],
|
||||
Assassin: [6001, 6002, 6003, 6004],
|
||||
Archer: [6004, 6006, 6007, 6008],
|
||||
Mage: [6009, 6010, 6011, 6012],
|
||||
Support: [6004, 6009, 6010, 6011, 6012],
|
||||
Mage: [6009, 6010, 6011, 6012, 6013, 6014, 6015],
|
||||
Support: [6004, 6009, 6010, 6011, 6012, 6013, 6014, 6015],
|
||||
}
|
||||
|
||||
// 按职业映射大招底座
|
||||
@@ -117,7 +117,7 @@ export function defaultHero() {
|
||||
dodge: null, // 闪避率(null = 全局默认 15,填值覆盖)
|
||||
accuracy: null, // 命中率(null = 全局默认 10,填值覆盖)
|
||||
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: {},
|
||||
fstart: {},
|
||||
fend: {},
|
||||
|
||||
@@ -4,6 +4,8 @@ import vue from '@vitejs/plugin-vue'
|
||||
export default defineConfig({
|
||||
plugins: [vue()],
|
||||
server: {
|
||||
// 监听所有网卡,容器/局域网内可直接访问开发服务器
|
||||
host: '0.0.0.0',
|
||||
port: 4004,
|
||||
strictPort: true,
|
||||
proxy: {
|
||||
|
||||
Reference in New Issue
Block a user