From ffc51c10a30adc9a3d517503884c33e84ef67f76 Mon Sep 17 00:00:00 2001 From: panfudan Date: Sat, 12 Jul 2025 21:40:54 +0800 Subject: [PATCH] =?UTF-8?q?+=E8=82=89=E9=B8=BD=E6=A8=A1=E5=BC=8F,=E6=8E=A5?= =?UTF-8?q?=E4=B8=8B=E6=9D=A5=E5=81=9Aboss=20=E5=8A=A8=E7=94=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- assets/resources/gui/role_controller.prefab | 2 - assets/script/Design.md | 4 +- assets/script/game/common/config/GameEvent.ts | 2 + assets/script/game/common/config/heroSet.ts | 244 +++++++--- assets/script/game/hero/Mon.ts | 112 +++-- .../game/{common => map}/FlashSprite.ts | 0 .../game/{common => map}/FlashSprite.ts.meta | 0 assets/script/game/map/MissionMonComp.ts | 147 +++++- assets/script/game/map/RogueConfig.ts | 455 ++++++++++++++++++ assets/script/game/map/RogueConfig.ts.meta | 9 + 10 files changed, 837 insertions(+), 138 deletions(-) rename assets/script/game/{common => map}/FlashSprite.ts (100%) rename assets/script/game/{common => map}/FlashSprite.ts.meta (100%) create mode 100644 assets/script/game/map/RogueConfig.ts create mode 100644 assets/script/game/map/RogueConfig.ts.meta diff --git a/assets/resources/gui/role_controller.prefab b/assets/resources/gui/role_controller.prefab index 1c9890c4..004ab4e3 100644 --- a/assets/resources/gui/role_controller.prefab +++ b/assets/resources/gui/role_controller.prefab @@ -84788,8 +84788,6 @@ "__id__": 0 }, "fileId": "f7/N7i8SZFDZ/cm3Iro3X8", - "instance": null, - "targetOverrides": null, "nestedPrefabInstanceRoots": null }, { diff --git a/assets/script/Design.md b/assets/script/Design.md index 9f43572e..b646c218 100644 --- a/assets/script/Design.md +++ b/assets/script/Design.md @@ -437,4 +437,6 @@ mermaid图片代码merm复制graph TD 例:主线900分 + 远征50波 → 总分 = 900×2.0=1800 → 避免无限分膨胀,让休闲玩家主线分也能竞争 -远征10波 送一张免广告券,最多1张,仅远征中使用 \ No newline at end of file +远征10波 送一张免广告券,最多1张,仅远征中使用 + +普通小怪冲锋或暂停的微小随机行为(不影响总路线时间和击杀策略)。避免视觉单调 \ No newline at end of file diff --git a/assets/script/game/common/config/GameEvent.ts b/assets/script/game/common/config/GameEvent.ts index 8573bc34..12055177 100644 --- a/assets/script/game/common/config/GameEvent.ts +++ b/assets/script/game/common/config/GameEvent.ts @@ -55,4 +55,6 @@ export enum GameEvent { EXPUP = "EXPUP", EQUIP_STONE_UP = "EQUIP_STONE_UP", SKILL_STONE_UP = "SKILL_STONE_UP", + ShopOpen = "ShopOpen", + RestOpen = "RestOpen", } \ No newline at end of file diff --git a/assets/script/game/common/config/heroSet.ts b/assets/script/game/common/config/heroSet.ts index 5ab69b76..51286fb0 100644 --- a/assets/script/game/common/config/heroSet.ts +++ b/assets/script/game/common/config/heroSet.ts @@ -321,112 +321,210 @@ export const HeroInfo = { //怪物 5201:{uuid:5201,name:"兽人战士",path:"mor1", quality:HQuality.GREEN,lv:1,kind:1, - type:HType.warrior,hp:25,ap:8,dis:200,cd:1.5,speed:45,skills:[6007], - buff:[ - - ],info:"普通怪物-战士型"}, + type:HType.warrior,hp:25,ap:8,dis:200,cd:2,speed:45,skills:[6007], + buff:[ ],info:"普通怪物-战士型"}, 5202:{uuid:5202,name:"兽人刺客",path:"mor2", quality:HQuality.GREEN,lv:1,kind:1, - type:HType.warrior,hp:25,ap:8,dis:200,cd:1.5,speed:45,skills:[6007], - buff:[ - - ],info:"普通怪物-战士型"}, + type:HType.remote,hp:20,ap:8,dis:350,cd:1.5,speed:45,skills:[6007], + buff:[ ],info:"普通怪物-战士型"}, 5203:{uuid:5203,name:"兽人护卫",path:"mor3", quality:HQuality.GREEN,lv:1,kind:1, - type:HType.remote,hp:20,ap:12,dis:200,cd:1.5,speed:50,skills:[6007], - buff:[ - - ],info:"远程怪物-高伤害"}, + type:HType.warrior,hp:25,ap:8,dis:200,cd:2,speed:45,skills:[6007], + buff:[ ],info:"普通怪物-战士型"}, 5204:{uuid:5204,name:"石卫", path:"mgem1",quality:HQuality.GREEN,lv:1,kind:1, - type:HType.warrior,hp:25,ap:8,dis:200,cd:1.5,speed:45,skills:[6007], - buff:[ - - ],info:"普通怪物-战士型"}, + type:HType.mage,hp:18,ap:15,dis:350,cd:2.5,speed:45,skills:[6007], + buff:[ ],info:"法师怪物-高伤害脆弱"}, 5205:{uuid:5205,name:"土卫", path:"mgem2",quality:HQuality.GREEN,lv:1,kind:1, - type:HType.warrior,hp:25,ap:8,dis:200,cd:1.5,speed:45,skills:[6007], - buff:[ - - ],info:"普通怪物-战士型"}, + type:HType.mage,hp:18,ap:15,dis:350,cd:2.5,speed:45,skills:[6007], + buff:[ ],info:"法师怪物-高伤害脆弱"}, - 5206:{uuid:5206,name:"树人", path:"mgem3",quality:HQuality.GREEN,lv:1,kind:1, - type:HType.warrior,hp:25,ap:8,dis:200,cd:1.5,speed:45,skills:[6007], - buff:[ - - ],info:"普通怪物-战士型"}, + 5206:{uuid:5206,name:"树卫", path:"mgem3",quality:HQuality.GREEN,lv:1,kind:1, + type:HType.mage,hp:18,ap:15,dis:350,cd:2.5,speed:45,skills:[6007], + buff:[ ],info:"法师怪物-高伤害脆弱"}, 5216:{uuid:5216,name:"元素1", path:"my1", quality:HQuality.GREEN,lv:2,kind:1, - type:HType.mage,hp:18,ap:15,dis:350,cd:1.2,speed:40,skills:[6007], - buff:[ - - ],info:"法师怪物-高伤害脆弱"}, + type:HType.mage,hp:18,ap:15,dis:350,cd:2.5,speed:40,skills:[6007], + buff:[ ],info:"法师怪物-高伤害脆弱"}, 5217:{uuid:5217,name:"元素2", path:"my2", quality:HQuality.GREEN,lv:2,kind:1, - type:HType.mage,hp:18,ap:15,dis:350,cd:1.2,speed:40,skills:[6007], - buff:[ - - ],info:"法师怪物-高伤害脆弱"}, + type:HType.mage,hp:18,ap:15,dis:350,cd:2.5,speed:40,skills:[6007], + buff:[ ],info:"法师怪物-高伤害脆弱"}, 5218:{uuid:5218,name:"元素3", path:"my3", quality:HQuality.GREEN,lv:2,kind:1, - type:HType.mage,hp:18,ap:15,dis:350,cd:1.2,speed:40,skills:[6007], - buff:[ - - ],info:"法师怪物-高伤害脆弱"}, + type:HType.mage,hp:18,ap:15,dis:350,cd:2.5,speed:40,skills:[6007], + buff:[ ],info:"法师怪物-高伤害脆弱"}, 5219:{uuid:5219,name:"牛头战士",path:"mn1", quality:HQuality.GREEN,lv:2,kind:1, - type:HType.warrior,hp:25,ap:8,dis:200,cd:1.5,speed:45,skills:[6007], - buff:[ - - ],info:"普通怪物-战士型"}, + type:HType.warrior,hp:25,ap:8,dis:200,cd:2,speed:45,skills:[6007], + buff:[ ],info:"普通怪物-战士型"}, 5220:{uuid:5220,name:"牛头战士",path:"mn2", quality:HQuality.GREEN,lv:1,kind:1, - type:HType.remote,hp:20,ap:12,dis:200,cd:1.5,speed:50,skills:[6007], - buff:[ - - ],info:"远程怪物-高伤害"}, + type:HType.warrior,hp:25,ap:8,dis:200,cd:2,speed:45,skills:[6007], + buff:[ ],info:"普通怪物-战士型"}, 5221:{uuid:5221,name:"牛头战士",path:"mn3", quality:HQuality.GREEN,lv:1,kind:1, - type:HType.warrior,hp:25,ap:8,dis:200,cd:1.5,speed:45,skills:[6007], - buff:[ - - ],info:"普通怪物-战士型"}, + type:HType.remote,hp:20,ap:8,dis:350,cd:1.5,speed:45,skills:[6007], + buff:[ ],info:"普通怪物-战士型"}, 5222:{uuid:5222,name:"独眼巨人",path:"md1", quality:HQuality.GREEN,lv:1,kind:1, - type:HType.warrior,hp:25,ap:8,dis:200,cd:1.5,speed:45,skills:[6007], - buff:[ - - ],info:"普通怪物-战士型"}, + type:HType.warrior,hp:25,ap:8,dis:200,cd:2,speed:45,skills:[6007], + buff:[ ],info:"普通怪物-战士型"}, 5223:{uuid:5223,name:"独眼巨人",path:"md2", quality:HQuality.GREEN,lv:1,kind:1, - type:HType.warrior,hp:25,ap:8,dis:200,cd:1.5,speed:45,skills:[6007], - buff:[ - - ],info:"普通怪物-战士型"}, + type:HType.warrior,hp:25,ap:8,dis:200,cd:2,speed:45,skills:[6007], + buff:[ ],info:"普通怪物-战士型"}, 5224:{uuid:5224,name:"独眼巨人",path:"md3", quality:HQuality.GREEN,lv:1,kind:1, - type:HType.remote,hp:20,ap:12,dis:200,cd:1.5,speed:50,skills:[6007], - buff:[ - - ],info:"远程怪物-高伤害"}, + type:HType.remote,hp:20,ap:8,dis:350,cd:1.5,speed:45,skills:[6007], + buff:[ ],info:"普通怪物-战士型"}, 5225:{uuid:5225,name:"精英独眼",path:"md4", quality:HQuality.BLUE,lv:1,kind:1, - type:HType.mage,hp:18,ap:15,dis:400,cd:1.2,speed:40,skills:[6007], - buff:[ - - ],info:"法师怪物-高伤害脆弱"}, + type:HType.warrior,hp:45,ap:12,dis:200,cd:2,speed:25,skills:[6007], + buff:[ ],info:"精英怪物-战士型"}, 5226:{uuid:5226,name:"精英牛头",path:"mn4", quality:HQuality.BLUE,lv:1,kind:1, - type:HType.mage,hp:18,ap:15,dis:400,cd:1.2,speed:40,skills:[6007], - buff:[ - - ],info:"法师怪物-高伤害脆弱"}, + type:HType.warrior,hp:45,ap:12,dis:200,cd:2,speed:25,skills:[6007], + buff:[ ],info:"精英怪物-战士型"}, 5227:{uuid:5227,name:"精英兽人",path:"mor4", quality:HQuality.BLUE,lv:1,kind:1, - type:HType.mage,hp:18,ap:15,dis:400,cd:1.2,speed:40,skills:[6007], - buff:[ - - ],info:"法师怪物-高伤害脆弱"} + type:HType.warrior,hp:45,ap:12,dis:200,cd:2,speed:25,skills:[6007], + buff:[ ],info:"精英怪物-战士型"} }; +// ==================== 怪物系列分类配置 ==================== + +// 怪物系列枚举 +export enum MonsterSeriesType { + ORC = "ORC", // 兽人系列 + CYCLOPS = "CYCLOPS", // 独眼系列 + MINOTAUR = "MINOTAUR", // 牛头系列 + NATURE = "NATURE", // 自然系列 + ELEMENTAL = "ELEMENTAL" // 元素系列 +} + +// 怪物系列配置 +export const MonsterSeriesConfig = { + // 兽人系列 (mor开头) + [MonsterSeriesType.ORC]: { + name: "兽人系列", + description: "来自荒野的兽人族群", + monsters: { + warrior: [5201, 5203, 5227], // 兽人战士、兽人护卫、精英兽人 + remote: [5202], // 兽人刺客 + mage: [] // 无法师 + }, + allMonsters: [5201, 5202, 5203, 5227] + }, + + // 独眼系列 (md开头) + [MonsterSeriesType.CYCLOPS]: { + name: "独眼系列", + description: "古老的独眼巨人族群", + monsters: { + warrior: [5222, 5223, 5225], // 独眼巨人x2、精英独眼 + remote: [5224], // 独眼巨人(远程) + mage: [] // 无法师 + }, + allMonsters: [5222, 5223, 5224, 5225] + }, + + // 牛头系列 (mn开头) + [MonsterSeriesType.MINOTAUR]: { + name: "牛头系列", + description: "迷宫中的牛头怪族群", + monsters: { + warrior: [5219, 5220, 5226], // 牛头战士x2、精英牛头 + remote: [5221], // 牛头战士(远程) + mage: [] // 无法师 + }, + allMonsters: [5219, 5220, 5221, 5226] + }, + + // 自然系列 (mgem开头) + [MonsterSeriesType.NATURE]: { + name: "自然系列", + description: "大地与自然的守护者", + monsters: { + warrior: [], // 无战士 + remote: [], // 无远程 + mage: [5204, 5205, 5206] // 石卫、土卫、树卫 + }, + allMonsters: [5204, 5205, 5206] + }, + + // 元素系列 (my开头) + [MonsterSeriesType.ELEMENTAL]: { + name: "元素系列", + description: "纯粹的元素力量化身", + monsters: { + warrior: [], // 无战士 + remote: [], // 无远程 + mage: [5216, 5217, 5218] // 元素1、元素2、元素3 + }, + allMonsters: [5216, 5217, 5218] + } +}; + +// 获取指定系列的怪物列表 +export const getMonstersBySeries = (series: MonsterSeriesType, type?: keyof typeof HType): number[] => { + const seriesConfig = MonsterSeriesConfig[series]; + if (!seriesConfig) { + console.warn(`[MonsterSeries]: 未找到系列 ${series}`); + return []; + } + + if (type !== undefined) { + const typeKey = HType[type] === HType.warrior ? "warrior" : + HType[type] === HType.remote ? "remote" : "mage"; + return seriesConfig.monsters[typeKey] || []; + } + + return seriesConfig.allMonsters; +}; + +// 根据怪物UUID获取所属系列 +export const getMonsterSeries = (uuid: number): MonsterSeriesType | null => { + for (const [seriesKey, config] of Object.entries(MonsterSeriesConfig)) { + if (config.allMonsters.includes(uuid)) { + return seriesKey as MonsterSeriesType; + } + } + return null; +}; + +// 获取系列信息 +export const getSeriesInfo = (series: MonsterSeriesType) => { + return MonsterSeriesConfig[series] || null; +}; + +// 获取所有系列列表 +export const getAllMonsterSeries = (): MonsterSeriesType[] => { + return Object.values(MonsterSeriesType); +}; + +// 按类型分组的怪物列表 +export const MonstersByType = { + warrior: [5201, 5203, 5219, 5220, 5222, 5223, 5225, 5226, 5227], // 所有战士类型怪物 + remote: [5202, 5221, 5224], // 所有远程类型怪物 + mage: [5204, 5205, 5206, 5216, 5217, 5218] // 所有法师类型怪物 +}; + +// 随机从指定系列获取怪物 +export const getRandomMonsterFromSeries = (series: MonsterSeriesType, type?: keyof typeof HType): number => { + const monsters = getMonstersBySeries(series, type); + if (monsters.length === 0) { + console.warn(`[MonsterSeries]: 系列 ${series} 中没有${type ? HType[type] : ''}类型怪物`); + return 5201; // 返回默认怪物 + } + return monsters[Math.floor(Math.random() * monsters.length)]; +}; + +// 随机选择一个系列 +export const getRandomSeries = (): MonsterSeriesType => { + const allSeries = getAllMonsterSeries(); + return allSeries[Math.floor(Math.random() * allSeries.length)]; +}; + diff --git a/assets/script/game/hero/Mon.ts b/assets/script/game/hero/Mon.ts index 5650f841..57612d5f 100644 --- a/assets/script/game/hero/Mon.ts +++ b/assets/script/game/hero/Mon.ts @@ -30,7 +30,7 @@ export class Monster extends ecs.Entity { } /** 加载角色 */ - load(pos: Vec3 = Vec3.ZERO,scale:number = 1,uuid:number=1001,is_boss:boolean=false,is_call:boolean=false,lv:number=1) { + load(pos: Vec3 = Vec3.ZERO,scale:number = 1,uuid:number=1001,is_boss:boolean=false,is_call:boolean=false,lv:number=1,rogueBuffData?: any[]) { scale=-1 let box_group=BoxSet.MONSTER console.log("mon load",uuid) @@ -42,7 +42,7 @@ export class Monster extends ecs.Entity { node.parent = scene.entityLayer!.node! node.setPosition(pos) - this.hero_init(uuid,node,scale,box_group,is_boss,is_call,lv) + this.hero_init(uuid,node,scale,box_group,is_boss,is_call,lv,rogueBuffData) oops.message.dispatchEvent("monster_load",this) // 初始化移动参数 @@ -51,7 +51,7 @@ export class Monster extends ecs.Entity { move.targetX = -800; // 左边界 } - hero_init(uuid:number=1001,node:Node,scale:number=1,box_group=BoxSet.HERO,is_boss:boolean=false,is_call:boolean=false,lv:number=1) { + hero_init(uuid:number=1001,node:Node,scale:number=1,box_group=BoxSet.HERO,is_boss:boolean=false,is_call:boolean=false,lv:number=1,rogueBuffData?: any[]) { var hv = node.getComponent(HeroViewComp)!; hv.hide_info() // console.log("hero_init",buff) @@ -86,50 +86,74 @@ export class Monster extends ecs.Entity { hv.cd = hero.cd hv.atk_skill=hero.skills[0] + + // 处理原有Buff hero.buff.forEach((buff:any)=>{ - switch(buff.buff_type){ - case BuffAttr.CRITICAL: - hv.crit=buff.value - break - case BuffAttr.CRITICAL_DMG: - hv.crit_d=buff.value - break - case BuffAttr.DODGE: - hv.dod=buff.value - break - case BuffAttr.DODGE_NO: - hv.dod_no=buff.value - break - case BuffAttr.CRITICAL_NO: - hv.crit_no=buff.value - break - case BuffAttr.BURN_COUNT: - hv.burn_count=buff.value - break - case BuffAttr.PUNCTURE: - hv.puncture=buff.value - break - case BuffAttr.PUNCTURE_DMG: - hv.puncture_damage=buff.value - break - case BuffAttr.WFUNY: - hv.wfuny=buff.value - break - case BuffAttr.ATK_CD: - hv.cd=hv.cd*(100-buff.value)/100 - break - case BuffAttr.HP: - hv.hp_max=hv.hp_max*(100+buff.value)/100 - break - case BuffAttr.DEF: - hv.def=buff.value - break - case BuffAttr.ATK: - hv.ap=hv.ap*(100+buff.value)/100 - break - } + this.applyBuffToMonster(hv, buff); }) + + // 处理肉鸽模式的词条Buff + if (rogueBuffData && rogueBuffData.length > 0) { + console.log(`[Monster]: 怪物${hero.name}应用肉鸽词条:`, rogueBuffData); + rogueBuffData.forEach((buff:any)=>{ + this.applyBuffToMonster(hv, buff); + }) + } + + // 重新计算最终HP(因为buff可能修改了hp_max) + hv.hp = hv.hp_max; + this.add(hv); } + + /** + * 应用Buff到怪物的通用方法 + */ + private applyBuffToMonster(hv: any, buff: any) { + switch(buff.buff_type){ + case BuffAttr.CRITICAL: + hv.crit+=buff.value + break + case BuffAttr.CRITICAL_DMG: + hv.crit_d+=buff.value + break + case BuffAttr.DODGE: + hv.dod+=buff.value + break + case BuffAttr.DODGE_NO: + hv.dod_no+=buff.value + break + case BuffAttr.CRITICAL_NO: + hv.crit_no+=buff.value + break + case BuffAttr.BURN_COUNT: + hv.burn_count+=buff.value + break + case BuffAttr.PUNCTURE: + hv.puncture+=buff.value + break + case BuffAttr.PUNCTURE_DMG: + hv.puncture_damage+=buff.value + break + case BuffAttr.WFUNY: + hv.wfuny+=buff.value + break + case BuffAttr.ATK_CD: + hv.cd=hv.cd*(100+buff.value)/100 + break + case BuffAttr.HP: + hv.hp_max=hv.hp_max*(100+buff.value)/100 + break + case BuffAttr.DEF: + hv.def+=buff.value + break + case BuffAttr.ATK: + hv.ap=hv.ap*(100+buff.value)/100 + break + case BuffAttr.FROST_RATIO: + hv.frost_ratto+=buff.value + break + } + } } \ No newline at end of file diff --git a/assets/script/game/common/FlashSprite.ts b/assets/script/game/map/FlashSprite.ts similarity index 100% rename from assets/script/game/common/FlashSprite.ts rename to assets/script/game/map/FlashSprite.ts diff --git a/assets/script/game/common/FlashSprite.ts.meta b/assets/script/game/map/FlashSprite.ts.meta similarity index 100% rename from assets/script/game/common/FlashSprite.ts.meta rename to assets/script/game/map/FlashSprite.ts.meta diff --git a/assets/script/game/map/MissionMonComp.ts b/assets/script/game/map/MissionMonComp.ts index fd97992a..b11c1344 100644 --- a/assets/script/game/map/MissionMonComp.ts +++ b/assets/script/game/map/MissionMonComp.ts @@ -9,6 +9,8 @@ import { Timer } from "db://oops-framework/core/common/timer/Timer"; import { smc } from "../common/SingletonModuleComp"; import { GameEvent } from "../common/config/GameEvent"; import { oops } from "db://oops-framework/core/Oops"; +// 导入肉鸽配置 +import { getRogueWaveConfig, RogueConfig, RogueWaveType, AffixCountConfig, MonsterAffixConfig } from "./RogueConfig"; const { ccclass, property } = _decorator; @@ -17,12 +19,23 @@ const { ccclass, property } = _decorator; @ecs.register('MissionMonComp', false) export class MissionMonCompComp extends CCComp { timer:Timer=new Timer(1) - // 添加刷怪队列 - 增加level字段 - private monsterQueue: Array<{uuid: number, position: number, isBoss: boolean, level: number}> = []; + // 添加刷怪队列 - 扩展支持词条 + private monsterQueue: Array<{ + uuid: number, + position: number, + isBoss: boolean, + level: number, + affixes?: any[], + buffData?: any[] // 使用BuffAttr格式的buff数据 + }> = []; private isSpawning: boolean = false;// 是否正在生成怪物 private spawnInterval: number = 0.5; // 每个怪物生成间隔时间 private spawnTimer: number = 0; // 生成计时器 private is_fight:boolean = false; + + // 肉鸽模式开关 + @property + useRogueMode: boolean = true; onLoad(){ this.on(GameEvent.FightStart,this.to_fight,this) } @@ -63,15 +76,20 @@ export class MissionMonCompComp extends CCComp { oops.message.dispatchEvent(GameEvent.WaveUpdate) console.log("[MissionMonComp]:怪物登场,当前波次 :",smc.vmdata.mission_data.current_wave) - // 使用新的波次配置系统 const currentWave = smc.vmdata.mission_data.current_wave; - const waveConfig = this.getWaveConfig(currentWave); - console.log(`[MissionMonComp]:第${currentWave}波配置:`, waveConfig.description); - console.log(`[MissionMonComp]:总HP: ${waveConfig.totalHp}, 总AP: ${waveConfig.totalAp}`); - - // 根据波次配置生成怪物 - this.generateMonstersFromConfig(waveConfig); + if (this.useRogueMode) { + // 使用肉鸽模式配置 + const rogueWaveConfig = getRogueWaveConfig(currentWave); + console.log(`[MissionMonComp]:肉鸽模式第${currentWave}波配置:`, rogueWaveConfig.description); + this.generateRogueMonstersFromConfig(rogueWaveConfig); + } else { + // 使用原有的波次配置系统 + const waveConfig = this.getWaveConfig(currentWave); + console.log(`[MissionMonComp]:普通模式第${currentWave}波配置:`, waveConfig.description); + console.log(`[MissionMonComp]:总HP: ${waveConfig.totalHp}, 总AP: ${waveConfig.totalAp}`); + this.generateMonstersFromConfig(waveConfig); + } } // 获取波次配置 @@ -83,7 +101,7 @@ export class MissionMonCompComp extends CCComp { } } - // 根据配置生成怪物 + // 根据配置生成怪物(普通模式) private generateMonstersFromConfig(waveConfig: any) { const { monsters } = waveConfig; const currentWave = smc.vmdata.mission_data.current_wave; @@ -101,8 +119,61 @@ export class MissionMonCompComp extends CCComp { console.log(`[MissionMonComp]:本波次将生成 ${monsters.reduce((total: number, group: any) => total + group.count, 0)} 只怪物,等级: ${monsterLevel}`); } + + // 根据肉鸽配置生成怪物(肉鸽模式) + private generateRogueMonstersFromConfig(rogueWaveConfig: any) { + const { monsters, waveType } = rogueWaveConfig; + const currentWave = smc.vmdata.mission_data.current_wave; + const monsterLevel = RogueConfig.getMonsterLevel(currentWave); + + // 处理非战斗波次 + if (waveType === RogueWaveType.SHOP || waveType === RogueWaveType.REST) { + console.log(`[MissionMonComp]:${waveType}波次,无需生成怪物`); + // 可以在这里触发商店或休息事件 + return; + } + + if (!monsters || monsters.length === 0) { + console.warn(`[MissionMonComp]:肉鸽波次配置中没有怪物信息`); + return; + } + + monsters.forEach((monsterGroup: any) => { + const { uuid, count, affixes, enhancedStats, buffData, isBoss } = monsterGroup; + + // 为每个怪物组生成指定数量的怪物 + for (let i = 0; i < count; i++) { + // 随机选择位置 (0-9) + this.addToSpawnQueueWithAffixes( + uuid, + i, + isBoss || false, + monsterLevel, + affixes, + buffData // 现在传递buffData而不是enhancedStats和specialEffects + ); + } + }); + + const totalMonsters = monsters.reduce((total: number, group: any) => total + group.count, 0); + console.log(`[MissionMonComp]:肉鸽模式本波次将生成 ${totalMonsters} 只怪物,等级: ${monsterLevel}`); + + // 输出词条信息 + monsters.forEach((monsterGroup: any) => { + if (monsterGroup.buffData && monsterGroup.buffData.length > 0) { + console.log(`[MissionMonComp]:怪物 ${monsterGroup.uuid} 拥有词条:`, monsterGroup.buffData); + // 输出词条名称 + monsterGroup.buffData.forEach((buff: any) => { + const config = MonsterAffixConfig[buff.buff_type]; + if (config) { + console.log(`[MissionMonComp]: - ${config.name}: ${config.description}`); + } + }); + } + }); + } - // 新增:添加到刷怪队列 - 增加level参数 + // 新增:添加到刷怪队列 - 增加level参数(普通模式) private addToSpawnQueue(uuid: number, position: number, isBoss: boolean = false, level: number = 1) { this.monsterQueue.push({ uuid: uuid, @@ -111,22 +182,62 @@ export class MissionMonCompComp extends CCComp { level: level }); } + + // 新增:添加到刷怪队列 - 支持词条(肉鸽模式) + private addToSpawnQueueWithAffixes( + uuid: number, + position: number, + isBoss: boolean = false, + level: number = 1, + affixes?: any[], + buffData?: any[] + ) { + this.monsterQueue.push({ + uuid: uuid, + position: position, + isBoss: isBoss, + level: level, + affixes: affixes, + buffData: buffData + }); + } - // 新增:从队列中生成下一个怪物 - 传递level参数 + // 新增:从队列中生成下一个怪物 - 传递词条参数 private spawnNextMonster() { if (this.monsterQueue.length === 0) return; const monsterData = this.monsterQueue.shift(); if (monsterData) { - this.addMonster(monsterData.uuid, monsterData.position, monsterData.isBoss, false, monsterData.level); + this.addMonster( + monsterData.uuid, + monsterData.position, + monsterData.isBoss, + false, + monsterData.level, + monsterData.buffData + ); } } - private addMonster(uuid:number=1001,i:number=0,is_boss:boolean=false,is_call:boolean=false,lv:number=1) { - let mon = ecs.getEntity(Monster); - let scale = -1 - let pos:Vec3 = v3(MonSet[i].pos); - mon.load(pos,scale,uuid,is_boss,is_call,lv); + private addMonster( + uuid: number = 1001, + i: number = 0, + is_boss: boolean = false, + is_call: boolean = false, + lv: number = 1, + buffData?: any[] + ) { + let mon = ecs.getEntity(Monster); + let scale = -1; + let pos: Vec3 = v3(MonSet[i].pos); + + // 生成怪物,传递词条buff数据 + mon.load(pos, scale, uuid, is_boss, is_call, lv, buffData); + + // 如果有词条buff数据,记录到控制台 + if (buffData && buffData.length > 0) { + console.log(`[MissionMonComp]: 怪物 ${uuid} 获得肉鸽词条Buff:`, buffData); + } } /** 视图对象通过 ecs.Entity.remove(ModuleViewComp) 删除组件是触发组件处理自定义释放逻辑 */ reset() { diff --git a/assets/script/game/map/RogueConfig.ts b/assets/script/game/map/RogueConfig.ts new file mode 100644 index 00000000..56d23f53 --- /dev/null +++ b/assets/script/game/map/RogueConfig.ts @@ -0,0 +1,455 @@ +/** + * 肉鸽模式配置脚本 + * + * 功能说明: + * - 提供肉鸽模式的波次生成配置 + * - 包含词条系统和怪物强化逻辑 + * - 供 MissionMonComp.ts 等组件调用 + * + * 波次规则: + * - 固定波次:5(商店)、10(Boss)、15(休息)、20(Boss)、25(商店)、30(Boss) + * - 精英波次:个位数是4和9的波次(4、9、14、19、24、29...) + * - 普通波次:其他所有波次 + * + * @author 游戏开发团队 + * @version 1.0 + * @date 2025-07-12 + */ + +// 导入配置 +import { HQuality, HeroInfo, MonsterSeriesConfig, getRandomSeries } from "../common/config/heroSet"; +import { BuffAttr } from "../common/config/SkillSet"; + +// ==================== 核心配置 ==================== + +/** + * 肉鸽模式波次类型枚举 + */ +export enum RogueWaveType { + NORMAL = "normal", + ELITE = "elite", + BOSS = "boss", + SHOP = "shop", + REST = "rest" +} + +/** + * 怪物词条配置(直接使用BuffAttr作为词条类型) + * 这样可以直接复用Mon.ts中的Buff处理逻辑 + */ +export const MonsterAffixConfig = { + [BuffAttr.ATK]: { + name: "狂暴", + description: "攻击力提升50%", + value: 50, + rarity: "common", + applicableQualities: [HQuality.GREEN, HQuality.BLUE, HQuality.PURPLE] + }, + [BuffAttr.ATK_CD]: { + name: "迅捷", + description: "攻击速度提升30%", + value: 30, // 正值表示提升,Mon.ts中会转换为负值 + rarity: "common", + applicableQualities: [HQuality.GREEN, HQuality.BLUE] + }, + [BuffAttr.CRITICAL]: { + name: "致命", + description: "暴击率提升25%", + value: 25, + rarity: "uncommon", + applicableQualities: [HQuality.BLUE, HQuality.PURPLE] + }, + [BuffAttr.DEF]: { + name: "装甲", + description: "减少受到的伤害30%", + value: 30, + rarity: "common", + applicableQualities: [HQuality.GREEN, HQuality.BLUE, HQuality.PURPLE] + }, + [BuffAttr.HP]: { + name: "坚韧", + description: "生命值提升50%", + value: 50, + rarity: "common", + applicableQualities: [HQuality.GREEN, HQuality.BLUE, HQuality.PURPLE] + }, + [BuffAttr.CRITICAL_DMG]: { + name: "嗜血", + description: "暴击伤害提升40%", + value: 40, + rarity: "uncommon", + applicableQualities: [HQuality.BLUE, HQuality.PURPLE] + }, + [BuffAttr.DODGE]: { + name: "敏捷", + description: "闪避率提升25%", + value: 25, + rarity: "uncommon", + applicableQualities: [HQuality.GREEN, HQuality.BLUE] + }, + [BuffAttr.BURN_COUNT]: { + name: "燃烧", + description: "攻击附带易伤效果,额外持续3次", + value: 3, + rarity: "uncommon", + applicableQualities: [HQuality.GREEN, HQuality.BLUE, HQuality.PURPLE] + }, + [BuffAttr.PUNCTURE]: { + name: "穿刺", + description: "攻击穿透1个敌人", + value: 1, + rarity: "uncommon", + applicableQualities: [HQuality.BLUE, HQuality.PURPLE] + }, + [BuffAttr.FROST_RATIO]: { + name: "冰冻", + description: "攻击有20%概率冰冻敌人", + value: 20, + rarity: "rare", + applicableQualities: [HQuality.BLUE, HQuality.PURPLE] + } +}; + +/** + * 词条数量配置 + */ +export const AffixCountConfig = { + currentMode: "normal" as "normal" | "enhanced", + + modes: { + normal: { + [RogueWaveType.NORMAL]: 0, + [RogueWaveType.ELITE]: 1, + [RogueWaveType.BOSS]: 2, + }, + enhanced: { + [RogueWaveType.NORMAL]: 1, + [RogueWaveType.ELITE]: 2, + [RogueWaveType.BOSS]: 3, + } + }, + + setMode(mode: "normal" | "enhanced") { + this.currentMode = mode; + }, + + getAffixCount(waveType: RogueWaveType): number { + return this.modes[this.currentMode][waveType] || 0; + }, + + enableNormalMode() { + this.setMode("normal"); + }, + + enableEnhancedMode() { + this.setMode("enhanced"); + } +}; + +/** + * 波次配置 + */ +export const RogueWaveConfig = { + fixedWaves: { + 5: RogueWaveType.SHOP, + 10: RogueWaveType.BOSS, + 15: RogueWaveType.REST, + 20: RogueWaveType.BOSS, + 25: RogueWaveType.SHOP, + 30: RogueWaveType.BOSS + }, + + isEliteWave: (waveNumber: number): boolean => { + const lastDigit = waveNumber % 10; + return lastDigit === 4 || lastDigit === 9; + } +}; + +// ==================== 肉鸽配置生成器 ==================== + +/** + * 肉鸽配置生成器 + */ +export class RogueConfig { + + /** + * 生成波次配置(主入口) + */ + static generateWaveConfig(waveNumber: number) { + let waveType: RogueWaveType; + + // 判断波次类型 + if (RogueWaveConfig.fixedWaves[waveNumber]) { + waveType = RogueWaveConfig.fixedWaves[waveNumber]; + } else if (RogueWaveConfig.isEliteWave(waveNumber)) { + waveType = RogueWaveType.ELITE; + } else { + waveType = RogueWaveType.NORMAL; + } + + console.log(`[RogueConfig]: 第${waveNumber}波 - 类型: ${waveType}`); + + // 根据类型生成配置 + switch (waveType) { + case RogueWaveType.NORMAL: + return this.generateNormalWave(waveNumber); + case RogueWaveType.ELITE: + return this.generateEliteWave(waveNumber); + case RogueWaveType.BOSS: + return this.generateBossWave(waveNumber); + case RogueWaveType.SHOP: + return this.generateShopWave(waveNumber); + case RogueWaveType.REST: + return this.generateRestWave(waveNumber); + default: + return this.generateNormalWave(waveNumber); + } + } + + /** + * 生成普通波次 + */ + static generateNormalWave(waveNumber: number) { + const series = getRandomSeries(); + const seriesConfig = MonsterSeriesConfig[series]; + const baseCount = Math.min(3 + Math.floor(waveNumber / 5), 8); + const monsters = []; + + // 选择怪物类型 + const availableTypes = []; + if (seriesConfig.monsters.warrior.length > 0) availableTypes.push("warrior"); + if (seriesConfig.monsters.remote.length > 0) availableTypes.push("remote"); + if (seriesConfig.monsters.mage.length > 0) availableTypes.push("mage"); + + if (availableTypes.length > 0) { + const randomType = availableTypes[Math.floor(Math.random() * availableTypes.length)]; + const typeMonsters = seriesConfig.monsters[randomType]; + const randomMonster = typeMonsters[Math.floor(Math.random() * typeMonsters.length)]; + const monsterInfo = HeroInfo[randomMonster]; + + // 生成词条 + const affixes = this.generateMonsterAffixes( + monsterInfo.quality, + waveNumber, + RogueWaveType.NORMAL + ); + + // 应用强化 + const enhanced = this.applyAffixesToMonster(affixes, monsterInfo); + + monsters.push({ + uuid: randomMonster, + count: baseCount, + type: randomType, + series: series, + affixes: affixes, + enhancedStats: enhanced.stats, + buffData: enhanced.buffData + }); + } + + return { + waveType: RogueWaveType.NORMAL, + monsters: monsters, + description: `普通波次 - ${seriesConfig.name}`, + waveNumber: waveNumber + }; + } + + /** + * 生成精英波次 + */ + static generateEliteWave(waveNumber: number) { + const series = getRandomSeries(); + const seriesConfig = MonsterSeriesConfig[series]; + + // 查找精英怪物 + const eliteMonsters = seriesConfig.allMonsters.filter(uuid => { + return HeroInfo[uuid] && HeroInfo[uuid].quality === HQuality.BLUE; + }); + + const monsters = []; + + if (eliteMonsters.length > 0) { + const eliteMonster = eliteMonsters[Math.floor(Math.random() * eliteMonsters.length)]; + const count = Math.max(1, Math.floor(2 + waveNumber / 8)); + const monsterInfo = HeroInfo[eliteMonster]; + + // 生成精英词条 + const affixes = this.generateMonsterAffixes( + monsterInfo.quality, + waveNumber, + RogueWaveType.ELITE + ); + + const enhanced = this.applyAffixesToMonster(affixes, monsterInfo); + + monsters.push({ + uuid: eliteMonster, + count: count, + type: "warrior", + series: series, + affixes: affixes, + enhancedStats: enhanced.stats, + buffData: enhanced.buffData + }); + } + + return { + waveType: RogueWaveType.ELITE, + monsters: monsters, + description: `精英波次 - ${seriesConfig.name}精锐`, + waveNumber: waveNumber + }; + } + + /** + * 生成Boss波次 + */ + static generateBossWave(waveNumber: number) { + const series = getRandomSeries(); + const seriesConfig = MonsterSeriesConfig[series]; + + // 查找Boss怪物 + const bossMonsters = seriesConfig.allMonsters.filter(uuid => { + return HeroInfo[uuid] && HeroInfo[uuid].quality === HQuality.PURPLE; + }); + + const bossMonster = bossMonsters.length > 0 ? + bossMonsters[Math.floor(Math.random() * bossMonsters.length)] : + seriesConfig.allMonsters[Math.floor(Math.random() * seriesConfig.allMonsters.length)]; + + const bossInfo = HeroInfo[bossMonster]; + + // 生成Boss词条 + const bossAffixes = this.generateMonsterAffixes( + bossInfo.quality, + waveNumber, + RogueWaveType.BOSS + ); + + const enhancedBoss = this.applyAffixesToMonster(bossAffixes, bossInfo); + + const monsters = [{ + uuid: bossMonster, + count: 1, + type: "boss", + series: series, + isBoss: true, + affixes: bossAffixes, + enhancedStats: enhancedBoss.stats, + buffData: enhancedBoss.buffData + }]; + + return { + waveType: RogueWaveType.BOSS, + monsters: monsters, + description: `Boss战 - ${seriesConfig.name}首领`, + waveNumber: waveNumber + }; + } + + /** + * 生成商店波次 + */ + static generateShopWave(waveNumber: number) { + return { + waveType: RogueWaveType.SHOP, + description: "商店波次", + waveNumber: waveNumber + }; + } + + /** + * 生成休息波次 + */ + static generateRestWave(waveNumber: number) { + return { + waveType: RogueWaveType.REST, + description: "休息波次", + waveNumber: waveNumber + }; + } + + /** + * 生成怪物词条(现在直接返回BuffAttr数组) + */ + static generateMonsterAffixes( + monsterQuality: number, + waveNumber: number, + waveType: RogueWaveType + ): BuffAttr[] { + const affixCount = AffixCountConfig.getAffixCount(waveType); + if (affixCount === 0) return []; + + const availableAffixes = Object.keys(MonsterAffixConfig).filter(affixType => { + const buffAttr = parseInt(affixType) as BuffAttr; + const config = MonsterAffixConfig[buffAttr]; + return config.applicableQualities.includes(monsterQuality); + }).map(key => parseInt(key) as BuffAttr); + + const selectedAffixes: BuffAttr[] = []; + + for (let i = 0; i < affixCount && availableAffixes.length > 0; i++) { + const randomIndex = Math.floor(Math.random() * availableAffixes.length); + const selectedAffix = availableAffixes[randomIndex]; + selectedAffixes.push(selectedAffix); + availableAffixes.splice(randomIndex, 1); + } + + return selectedAffixes; + } + + /** + * 应用词条到怪物(简化版本,主要用于日志显示) + */ + static applyAffixesToMonster(affixes: BuffAttr[], baseStats: any) { + const modifiedStats = { ...baseStats }; + const buffData = []; + + for (const affix of affixes) { + const config = MonsterAffixConfig[affix]; + if (config) { + buffData.push({ + buff_type: affix, + value: config.value + }); + + // 预览属性变化(实际应用在Mon.ts中) + switch (affix) { + case BuffAttr.ATK: + modifiedStats.ap = Math.floor(modifiedStats.ap * (1 + config.value / 100)); + break; + case BuffAttr.HP: + modifiedStats.hp = Math.floor(modifiedStats.hp * (1 + config.value / 100)); + break; + case BuffAttr.ATK_CD: + modifiedStats.cd = Math.max(0.1, modifiedStats.cd * (1 - config.value / 100)); + break; + } + } + } + + return { + stats: modifiedStats, + buffData: buffData, // 返回Buff数据格式,与Mon.ts兼容 + affixes: affixes + }; + } + + /** + * 获取怪物等级 + */ + static getMonsterLevel(waveNumber: number): number { + return Math.max(1, Math.floor(waveNumber / 5) + 1); + } +} + +// ==================== 导出接口 ==================== + +/** + * 外部调用接口 - 获取波次配置 + */ +export const getRogueWaveConfig = (waveNumber: number) => { + return RogueConfig.generateWaveConfig(waveNumber); +}; \ No newline at end of file diff --git a/assets/script/game/map/RogueConfig.ts.meta b/assets/script/game/map/RogueConfig.ts.meta new file mode 100644 index 00000000..8579202e --- /dev/null +++ b/assets/script/game/map/RogueConfig.ts.meta @@ -0,0 +1,9 @@ +{ + "ver": "4.0.23", + "importer": "typescript", + "imported": true, + "uuid": "f432a03f-6b3c-43a9-bdd8-845aeec7a019", + "files": [], + "subMetas": {}, + "userData": {} +}