Compare commits
3 Commits
card
...
e5e379aecc
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e5e379aecc | ||
|
|
9687adb559 | ||
|
|
af5b79b9a1 |
@@ -99,7 +99,7 @@
|
||||
"_lpos": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 200,
|
||||
"y": 177.92700000000002,
|
||||
"y": 177,
|
||||
"z": 0
|
||||
},
|
||||
"_lrot": {
|
||||
@@ -266,8 +266,8 @@
|
||||
},
|
||||
"_lpos": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 100,
|
||||
"y": 177.92700000000002,
|
||||
"x": 91.434,
|
||||
"y": 99.82,
|
||||
"z": 0
|
||||
},
|
||||
"_lrot": {
|
||||
@@ -434,8 +434,8 @@
|
||||
},
|
||||
"_lpos": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 0,
|
||||
"y": 177.92700000000002,
|
||||
"x": 110.644,
|
||||
"y": 234.75,
|
||||
"z": 0
|
||||
},
|
||||
"_lrot": {
|
||||
@@ -602,8 +602,8 @@
|
||||
},
|
||||
"_lpos": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": -100,
|
||||
"y": 177.92700000000002,
|
||||
"x": -47.56,
|
||||
"y": 261.112,
|
||||
"z": 0
|
||||
},
|
||||
"_lrot": {
|
||||
@@ -770,8 +770,8 @@
|
||||
},
|
||||
"_lpos": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": -200,
|
||||
"y": 177.92700000000002,
|
||||
"x": -30.737,
|
||||
"y": 68.374,
|
||||
"z": 0
|
||||
},
|
||||
"_lrot": {
|
||||
|
||||
@@ -1382,7 +1382,7 @@
|
||||
"_lpos": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": -330,
|
||||
"y": 390.888,
|
||||
"y": 372.03,
|
||||
"z": 0
|
||||
},
|
||||
"_lrot": {
|
||||
@@ -2604,7 +2604,7 @@
|
||||
"__id__": 148
|
||||
}
|
||||
],
|
||||
"_active": false,
|
||||
"_active": true,
|
||||
"_components": [
|
||||
{
|
||||
"__id__": 156
|
||||
@@ -2621,8 +2621,8 @@
|
||||
},
|
||||
"_lpos": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 0,
|
||||
"y": 208.926,
|
||||
"x": 259.067,
|
||||
"y": 158.268,
|
||||
"z": 0
|
||||
},
|
||||
"_lrot": {
|
||||
@@ -2715,7 +2715,7 @@
|
||||
},
|
||||
"_contentSize": {
|
||||
"__type__": "cc.Size",
|
||||
"width": 720,
|
||||
"width": 510.00000000000006,
|
||||
"height": 50
|
||||
},
|
||||
"_anchorPoint": {
|
||||
@@ -3166,7 +3166,7 @@
|
||||
},
|
||||
"_contentSize": {
|
||||
"__type__": "cc.Size",
|
||||
"width": 720,
|
||||
"width": 510.00000000000006,
|
||||
"height": 50
|
||||
},
|
||||
"_anchorPoint": {
|
||||
@@ -3236,8 +3236,8 @@
|
||||
},
|
||||
"_alignFlags": 40,
|
||||
"_target": null,
|
||||
"_left": 0,
|
||||
"_right": 0,
|
||||
"_left": 4.06699999999995,
|
||||
"_right": -4.06699999999995,
|
||||
"_top": 0,
|
||||
"_bottom": 0,
|
||||
"_horizontalCenter": 0,
|
||||
@@ -3316,7 +3316,7 @@
|
||||
"_left": 30,
|
||||
"_right": 515,
|
||||
"_top": 0,
|
||||
"_bottom": 260.888,
|
||||
"_bottom": 242.02999999999997,
|
||||
"_horizontalCenter": 0,
|
||||
"_verticalCenter": 0,
|
||||
"_isAbsLeft": true,
|
||||
|
||||
@@ -22,26 +22,26 @@
|
||||
"__id__": 2
|
||||
},
|
||||
{
|
||||
"__id__": 286
|
||||
"__id__": 272
|
||||
},
|
||||
{
|
||||
"__id__": 295
|
||||
"__id__": 281
|
||||
}
|
||||
],
|
||||
"_active": true,
|
||||
"_components": [
|
||||
{
|
||||
"__id__": 307
|
||||
"__id__": 293
|
||||
},
|
||||
{
|
||||
"__id__": 309
|
||||
"__id__": 295
|
||||
},
|
||||
{
|
||||
"__id__": 311
|
||||
"__id__": 297
|
||||
}
|
||||
],
|
||||
"_prefab": {
|
||||
"__id__": 313
|
||||
"__id__": 299
|
||||
},
|
||||
"_lpos": {
|
||||
"__type__": "cc.Vec3",
|
||||
@@ -94,17 +94,17 @@
|
||||
"_active": true,
|
||||
"_components": [
|
||||
{
|
||||
"__id__": 279
|
||||
"__id__": 265
|
||||
},
|
||||
{
|
||||
"__id__": 281
|
||||
"__id__": 267
|
||||
},
|
||||
{
|
||||
"__id__": 283
|
||||
"__id__": 269
|
||||
}
|
||||
],
|
||||
"_prefab": {
|
||||
"__id__": 285
|
||||
"__id__": 271
|
||||
},
|
||||
"_lpos": {
|
||||
"__type__": "cc.Vec3",
|
||||
@@ -6090,108 +6090,32 @@
|
||||
},
|
||||
{
|
||||
"__type__": "cc.PrefabInstance",
|
||||
"fileId": "c8OWze/z9IMpmg5hcYAPwM",
|
||||
"fileId": "87n/wcZ7tIPbu7m1+Q/KV3",
|
||||
"prefabRootNode": {
|
||||
"__id__": 1
|
||||
},
|
||||
"mountedChildren": [],
|
||||
"mountedComponents": [
|
||||
{
|
||||
"__id__": 260
|
||||
}
|
||||
],
|
||||
"mountedComponents": [],
|
||||
"propertyOverrides": [
|
||||
{
|
||||
"__id__": 260
|
||||
},
|
||||
{
|
||||
"__id__": 262
|
||||
},
|
||||
{
|
||||
"__id__": 263
|
||||
},
|
||||
{
|
||||
"__id__": 264
|
||||
},
|
||||
{
|
||||
"__id__": 266
|
||||
},
|
||||
{
|
||||
"__id__": 267
|
||||
},
|
||||
{
|
||||
"__id__": 268
|
||||
},
|
||||
{
|
||||
"__id__": 269
|
||||
},
|
||||
{
|
||||
"__id__": 271
|
||||
},
|
||||
{
|
||||
"__id__": 273
|
||||
},
|
||||
{
|
||||
"__id__": 275
|
||||
},
|
||||
{
|
||||
"__id__": 277
|
||||
}
|
||||
],
|
||||
"removedComponents": []
|
||||
},
|
||||
{
|
||||
"__type__": "cc.MountedComponentsInfo",
|
||||
"targetInfo": {
|
||||
"__id__": 261
|
||||
},
|
||||
"components": [
|
||||
{
|
||||
"__id__": 262
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"__type__": "cc.TargetInfo",
|
||||
"localID": [
|
||||
"f1ya2LoYBB547vP13Ydezp"
|
||||
]
|
||||
},
|
||||
{
|
||||
"__type__": "cc.Widget",
|
||||
"_name": "",
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {
|
||||
"mountedRoot": {
|
||||
"__id__": 257
|
||||
}
|
||||
},
|
||||
"node": {
|
||||
"__id__": 257
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 263
|
||||
},
|
||||
"_alignFlags": 18,
|
||||
"_target": null,
|
||||
"_left": 0,
|
||||
"_right": 0,
|
||||
"_top": 0,
|
||||
"_bottom": 0,
|
||||
"_horizontalCenter": -76.841,
|
||||
"_verticalCenter": 200,
|
||||
"_isAbsLeft": true,
|
||||
"_isAbsRight": true,
|
||||
"_isAbsTop": true,
|
||||
"_isAbsBottom": true,
|
||||
"_isAbsHorizontalCenter": true,
|
||||
"_isAbsVerticalCenter": true,
|
||||
"_originalWidth": 0,
|
||||
"_originalHeight": 0,
|
||||
"_alignMode": 2,
|
||||
"_lockFlags": 0,
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "cc.CompPrefabInfo",
|
||||
"fileId": "3eiYz0maFGj5G3KaylC3ro"
|
||||
},
|
||||
{
|
||||
"__type__": "CCPropertyOverrideInfo",
|
||||
"targetInfo": {
|
||||
"__id__": 265
|
||||
"__id__": 261
|
||||
},
|
||||
"propertyPath": [
|
||||
"_name"
|
||||
@@ -6207,22 +6131,22 @@
|
||||
{
|
||||
"__type__": "CCPropertyOverrideInfo",
|
||||
"targetInfo": {
|
||||
"__id__": 265
|
||||
"__id__": 261
|
||||
},
|
||||
"propertyPath": [
|
||||
"_lpos"
|
||||
],
|
||||
"value": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": -76.841,
|
||||
"y": 840,
|
||||
"x": -143.895,
|
||||
"y": 622.066,
|
||||
"z": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"__type__": "CCPropertyOverrideInfo",
|
||||
"targetInfo": {
|
||||
"__id__": 265
|
||||
"__id__": 261
|
||||
},
|
||||
"propertyPath": [
|
||||
"_lrot"
|
||||
@@ -6238,7 +6162,7 @@
|
||||
{
|
||||
"__type__": "CCPropertyOverrideInfo",
|
||||
"targetInfo": {
|
||||
"__id__": 265
|
||||
"__id__": 261
|
||||
},
|
||||
"propertyPath": [
|
||||
"_euler"
|
||||
@@ -6250,111 +6174,6 @@
|
||||
"z": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"__type__": "CCPropertyOverrideInfo",
|
||||
"targetInfo": {
|
||||
"__id__": 270
|
||||
},
|
||||
"propertyPath": [
|
||||
"_lpos"
|
||||
],
|
||||
"value": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 200,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"__type__": "cc.TargetInfo",
|
||||
"localID": [
|
||||
"bdA9GHaYtL34EFtEibL2hR"
|
||||
]
|
||||
},
|
||||
{
|
||||
"__type__": "CCPropertyOverrideInfo",
|
||||
"targetInfo": {
|
||||
"__id__": 272
|
||||
},
|
||||
"propertyPath": [
|
||||
"_lpos"
|
||||
],
|
||||
"value": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 100,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"__type__": "cc.TargetInfo",
|
||||
"localID": [
|
||||
"adFmHHJ5BBAY0CazvLDgGw"
|
||||
]
|
||||
},
|
||||
{
|
||||
"__type__": "CCPropertyOverrideInfo",
|
||||
"targetInfo": {
|
||||
"__id__": 274
|
||||
},
|
||||
"propertyPath": [
|
||||
"_lpos"
|
||||
],
|
||||
"value": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"__type__": "cc.TargetInfo",
|
||||
"localID": [
|
||||
"96QFNOz55OyZEByIPMUwVi"
|
||||
]
|
||||
},
|
||||
{
|
||||
"__type__": "CCPropertyOverrideInfo",
|
||||
"targetInfo": {
|
||||
"__id__": 276
|
||||
},
|
||||
"propertyPath": [
|
||||
"_lpos"
|
||||
],
|
||||
"value": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": -100,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"__type__": "cc.TargetInfo",
|
||||
"localID": [
|
||||
"82phyYrMBJLLQftj0f4fIS"
|
||||
]
|
||||
},
|
||||
{
|
||||
"__type__": "CCPropertyOverrideInfo",
|
||||
"targetInfo": {
|
||||
"__id__": 278
|
||||
},
|
||||
"propertyPath": [
|
||||
"_lpos"
|
||||
],
|
||||
"value": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": -200,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"__type__": "cc.TargetInfo",
|
||||
"localID": [
|
||||
"aenGhipwJAKZ3DgYqvrUgU"
|
||||
]
|
||||
},
|
||||
{
|
||||
"__type__": "cc.UITransform",
|
||||
"_name": "",
|
||||
@@ -6365,7 +6184,7 @@
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 280
|
||||
"__id__": 266
|
||||
},
|
||||
"_contentSize": {
|
||||
"__type__": "cc.Size",
|
||||
@@ -6393,7 +6212,7 @@
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 282
|
||||
"__id__": 268
|
||||
},
|
||||
"_alignFlags": 21,
|
||||
"_target": null,
|
||||
@@ -6429,7 +6248,7 @@
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 284
|
||||
"__id__": 270
|
||||
},
|
||||
"home_btn": {
|
||||
"__id__": 45
|
||||
@@ -6466,14 +6285,14 @@
|
||||
"__id__": 1
|
||||
},
|
||||
"_prefab": {
|
||||
"__id__": 287
|
||||
"__id__": 273
|
||||
},
|
||||
"__editorExtras__": {}
|
||||
},
|
||||
{
|
||||
"__type__": "cc.PrefabInfo",
|
||||
"root": {
|
||||
"__id__": 286
|
||||
"__id__": 272
|
||||
},
|
||||
"asset": {
|
||||
"__uuid__": "26bff847-cd29-48a5-bbfa-c3e2dbda688d",
|
||||
@@ -6481,7 +6300,7 @@
|
||||
},
|
||||
"fileId": "5a9CMsVQhKP5Y+UJfTKPbx",
|
||||
"instance": {
|
||||
"__id__": 288
|
||||
"__id__": 274
|
||||
},
|
||||
"targetOverrides": null
|
||||
},
|
||||
@@ -6495,19 +6314,19 @@
|
||||
"mountedComponents": [],
|
||||
"propertyOverrides": [
|
||||
{
|
||||
"__id__": 289
|
||||
"__id__": 275
|
||||
},
|
||||
{
|
||||
"__id__": 291
|
||||
"__id__": 277
|
||||
},
|
||||
{
|
||||
"__id__": 292
|
||||
"__id__": 278
|
||||
},
|
||||
{
|
||||
"__id__": 293
|
||||
"__id__": 279
|
||||
},
|
||||
{
|
||||
"__id__": 294
|
||||
"__id__": 280
|
||||
}
|
||||
],
|
||||
"removedComponents": []
|
||||
@@ -6515,7 +6334,7 @@
|
||||
{
|
||||
"__type__": "CCPropertyOverrideInfo",
|
||||
"targetInfo": {
|
||||
"__id__": 290
|
||||
"__id__": 276
|
||||
},
|
||||
"propertyPath": [
|
||||
"_name"
|
||||
@@ -6531,7 +6350,7 @@
|
||||
{
|
||||
"__type__": "CCPropertyOverrideInfo",
|
||||
"targetInfo": {
|
||||
"__id__": 290
|
||||
"__id__": 276
|
||||
},
|
||||
"propertyPath": [
|
||||
"_lpos"
|
||||
@@ -6546,7 +6365,7 @@
|
||||
{
|
||||
"__type__": "CCPropertyOverrideInfo",
|
||||
"targetInfo": {
|
||||
"__id__": 290
|
||||
"__id__": 276
|
||||
},
|
||||
"propertyPath": [
|
||||
"_lrot"
|
||||
@@ -6562,7 +6381,7 @@
|
||||
{
|
||||
"__type__": "CCPropertyOverrideInfo",
|
||||
"targetInfo": {
|
||||
"__id__": 290
|
||||
"__id__": 276
|
||||
},
|
||||
"propertyPath": [
|
||||
"_euler"
|
||||
@@ -6577,7 +6396,7 @@
|
||||
{
|
||||
"__type__": "CCPropertyOverrideInfo",
|
||||
"targetInfo": {
|
||||
"__id__": 290
|
||||
"__id__": 276
|
||||
},
|
||||
"propertyPath": [
|
||||
"_active"
|
||||
@@ -6591,14 +6410,14 @@
|
||||
"__id__": 1
|
||||
},
|
||||
"_prefab": {
|
||||
"__id__": 296
|
||||
"__id__": 282
|
||||
},
|
||||
"__editorExtras__": {}
|
||||
},
|
||||
{
|
||||
"__type__": "cc.PrefabInfo",
|
||||
"root": {
|
||||
"__id__": 295
|
||||
"__id__": 281
|
||||
},
|
||||
"asset": {
|
||||
"__uuid__": "56aee962-4a5e-45ae-a779-999444d06d18",
|
||||
@@ -6606,7 +6425,7 @@
|
||||
},
|
||||
"fileId": "cboM54s0hM07XCtrpFp0/b",
|
||||
"instance": {
|
||||
"__id__": 297
|
||||
"__id__": 283
|
||||
},
|
||||
"targetOverrides": null
|
||||
},
|
||||
@@ -6620,25 +6439,25 @@
|
||||
"mountedComponents": [],
|
||||
"propertyOverrides": [
|
||||
{
|
||||
"__id__": 298
|
||||
"__id__": 284
|
||||
},
|
||||
{
|
||||
"__id__": 300
|
||||
"__id__": 286
|
||||
},
|
||||
{
|
||||
"__id__": 301
|
||||
"__id__": 287
|
||||
},
|
||||
{
|
||||
"__id__": 302
|
||||
"__id__": 288
|
||||
},
|
||||
{
|
||||
"__id__": 303
|
||||
"__id__": 289
|
||||
},
|
||||
{
|
||||
"__id__": 305
|
||||
"__id__": 291
|
||||
},
|
||||
{
|
||||
"__id__": 306
|
||||
"__id__": 292
|
||||
}
|
||||
],
|
||||
"removedComponents": []
|
||||
@@ -6646,7 +6465,7 @@
|
||||
{
|
||||
"__type__": "CCPropertyOverrideInfo",
|
||||
"targetInfo": {
|
||||
"__id__": 299
|
||||
"__id__": 285
|
||||
},
|
||||
"propertyPath": [
|
||||
"_name"
|
||||
@@ -6662,7 +6481,7 @@
|
||||
{
|
||||
"__type__": "CCPropertyOverrideInfo",
|
||||
"targetInfo": {
|
||||
"__id__": 299
|
||||
"__id__": 285
|
||||
},
|
||||
"propertyPath": [
|
||||
"_lpos"
|
||||
@@ -6677,7 +6496,7 @@
|
||||
{
|
||||
"__type__": "CCPropertyOverrideInfo",
|
||||
"targetInfo": {
|
||||
"__id__": 299
|
||||
"__id__": 285
|
||||
},
|
||||
"propertyPath": [
|
||||
"_lrot"
|
||||
@@ -6693,7 +6512,7 @@
|
||||
{
|
||||
"__type__": "CCPropertyOverrideInfo",
|
||||
"targetInfo": {
|
||||
"__id__": 299
|
||||
"__id__": 285
|
||||
},
|
||||
"propertyPath": [
|
||||
"_euler"
|
||||
@@ -6708,7 +6527,7 @@
|
||||
{
|
||||
"__type__": "CCPropertyOverrideInfo",
|
||||
"targetInfo": {
|
||||
"__id__": 304
|
||||
"__id__": 290
|
||||
},
|
||||
"propertyPath": [
|
||||
"_top"
|
||||
@@ -6724,7 +6543,7 @@
|
||||
{
|
||||
"__type__": "CCPropertyOverrideInfo",
|
||||
"targetInfo": {
|
||||
"__id__": 304
|
||||
"__id__": 290
|
||||
},
|
||||
"propertyPath": [
|
||||
"_alignFlags"
|
||||
@@ -6734,7 +6553,7 @@
|
||||
{
|
||||
"__type__": "CCPropertyOverrideInfo",
|
||||
"targetInfo": {
|
||||
"__id__": 304
|
||||
"__id__": 290
|
||||
},
|
||||
"propertyPath": [
|
||||
"_bottom"
|
||||
@@ -6751,7 +6570,7 @@
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 308
|
||||
"__id__": 294
|
||||
},
|
||||
"_contentSize": {
|
||||
"__type__": "cc.Size",
|
||||
@@ -6779,7 +6598,7 @@
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 310
|
||||
"__id__": 296
|
||||
},
|
||||
"_alignFlags": 45,
|
||||
"_target": null,
|
||||
@@ -6815,7 +6634,7 @@
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 312
|
||||
"__id__": 298
|
||||
},
|
||||
"debugMode": false,
|
||||
"_id": ""
|
||||
@@ -6837,10 +6656,10 @@
|
||||
"targetOverrides": null,
|
||||
"nestedPrefabInstanceRoots": [
|
||||
{
|
||||
"__id__": 295
|
||||
"__id__": 281
|
||||
},
|
||||
{
|
||||
"__id__": 286
|
||||
"__id__": 272
|
||||
},
|
||||
{
|
||||
"__id__": 257
|
||||
|
||||
@@ -176,43 +176,54 @@ export const HeroInfo: Record<number, heroInfo> = {
|
||||
|
||||
/*
|
||||
*=============怪物配置列表================
|
||||
* 基础近战型(lv:1) : SPEED:800 |AP:12 | HP:120 | skills[0].cd=0.65
|
||||
* 重型坦克型(lv:1) : SPEED:800 |AP:30 | HP:350 | skills[0].cd=2
|
||||
* 远程dps(lv:1) : SPEED:800 |AP:45 | HP:80 | skills[0].cd=1.5
|
||||
* 远程辅助(lv:1) : SPEED:800 |AP:20 | HP:80 | skills[0].cd=1
|
||||
* 精英 (lv:1) : SPEED:800 |AP:20 | HP:1500 | skills[0].cd=1
|
||||
* 基础近战型(lv:1) : SPEED:800 |AP:12 | HP:360 | skills[0].cd=0.65
|
||||
* 重型坦克型(lv:1) : SPEED:800 |AP:30 | HP:1050 | skills[0].cd=2
|
||||
* 远程dps(lv:1) : SPEED:800 |AP:45 | HP:240 | skills[0].cd=1.5
|
||||
* 远程辅助(lv:1) : SPEED:800 |AP:20 | HP:240 | skills[0].cd=1
|
||||
* 精英 (lv:1) : SPEED:800 |AP:20 | HP:4500 | skills[0].cd=1
|
||||
*/
|
||||
|
||||
//============== 兽人系列 ===============
|
||||
// 近战型
|
||||
6001:{uuid:6001,name:"兽人战士",path:"mo1", fac:FacSet.MON,cards_lv:1,lv:1,type:HType.Melee,hp:120,ap:12,speed:100,
|
||||
6001:{uuid:6001,name:"兽人战士",path:"mo1", fac:FacSet.MON,cards_lv:1,lv:1,type:HType.Melee,hp:360,ap:12,speed:100,
|
||||
skills:{6001:{uuid:6001,lv:1,cd:0.65,ccd:0}},info:""},
|
||||
6002:{uuid:6002,name:"兽人斥候",path:"mo3", fac:FacSet.MON,cards_lv:1,lv:1,type:HType.Melee,hp:120,ap:12,speed:100,
|
||||
6002:{uuid:6002,name:"兽人斥候",path:"mo3", fac:FacSet.MON,cards_lv:1,lv:1,type:HType.Melee,hp:360,ap:12,speed:100,
|
||||
skills:{6001:{uuid:6001,lv:1,cd:0.65,ccd:0}},info:""},
|
||||
6003:{uuid:6003,name:"兽人卫士",path:"mo4", fac:FacSet.MON,cards_lv:1,lv:1,type:HType.Melee,hp:350,ap:30,speed:100,
|
||||
6003:{uuid:6003,name:"兽人卫士",path:"mo4", fac:FacSet.MON,cards_lv:1,lv:1,type:HType.Melee,hp:1050,ap:30,speed:100,
|
||||
skills:{6001:{uuid:6001,lv:1,cd:2,ccd:0}},info:""},
|
||||
6004:{uuid:6004,name:"兽人射手",path:"mo2", fac:FacSet.MON,cards_lv:1,lv:1,type:HType.Long,hp:80,ap:45,speed:100,
|
||||
6004:{uuid:6004,name:"兽人射手",path:"mo2", fac:FacSet.MON,cards_lv:1,lv:1,type:HType.Long,hp:240,ap:45,speed:100,
|
||||
skills:{6001:{uuid:6101,lv:1,cd:1.5,ccd:0}},info:""},
|
||||
6005:{uuid:6005,name:"兽人法师",path:"mo5", fac:FacSet.MON,cards_lv:1,lv:1,type:HType.Long,hp:80,ap:20,speed:100,
|
||||
6005:{uuid:6005,name:"兽人法师",path:"mo5", fac:FacSet.MON,cards_lv:1,lv:1,type:HType.Long,hp:240,ap:20,speed:100,
|
||||
skills:{6001:{uuid:6203,lv:1,cd:1.5,ccd:0}},info:""},
|
||||
6006:{uuid:6006,name:"兽人首领",path:"mo6", fac:FacSet.MON,cards_lv:1,lv:1,type:HType.Melee,hp:1500,ap:20,speed:100,
|
||||
6006:{uuid:6006,name:"兽人首领",path:"mo6", fac:FacSet.MON,cards_lv:1,lv:1,type:HType.Melee,hp:4500,ap:20,speed:100,
|
||||
skills:{6002:{uuid:6002,lv:1,cd:2,ccd:0}},info:""},
|
||||
//============== 亡灵系列 ===============
|
||||
// 近战型
|
||||
6101:{uuid:6101,name:"亡灵战士",path:"mud1", fac:FacSet.MON,cards_lv:1,lv:1,type:HType.Melee,hp:120,ap:12,speed:100,
|
||||
6101:{uuid:6101,name:"亡灵战士",path:"mud1", fac:FacSet.MON,cards_lv:1,lv:1,type:HType.Melee,hp:360,ap:12,speed:100,
|
||||
skills:{6001:{uuid:6001,lv:1,cd:0.65,ccd:0}},info:""},
|
||||
6103:{uuid:6103,name:"亡灵斥候",path:"mud3", fac:FacSet.MON,cards_lv:1,lv:1,type:HType.Melee,hp:120,ap:12,speed:100,
|
||||
6103:{uuid:6103,name:"亡灵斥候",path:"mud3", fac:FacSet.MON,cards_lv:1,lv:1,type:HType.Melee,hp:360,ap:12,speed:100,
|
||||
skills:{6001:{uuid:6001,lv:1,cd:0.65,ccd:0}},info:""},
|
||||
6102:{uuid:6102,name:"亡灵射手",path:"mud2", fac:FacSet.MON,cards_lv:1,lv:1,type:HType.Long,hp:80,ap:45,speed:100,
|
||||
6102:{uuid:6102,name:"亡灵射手",path:"mud2", fac:FacSet.MON,cards_lv:1,lv:1,type:HType.Long,hp:240,ap:45,speed:100,
|
||||
skills:{6001:{uuid:6101,lv:1,cd:1.5,ccd:0}},info:""},
|
||||
// 6105:{uuid:6105,name:"兽人法师",path:"mud5", fac:FacSet.MON,cards_lv:1,lv:1,type:HType.Melee,hp:80,ap:20,speed:100,
|
||||
// 6105:{uuid:6105,name:"兽人法师",path:"mud5", fac:FacSet.MON,cards_lv:1,lv:1,type:HType.Melee,hp:240,ap:20,speed:100,
|
||||
// skills:{6001:{uuid:6001,lv:1,cd:1,ccd:0},6003:{uuid:6003,lv:1,cd:10,ccd:0}},info:""},
|
||||
// 6. 精英/BOSS型
|
||||
6104:{uuid:6104,name:"亡灵法师",path:"mud4", fac:FacSet.MON,cards_lv:1,lv:1,type:HType.Long,hp:350,ap:30,speed:100,
|
||||
6104:{uuid:6104,name:"亡灵法师",path:"mud4", fac:FacSet.MON,cards_lv:1,lv:1,type:HType.Long,hp:1050,ap:30,speed:100,
|
||||
skills:{6204:{uuid:6204,lv:1,cd:2,ccd:0},6206:{uuid:6206,lv:1,cd:10,ccd:0}},info:""},
|
||||
6105:{uuid:6105,name:"亡灵首领",path:"mud5", fac:FacSet.MON,cards_lv:1,lv:1,type:HType.Melee,hp:1500,ap:20,speed:100,
|
||||
6105:{uuid:6105,name:"亡灵首领",path:"mud5", fac:FacSet.MON,cards_lv:1,lv:1,type:HType.Melee,hp:4500,ap:20,speed:100,
|
||||
skills:{6002:{uuid:6002,lv:1,cd:2,ccd:0},6005:{uuid:6005,lv:1,cd:10,ccd:0}},info:""},
|
||||
|
||||
//============== 特殊类型 (Bomber, Summoner, Assassin, Splitter) ===============
|
||||
6201:{uuid:6201,name:"哥布林自爆兵",path:"mo2", fac:FacSet.MON,cards_lv:1,lv:1,type:HType.Melee,hp:180,ap:80,speed:150,
|
||||
skills:{6001:{uuid:6001,lv:1,cd:1,ccd:0}},info:"自爆兵"},
|
||||
6202:{uuid:6202,name:"骷髅自爆兵",path:"mud2", fac:FacSet.MON,cards_lv:1,lv:1,type:HType.Melee,hp:180,ap:80,speed:150,
|
||||
skills:{6001:{uuid:6001,lv:1,cd:1,ccd:0}},info:"自爆兵"},
|
||||
6203:{uuid:6203,name:"深渊召唤师",path:"hm2", fac:FacSet.MON,cards_lv:1,lv:1,type:HType.Long,hp:300,ap:15,speed:80,
|
||||
skills:{6001:{uuid:6203,lv:1,cd:2,ccd:0}},info:"召唤师"},
|
||||
6204:{uuid:6204,name:"暗影刺客",path:"hc1", fac:FacSet.MON,cards_lv:1,lv:1,type:HType.Melee,hp:270,ap:55,speed:200,
|
||||
skills:{6001:{uuid:6001,lv:1,cd:0.5,ccd:0}},info:"刺客"},
|
||||
6205:{uuid:6205,name:"分裂软泥",path:"mo1", fac:FacSet.MON,cards_lv:1,lv:1,type:HType.Melee,hp:450,ap:20,speed:90,
|
||||
skills:{6001:{uuid:6001,lv:1,cd:1,ccd:0}},info:"分裂怪"},
|
||||
};
|
||||
|
||||
export const HeroList: number[] = [
|
||||
|
||||
@@ -320,6 +320,7 @@ export class HeroAttrsComp extends ecs.Comp {
|
||||
this.maxSkillDistance = 0;
|
||||
this.minSkillDistance = 0;
|
||||
|
||||
|
||||
this.is_dead = false;
|
||||
this.is_count_dead = false;
|
||||
this.is_atking = false;
|
||||
|
||||
@@ -446,13 +446,14 @@ export class HeroViewComp extends CCComp {
|
||||
}
|
||||
|
||||
if(this.model.fac === FacSet.HERO){
|
||||
// 英雄直接销毁,不再进入墓地
|
||||
// 将英雄移到玩家看不到的墓地
|
||||
this.node.setPosition(v3(-2000, -2000, 0));
|
||||
const collider = this.node.getComponent(Collider2D);
|
||||
if (collider) {
|
||||
collider.enabled = false;
|
||||
}
|
||||
// 隐藏UI
|
||||
this.top_node.active = false;
|
||||
this.ent.destroy();
|
||||
} else {
|
||||
// 🔥 方案B:治理性措施 - 在销毁实体前先禁用碰撞体,从源头减少"尸体"参与碰撞
|
||||
const collider = this.node.getComponent(Collider2D);
|
||||
|
||||
@@ -432,6 +432,13 @@ export class MissionCardComp extends CCComp {
|
||||
private onUseHeroCard(event: string, args: any) {
|
||||
const payload = args ?? event;
|
||||
if (!payload) return;
|
||||
|
||||
if (this.isBattlePhase) {
|
||||
payload.cancel = true;
|
||||
payload.reason = "battle_phase";
|
||||
oops.gui.toast("战斗阶段无法召唤英雄");
|
||||
return;
|
||||
}
|
||||
|
||||
const current = this.getAliveHeroCount();
|
||||
this.syncMissionHeroData(current);
|
||||
@@ -664,10 +671,16 @@ export class MissionCardComp extends CCComp {
|
||||
private enterBattlePhase() {
|
||||
if (!this.cards_node || !this.cards_node.isValid) return;
|
||||
this.initCardsPanelPos();
|
||||
// 战斗阶段抽卡面板不再收起
|
||||
this.cards_node.active = true;
|
||||
Tween.stopAllByTarget(this.cards_node);
|
||||
this.cards_node.setScale(this.cardsShowScale);
|
||||
// 战斗阶段不再隐藏抽卡面板
|
||||
// Tween.stopAllByTarget(this.cards_node);
|
||||
// tween(this.cards_node)
|
||||
// .to(this.cardsPanelMoveDuration, { scale: this.cardsHideScale })
|
||||
// .call(() => {
|
||||
// if (this.cards_node && this.cards_node.isValid) {
|
||||
// this.cards_node.active = false;
|
||||
// }
|
||||
// })
|
||||
// .start();
|
||||
|
||||
this.cachedHInfoComps.forEach(comp => {
|
||||
if (comp && comp.isValid) {
|
||||
@@ -680,8 +693,7 @@ export class MissionCardComp extends CCComp {
|
||||
private buildDrawCards(): CardConfig[] {
|
||||
let targetType: CardType | CardType[] | undefined = undefined;
|
||||
if (this.isBattlePhase) {
|
||||
// 战斗阶段只刷英雄卡牌,不刷其他卡牌
|
||||
targetType = CardType.Hero;
|
||||
targetType = CardType.Skill;
|
||||
} else {
|
||||
targetType = [CardType.Hero, CardType.SpecialRefresh];
|
||||
}
|
||||
|
||||
@@ -520,9 +520,9 @@ export class MissionComp extends CCComp {
|
||||
case MissionPhase.BattleEnd:
|
||||
// BattleEnd 计时结束后,如果是因为全灭或手动调用的 fight_end,进入 Settle
|
||||
// 需要注意的是,open_Victory / fight_end 现在只需切换到 BattleEnd 即可,Settle 由这里自动接管
|
||||
// 如果游戏正在运行(波次更迭),直接进入下一波的 BattleStart,不再进入 PrepareStart
|
||||
// 如果游戏正在运行(波次更迭),则自动进入 PrepareStart 阶段
|
||||
if (smc.mission.play && !smc.mission.pause) {
|
||||
this.changePhase(MissionPhase.BattleStart);
|
||||
this.changePhase(MissionPhase.PrepareStart);
|
||||
} else {
|
||||
this.changePhase(MissionPhase.Settle);
|
||||
|
||||
@@ -566,7 +566,7 @@ export class MissionComp extends CCComp {
|
||||
* - 显示开始按钮
|
||||
* - 触发英雄战斗结束技能
|
||||
*/
|
||||
enterPreparePhase() {
|
||||
private enterPreparePhase() {
|
||||
this.changePhase(MissionPhase.PrepareStart);
|
||||
}
|
||||
|
||||
|
||||
@@ -121,14 +121,24 @@ export class MissionHeroCompComp extends CCComp {
|
||||
}
|
||||
}
|
||||
|
||||
/** 战斗准备阶段:重置出战英雄计数,恢复满血 */
|
||||
/** 战斗准备阶段:重置出战英雄计数,恢复满血重新登场 */
|
||||
fight_ready(){
|
||||
const heroes = this.getAllHeroes();
|
||||
smc.vmdata.mission_data.hero_num = heroes.length;
|
||||
for (let i = 0; i < heroes.length; i++) {
|
||||
const hero = heroes[i];
|
||||
const model = hero.get(HeroAttrsComp);
|
||||
if (model) {
|
||||
const view = hero.get(HeroViewComp);
|
||||
if (model && view) {
|
||||
if (model.is_dead) {
|
||||
view.alive();
|
||||
const landingPos = this.pickPositionForHero([hero.eid]);
|
||||
// 不再直接设置位置,而是播放下落入场动画
|
||||
// 计算出出生点(空中)
|
||||
const spawnPos: Vec3 = v3(landingPos.x, landingPos.y + MissionHeroCompComp.HERO_DROP_HEIGHT, 0);
|
||||
view.node.setPosition(spawnPos);
|
||||
hero.playDropAnim(spawnPos, landingPos.y);
|
||||
}
|
||||
model.dirty_hp = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
* @description 肉鸽刷怪系统 v2 —— 三层程序化生成架构
|
||||
*
|
||||
* 架构:蓝图模板(节奏) + 权重填充(内容) + 自适应微调(数值)
|
||||
* 主线 30 波 / 10 阶梯 / 每档 3 波(恢复→攀升→高潮)
|
||||
* 主线 15 波 / 5 阶梯 / 每档 3 波(恢复→攀升→高潮)
|
||||
* 10 种怪物 + 8 种词缀 + 自适应难度 ±15%
|
||||
* 通关后可选无限模式(分层推进)
|
||||
*
|
||||
@@ -86,47 +86,47 @@ export interface AffixConfig {
|
||||
export const AffixConfigs: Record<AffixType, AffixConfig> = {
|
||||
[AffixType.Elite]: {
|
||||
name: "精英", hpMultiplier: 1.5, apMultiplier: 1.3,
|
||||
cost: 20, tierMin: 5, description: "+50% HP, +30% AP",
|
||||
cost: 20, tierMin: 3, description: "+50% HP, +30% AP",
|
||||
},
|
||||
[AffixType.Berserk]: {
|
||||
name: "狂暴", hpMultiplier: 1.0, apMultiplier: 1.0,
|
||||
cost: 15, tierMin: 5, description: "攻速 ×1.5 (行为层实现)",
|
||||
cost: 15, tierMin: 3, description: "攻速 ×1.5 (行为层实现)",
|
||||
},
|
||||
[AffixType.Shield]: {
|
||||
name: "护盾", hpMultiplier: 1.0, apMultiplier: 1.0,
|
||||
cost: 25, tierMin: 6, description: "开局带 抵御2次 伤害吸收盾",
|
||||
cost: 25, tierMin: 3, description: "开局带 抵御2次 伤害吸收盾",
|
||||
},
|
||||
[AffixType.Regen]: {
|
||||
name: "再生", hpMultiplier: 1.0, apMultiplier: 1.0,
|
||||
cost: 20, tierMin: 7, description: "每秒回复 2% HP",
|
||||
cost: 20, tierMin: 4, description: "每秒回复 2% HP",
|
||||
},
|
||||
[AffixType.Swift]: {
|
||||
name: "疾速", hpMultiplier: 1.0, apMultiplier: 1.0,
|
||||
cost: 10, tierMin: 7, description: "移速 ×2",
|
||||
cost: 10, tierMin: 4, description: "移速 ×2",
|
||||
},
|
||||
[AffixType.Giant]: {
|
||||
name: "巨型", hpMultiplier: 2.0, apMultiplier: 1.5,
|
||||
cost: 30, tierMin: 8, description: "×2 体型, +100% HP, +50% AP",
|
||||
cost: 30, tierMin: 4, description: "×2 体型, +100% HP, +50% AP",
|
||||
},
|
||||
[AffixType.Chain]: {
|
||||
name: "连锁", hpMultiplier: 1.0, apMultiplier: 1.0,
|
||||
cost: 20, tierMin: 9, description: "攻击附带 50% 溅射伤害",
|
||||
cost: 20, tierMin: 5, description: "攻击附带 50% 溅射伤害",
|
||||
},
|
||||
[AffixType.SummonerA]: {
|
||||
name: "召唤", hpMultiplier: 1.0, apMultiplier: 1.0,
|
||||
cost: 25, tierMin: 10, description: "每 8 秒召唤 1 个小怪",
|
||||
cost: 25, tierMin: 5, description: "每 8 秒召唤 1 个小怪",
|
||||
},
|
||||
[AffixType.CritRes]: {
|
||||
name: "坚韧", hpMultiplier: 1.0, apMultiplier: 1.0,
|
||||
cost: 15, tierMin: 6, description: "+暴击抗性",
|
||||
cost: 15, tierMin: 3, description: "+暴击抗性",
|
||||
},
|
||||
[AffixType.FreezeRes]: {
|
||||
name: "防寒", hpMultiplier: 1.0, apMultiplier: 1.0,
|
||||
cost: 15, tierMin: 6, description: "+冰冻抗性",
|
||||
cost: 15, tierMin: 3, description: "+冰冻抗性",
|
||||
},
|
||||
[AffixType.KnockbackRes]: {
|
||||
name: "稳固", hpMultiplier: 1.0, apMultiplier: 1.0,
|
||||
cost: 15, tierMin: 6, description: "+击退抗性",
|
||||
cost: 15, tierMin: 3, description: "+击退抗性",
|
||||
},
|
||||
}
|
||||
|
||||
@@ -221,16 +221,16 @@ export interface MonsterBaseStats {
|
||||
* @see MonsterBaseStats 字段说明
|
||||
*/
|
||||
export const MonsterStats: Record<MonType, MonsterBaseStats> = {
|
||||
[MonType.Melee]: { hp: 120, ap: 12, cost: 30, isBoss: false },
|
||||
[MonType.Heavy]: { hp: 350, ap: 30, cost: 50, isBoss: false },
|
||||
[MonType.Long]: { hp: 80, ap: 45, cost: 40, isBoss: false },
|
||||
[MonType.Support]: { hp: 80, ap: 20, cost: 50, isBoss: false },
|
||||
[MonType.Bomber]: { hp: 60, ap: 80, cost: 35, isBoss: false },
|
||||
[MonType.Summoner]: { hp: 100, ap: 15, cost: 60, isBoss: false },
|
||||
[MonType.Assassin]: { hp: 90, ap: 55, cost: 45, isBoss: false },
|
||||
[MonType.Splitter]: { hp: 150, ap: 20, cost: 55, isBoss: false },
|
||||
[MonType.MeleeBoss]: { hp: 1500, ap: 20, cost: 200, isBoss: true },
|
||||
[MonType.LongBoss]: { hp: 350, ap: 30, cost: 200, isBoss: true },
|
||||
[MonType.Melee]: { hp: 360, ap: 12, cost: 30, isBoss: false },
|
||||
[MonType.Heavy]: { hp: 1050, ap: 30, cost: 50, isBoss: false },
|
||||
[MonType.Long]: { hp: 240, ap: 45, cost: 40, isBoss: false },
|
||||
[MonType.Support]: { hp: 240, ap: 20, cost: 50, isBoss: false },
|
||||
[MonType.Bomber]: { hp: 180, ap: 80, cost: 35, isBoss: false },
|
||||
[MonType.Summoner]: { hp: 300, ap: 15, cost: 60, isBoss: false },
|
||||
[MonType.Assassin]: { hp: 270, ap: 55, cost: 45, isBoss: false },
|
||||
[MonType.Splitter]: { hp: 450, ap: 20, cost: 55, isBoss: false },
|
||||
[MonType.MeleeBoss]: { hp: 4500, ap: 20, cost: 200, isBoss: true },
|
||||
[MonType.LongBoss]: { hp: 1050, ap: 30, cost: 200, isBoss: true },
|
||||
}
|
||||
|
||||
// ======================== 阶梯(Tier)配置 ========================
|
||||
@@ -250,38 +250,29 @@ export interface TierConfig {
|
||||
}
|
||||
|
||||
/** Boss 出现的 Tier 集合(MiniBoss 或 MajorBoss) */
|
||||
const BOSS_TIERS = new Set([2, 4, 5, 7, 9, 10])
|
||||
const BOSS_TIERS = new Set([1, 2, 3, 4, 5])
|
||||
/** MajorBoss(高难度 Boss)出现的 Tier 集合 */
|
||||
const MAJOR_BOSS_TIERS = new Set([5, 10])
|
||||
const MAJOR_BOSS_TIERS = new Set([3, 5])
|
||||
|
||||
/**
|
||||
* 10 阶梯配置表
|
||||
* key = 阶梯编号 1-10,value = 该阶梯的完整配置
|
||||
* 主线 30 波映射:wave 1-3 → T1, wave 4-6 → T2, ..., wave 28-30 → T10
|
||||
* 5 阶梯配置表
|
||||
* key = 阶梯编号 1-5,value = 该阶梯的完整配置
|
||||
* 主线 15 波映射:wave 1-3 → T1, wave 4-6 → T2, ..., wave 13-15 → T5
|
||||
*/
|
||||
export const TierConfigs: Record<number, TierConfig> = {
|
||||
1: { multiplier: 1.0, budget: 100, availableTypes: [MonType.Melee], isBossTier: false },
|
||||
2: { multiplier: 1.3, budget: 150, availableTypes: [MonType.Melee, MonType.Heavy, MonType.Long], isBossTier: true },
|
||||
3: { multiplier: 1.6, budget: 200, availableTypes: [MonType.Melee, MonType.Heavy, MonType.Long], isBossTier: false },
|
||||
4: { multiplier: 1.9, budget: 260, availableTypes: [MonType.Melee, MonType.Heavy, MonType.Long, MonType.Support], isBossTier: true },
|
||||
5: { multiplier: 2.3, budget: 340, availableTypes: [MonType.Melee, MonType.Heavy, MonType.Long, MonType.Support, MonType.Bomber], isBossTier: true },
|
||||
6: { multiplier: 2.8, budget: 440, availableTypes: [MonType.Melee, MonType.Heavy, MonType.Long, MonType.Support, MonType.Bomber, MonType.Assassin], isBossTier: false },
|
||||
7: { multiplier: 3.3, budget: 560, availableTypes: [MonType.Melee, MonType.Heavy, MonType.Long, MonType.Support, MonType.Bomber, MonType.Assassin, MonType.Summoner, MonType.Splitter], isBossTier: true },
|
||||
8: { multiplier: 3.9, budget: 700, availableTypes: [MonType.Melee, MonType.Heavy, MonType.Long, MonType.Support, MonType.Bomber, MonType.Assassin, MonType.Summoner, MonType.Splitter], isBossTier: false },
|
||||
9: { multiplier: 4.6, budget: 860, availableTypes: [MonType.Melee, MonType.Heavy, MonType.Long, MonType.Support, MonType.Bomber, MonType.Assassin, MonType.Summoner, MonType.Splitter], isBossTier: true },
|
||||
10: { multiplier: 5.5, budget: 1050, availableTypes: [MonType.Melee, MonType.Heavy, MonType.Long, MonType.Support, MonType.Bomber, MonType.Assassin, MonType.Summoner, MonType.Splitter], isBossTier: true },
|
||||
1: { multiplier: 1.0, budget: 500, availableTypes: [MonType.Melee, MonType.Heavy, MonType.Long], isBossTier: false },
|
||||
2: { multiplier: 1.6, budget: 1000, availableTypes: [MonType.Melee, MonType.Heavy, MonType.Long, MonType.Support], isBossTier: true },
|
||||
3: { multiplier: 2.5, budget: 1800, availableTypes: [MonType.Melee, MonType.Heavy, MonType.Long, MonType.Support, MonType.Bomber, MonType.Assassin], isBossTier: true },
|
||||
4: { multiplier: 3.8, budget: 3000, availableTypes: [MonType.Melee, MonType.Heavy, MonType.Long, MonType.Support, MonType.Bomber, MonType.Assassin, MonType.Summoner, MonType.Splitter], isBossTier: true },
|
||||
5: { multiplier: 5.5, budget: 5000, availableTypes: [MonType.Melee, MonType.Heavy, MonType.Long, MonType.Support, MonType.Bomber, MonType.Assassin, MonType.Summoner, MonType.Splitter], isBossTier: true },
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定阶梯的配置
|
||||
* 支持 Tier 1-10(查表)和 Tier 11+(无限模式,递推计算:T(n) = T(n-1) × 1.2)
|
||||
* 支持 Tier 1-5(查表)和 Tier 6+(无限模式,递推计算:T(n) = T(n-1) × 1.2)
|
||||
*
|
||||
* @param tier - 阶梯编号(1-10 主线,11+ 无限模式)
|
||||
* @param tier - 阶梯编号(1-5 主线,6+ 无限模式)
|
||||
* @returns TierConfig 该阶梯的完整配置
|
||||
*
|
||||
* @example
|
||||
* getTierConfig(1) // { multiplier: 1.0, budget: 100, ... }
|
||||
* getTierConfig(11) // { multiplier: 6.6, budget: 1260, ... } (5.5 × 1.2)
|
||||
*/
|
||||
export function getTierConfig(tier: number): TierConfig {
|
||||
if (TierConfigs[tier]) return TierConfigs[tier]
|
||||
@@ -305,13 +296,12 @@ export function getTierConfig(tier: number): TierConfig {
|
||||
|
||||
/**
|
||||
* 每个 Tier 的基础词缀触发概率(0.0-1.0)
|
||||
* T1-T4: 0%(教学期无词缀)
|
||||
* T5: 10%, T6: 15%, T7: 25%, T8: 30%, T9: 40%, T10: 50%
|
||||
* T1-T2: 0%(前期无词缀)
|
||||
* T3: 15%, T4: 30%, T5: 50%
|
||||
* 最终概率 = baseAffixChance × roleMultiplier
|
||||
*/
|
||||
export const BaseAffixChance: Record<number, number> = {
|
||||
1: 0, 2: 0, 3: 0, 4: 0,
|
||||
5: 0.10, 6: 0.15, 7: 0.25, 8: 0.30, 9: 0.40, 10: 0.50,
|
||||
1: 0, 2: 0, 3: 0.15, 4: 0.30, 5: 0.50,
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -381,100 +371,100 @@ export interface BlueprintTemplate {
|
||||
export const BlueprintTemplates: BlueprintTemplate[] = [
|
||||
// ---- REST 类 ----
|
||||
{ id: "R1", type: TemplateType.REST, tierMin: 1, allowAffix: false,
|
||||
slots: [{ typePool: [MonType.Melee], countMin: 1, countMax: 2, weight: 1.0 }] },
|
||||
{ id: "R2", type: TemplateType.REST, tierMin: 2, allowAffix: false,
|
||||
slots: [{ typePool: [MonType.Melee, MonType.Heavy], countMin: 1, countMax: 3, weight: 1.0 }] },
|
||||
{ id: "R3", type: TemplateType.REST, tierMin: 5, allowAffix: false,
|
||||
slots: [{ typePool: [MonType.Melee, MonType.Long], countMin: 2, countMax: 3, weight: 1.0 }] },
|
||||
slots: [{ typePool: [MonType.Melee], countMin: 5, countMax: 10, weight: 1.0 }] },
|
||||
{ id: "R2", type: TemplateType.REST, tierMin: 1, allowAffix: false,
|
||||
slots: [{ typePool: [MonType.Melee, MonType.Heavy], countMin: 5, countMax: 15, weight: 1.0 }] },
|
||||
{ id: "R3", type: TemplateType.REST, tierMin: 3, allowAffix: false,
|
||||
slots: [{ typePool: [MonType.Melee, MonType.Long], countMin: 10, countMax: 15, weight: 1.0 }] },
|
||||
|
||||
// ---- NORMAL 类 ----
|
||||
{ id: "N1", type: TemplateType.NORMAL, tierMin: 1, allowAffix: false,
|
||||
slots: [{ typePool: [MonType.Melee], countMin: 2, countMax: 4, weight: 1.0 }] },
|
||||
{ id: "N2", type: TemplateType.NORMAL, tierMin: 2, allowAffix: false,
|
||||
slots: [{ typePool: [MonType.Melee], countMin: 10, countMax: 20, weight: 1.0 }] },
|
||||
{ id: "N2", type: TemplateType.NORMAL, tierMin: 1, allowAffix: false,
|
||||
slots: [
|
||||
{ typePool: [MonType.Melee], countMin: 1, countMax: 3, weight: 0.6 },
|
||||
{ typePool: [MonType.Long, MonType.Heavy], countMin: 1, countMax: 2, weight: 0.4 },
|
||||
{ typePool: [MonType.Melee], countMin: 5, countMax: 15, weight: 0.6 },
|
||||
{ typePool: [MonType.Long, MonType.Heavy], countMin: 5, countMax: 10, weight: 0.4 },
|
||||
] },
|
||||
{ id: "N3", type: TemplateType.NORMAL, tierMin: 4, allowAffix: true,
|
||||
{ id: "N3", type: TemplateType.NORMAL, tierMin: 2, allowAffix: true,
|
||||
slots: [
|
||||
{ typePool: [MonType.Melee, MonType.Heavy], countMin: 2, countMax: 3, weight: 0.5 },
|
||||
{ typePool: [MonType.Long], countMin: 1, countMax: 2, weight: 0.3 },
|
||||
{ typePool: [MonType.Support], countMin: 1, countMax: 1, weight: 0.2 },
|
||||
{ typePool: [MonType.Melee, MonType.Heavy], countMin: 10, countMax: 15, weight: 0.5 },
|
||||
{ typePool: [MonType.Long], countMin: 5, countMax: 10, weight: 0.3 },
|
||||
{ typePool: [MonType.Support], countMin: 5, countMax: 5, weight: 0.2 },
|
||||
] },
|
||||
{ id: "N4", type: TemplateType.NORMAL, tierMin: 6, allowAffix: true,
|
||||
{ id: "N4", type: TemplateType.NORMAL, tierMin: 3, allowAffix: true,
|
||||
slots: [
|
||||
{ typePool: [MonType.Melee, MonType.Heavy], countMin: 2, countMax: 4, weight: 0.4 },
|
||||
{ typePool: [MonType.Long, MonType.Assassin], countMin: 1, countMax: 3, weight: 0.3 },
|
||||
{ typePool: [MonType.Support, MonType.Bomber], countMin: 1, countMax: 2, weight: 0.3 },
|
||||
{ typePool: [MonType.Melee, MonType.Heavy], countMin: 10, countMax: 20, weight: 0.4 },
|
||||
{ typePool: [MonType.Long, MonType.Assassin], countMin: 5, countMax: 15, weight: 0.3 },
|
||||
{ typePool: [MonType.Support, MonType.Bomber], countMin: 5, countMax: 10, weight: 0.3 },
|
||||
] },
|
||||
|
||||
// ---- MIXED 类 ----
|
||||
{ id: "M1", type: TemplateType.MIXED, tierMin: 3, allowAffix: true,
|
||||
{ id: "M1", type: TemplateType.MIXED, tierMin: 1, allowAffix: true,
|
||||
slots: [
|
||||
{ typePool: [MonType.Melee, MonType.Heavy], countMin: 2, countMax: 3, weight: 0.4 },
|
||||
{ typePool: [MonType.Long], countMin: 1, countMax: 2, weight: 0.3 },
|
||||
{ typePool: [MonType.Support], countMin: 1, countMax: 1, weight: 0.3 },
|
||||
{ typePool: [MonType.Melee, MonType.Heavy], countMin: 10, countMax: 15, weight: 0.4 },
|
||||
{ typePool: [MonType.Long], countMin: 5, countMax: 10, weight: 0.3 },
|
||||
{ typePool: [MonType.Support], countMin: 5, countMax: 5, weight: 0.3 },
|
||||
] },
|
||||
{ id: "M2", type: TemplateType.MIXED, tierMin: 5, allowAffix: true,
|
||||
{ id: "M2", type: TemplateType.MIXED, tierMin: 3, allowAffix: true,
|
||||
slots: [
|
||||
{ typePool: [MonType.Melee, MonType.Heavy], countMin: 2, countMax: 4, weight: 0.3 },
|
||||
{ typePool: [MonType.Long, MonType.Assassin], countMin: 2, countMax: 3, weight: 0.3 },
|
||||
{ typePool: [MonType.Bomber], countMin: 1, countMax: 2, weight: 0.2 },
|
||||
{ typePool: [MonType.Support], countMin: 1, countMax: 1, weight: 0.2 },
|
||||
{ typePool: [MonType.Melee, MonType.Heavy], countMin: 10, countMax: 20, weight: 0.3 },
|
||||
{ typePool: [MonType.Long, MonType.Assassin], countMin: 10, countMax: 15, weight: 0.3 },
|
||||
{ typePool: [MonType.Bomber], countMin: 5, countMax: 10, weight: 0.2 },
|
||||
{ typePool: [MonType.Support], countMin: 5, countMax: 5, weight: 0.2 },
|
||||
] },
|
||||
{ id: "M3", type: TemplateType.MIXED, tierMin: 7, allowAffix: true,
|
||||
{ id: "M3", type: TemplateType.MIXED, tierMin: 4, allowAffix: true,
|
||||
slots: [
|
||||
{ typePool: [MonType.Melee, MonType.Heavy], countMin: 3, countMax: 4, weight: 0.3 },
|
||||
{ typePool: [MonType.Long, MonType.Assassin], countMin: 2, countMax: 3, weight: 0.25 },
|
||||
{ typePool: [MonType.Summoner, MonType.Splitter], countMin: 1, countMax: 2, weight: 0.25 },
|
||||
{ typePool: [MonType.Bomber, MonType.Support], countMin: 1, countMax: 2, weight: 0.2 },
|
||||
{ typePool: [MonType.Melee, MonType.Heavy], countMin: 15, countMax: 20, weight: 0.3 },
|
||||
{ typePool: [MonType.Long, MonType.Assassin], countMin: 10, countMax: 15, weight: 0.25 },
|
||||
{ typePool: [MonType.Summoner, MonType.Splitter], countMin: 5, countMax: 10, weight: 0.25 },
|
||||
{ typePool: [MonType.Bomber, MonType.Support], countMin: 5, countMax: 10, weight: 0.2 },
|
||||
] },
|
||||
|
||||
// ---- ELITE 类 ----
|
||||
{ id: "E1", type: TemplateType.ELITE, tierMin: 5, allowAffix: true,
|
||||
{ id: "E1", type: TemplateType.ELITE, tierMin: 3, allowAffix: true,
|
||||
slots: [
|
||||
{ typePool: [MonType.Melee, MonType.Heavy], countMin: 1, countMax: 2, weight: 0.5, forceAffix: true },
|
||||
{ typePool: [MonType.Long, MonType.Assassin], countMin: 1, countMax: 2, weight: 0.5, forceAffix: true },
|
||||
{ typePool: [MonType.Melee, MonType.Heavy], countMin: 5, countMax: 10, weight: 0.5, forceAffix: true },
|
||||
{ typePool: [MonType.Long, MonType.Assassin], countMin: 5, countMax: 10, weight: 0.5, forceAffix: true },
|
||||
] },
|
||||
{ id: "E2", type: TemplateType.ELITE, tierMin: 7, allowAffix: true,
|
||||
{ id: "E2", type: TemplateType.ELITE, tierMin: 4, allowAffix: true,
|
||||
slots: [
|
||||
{ typePool: [MonType.Heavy], countMin: 1, countMax: 2, weight: 0.3, forceAffix: true },
|
||||
{ typePool: [MonType.Assassin, MonType.Splitter], countMin: 1, countMax: 2, weight: 0.4, forceAffix: true },
|
||||
{ typePool: [MonType.Bomber], countMin: 1, countMax: 2, weight: 0.3, forceAffix: true },
|
||||
{ typePool: [MonType.Heavy], countMin: 5, countMax: 10, weight: 0.3, forceAffix: true },
|
||||
{ typePool: [MonType.Assassin, MonType.Splitter], countMin: 5, countMax: 10, weight: 0.4, forceAffix: true },
|
||||
{ typePool: [MonType.Bomber], countMin: 5, countMax: 10, weight: 0.3, forceAffix: true },
|
||||
] },
|
||||
|
||||
// ---- BOSS 类 ----
|
||||
{ id: "B1", type: TemplateType.BOSS, tierMin: 2, allowAffix: true,
|
||||
{ id: "B1", type: TemplateType.BOSS, tierMin: 1, allowAffix: true,
|
||||
slots: [
|
||||
{ typePool: [MonType.MeleeBoss], countMin: 1, countMax: 1, weight: 1.0 },
|
||||
{ typePool: [MonType.Melee], countMin: 2, countMax: 3, weight: 0.6 },
|
||||
{ typePool: [MonType.Long], countMin: 0, countMax: 2, weight: 0.4 },
|
||||
{ typePool: [MonType.Melee], countMin: 10, countMax: 15, weight: 0.6 },
|
||||
{ typePool: [MonType.Long], countMin: 0, countMax: 10, weight: 0.4 },
|
||||
] },
|
||||
{ id: "B2", type: TemplateType.BOSS, tierMin: 4, allowAffix: true,
|
||||
{ id: "B2", type: TemplateType.BOSS, tierMin: 2, allowAffix: true,
|
||||
slots: [
|
||||
{ typePool: [MonType.MeleeBoss], countMin: 1, countMax: 1, weight: 1.0 },
|
||||
{ typePool: [MonType.Melee, MonType.Heavy], countMin: 2, countMax: 3, weight: 0.5 },
|
||||
{ typePool: [MonType.Long, MonType.Support], countMin: 1, countMax: 2, weight: 0.5 },
|
||||
{ typePool: [MonType.Melee, MonType.Heavy], countMin: 10, countMax: 15, weight: 0.5 },
|
||||
{ typePool: [MonType.Long, MonType.Support], countMin: 5, countMax: 10, weight: 0.5 },
|
||||
] },
|
||||
{ id: "B3", type: TemplateType.BOSS, tierMin: 5, allowAffix: true,
|
||||
{ id: "B3", type: TemplateType.BOSS, tierMin: 3, allowAffix: true,
|
||||
slots: [
|
||||
{ typePool: [MonType.MeleeBoss, MonType.LongBoss], countMin: 1, countMax: 1, weight: 1.0 },
|
||||
{ typePool: [MonType.Melee, MonType.Heavy], countMin: 2, countMax: 4, weight: 0.4 },
|
||||
{ typePool: [MonType.Long, MonType.Assassin], countMin: 1, countMax: 3, weight: 0.3 },
|
||||
{ typePool: [MonType.Bomber, MonType.Support], countMin: 1, countMax: 2, weight: 0.3 },
|
||||
{ typePool: [MonType.Melee, MonType.Heavy], countMin: 10, countMax: 20, weight: 0.4 },
|
||||
{ typePool: [MonType.Long, MonType.Assassin], countMin: 5, countMax: 15, weight: 0.3 },
|
||||
{ typePool: [MonType.Bomber, MonType.Support], countMin: 5, countMax: 10, weight: 0.3 },
|
||||
] },
|
||||
{ id: "B4", type: TemplateType.BOSS, tierMin: 7, allowAffix: true,
|
||||
{ id: "B4", type: TemplateType.BOSS, tierMin: 4, allowAffix: true,
|
||||
slots: [
|
||||
{ typePool: [MonType.MeleeBoss, MonType.LongBoss], countMin: 1, countMax: 1, weight: 1.0 },
|
||||
{ typePool: [MonType.Heavy], countMin: 2, countMax: 3, weight: 0.3 },
|
||||
{ typePool: [MonType.Assassin, MonType.Splitter], countMin: 1, countMax: 2, weight: 0.3 },
|
||||
{ typePool: [MonType.Summoner, MonType.Support], countMin: 1, countMax: 2, weight: 0.2 },
|
||||
{ typePool: [MonType.Bomber], countMin: 1, countMax: 2, weight: 0.2 },
|
||||
{ typePool: [MonType.Heavy], countMin: 10, countMax: 15, weight: 0.3 },
|
||||
{ typePool: [MonType.Assassin, MonType.Splitter], countMin: 5, countMax: 10, weight: 0.3 },
|
||||
{ typePool: [MonType.Summoner, MonType.Support], countMin: 5, countMax: 10, weight: 0.2 },
|
||||
{ typePool: [MonType.Bomber], countMin: 5, countMax: 10, weight: 0.2 },
|
||||
] },
|
||||
|
||||
// ---- 教程专用 ----
|
||||
{ id: "TUTORIAL", type: TemplateType.NORMAL, tierMin: 1, allowAffix: false,
|
||||
slots: [{ typePool: [MonType.Melee], countMin: 1, countMax: 1, weight: 1.0 }] },
|
||||
slots: [{ typePool: [MonType.Melee], countMin: 5, countMax: 5, weight: 1.0 }] },
|
||||
]
|
||||
|
||||
// ======================== 自适应难度配置 ========================
|
||||
@@ -598,17 +588,17 @@ export class RogueSpawningEngine {
|
||||
private consecutiveTemplateCount = 0
|
||||
|
||||
/**
|
||||
* 生成指定波次的怪物列表(主线 1-30 波)
|
||||
* 生成指定波次的怪物列表(主线 1-15 波)
|
||||
*
|
||||
* 内部流程:
|
||||
* 1. 根据 waveNumber 计算 tier 和 waveInTier
|
||||
* 2. W1 特殊处理(固定教程模板:1 个 Melee)
|
||||
* 2. W1 特殊处理(固定教程模板:5 个 Melee)
|
||||
* 3. 根据 waveInTier 和 isBossTier 选择蓝图模板
|
||||
* 4. 计算难度预算 = base_budget × template_modifier × adaptive_factor
|
||||
* 5. 按模板槽位填充怪物、应用词缀、计算最终属性
|
||||
*
|
||||
* @param waveNumber - 波次编号(1-30)
|
||||
* 1-3 → Tier 1, 4-6 → Tier 2, ..., 28-30 → Tier 10
|
||||
* @param waveNumber - 波次编号(1-15)
|
||||
* 1-3 → Tier 1, 4-6 → Tier 2, ..., 13-15 → Tier 5
|
||||
* < 1 返回空数组
|
||||
*
|
||||
* @returns GeneratedMonster[] 该波次的怪物实例数组,按 spawnIndex 排列。
|
||||
@@ -616,9 +606,9 @@ export class RogueSpawningEngine {
|
||||
* 每次调用结果不同(随机生成),如需固定结果请在同一次调用中缓存。
|
||||
*
|
||||
* @example
|
||||
* // 生成第 1 波(教程:1 个 Melee)
|
||||
* // 生成第 1 波(教程:5 个 Melee)
|
||||
* const w1 = engine.generateWave(1)
|
||||
* // w1 = [{ uuid: 6001, type: 0, hp: 120, ap: 12, affixes: [], isBoss: false, spawnIndex: 0 }]
|
||||
* // w1 = [{ uuid: 6001, type: 0, hp: 120, ap: 12, affixes: [], isBoss: false, spawnIndex: 0 }, ...]
|
||||
*
|
||||
* // 生成第 6 波(Tier 2 Boss 波)
|
||||
* const w6 = engine.generateWave(6)
|
||||
@@ -634,7 +624,7 @@ export class RogueSpawningEngine {
|
||||
if (waveNumber === 1) {
|
||||
return this.spawnFromTemplate(
|
||||
BlueprintTemplates.find(t => t.id === "TUTORIAL")!,
|
||||
1, 1
|
||||
1, getTierConfig(1).budget * this.adaptiveFactor
|
||||
)
|
||||
}
|
||||
|
||||
@@ -651,11 +641,11 @@ export class RogueSpawningEngine {
|
||||
/**
|
||||
* 生成无限模式指定层的指定波
|
||||
*
|
||||
* 无限模式结构:每层 4 波(REST → NORMAL → MIXED → BOSS),Tier 从 11 开始递增。
|
||||
* 无限模式结构:每层 4 波(REST → NORMAL → MIXED → BOSS),Tier 从 6 开始递增。
|
||||
* 属性倍率按 T(n) = T(n-1) × 1.2 递推,无上限。
|
||||
*
|
||||
* @param layer - 层编号(从 1 开始)
|
||||
* Tier = 10 + layer(layer=1 → Tier 11, multiplier=6.6)
|
||||
* Tier = 5 + layer(layer=1 → Tier 6, multiplier=6.6)
|
||||
* @param waveInLayer - 层内波次编号(1-4)
|
||||
* 1: REST(恢复波)
|
||||
* 2: NORMAL(标准波)
|
||||
@@ -665,12 +655,12 @@ export class RogueSpawningEngine {
|
||||
* @returns GeneratedMonster[] 该波的怪物实例数组
|
||||
*
|
||||
* @example
|
||||
* // 无限模式第 1 层第 4 波(Boss 波,Tier 11)
|
||||
* // 无限模式第 1 层第 4 波(Boss 波,Tier 6)
|
||||
* const boss = engine.generateInfiniteWave(1, 4)
|
||||
* // boss 包含 1 个 Boss + 若干小怪,属性倍率 = 6.6x
|
||||
*/
|
||||
generateInfiniteWave(layer: number, waveInLayer: number): GeneratedMonster[] {
|
||||
const tier = 10 + layer
|
||||
const tier = 5 + layer
|
||||
const tierConfig = getTierConfig(tier)
|
||||
let templateType: TemplateType
|
||||
|
||||
@@ -684,7 +674,7 @@ export class RogueSpawningEngine {
|
||||
}
|
||||
|
||||
const templates = BlueprintTemplates.filter(t =>
|
||||
t.type === templateType && t.tierMin <= 10
|
||||
t.type === templateType && t.tierMin <= 5
|
||||
)
|
||||
const template = this.pickRandomTemplate(templates)
|
||||
const budget = Math.round(
|
||||
@@ -888,7 +878,7 @@ export class RogueSpawningEngine {
|
||||
|
||||
// 预算利用率检查 (目标 >= 70%)
|
||||
let totalCost = budget - remainingBudget
|
||||
if (budget > 0 && totalCost / budget < 0.7) {
|
||||
if (budget > 0 && totalCost / budget < 0.7 && template.id !== "TUTORIAL") {
|
||||
const tierConfig = getTierConfig(tier)
|
||||
const type = MonType.Melee
|
||||
const stats = MonsterStats[type]
|
||||
@@ -982,7 +972,7 @@ export class RogueSpawningEngine {
|
||||
* 将 generateWave() 的结果按怪物类型合并,返回简化的 [{type, count}] 格式。
|
||||
* 注意:此方法不返回 HP/AP 值,调用方需自行处理属性计算或改用 generateWave()。
|
||||
*
|
||||
* @param waveNumber - 波次编号(1-30)
|
||||
* @param waveNumber - 波次编号(1-15)
|
||||
* @returns IWaveSlot[] 按怪物类型合并后的数组
|
||||
* - type: MonType 枚举值
|
||||
* - count: 该类型的怪物总数
|
||||
@@ -990,8 +980,8 @@ export class RogueSpawningEngine {
|
||||
*
|
||||
* @example
|
||||
* engine.getWaveSlotConfig(6)
|
||||
* // [{ type: 8, count: 1 }, { type: 0, count: 2 }, { type: 2, count: 1 }]
|
||||
* // = 1 个 MeleeBoss + 2 个 Melee + 1 个 Long
|
||||
* // [{ type: 8, count: 1 }, { type: 0, count: 10 }, { type: 2, count: 5 }]
|
||||
* // = 1 个 MeleeBoss + 10 个 Melee + 5 个 Long
|
||||
*/
|
||||
getWaveSlotConfig(waveNumber: number): IWaveSlot[] {
|
||||
const generated = this.generateWave(waveNumber)
|
||||
@@ -1035,14 +1025,14 @@ export function getWaveSlotConfig(waveNumber: number): IWaveSlot[] {
|
||||
}
|
||||
|
||||
/**
|
||||
* 向后兼容:默认占位配置(波次 > 30 或异常时的兜底配置)
|
||||
* 4 个 Melee + 3 个 Long + 1 个 Support + 1 个 Bomber
|
||||
* 向后兼容:默认占位配置(波次 > 15 或异常时的兜底配置)
|
||||
* 20 个 Melee + 15 个 Long + 5 个 Support + 5 个 Bomber
|
||||
*/
|
||||
export const DefaultWaveSlot: IWaveSlot[] = [
|
||||
{ type: MonType.Melee, count: 4 },
|
||||
{ type: MonType.Long, count: 3 },
|
||||
{ type: MonType.Support, count: 1 },
|
||||
{ type: MonType.Bomber, count: 1 },
|
||||
{ type: MonType.Melee, count: 20 },
|
||||
{ type: MonType.Long, count: 15 },
|
||||
{ type: MonType.Support, count: 5 },
|
||||
{ type: MonType.Bomber, count: 5 },
|
||||
]
|
||||
|
||||
/**
|
||||
@@ -1053,14 +1043,14 @@ export const DefaultWaveSlot: IWaveSlot[] = [
|
||||
*
|
||||
* @example
|
||||
* WaveSlotConfig[5] // 动态生成第 5 波的 IWaveSlot[]
|
||||
* WaveSlotConfig[30] // 动态生成第 30 波的 IWaveSlot[]
|
||||
* WaveSlotConfig[15] // 动态生成第 15 波的 IWaveSlot[]
|
||||
*/
|
||||
export const WaveSlotConfig: { [wave: number]: IWaveSlot[] } = new Proxy(
|
||||
{} as { [wave: number]: IWaveSlot[] },
|
||||
{
|
||||
get(_target, prop: string) {
|
||||
const wave = parseInt(prop, 10)
|
||||
if (!isNaN(wave) && wave >= 1 && wave <= 30) {
|
||||
if (!isNaN(wave) && wave >= 1 && wave <= 15) {
|
||||
return spawningEngine.getWaveSlotConfig(wave)
|
||||
}
|
||||
if (prop === "toJSON") return () => ({})
|
||||
@@ -1068,7 +1058,7 @@ export const WaveSlotConfig: { [wave: number]: IWaveSlot[] } = new Proxy(
|
||||
},
|
||||
has(_target, prop: string) {
|
||||
const wave = parseInt(prop, 10)
|
||||
return !isNaN(wave) && wave >= 1 && wave <= 30
|
||||
return !isNaN(wave) && wave >= 1 && wave <= 15
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
## Overview
|
||||
|
||||
肉鸽刷怪系统是控制每局游戏怪物生成的核心引擎。它从固定 30 波硬编码配置演进为**蓝图模板 + 权重填充 + 自适应微调**的三层程序化生成架构。主线 30 波分为 10 个难度阶梯(每档 3 波),每档内遵循"恢复→攀升→高潮"的心流节奏。10 种怪物类型配合 8 种词缀修饰,使同一基础怪物产生多种变体。通关后玩家可选进入无限模式,以分层推进方式无限挑战。自适应难度引擎追踪玩家表现,在 ±15% 范围内微调强度,确保始终处于心流通道内。
|
||||
肉鸽刷怪系统是控制每局游戏怪物生成的核心引擎。它从固定 15 波硬编码配置演进为**蓝图模板 + 权重填充 + 自适应微调**的三层程序化生成架构。主线 15 波分为 5 个难度阶梯(每档 3 波),每档内遵循"恢复→攀升→高潮"的心流节奏。10 种怪物类型配合 8 种词缀修饰,使同一基础怪物产生多种变体。通关后玩家可选进入无限模式,以分层推进方式无限挑战。自适应难度引擎追踪玩家表现,在 ±15% 范围内微调强度,确保始终处于心流通道内。
|
||||
|
||||
## Player Fantasy
|
||||
|
||||
@@ -34,22 +34,17 @@
|
||||
2. **权重填充层**:根据蓝图中的槽位定义,从怪物池中按权重随机抽取具体怪物,填充数量
|
||||
3. **自适应微调层**:根据玩家历史表现,对难度预算进行 ±15% 浮动调整
|
||||
|
||||
**规则 2:10 阶梯 × 3 波结构**
|
||||
**规则 2:5 阶梯 × 3 波结构**
|
||||
|
||||
主线 30 波分为 10 个阶梯(Tier),每个 Tier 3 波:
|
||||
主线 15 波分为 5 个阶梯(Tier),每个 Tier 3 波:
|
||||
|
||||
| Tier | 波次 | 主题 | 新引入元素 | Boss |
|
||||
|------|------|------|-----------|------|
|
||||
| 1 | W1-3 | 入门教程 | Melee | - |
|
||||
| 2 | W4-6 | 远程登场 | Long, Heavy | W6 MiniBoss |
|
||||
| 3 | W7-9 | 刺客登场 | Assassin(突后排威胁) | - |
|
||||
| 4 | W10-12 | 辅助登场 | Support + 近远程刺协同 | W12 MiniBoss |
|
||||
| 5 | W13-15 | 中期 Boss | Bomber, Summoner + 词缀系统首次出现 | **W15 MajorBoss** |
|
||||
| 6 | W16-18 | 分裂时代 | Splitter(死亡触发型) | - |
|
||||
| 7 | W19-21 | 精英时代 | 词缀大量出现(全种类) | W21 MiniBoss |
|
||||
| 8 | W22-24 | 全兵种混合 | 所有类型协同 | - |
|
||||
| 9 | W25-27 | 终极压力 | 极限数量 | W27 MiniBoss |
|
||||
| 10 | W28-30 | 最终 Boss | 全词缀组合 | **W30 FinalBoss** |
|
||||
| 1 | W1-3 | 入门教程 | Melee, Long, Heavy | - |
|
||||
| 2 | W4-6 | 辅助登场 | Support | W6 MiniBoss |
|
||||
| 3 | W7-9 | 刺客与自爆 | Bomber, Assassin + 词缀系统首次出现 | **W9 MajorBoss** |
|
||||
| 4 | W10-12 | 召唤与分裂 | Summoner, Splitter + 词缀大量出现 | W12 MiniBoss |
|
||||
| 5 | W13-15 | 最终 Boss | 全兵种混合,全词缀组合 | **W15 FinalBoss** |
|
||||
|
||||
**规则 3:档内三拍节奏**
|
||||
|
||||
@@ -156,37 +151,37 @@ function fill_wave(template, budget, tier, adaptive_factor):
|
||||
**REST 类型(tier_min=1):**
|
||||
| ID | 槽位配置 | 说明 |
|
||||
|----|---------|------|
|
||||
| REST_01 | 1-2 × Melee(权重10) | 纯近战休息波 |
|
||||
| REST_02 | 1 × Melee(8) + 1 × Long(4) | 轻混合休息波 |
|
||||
| REST_03 | 2 × 随机(权重均分) | 随机轻波 |
|
||||
| REST_01 | 5-10 × Melee(权重10) | 纯近战休息波 |
|
||||
| REST_02 | 5 × Melee(8) + 5 × Long(4) | 轻混合休息波 |
|
||||
| REST_03 | 10 × 随机(权重均分) | 随机轻波 |
|
||||
|
||||
**NORMAL 类型(tier_min=1):**
|
||||
| ID | 槽位配置 | 说明 |
|
||||
|----|---------|------|
|
||||
| NORM_01 | 3-4 × Melee(10) | 近战群 |
|
||||
| NORM_02 | 2 × Melee(6) + 2 × Long(6) | 标准混合 |
|
||||
| NORM_03 | 2 × Melee(4) + 1 × Long(6) + 1 × Heavy(4) | 重型混合 |
|
||||
| NORM_01 | 15-20 × Melee(10) | 近战群 |
|
||||
| NORM_02 | 10 × Melee(6) + 10 × Long(6) | 标准混合 |
|
||||
| NORM_03 | 10 × Melee(4) + 5 × Long(6) + 5 × Heavy(4) | 重型混合 |
|
||||
|
||||
**MIXED 类型(tier_min=3):**
|
||||
**MIXED 类型(tier_min=2):**
|
||||
| ID | 槽位配置 | 说明 |
|
||||
|----|---------|------|
|
||||
| MIX_01 | 2 × Melee(4) + 2 × Long(4) + 1 × Assassin(4) | 刺客突袭 |
|
||||
| MIX_02 | 1 × Heavy(6) + 2 × Long(6) + 1 × Support(3) | 远程压制 |
|
||||
| MIX_03 | 2 × Melee(4) + 1 × Long(4) + 1 × Assassin(4) + 1 × Bomber(3) | 多线威胁 |
|
||||
| MIX_01 | 10 × Melee(4) + 10 × Long(4) + 5 × Assassin(4) | 刺客突袭 |
|
||||
| MIX_02 | 5 × Heavy(6) + 10 × Long(6) + 5 × Support(3) | 远程压制 |
|
||||
| MIX_03 | 10 × Melee(4) + 5 × Long(4) + 5 × Assassin(4) + 5 × Bomber(3) | 多线威胁 |
|
||||
|
||||
**ELITE 类型(tier_min=5, allow_affix=true):**
|
||||
**ELITE 类型(tier_min=3, allow_affix=true):**
|
||||
| ID | 槽位配置 | 说明 |
|
||||
|----|---------|------|
|
||||
| ELIT_01 | 2-3 × 随机(权重均分, 必带词缀) | 精英小队 |
|
||||
| ELIT_02 | 1 × Heavy(必带词缀) + 1 × Support(必带词缀) | 重装精英 |
|
||||
| ELIT_03 | 2 × Assassin(必带词缀) + 1 × Long(必带词缀) | 精锐突袭 |
|
||||
| ELIT_01 | 10-15 × 随机(权重均分, 必带词缀) | 精英小队 |
|
||||
| ELIT_02 | 5 × Heavy(必带词缀) + 5 × Support(必带词缀) | 重装精英 |
|
||||
| ELIT_03 | 10 × Assassin(必带词缀) + 5 × Long(必带词缀) | 精锐突袭 |
|
||||
|
||||
**BOSS 类型(tier_min=2, mandatory_slots 包含 Boss):**
|
||||
**BOSS 类型(tier_min=1, mandatory_slots 包含 Boss):**
|
||||
| ID | 槽位配置 | 说明 |
|
||||
|----|---------|------|
|
||||
| BOSS_01 | 1 × MeleeBoss(强制) + 2-3 × Melee | 近战 Boss + 小怪 |
|
||||
| BOSS_02 | 1 × LongBoss(强制) + 1-2 × Support | 远程 Boss + 治疗 |
|
||||
| BOSS_03 | 1 × MeleeBoss 或 LongBoss(强制) + 1 × Assassin + 1 × Bomber | Boss + 精锐护卫 |
|
||||
| BOSS_01 | 1 × MeleeBoss(强制) + 10-15 × Melee | 近战 Boss + 小怪 |
|
||||
| BOSS_02 | 1 × LongBoss(强制) + 5-10 × Support | 远程 Boss + 治疗 |
|
||||
| BOSS_03 | 1 × MeleeBoss 或 LongBoss(强制) + 5 × Assassin + 5 × Bomber | Boss + 精锐护卫 |
|
||||
|
||||
**规则 6:词缀系统**
|
||||
|
||||
@@ -194,14 +189,14 @@ function fill_wave(template, budget, tier, adaptive_factor):
|
||||
|
||||
| 词缀 | 效果 | 首次出现 Tier |
|
||||
|------|------|-------------|
|
||||
| Elite | +50% HP, +30% AP | T5 |
|
||||
| Berserk | 攻速 ×1.5 | T5 |
|
||||
| Shield | 开局带伤害吸收盾(20% HP) | T6 |
|
||||
| Regen | 每秒回复 2% HP | T7 |
|
||||
| Swift | 移速 ×2 | T7 |
|
||||
| Giant | ×2 体型, +100% HP, +50% AP | T8 |
|
||||
| Chain | 攻击附带 50% 溅射伤害 | T9 |
|
||||
| Summoner | 每 8 秒召唤 1 个小怪(Melee,1 级属性) | T10 |
|
||||
| Elite | +50% HP, +30% AP | T3 |
|
||||
| Berserk | 攻速 ×1.5 | T3 |
|
||||
| Shield | 开局带伤害吸收盾(20% HP) | T3 |
|
||||
| Regen | 每秒回复 2% HP | T4 |
|
||||
| Swift | 移速 ×2 | T4 |
|
||||
| Giant | ×2 体型, +100% HP, +50% AP | T4 |
|
||||
| Chain | 攻击附带 50% 溅射伤害 | T5 |
|
||||
| Summoner | 每 8 秒召唤 1 个小怪(Melee,1 级属性) | T5 |
|
||||
|
||||
词缀触发概率:
|
||||
|
||||
@@ -209,8 +204,8 @@ function fill_wave(template, budget, tier, adaptive_factor):
|
||||
affix_chance = min(base_affix_chance[tier] × role_multiplier, 1.0)
|
||||
|
||||
base_affix_chance:
|
||||
T1-T4: 0%
|
||||
T5: 10%, T6: 15%, T7: 25%, T8: 30%, T9: 40%, T10: 50%
|
||||
T1-T2: 0%
|
||||
T3: 15%, T4: 30%, T5: 50%
|
||||
|
||||
role_multiplier:
|
||||
普通怪: 1.0x
|
||||
@@ -297,23 +292,23 @@ tier_multiplier = tier_multiplier_table[tier]
|
||||
|
||||
| Variable | Symbol | Type | Range | Description |
|
||||
|----------|--------|------|-------|-------------|
|
||||
| tier | T | int | 1-10 (主线), 11+ (无限) | 当前难度阶梯 |
|
||||
| tier | T | int | 1-5 (主线), 6+ (无限) | 当前难度阶梯 |
|
||||
| tier_multiplier | TM | float | 1.0-5.5 | 属性倍率 |
|
||||
|
||||
**Tier Multiplier 表:**
|
||||
|
||||
| Tier | Multiplier | Tier | Multiplier |
|
||||
|------|-----------|------|-----------|
|
||||
| T1 | 1.0x | T6 | 2.8x |
|
||||
| T2 | 1.3x | T7 | 3.3x |
|
||||
| T3 | 1.6x | T8 | 3.9x |
|
||||
| T4 | 1.9x | T9 | 4.6x |
|
||||
| T5 | 2.3x | T10 | 5.5x |
|
||||
| Tier | Multiplier |
|
||||
|------|-----------|
|
||||
| T1 | 1.0x |
|
||||
| T2 | 1.6x |
|
||||
| T3 | 2.5x |
|
||||
| T4 | 3.8x |
|
||||
| T5 | 5.5x |
|
||||
|
||||
**无限模式扩展:** T(n) = T(n-1) × 1.2(T11=6.6x, T12=7.9x, ...)
|
||||
**无限模式扩展:** T(n) = T(n-1) × 1.2(T6=6.6x, T7=7.9x, ...)
|
||||
|
||||
**Output Range:** 1.0x (T1) to 5.5x (T10 主线), 无限模式无限递增
|
||||
**Example:** 基础 Melee 怪在 T5 的属性 = 120×2.3=276 HP, 12×2.3=27.6 AP
|
||||
**Output Range:** 1.0x (T1) to 5.5x (T5 主线), 无限模式无限递增
|
||||
**Example:** 基础 Melee 怪在 T3 的属性 = 120×2.5=300 HP, 12×2.5=30 AP
|
||||
|
||||
### F2: 难度预算
|
||||
|
||||
@@ -328,13 +323,13 @@ wave_budget = base_budget[tier] × template_modifier[type]
|
||||
|
||||
**Base Budget 表:**
|
||||
|
||||
| Tier | Budget | Tier | Budget |
|
||||
|------|--------|------|--------|
|
||||
| T1 | 100 | T6 | 440 |
|
||||
| T2 | 150 | T7 | 560 |
|
||||
| T3 | 200 | T8 | 700 |
|
||||
| T4 | 260 | T9 | 860 |
|
||||
| T5 | 340 | T10 | 1050 |
|
||||
| Tier | Budget |
|
||||
|------|--------|
|
||||
| T1 | 500 |
|
||||
| T2 | 1000 |
|
||||
| T3 | 1800 |
|
||||
| T4 | 3000 |
|
||||
| T5 | 5000 |
|
||||
|
||||
**Template Modifier:**
|
||||
- REST: 0.5x
|
||||
@@ -343,8 +338,8 @@ wave_budget = base_budget[tier] × template_modifier[type]
|
||||
- ELITE: 0.8x
|
||||
- BOSS: 1.5x
|
||||
|
||||
**Output Range:** 50 (T1 REST) to 1575 (T10 BOSS)
|
||||
**Example:** T5 NORMAL 波 → budget = 340 × 1.0 = 340 → 可生成约 8 个 Melee 或 4 个 Melee + 2 个 Long + 1 个 Support
|
||||
**Output Range:** 250 (T1 REST) to 7500 (T5 BOSS)
|
||||
**Example:** T3 NORMAL 波 → budget = 1800 × 1.0 = 1800 → 可生成约 40 个 Melee 或 20 个 Melee + 10 个 Long + 5 个 Support
|
||||
|
||||
### F3: 怪物最终属性
|
||||
|
||||
@@ -359,8 +354,8 @@ final_ap = base_ap × tier_multiplier × affix_ap_multiplier × adaptive_factor
|
||||
| affix_hp/ap_multiplier | AHM/AAM | float | 1.0-2.5 | 词缀属性倍率(加法叠加,Elite+Giant 最大 2.5) |
|
||||
| adaptive_factor | AF | float | 0.85-1.15 | 自适应系数 |
|
||||
|
||||
**Output Range:** HP 51 (Bomber, T1, no affix, AF=0.85) to 19,031+ (MeleeBoss, T15 无限, Elite+Giant, AF=1.15)
|
||||
**Example:** Melee 怪在 T7, 带 Elite 词缀, AF=1.0 → HP=120×3.3×1.5×1.0=594, AP=12×3.3×1.3×1.0=51.5
|
||||
**Output Range:** HP 51 (Bomber, T1, no affix, AF=0.85) to 19,031+ (MeleeBoss, T6 无限, Elite+Giant, AF=1.15)
|
||||
**Example:** Melee 怪在 T4, 带 Elite 词缀, AF=1.0 → HP=120×3.8×1.5×1.0=684, AP=12×3.8×1.3×1.0=59.28
|
||||
|
||||
### F4: 自适应难度系数
|
||||
|
||||
@@ -424,15 +419,15 @@ delta calculation per wave:
|
||||
|
||||
| 旋钮 | 当前值 | 安全范围 | 超出后果 |
|
||||
|------|--------|---------|---------|
|
||||
| `tier_multiplier_table[T1-T10]` | 1.0-5.5 | 0.5-10.0 | 过低→后期无挑战;过高→后期不可打 |
|
||||
| `base_budget[T1-T10]` | 100-1050 | 50-2000 | 过低→怪物太少无聊;过高→怪物太多卡顿 |
|
||||
| `tier_multiplier_table[T1-T5]` | 1.0-5.5 | 0.5-10.0 | 过低→后期无挑战;过高→后期不可打 |
|
||||
| `base_budget[T1-T5]` | 500-5000 | 250-10000 | 过低→怪物太少无聊;过高→怪物太多卡顿 |
|
||||
| `template_modifier[REST]` | 0.5x | 0.3-0.8 | 过低→恢复波太弱无意义;过高→节奏混乱 |
|
||||
| `template_modifier[BOSS]` | 1.5x | 1.0-2.5 | 过低→Boss 无感;过高→Boss 波必团灭 |
|
||||
| `adaptive_factor_min` | 0.85 | 0.7-0.95 | 过低→自适应降难太明显 |
|
||||
| `adaptive_factor_max` | 1.15 | 1.05-1.3 | 过高→自适应加难太明显 |
|
||||
| `adaptive_delta_per_wave` | 0.03 | 0.01-0.08 | 过低→反应迟钝;过高→体验不稳定 |
|
||||
| `target_clear_time` | 15.0s | 5.0-30.0 | 影响自适应判断阈值 |
|
||||
| `base_affix_chance[T5-T10]` | 10%-50% | 0%-80% | 过低→词缀系统无意义;过高→全是精英怪 |
|
||||
| `base_affix_chance[T3-T5]` | 15%-50% | 0%-80% | 过低→词缀系统无意义;过高→全是精英怪 |
|
||||
| `bomber_explosion_multiplier` | 200% | 100%-400% | 爆炸伤害占 AP 的比例 |
|
||||
| `splitter_child_hp_ratio` | 50% | 25%-75% | 分裂子体 HP 占母体比例 |
|
||||
| `splitter_child_ap_ratio` | 50% | 25%-75% | 分裂子体 AP 占母体比例 |
|
||||
@@ -440,30 +435,30 @@ delta calculation per wave:
|
||||
| `summoner_max_minions` | 3 | 1-5 | 场上最多同时存在的小怪数 |
|
||||
| `minion_lifetime` | 30s | 10-60s | 小怪存活上限 |
|
||||
| `infinite_tier_growth_rate` | 1.2x | 1.1-1.5 | 无限模式每档递增率 |
|
||||
| `monster_types_available[T1-T10]` | 见规则2 | - | 每档可用怪物类型集合 |
|
||||
| `monster_types_available[T1-T5]` | 见规则2 | - | 每档可用怪物类型集合 |
|
||||
| `affix_mutual_exclusion` | Giant×Swift, Regen×Shield | - | 互斥词缀对 |
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
### 核心波次生成
|
||||
|
||||
- **GIVEN** 游戏开始(adaptive_factor=1.0),**WHEN** 进入 W1,**THEN** 生成 1 个 Melee 怪(T1, 无词缀),HP=120, AP=12。
|
||||
- **GIVEN** 当前 Tier 2 W2(攀升波),**WHEN** 模板选取完成,**THEN** 模板类型为 NORMAL 或 MIXED,且模板的怪物槽位池中包含 Long 类型(cost=40)。运行 100 次抽取,Long 类型出现在槽位池中的比例为 100%。
|
||||
- **GIVEN** W6(Boss 波),**WHEN** 模板选取完成,**THEN** 模板类型为 BOSS,mandatory_slots 包含 Boss 类型,至少生成 1 个 MeleeBoss + 0-3 个普通怪。
|
||||
- **GIVEN** Tier 3 W1(REST 波),**WHEN** 模板选取完成,**THEN** 模板类型为 REST,template_modifier=0.5x。
|
||||
- **GIVEN** Tier 4 W3(非 Boss 高潮波),**WHEN** 模板选取完成,**THEN** 模板类型为 MIXED,template_modifier=1.2x。
|
||||
- **GIVEN** 游戏开始(adaptive_factor=1.0),**WHEN** 进入 W1,**THEN** 生成 5 个 Melee 怪(T1, 无词缀),HP=120, AP=12。
|
||||
- **GIVEN** 当前 Tier 1 W2(攀升波),**WHEN** 模板选取完成,**THEN** 模板类型为 NORMAL 或 MIXED,且模板的怪物槽位池中包含 Long 类型(cost=40)。运行 100 次抽取,Long 类型出现在槽位池中的比例为 100%。
|
||||
- **GIVEN** W6(Boss 波),**WHEN** 模板选取完成,**THEN** 模板类型为 BOSS,mandatory_slots 包含 Boss 类型,至少生成 1 个 MeleeBoss + 10-15 个普通怪。
|
||||
- **GIVEN** Tier 2 W1(REST 波),**WHEN** 模板选取完成,**THEN** 模板类型为 REST,template_modifier=0.5x。
|
||||
- **GIVEN** Tier 3 W3(非 Boss 高潮波),**WHEN** 模板选取完成,**THEN** 模板类型为 MIXED,template_modifier=1.2x。
|
||||
|
||||
### 预算系统
|
||||
|
||||
- **GIVEN** Tier 5 NORMAL 波(budget=340, AF 不影响预算),**WHEN** 填充怪物完成,**THEN** 所有怪物成本总和在 340 × 0.7 到 340 × 1.0 之间(即 238-340),且至少生成 3 只怪物。
|
||||
- **GIVEN** Tier 3 NORMAL 波(budget=1800, AF 不影响预算),**WHEN** 填充怪物完成,**THEN** 所有怪物成本总和在 1800 × 0.7 到 1800 × 1.0 之间(即 1260-1800),且至少生成 15 只怪物。
|
||||
- **GIVEN** 预算不足以生成任何怪物,**WHEN** 填充阶段,**THEN** 保底生成 1 个 Melee 怪(忽略预算限制)。
|
||||
|
||||
### 词缀系统
|
||||
|
||||
- **GIVEN** Tier 5 正常波(10+ 只怪),**WHEN** 运行 1000 次统计测试,**THEN** 词缀触发率落在 8%-12% 区间(90% 置信度),且所有触发的词缀类型均为 Elite 或 Berserk。单次运行中无词缀怪物比例在 20%-50% 区间内。
|
||||
- **GIVEN** Tier 10 FinalBoss(W30),**WHEN** 词缀应用完成,**THEN** FinalBoss 拥有 2-3 个词缀,且任意两个词缀的组合不属于互斥组(Giant+Swift, Regen+Shield, Summoner类型+Summoner词缀)。运行 100 次模拟,0 次出现互斥词缀同时生效。
|
||||
- **GIVEN** Tier 7 正常波,**WHEN** 词缀应用完成,**THEN** 每只普通怪最多拥有 1 个词缀。运行 1000 次模拟,0 次出现普通怪拥有 >1 个词缀的情况。
|
||||
- **GIVEN** Tier 7 W21 MiniBoss,**WHEN** 词缀应用完成,**THEN** MiniBoss 拥有 0-2 个词缀,0 次超过 2 个词缀。
|
||||
- **GIVEN** Tier 3 正常波(30+ 只怪),**WHEN** 运行 1000 次统计测试,**THEN** 词缀触发率落在 13%-17% 区间(90% 置信度),且所有触发的词缀类型均为 Elite, Berserk 或 Shield 等 T3 可用词缀。单次运行中无词缀怪物比例在 20%-50% 区间内。
|
||||
- **GIVEN** Tier 5 FinalBoss(W15),**WHEN** 词缀应用完成,**THEN** FinalBoss 拥有 2-3 个词缀,且任意两个词缀的组合不属于互斥组(Giant+Swift, Regen+Shield, Summoner类型+Summoner词缀)。运行 100 次模拟,0 次出现互斥词缀同时生效。
|
||||
- **GIVEN** Tier 4 正常波,**WHEN** 词缀应用完成,**THEN** 每只普通怪最多拥有 1 个词缀。运行 1000 次模拟,0 次出现普通怪拥有 >1 个词缀的情况。
|
||||
- **GIVEN** Tier 4 W12 MiniBoss,**WHEN** 词缀应用完成,**THEN** MiniBoss 拥有 0-2 个词缀,0 次超过 2 个词缀。
|
||||
- **GIVEN** 两个互斥词缀(Giant + Swift)同时被选中,**WHEN** 词缀应用阶段,**THEN** 保留优先级更高的词缀(Giant),丢弃 Swift。
|
||||
- **GIVEN** 两个互斥词缀(Regen + Shield)同时被选中,**WHEN** 词缀应用阶段,**THEN** 保留优先级更高的词缀(Shield),丢弃 Regen。
|
||||
|
||||
@@ -485,13 +480,13 @@ delta calculation per wave:
|
||||
|
||||
### 属性计算
|
||||
|
||||
- **GIVEN** Tier 7 Melee 怪,带 Elite 词缀(+50% HP, +30% AP),AF=1.0,**WHEN** 属性计算完成,**THEN** HP = 120 × 3.3 × 1.5 × 1.0 = 594,AP = 12 × 3.3 × 1.3 × 1.0 = 51.48。
|
||||
- **GIVEN** Tier 4 Melee 怪,带 Elite 词缀(+50% HP, +30% AP),AF=1.0,**WHEN** 属性计算完成,**THEN** HP = 120 × 3.8 × 1.5 × 1.0 = 684,AP = 12 × 3.8 × 1.3 × 1.0 = 59.28。
|
||||
- **GIVEN** 任何怪物,**WHEN** 最终属性计算完成(base × tier_multiplier × affix_multiplier × adaptive_factor),**THEN** final_hp ≥ 1 且 final_ap ≥ 1。
|
||||
|
||||
### 无限模式与模板多样性
|
||||
|
||||
- **GIVEN** 主线 W30 通关,**WHEN** 玩家选择进入无限模式,**THEN** 从 T11 开始,每层 4 波(REST→NORMAL→MIXED→BOSS),属性倍率 = tier_multiplier_table[T10] × infinite_tier_growth_rate = 5.5 × 1.2 = 6.6x。
|
||||
- **GIVEN** 无限模式 T12,**WHEN** 属性倍率计算,**THEN** tier_multiplier = 6.6 × 1.2 = 7.92x。
|
||||
- **GIVEN** 主线 W15 通关,**WHEN** 玩家选择进入无限模式,**THEN** 从 T6 开始,每层 4 波(REST→NORMAL→MIXED→BOSS),属性倍率 = tier_multiplier_table[T5] × infinite_tier_growth_rate = 5.5 × 1.2 = 6.6x。
|
||||
- **GIVEN** 无限模式 T7,**WHEN** 属性倍率计算,**THEN** tier_multiplier = 6.6 × 1.2 = 7.92x。
|
||||
- **GIVEN** 同一模板(id 相同)被连续抽取 3 次,**WHEN** 第 4 波模板选取,**THEN** 选出的模板类型与连续 3 次的类型不同(如连续 3 次 NORMAL 则强制从 REST/MIXED/ELITE/BOSS 池中抽取)。
|
||||
|
||||
### 游戏结束条件
|
||||
@@ -546,6 +541,6 @@ delta calculation per wave:
|
||||
| 4 | 蓝图模板池具体需要多少个模板? | 策划 | 待定 | 目前每类定义了 3 个示例模板,正式版每类需要 5-8 个 |
|
||||
| 5 | 新怪物类型(Bomber/Summoner/Assassin/Splitter/Heavy)的 UUID 编号段? | 开发 | 待定 | 需与 HeroAttrs.ts 中的编号体系对齐,需独立怪物定义文档(UUID、AI 行为树、资源规范) |
|
||||
| 6 | 飞行怪移除后,现有 Fly/FlyBoss 的 UUID 是否回收? | 开发 | 待定 | 影响资源管理 |
|
||||
| 7 | **英雄战力曲线验证** — 怪物缩放(5.5×)需对照玩家 DPS 曲线校准 | 策划 | 待定 | 缺少英雄成长 GDD,所有平衡数值未验证。需定义:T1/T5/T10 预期团队 DPS、每波怪物预期存活时间 |
|
||||
| 7 | **英雄战力曲线验证** — 怪物缩放(5.5×)需对照玩家 DPS 曲线校准 | 策划 | 待定 | 缺少英雄成长 GDD,所有平衡数值未验证。需定义:T1/T3/T5 预期团队 DPS、每波怪物预期存活时间 |
|
||||
| 8 | **Bomber 爆炸 AOE 半径** — AC 引用了 AOE_RADIUS 但未在调参旋钮中定义 | 策划 | 待定 | 需添加到 Tuning Knobs 表 |
|
||||
| 9 | **MajorBoss vs MiniBoss 机械区别** — 当前仅数值差异,是否有特殊技能/阶段转换? | 策划 | 待定 | W15 MajorBoss 需要与非 MajorBoss 的体验差异 |
|
||||
| 9 | **MajorBoss vs MiniBoss 机械区别** — 当前仅数值差异,是否有特殊技能/阶段转换? | 策划 | 待定 | W9/W15 MajorBoss 需要与非 MajorBoss 的体验差异 |
|
||||
|
||||
4
test_spawn.js
Normal file
4
test_spawn.js
Normal file
@@ -0,0 +1,4 @@
|
||||
import { spawningEngine } from "./assets/script/game/map/RogueConfig.js";
|
||||
console.log("Wave 1:", spawningEngine.generateWave(1).length);
|
||||
console.log("Wave 2:", spawningEngine.generateWave(2).length);
|
||||
console.log("Wave 3:", spawningEngine.generateWave(3).length);
|
||||
4
test_spawn.ts
Normal file
4
test_spawn.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
import { spawningEngine } from "./assets/script/game/map/RogueConfig";
|
||||
console.log("Wave 1:", spawningEngine.generateWave(1).length);
|
||||
console.log("Wave 2:", spawningEngine.generateWave(2).length);
|
||||
console.log("Wave 3:", spawningEngine.generateWave(3).length);
|
||||
Reference in New Issue
Block a user