refactor(game): 简化怪物生成逻辑并移除肉鸽配置
- 移除 RogueConfig 及相关动态成长系统 - 简化 Monster.load() 方法参数,直接使用 heroSet 配置 - 移除 MissionMonComp 中的波次生成逻辑和特殊队列 - 清理 MissionComp 中与肉鸽相关的特殊刷怪检查 - 调整 heroSet 配置,移除 buff 字段并统一技能 - 更新技能配置,增加更多攻击特效
This commit is contained in:
@@ -192,13 +192,13 @@ export const SkillSet: Record<number, SkillConfig> = {
|
||||
buffs:[],debuffs:[],info:"对前方目标造成100%攻击的伤害",
|
||||
},
|
||||
6002: {
|
||||
uuid:6002,name:"电击",sp_name:"atk_s3",icon:"1173",TGroup:TGroup.Enemy,TType:TType.Frontline,readyAnm:"",endAnm:"",act:"max",DTType:DTType.single,
|
||||
uuid:6002,name:"电击",sp_name:"atk_s4",icon:"1173",TGroup:TGroup.Enemy,TType:TType.Frontline,readyAnm:"",endAnm:"",act:"max",DTType:DTType.single,
|
||||
ap:100,hit_count:1,hitcd:0.2,speed:720,with:0,
|
||||
ready:0,EAnm:0,DAnm:9001,RType:RType.fixed,EType:EType.collision,
|
||||
buffs:[],debuffs:[],info:"对前方目标造成150%攻击的伤害",
|
||||
},
|
||||
6003: {
|
||||
uuid:6003,name:"闪击",sp_name:"atk_s1",icon:"1173",TGroup:TGroup.Enemy,TType:TType.Frontline,readyAnm:"",endAnm:"",act:"max",DTType:DTType.single,
|
||||
uuid:6003,name:"闪击",sp_name:"atk_s3",icon:"1173",TGroup:TGroup.Enemy,TType:TType.Frontline,readyAnm:"",endAnm:"",act:"max",DTType:DTType.single,
|
||||
ap:100,hit_count:1,hitcd:0.2,speed:720,with:0,
|
||||
ready:0,EAnm:0,DAnm:9001,RType:RType.fixed,EType:EType.animationEnd,
|
||||
buffs:[],debuffs:[],info:"对前方目标造成150%攻击的伤害",
|
||||
@@ -226,39 +226,64 @@ export const SkillSet: Record<number, SkillConfig> = {
|
||||
ap:100,hit_count:1,hitcd:0.2,speed:720,with:0,
|
||||
ready:0,EAnm:0,DAnm:9001,RType:RType.linear,EType:EType.collision,
|
||||
buffs:[],debuffs:[],info:"对前方单个目标造成100%攻击的伤害",
|
||||
},
|
||||
},
|
||||
6008: {
|
||||
uuid:6008,name:"水球",sp_name:"ball_water",icon:"1126",TGroup:TGroup.Enemy,TType:TType.Frontline,readyAnm:"",endAnm:"",act:"atk",DTType:DTType.single,
|
||||
uuid:6008,name:"光箭",sp_name:"arrow_big_yellow",icon:"1135",TGroup:TGroup.Enemy,TType:TType.Frontline,readyAnm:"",endAnm:"",act:"atk",DTType:DTType.single,
|
||||
ap:100,hit_count:1,hitcd:0.2,speed:720,with:0,
|
||||
ready:0,EAnm:0,DAnm:9001,RType:RType.linear,EType:EType.animationEnd,
|
||||
buffs:[],debuffs:[],info:"对前方单个目标造成100%攻击的伤害",
|
||||
},
|
||||
6009: {
|
||||
uuid:6009,name:"冰球",sp_name:"ball_ice",icon:"1126",TGroup:TGroup.Enemy,TType:TType.Frontline,readyAnm:"",endAnm:"",act:"atk",DTType:DTType.single,
|
||||
ap:100,hit_count:2,hitcd:0.3,speed:720,with:90,
|
||||
ready:0,EAnm:0,DAnm:9001,RType:RType.linear,EType:EType.collision,
|
||||
buffs:[],debuffs:[],info:"对前方单个目标造成100%攻击的伤害",
|
||||
},
|
||||
6010: {
|
||||
uuid:6010,name:"冰锥",sp_name:"ball_forst",icon:"1126",TGroup:TGroup.Enemy,TType:TType.Frontline,readyAnm:"",endAnm:"",act:"atk",DTType:DTType.single,
|
||||
ap:100,hit_count:2,hitcd:0.3,speed:720,with:90,
|
||||
ready:0,EAnm:0,DAnm:9001,RType:RType.linear,EType:EType.collision,
|
||||
buffs:[],debuffs:[],info:"对前方单个目标造成100%攻击的伤害",
|
||||
},
|
||||
6011: {
|
||||
uuid:6011,name:"火球",sp_name:"ball_fire",icon:"1126",TGroup:TGroup.Enemy,TType:TType.Frontline,readyAnm:"",endAnm:"",act:"atk",DTType:DTType.single,
|
||||
ap:100,hit_count:2,hitcd:0.3,speed:720,with:90,
|
||||
ready:0,EAnm:0,DAnm:9001,RType:RType.linear,EType:EType.collision,
|
||||
buffs:[],debuffs:[],info:"对前方单个目标造成100%攻击的伤害",
|
||||
},
|
||||
6012: {
|
||||
uuid:6012,name:"光波",sp_name:"ball_guang",icon:"1126",TGroup:TGroup.Enemy,TType:TType.Frontline,readyAnm:"",endAnm:"",act:"atk",DTType:DTType.single,
|
||||
ap:100,hit_count:2,hitcd:0.3,speed:720,with:90,
|
||||
ready:0,EAnm:0,DAnm:9001,RType:RType.linear,EType:EType.collision,
|
||||
buffs:[],debuffs:[],info:"对前方单个目标造成100%攻击的伤害",
|
||||
},
|
||||
6013: {
|
||||
uuid:6013,name:"半月波",sp_name:"ball_light",icon:"1126",TGroup:TGroup.Enemy,TType:TType.Frontline,readyAnm:"",endAnm:"",act:"atk",DTType:DTType.single,
|
||||
ap:100,hit_count:2,hitcd:0.3,speed:720,with:90,
|
||||
ready:0,EAnm:0,DAnm:9001,RType:RType.linear,EType:EType.collision,
|
||||
buffs:[],debuffs:[],info:"对前方单个目标造成100%攻击的伤害",
|
||||
},
|
||||
6014: {
|
||||
uuid:6014,name:"月波",sp_name:"ball_gquan",icon:"1126",TGroup:TGroup.Enemy,TType:TType.Frontline,readyAnm:"",endAnm:"",act:"atk",DTType:DTType.single,
|
||||
ap:100,hit_count:2,hitcd:0.3,speed:720,with:90,
|
||||
ready:0,EAnm:0,DAnm:9001,RType:RType.linear,EType:EType.collision,
|
||||
buffs:[],debuffs:[],info:"对前方单个目标造成100%攻击的伤害",
|
||||
},
|
||||
|
||||
//============================= ====== 基础buff ====== ========================== 6100-6199
|
||||
6100: {
|
||||
uuid:6100,name:"治疗",sp_name:"buff_wind",icon:"1292",TGroup:TGroup.Self,TType:TType.LowestHP,readyAnm:"",endAnm:"",act:"atk",DTType:DTType.single,
|
||||
ap:30,hit_count:1,hitcd:0.2,speed:720,with:0,
|
||||
ready:0,EAnm:0,DAnm:9001,RType:RType.fixed,EType:EType.animationEnd,
|
||||
kind:SkillKind.Heal,buffs:[],debuffs:[],info:"治疗自己,回复30%最大生命值",
|
||||
},
|
||||
6101:{
|
||||
uuid:6101,name:"魔法盾",sp_name:"buff_wind",icon:"1255",TGroup:TGroup.Self,TType:TType.LowestHP,readyAnm:"",endAnm:"",act:"atk",DTType:DTType.single,
|
||||
6100:{
|
||||
uuid:6100,name:"魔法盾",sp_name:"buff_wind",icon:"1255",TGroup:TGroup.Self,TType:TType.LowestHP,readyAnm:"",endAnm:"",act:"atk",DTType:DTType.single,
|
||||
ap:30,hit_count:1,hitcd:0.2,speed:720,with:0,
|
||||
ready:0,EAnm:0,DAnm:9001,RType:RType.fixed,EType:EType.animationEnd,
|
||||
kind:SkillKind.Shield,buffs:[],debuffs:[],info:"获得30%最大生命值的护盾,持续60秒",
|
||||
},
|
||||
6102:{
|
||||
uuid:6102,name:"强壮",sp_name:"buff_wind",icon:"3036",TGroup:TGroup.Team,TType:TType.HighestAP,readyAnm:"",endAnm:"",act:"atk",DTType:DTType.single,
|
||||
6101: {
|
||||
uuid:6101,name:"治疗",sp_name:"buff_wind",icon:"1292",TGroup:TGroup.Self,TType:TType.LowestHP,readyAnm:"",endAnm:"",act:"atk",DTType:DTType.single,
|
||||
ap:30,hit_count:1,hitcd:0.2,speed:720,with:0,
|
||||
ready:0,EAnm:0,DAnm:9001,RType:RType.fixed,EType:EType.animationEnd,
|
||||
kind:SkillKind.Support,buffs:[10001],debuffs:[],info:"增加目标10%攻击力,持续30秒",
|
||||
},
|
||||
6103:{
|
||||
uuid:6103,name:"群体强壮",sp_name:"buff_wind",icon:"3036",TGroup:TGroup.Team,TType:TType.HighestAP,readyAnm:"",endAnm:"",act:"atk",DTType:DTType.range,
|
||||
ap:30,hit_count:1,hitcd:0.2,speed:720,with:0,
|
||||
ready:0,EAnm:0,DAnm:9001,RType:RType.fixed,EType:EType.animationEnd,
|
||||
kind:SkillKind.Support,buffs:[10011],debuffs:[],info:"增加目标10%攻击力,持续30秒",
|
||||
kind:SkillKind.Heal,buffs:[],debuffs:[],info:"治疗自己,回复30%最大生命值",
|
||||
},
|
||||
|
||||
// ========== 怪物基础技能 ========== 6200-6299
|
||||
6201: {
|
||||
uuid:6201, name:"怪物近战", sp_name:"atk_s1", icon:"3036",
|
||||
|
||||
@@ -139,7 +139,6 @@ export interface heroInfo {
|
||||
// dis: number; // 攻击距离(像素)
|
||||
speed: number; // 移动速度(像素/秒)
|
||||
skills: number[]; // 携带技能ID列表
|
||||
buff: BuffConf[]; // 自带buff配置(通常为空,由技能动态添加)
|
||||
info: string; // 描述文案
|
||||
}
|
||||
|
||||
@@ -158,73 +157,52 @@ export const HeroInfo: Record<number, heroInfo> = {
|
||||
// ========== 英雄角色 ==========
|
||||
|
||||
5001:{uuid:5001,name:"盾战士",icon:"1001",path:"hk1", fac:FacSet.HERO, kind:1,as:1,ss:5,
|
||||
type:HType.Melee,lv:1,hp:300,ap:25,speed:120,skills:[6001,6004],
|
||||
buff:[],info:"盾战士"},
|
||||
type:HType.Melee,lv:1,hp:300,ap:25,speed:120,skills:[6001,6004],info:"盾战士"},
|
||||
|
||||
5002:{uuid:5002,name:"奥术法师",icon:"1001",path:"hm2", fac:FacSet.HERO, kind:2,as:1,ss:5,
|
||||
type:HType.Long,lv:1,hp:150,ap:40,speed:95,skills:[6003,6101],
|
||||
buff:[],info:"奥术法师"},
|
||||
type:HType.Long,lv:1,hp:150,ap:40,speed:95,skills:[6003,6101],info:"奥术法师"},
|
||||
|
||||
5003:{uuid:5003,name:"射手",icon:"1001",path:"ha1", fac:FacSet.HERO, kind:2,as:1,ss:5,
|
||||
type:HType.Long,lv:1,hp:180,ap:30,speed:140,skills:[6005,6006],
|
||||
buff:[],info:"射手"},
|
||||
type:HType.Long,lv:1,hp:180,ap:30,speed:140,skills:[6005,6006],info:"射手"},
|
||||
|
||||
5005:{uuid:5005,name:"牧师",icon:"1001",path:"hh1", fac:FacSet.HERO, kind:2,as:1,ss:5,
|
||||
type:HType.Long,lv:1,hp:160,ap:25,speed:100,skills:[6003,6100],
|
||||
buff:[],info:"牧师"},
|
||||
type:HType.Long,lv:1,hp:160,ap:25,speed:100,skills:[6003,6100],info:"牧师"},
|
||||
|
||||
5004:{uuid:5004,name:"火焰法师",icon:"1001",path:"hm1", fac:FacSet.HERO, kind:2,as:1,ss:5,
|
||||
type:HType.Long,lv:1,hp:150,ap:45,speed:90,skills:[6003,6101],
|
||||
buff:[],info:"火焰法师"},
|
||||
type:HType.Long,lv:1,hp:150,ap:45,speed:90,skills:[6003,6101],info:"火焰法师"},
|
||||
|
||||
5006:{uuid:5006,name:"召唤法师",icon:"1001",path:"hz1", fac:FacSet.HERO, kind:2,as:1,ss:5,
|
||||
type:HType.Long,lv:1,hp:200,ap:20,speed:105,skills:[6003,6101],
|
||||
buff:[],info:"召唤法师"},
|
||||
type:HType.Long,lv:1,hp:200,ap:20,speed:105,skills:[6003,6101],info:"召唤法师"},
|
||||
|
||||
5007:{uuid:5007,name:"刺客",icon:"1001",path:"hc1", fac:FacSet.HERO, kind:1,as:1,ss:5,
|
||||
type:HType.Melee,lv:1,hp:140,ap:50,speed:180,skills:[6001,6004],
|
||||
buff:[],info:"刺客"},
|
||||
type:HType.Melee,lv:1,hp:140,ap:50,speed:180,skills:[6001,6004],info:"刺客"},
|
||||
|
||||
|
||||
|
||||
|
||||
// 1. 基础近战型
|
||||
5201:{uuid:5201,name:"兽人战士",icon:"1001",path:"mo1", fac:FacSet.MON, kind:1,as:3.0,ss:10,
|
||||
type:HType.Melee,lv:1,hp:60,ap:8,speed:180,skills:[6003],
|
||||
buff:[],info:"标准炮灰:确保英雄能完成3次普攻积累天赋计数"},
|
||||
type:HType.Melee,lv:1,hp:60,ap:8,speed:180,skills:[6001,6003],info:"标准炮灰:确保英雄能完成3次普攻积累天赋计数"},
|
||||
// 2. 快速突击型
|
||||
5301:{uuid:5301,name:"兽人斥候",icon:"1001",path:"mo1", fac:FacSet.MON, kind:1,as:1.2,ss:10,
|
||||
type:HType.Melee,lv:1,hp:40,ap:12,speed:400,skills:[6003],
|
||||
buff:[],info:"快速突击:极高移速贴脸,检测护盾(7102)刷新率"},
|
||||
type:HType.Melee,lv:1,hp:40,ap:12,speed:400,skills:[6001,6003],info:"快速突击:极高移速贴脸,检测护盾(7102)刷新率"},
|
||||
// 3. 重型坦克型
|
||||
5401:{uuid:5401,name:"兽人卫士",icon:"1001",path:"mo3", fac:FacSet.MON, kind:1,as:5.0,ss:10,
|
||||
type:HType.Melee,lv:1,hp:200,ap:15,speed:60,skills:[6003],
|
||||
buff:[],info:"重型坦克:数值墙,检测玩家破甲(7008)与持续输出"},
|
||||
type:HType.Melee,lv:1,hp:200,ap:15,speed:60,skills:[6001,6003],info:"重型坦克:数值墙,检测玩家破甲(7008)与持续输出"},
|
||||
|
||||
// 4. 远程骚扰型
|
||||
5501:{uuid:5501,name:"兽人射手",icon:"1001",path:"mo1", fac:FacSet.MON, kind:1,as:3.0,ss:10,
|
||||
type:HType.Long,lv:1,hp:50,ap:10,speed:90,skills:[6203],
|
||||
buff:[],info:"远程骚扰:跨屏打击,迫使阵地分散或移动英雄"},
|
||||
type:HType.Long,lv:1,hp:50,ap:10,speed:90,skills:[6001,6003],info:"远程骚扰:跨屏打击,迫使阵地分散或移动英雄"},
|
||||
|
||||
// 5. 特殊机制型
|
||||
5601:{uuid:5601,name:"兽人自爆兵",icon:"1001",path:"mo1", fac:FacSet.MON, kind:1,as:3.0,ss:10,
|
||||
type:HType.Melee,lv:1,hp:80,ap:200,speed:220,skills:[6003],
|
||||
buff:[],info:"特殊机制:极端伤害,漏怪即秒杀,检测减伤(7103)"},
|
||||
// 召唤师:持续召唤小怪(后续可在技能系统中实现 SType.zhaohuan)
|
||||
type:HType.Melee,lv:1,hp:80,ap:200,speed:220,skills:[6001,6003],info:"特殊机制:极端伤害,漏怪即秒杀,检测减伤(7103)"},
|
||||
5602:{uuid:5602,name:"兽人召唤师",icon:"1001",path:"mo1", fac:FacSet.MON, kind:1,as:3.0,ss:10,
|
||||
type:HType.Long,lv:1,hp:150,ap:10,speed:100,skills:[6003],
|
||||
buff:[],info:"战术目标:持续召唤小怪,检测英雄大招清场频率"},
|
||||
// 治疗者:为周围怪物回血(此处以提升治疗效果和生命回复为基础被动)
|
||||
type:HType.Long,lv:1,hp:150,ap:10,speed:100,skills:[6001,6003],info:"战术目标:持续召唤小怪,检测英雄大招清场频率"},
|
||||
5603:{uuid:5603,name:"兽人祭司",icon:"1001",path:"mo1", fac:FacSet.MON, kind:1,as:3.0,ss:10,
|
||||
type:HType.Long,lv:1,hp:150,ap:10,speed:105,skills:[6003],
|
||||
buff:[],info:"战术目标:为怪群回血,检测玩家沉默(7006)覆盖率"},
|
||||
// 光环怪:为周围怪物提供增益(此处以Buff效果提升与移动速度提升为基础被动)
|
||||
// Attrs.BUFF_UP=60 (RATIO=1),Attrs.SPEED=63 (RATIO=1)
|
||||
5604:{uuid:5604,name:"兽人图腾师",icon:"1001",path:"mo1", fac:FacSet.MON, kind:1,as:3.0,ss:10,
|
||||
type:HType.Long,lv:1,hp:150,ap:10,speed:110,skills:[6003],
|
||||
buff:[],info:"战术目标:提供加速光环,改变怪群推进节奏"},
|
||||
type:HType.Long,lv:1,hp:150,ap:10,speed:105,skills:[6001,6003],info:"战术目标:为怪群回血,检测玩家沉默(7006)覆盖率"},
|
||||
5604:{uuid:5604,name:"兽人图腾师",icon:"1001",path:"mo1", fac:FacSet.MON, kind:1,as:3.0,ss:10,
|
||||
type:HType.Long,lv:1,hp:150,ap:10,speed:110,skills:[6001,6003],info:"战术目标:提供加速光环,改变怪群推进节奏"},
|
||||
// 6. 精英/BOSS型
|
||||
5701:{uuid:5701,name:"兽人首领(BOSS)",icon:"1001",path:"mo4", fac:FacSet.MON, kind:1,as:2.5,ss:10,
|
||||
type:HType.Melee,lv:3,hp:2000,ap:60,speed:120,skills:[6003],
|
||||
buff:[],info:"终极考验:极高HP,检测大招重置与辐射协同输出"},
|
||||
type:HType.Melee,lv:3,hp:2000,ap:60,speed:120,skills:[6001,6003],info:"终极考验:极高HP,检测大招重置与辐射协同输出"},
|
||||
};
|
||||
|
||||
@@ -6,7 +6,6 @@ import { BoxSet, FacSet, FightSet, IndexSet } from "../common/config/GameSet";
|
||||
import { HeroInfo } from "../common/config/heroSet";
|
||||
import { HeroAttrsComp } from "./HeroAttrsComp";
|
||||
import { BuffConf, SkillSet } from "../common/config/SkillSet";
|
||||
import { getMonAttr, MonType } from "../map/RogueConfig";
|
||||
import { HeroViewComp } from "./HeroViewComp";
|
||||
import { MoveComp } from "./MoveComp";
|
||||
import { mLogger } from "../common/Logger";
|
||||
@@ -89,7 +88,7 @@ export class Monster extends ecs.Entity {
|
||||
}
|
||||
|
||||
/** 加载角色 */
|
||||
load(pos: Vec3 = Vec3.ZERO,scale:number = 1,uuid:number=1001,lv:number=1,monType:MonType=MonType.NORMAL, buffs: BuffConf[] = [],is_call=false, lane: number = 0, spawnOrder: number = 0, gameTime: number = 0) {
|
||||
load(pos: Vec3 = Vec3.ZERO,scale:number = 1,uuid:number=1001, is_boss:boolean=false) {
|
||||
scale=-1
|
||||
let size=1
|
||||
var scene = smc.map.MapView.scene;
|
||||
@@ -124,23 +123,18 @@ export class Monster extends ecs.Entity {
|
||||
// 设置 View 层属性(表现相关)
|
||||
view.scale = scale;
|
||||
view.box_group = BoxSet.MONSTER;
|
||||
|
||||
// 设置 Model 层属性(数据相关)
|
||||
// 设置 Model 层属性 基础属性
|
||||
model.hero_uuid = uuid;
|
||||
model.hero_name = hero.name;
|
||||
model.lv = lv;
|
||||
model.hp = model.hp_max = hero.hp;
|
||||
model.ap = hero.ap;
|
||||
model.speed = hero.speed; // 使用成长后的速度
|
||||
model.type = hero.type;
|
||||
model.fac = FacSet.MON;
|
||||
model.is_boss = monType == MonType.BOSS;
|
||||
model.is_boss =is_boss
|
||||
if(!model.is_boss){
|
||||
model.is_kalami = true;
|
||||
}
|
||||
// 根据等级和类型获取怪物属性(使用新的动态成长系统)
|
||||
const {hp,ap, speed} = getMonAttr(lv, uuid, monType, gameTime);
|
||||
// 初始化属性数组
|
||||
model.hp = model.hp_max = hp;
|
||||
model.ap = ap;
|
||||
model.speed = speed; // 使用成长后的速度
|
||||
model.a_cd_max=hero.as
|
||||
model.s_cd_max=hero.ss
|
||||
model.back_chance=FightSet.BACK_CHANCE
|
||||
@@ -148,22 +142,20 @@ export class Monster extends ecs.Entity {
|
||||
if(hero.skills[0]) model.atk_id=hero.skills[0]
|
||||
if(hero.skills[1]) model.skill_id=hero.skills[1]
|
||||
model.updateSkillDistanceCache(model.skill_id || model.atk_id);
|
||||
|
||||
//根据刷怪控制脚本对ap和hp进行加强
|
||||
|
||||
|
||||
|
||||
this.add(view);
|
||||
// 重置视图状态(对象池复用时必须)
|
||||
view.init();
|
||||
|
||||
oops.message.dispatchEvent("monster_load",this)
|
||||
|
||||
// 初始化移动参数,包括线路和生成顺序
|
||||
const move = this.get(MoveComp);
|
||||
move.reset();
|
||||
move.direction = -1; // 向左移动
|
||||
move.targetX = Math.max(-320, Math.min(320, pos.x));
|
||||
move.baseY = pos.y;
|
||||
move.lane = lane; // 设置线路标识
|
||||
move.spawnOrder = spawnOrder; // 设置生成顺序
|
||||
smc.vmdata.mission_data.mon_num++
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,6 @@ import { CCComp } from "../../../../extensions/oops-plugin-framework/assets/modu
|
||||
import { smc } from "../common/SingletonModuleComp";
|
||||
import { oops } from "../../../../extensions/oops-plugin-framework/assets/core/Oops";
|
||||
import { HeroAttrsComp } from "../hero/HeroAttrsComp";
|
||||
import { MonsterCost, MonType, calculateMonsterGold, getLevelExp, calculateMonsterExp, SpecialMonsterSchedule } from "./RogueConfig";
|
||||
import { GameEvent } from "../common/config/GameEvent";
|
||||
import { HeroViewComp } from "../hero/HeroViewComp";
|
||||
import { UIID } from "../common/config/GameUIConfig";
|
||||
@@ -69,7 +68,6 @@ export class MissionComp extends CCComp {
|
||||
private readonly skillViewMatcher = ecs.allOf(SkillView);
|
||||
|
||||
// 记录已触发的特殊刷怪索引
|
||||
private spawnedSpecialIndices: Set<number> = new Set();
|
||||
|
||||
onLoad(){
|
||||
this.on(GameEvent.MissionStart,this.mission_start,this)
|
||||
@@ -86,9 +84,7 @@ export class MissionComp extends CCComp {
|
||||
if(smc.mission.stop_mon_action) return
|
||||
smc.vmdata.mission_data.fight_time+=dt
|
||||
this.FightTime-=dt
|
||||
|
||||
// 检查特殊刷怪时间
|
||||
this.checkSpecialSpawns(smc.vmdata.mission_data.fight_time);
|
||||
this.update_time();
|
||||
this.updateMemoryPanel(dt);
|
||||
}
|
||||
@@ -106,90 +102,6 @@ export class MissionComp extends CCComp {
|
||||
this.lastTimeStr = str;
|
||||
}
|
||||
}
|
||||
private checkSpecialSpawns(fightTime: number) {
|
||||
SpecialMonsterSchedule.forEach((item, index) => {
|
||||
if (!this.spawnedSpecialIndices.has(index) && fightTime >= item.time) {
|
||||
this.spawnedSpecialIndices.add(index);
|
||||
mLogger.log(this.debugMode, 'MissionComp', ` 触发特殊刷怪: ${item.desc}`);
|
||||
oops.message.dispatchEvent("SpawnSpecialMonster", {
|
||||
uuid: item.uuid,
|
||||
type: item.type,
|
||||
level: item.level
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private initMemoryPanel() {
|
||||
if (!this.showMemoryPanel || !this.time_node) return;
|
||||
let panel = this.time_node.getChildByName("mem_panel");
|
||||
if (!panel) {
|
||||
panel = new Node("mem_panel");
|
||||
panel.parent = this.time_node;
|
||||
panel.setPosition(0, -32, 0);
|
||||
}
|
||||
let label = panel.getComponent(Label);
|
||||
if (!label) {
|
||||
label = panel.addComponent(Label);
|
||||
}
|
||||
label.fontSize = 16;
|
||||
label.lineHeight = 20;
|
||||
this.memoryLabel = label;
|
||||
}
|
||||
|
||||
private updateMemoryPanel(dt: number) {
|
||||
if (!this.showMemoryPanel || !this.memoryLabel) return;
|
||||
this.perfDtAcc += dt;
|
||||
this.perfFrameCount += 1;
|
||||
this.memoryRefreshTimer += dt;
|
||||
if (this.memoryRefreshTimer < 0.5) return;
|
||||
this.memoryRefreshTimer = 0;
|
||||
let heroCount = 0;
|
||||
ecs.query(this.heroViewMatcher).forEach(() => {
|
||||
heroCount++;
|
||||
});
|
||||
let skillCount = 0;
|
||||
ecs.query(this.skillViewMatcher).forEach(() => {
|
||||
skillCount++;
|
||||
});
|
||||
const monPool = Monster.getPoolStats();
|
||||
const skillPool = Skill.getPoolStats();
|
||||
const perf = (globalThis as any).performance;
|
||||
const heapBytes = perf && perf.memory ? perf.memory.usedJSHeapSize : 0;
|
||||
let heapMB = heapBytes > 0 ? heapBytes / 1024 / 1024 : -1;
|
||||
if (heapMB > 0 && this.heapBaseMB < 0) {
|
||||
this.heapBaseMB = heapMB;
|
||||
this.heapPeakMB = heapMB;
|
||||
this.heapTrendBaseMB = heapMB;
|
||||
this.heapTrendTimer = 0;
|
||||
}
|
||||
if (heapMB > this.heapPeakMB) {
|
||||
this.heapPeakMB = heapMB;
|
||||
}
|
||||
this.heapTrendTimer += 0.5;
|
||||
if (heapMB > 0 && this.heapTrendBaseMB > 0 && this.heapTrendTimer >= 10) {
|
||||
const deltaMB = heapMB - this.heapTrendBaseMB;
|
||||
this.heapTrendPerMinMB = (deltaMB / this.heapTrendTimer) * 60;
|
||||
this.heapTrendBaseMB = heapMB;
|
||||
this.heapTrendTimer = 0;
|
||||
}
|
||||
const heapText = heapMB > 0 ? heapMB.toFixed(1) : "N/A";
|
||||
const heapDeltaText = this.heapBaseMB > 0 && heapMB > 0 ? (heapMB - this.heapBaseMB).toFixed(1) : "N/A";
|
||||
const heapPeakText = this.heapPeakMB > 0 ? this.heapPeakMB.toFixed(1) : "N/A";
|
||||
const avgDt = this.perfFrameCount > 0 ? this.perfDtAcc / this.perfFrameCount : 0;
|
||||
const fps = avgDt > 0 ? 1 / avgDt : 0;
|
||||
this.perfDtAcc = 0;
|
||||
this.perfFrameCount = 0;
|
||||
const text =
|
||||
`Heap:${heapText}MB Δ:${heapDeltaText} Peak:${heapPeakText}\n` +
|
||||
`Trend:${this.heapTrendPerMinMB.toFixed(2)}MB/min\n` +
|
||||
`Perf dt:${(avgDt * 1000).toFixed(1)}ms fps:${fps.toFixed(1)}\n` +
|
||||
`Ent H:${heroCount} S:${skillCount}\n` +
|
||||
`Pool M:${monPool.total}(${monPool.paths}) K:${skillPool.total}(${skillPool.paths})`;
|
||||
if (text === this.lastMemoryText) return;
|
||||
this.lastMemoryText = text;
|
||||
this.memoryLabel.string = text;
|
||||
}
|
||||
|
||||
|
||||
//奖励发放
|
||||
@@ -197,18 +109,7 @@ export class MissionComp extends CCComp {
|
||||
// 奖励发放
|
||||
}
|
||||
|
||||
|
||||
cal_gold_reward(data: any, type: MonType) {
|
||||
const cost = MonsterCost[data.uuid] || 1;
|
||||
const level = data.lv || 1;
|
||||
let add_gold = calculateMonsterGold(data.uuid, level, type);
|
||||
smc.updateGold(add_gold, false);
|
||||
}
|
||||
|
||||
do_hero_dead(event:any,data:any){
|
||||
|
||||
}
|
||||
do_ad(){
|
||||
do_ad(){
|
||||
if(this.ad_back()){
|
||||
oops.message.dispatchEvent(GameEvent.AD_BACK_TRUE)
|
||||
smc.vmdata.mission_data.refresh_count+=FightSet.MORE_RC
|
||||
@@ -216,11 +117,8 @@ do_ad(){
|
||||
oops.message.dispatchEvent(GameEvent.AD_BACK_FALSE)
|
||||
}
|
||||
}
|
||||
|
||||
ad_back(){
|
||||
|
||||
return true
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -298,7 +196,6 @@ do_ad(){
|
||||
this.FightTime=FightSet.FiIGHT_TIME
|
||||
this.rewards=[] // 改为数组,用于存储掉落物品列表
|
||||
this.revive_times = 1; // 每次任务开始重置复活次数
|
||||
this.spawnedSpecialIndices.clear(); // 重置特殊刷怪记录
|
||||
this.lastTimeStr = "";
|
||||
this.lastTimeSecond = -1;
|
||||
this.memoryRefreshTimer = 0;
|
||||
@@ -336,8 +233,82 @@ do_ad(){
|
||||
Skill.clearPools();
|
||||
}
|
||||
|
||||
/** 性能监控相关代码 */
|
||||
|
||||
private initMemoryPanel() {
|
||||
if (!this.showMemoryPanel || !this.time_node) return;
|
||||
let panel = this.time_node.getChildByName("mem_panel");
|
||||
if (!panel) {
|
||||
panel = new Node("mem_panel");
|
||||
panel.parent = this.time_node;
|
||||
panel.setPosition(0, -32, 0);
|
||||
}
|
||||
let label = panel.getComponent(Label);
|
||||
if (!label) {
|
||||
label = panel.addComponent(Label);
|
||||
}
|
||||
label.fontSize = 16;
|
||||
label.lineHeight = 20;
|
||||
this.memoryLabel = label;
|
||||
}
|
||||
|
||||
|
||||
private updateMemoryPanel(dt: number) {
|
||||
if (!this.showMemoryPanel || !this.memoryLabel) return;
|
||||
this.perfDtAcc += dt;
|
||||
this.perfFrameCount += 1;
|
||||
this.memoryRefreshTimer += dt;
|
||||
if (this.memoryRefreshTimer < 0.5) return;
|
||||
this.memoryRefreshTimer = 0;
|
||||
let heroCount = 0;
|
||||
ecs.query(this.heroViewMatcher).forEach(() => {
|
||||
heroCount++;
|
||||
});
|
||||
let skillCount = 0;
|
||||
ecs.query(this.skillViewMatcher).forEach(() => {
|
||||
skillCount++;
|
||||
});
|
||||
const monPool = Monster.getPoolStats();
|
||||
const skillPool = Skill.getPoolStats();
|
||||
const perf = (globalThis as any).performance;
|
||||
const heapBytes = perf && perf.memory ? perf.memory.usedJSHeapSize : 0;
|
||||
let heapMB = heapBytes > 0 ? heapBytes / 1024 / 1024 : -1;
|
||||
if (heapMB > 0 && this.heapBaseMB < 0) {
|
||||
this.heapBaseMB = heapMB;
|
||||
this.heapPeakMB = heapMB;
|
||||
this.heapTrendBaseMB = heapMB;
|
||||
this.heapTrendTimer = 0;
|
||||
}
|
||||
if (heapMB > this.heapPeakMB) {
|
||||
this.heapPeakMB = heapMB;
|
||||
}
|
||||
this.heapTrendTimer += 0.5;
|
||||
if (heapMB > 0 && this.heapTrendBaseMB > 0 && this.heapTrendTimer >= 10) {
|
||||
const deltaMB = heapMB - this.heapTrendBaseMB;
|
||||
this.heapTrendPerMinMB = (deltaMB / this.heapTrendTimer) * 60;
|
||||
this.heapTrendBaseMB = heapMB;
|
||||
this.heapTrendTimer = 0;
|
||||
}
|
||||
const heapText = heapMB > 0 ? heapMB.toFixed(1) : "N/A";
|
||||
const heapDeltaText = this.heapBaseMB > 0 && heapMB > 0 ? (heapMB - this.heapBaseMB).toFixed(1) : "N/A";
|
||||
const heapPeakText = this.heapPeakMB > 0 ? this.heapPeakMB.toFixed(1) : "N/A";
|
||||
const avgDt = this.perfFrameCount > 0 ? this.perfDtAcc / this.perfFrameCount : 0;
|
||||
const fps = avgDt > 0 ? 1 / avgDt : 0;
|
||||
this.perfDtAcc = 0;
|
||||
this.perfFrameCount = 0;
|
||||
const text =
|
||||
`Heap:${heapText}MB Δ:${heapDeltaText} Peak:${heapPeakText}\n` +
|
||||
`Trend:${this.heapTrendPerMinMB.toFixed(2)}MB/min\n` +
|
||||
`Perf dt:${(avgDt * 1000).toFixed(1)}ms fps:${fps.toFixed(1)}\n` +
|
||||
`Ent H:${heroCount} S:${skillCount}\n` +
|
||||
`Pool M:${monPool.total}(${monPool.paths}) K:${skillPool.total}(${skillPool.paths})`;
|
||||
if (text === this.lastMemoryText) return;
|
||||
this.lastMemoryText = text;
|
||||
this.memoryLabel.string = text;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** 视图层逻辑代码分离演示 */
|
||||
|
||||
/** 视图对象通过 ecs.Entity.remove(ModuleViewComp) 删除组件是触发组件处理自定义释放逻辑 */
|
||||
reset() {
|
||||
|
||||
@@ -7,11 +7,8 @@ import { MonStart } from "../common/config/heroSet";
|
||||
import { smc } from "../common/SingletonModuleComp";
|
||||
import { GameEvent } from "../common/config/GameEvent";
|
||||
// 导入新的肉鸽配置
|
||||
import { getCurrentWave, MonType, WaveConfig } from "./RogueConfig";
|
||||
import { BuffConf } from "../common/config/SkillSet";
|
||||
import { IndexSet, FacSet, BoxSet } from "../common/config/GameSet";
|
||||
import { HeroAttrsComp } from "../hero/HeroAttrsComp";
|
||||
import { Attrs } from "../common/config/HeroAttrs";
|
||||
import {BoxSet } from "../common/config/GameSet";
|
||||
const { ccclass, property } = _decorator;
|
||||
|
||||
/** 视图层对象 */
|
||||
@@ -24,26 +21,18 @@ export class MissionMonCompComp extends CCComp {
|
||||
// 刷怪队列 (主要用于特殊事件插队)
|
||||
private MonQueue: Array<{
|
||||
uuid: number,
|
||||
position: number,
|
||||
type: MonType,
|
||||
level: number,
|
||||
buffs: BuffConf[]
|
||||
}> = [];
|
||||
|
||||
private spawnCount: number = 0; // 召唤计数器
|
||||
|
||||
/** 全局生成顺序计数器,用于层级管理 */
|
||||
private globalSpawnOrder: number = 0;
|
||||
|
||||
/** 游戏进行时间(秒) */
|
||||
private gameTime: number = 0;
|
||||
|
||||
/** 波次刷怪计时器 */
|
||||
private waveTimer: number = 0;
|
||||
|
||||
/** 队列处理计时器 */
|
||||
private queueTimer: number = 0;
|
||||
|
||||
onLoad(){
|
||||
this.on(GameEvent.FightReady,this.fight_ready,this)
|
||||
this.on(GameEvent.NewWave,this.fight_ready,this)
|
||||
@@ -59,16 +48,11 @@ export class MissionMonCompComp extends CCComp {
|
||||
private onSpawnSpecialMonster(event: string, args: any) {
|
||||
if (!args) return;
|
||||
mLogger.log(this.debugMode, 'MissionMonComp', `[MissionMonComp] 收到特殊刷怪指令:`, args);
|
||||
|
||||
// 插入队列
|
||||
this.MonQueue.push({
|
||||
uuid: args.uuid,
|
||||
position: args.position !== undefined ? args.position : 2, // 默认中间
|
||||
type: args.type,
|
||||
level: args.level,
|
||||
buffs: args.buffs || []
|
||||
});
|
||||
|
||||
// 立即触发一次队列检查 (可选,让 update 尽快处理)
|
||||
this.queueTimer = 1.0;
|
||||
}
|
||||
@@ -98,112 +82,28 @@ export class MissionMonCompComp extends CCComp {
|
||||
// 累加游戏时间
|
||||
this.gameTime += dt;
|
||||
|
||||
// 获取当前波次配置
|
||||
const currentWave = getCurrentWave(this.gameTime);
|
||||
|
||||
// 1. 优先处理特殊怪队列
|
||||
if (this.MonQueue.length > 0) {
|
||||
this.queueTimer += dt;
|
||||
// 队列出怪速度快于普通波次 (0.5秒一只)
|
||||
if (this.queueTimer >= 0.5) {
|
||||
this.spawnNextFromQueue();
|
||||
this.queueTimer = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// 2. 处理波次自然刷怪
|
||||
this.waveTimer += dt;
|
||||
if (this.waveTimer >= currentWave.spawnInterval) {
|
||||
this.waveTimer = 0;
|
||||
|
||||
// 检查同屏数量限制
|
||||
if (smc.vmdata.mission_data.mon_num < currentWave.maxActive) {
|
||||
this.spawnWaveMonster(currentWave);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 从当前波次配置生成并生成怪物
|
||||
*/
|
||||
private spawnWaveMonster(wave: WaveConfig) {
|
||||
if (!wave.weights || wave.weights.length === 0) return;
|
||||
|
||||
// 权重随机算法
|
||||
const totalWeight = wave.weights.reduce((sum, item) => sum + item.weight, 0);
|
||||
let random = Math.random() * totalWeight;
|
||||
let selectedUuid = wave.weights[0].uuid;
|
||||
let selectedType = wave.weights[0].type || MonType.NORMAL;
|
||||
|
||||
for (const item of wave.weights) {
|
||||
random -= item.weight;
|
||||
if (random <= 0) {
|
||||
selectedUuid = item.uuid;
|
||||
selectedType = item.type || MonType.NORMAL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// 随机位置 (0-4)
|
||||
const position = Math.floor(Math.random() * 5);
|
||||
|
||||
// 等级随时间增长 (每分钟+1级)
|
||||
const level = Math.floor(this.gameTime / 60) + 1;
|
||||
|
||||
this.addMonster(
|
||||
selectedUuid,
|
||||
position,
|
||||
selectedType,
|
||||
level,
|
||||
[],
|
||||
this.gameTime
|
||||
);
|
||||
|
||||
this.spawnCount++;
|
||||
}
|
||||
|
||||
/**
|
||||
* 从队列中生成下一个怪物
|
||||
*/
|
||||
private spawnNextFromQueue() {
|
||||
if (this.MonQueue.length === 0) return;
|
||||
|
||||
const monsterData = this.MonQueue.shift();
|
||||
if (monsterData) {
|
||||
this.addMonster(
|
||||
monsterData.uuid,
|
||||
monsterData.position,
|
||||
monsterData.type,
|
||||
monsterData.level,
|
||||
monsterData.buffs,
|
||||
this.gameTime
|
||||
);
|
||||
this.spawnCount++;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
private addMonster(
|
||||
uuid: number = 1001,
|
||||
i: number = 0,
|
||||
monType: number = 0,
|
||||
lv: number = 1,
|
||||
buffs: BuffConf[] = [],
|
||||
gameTime: number = 0
|
||||
) {
|
||||
let mon = ecs.getEntity<Monster>(Monster);
|
||||
let scale = -1;
|
||||
|
||||
const x = MonStart.START_X + Math.floor(i / 4) * MonStart.START_I;
|
||||
let y = BoxSet.GAME_LINE;
|
||||
let lane = 0;
|
||||
|
||||
|
||||
let pos: Vec3 = v3(x, y, 0);
|
||||
|
||||
// 递增全局生成顺序 - 溢出保护
|
||||
this.globalSpawnOrder = (this.globalSpawnOrder + 1) % 999;
|
||||
|
||||
// 生成怪物
|
||||
mon.load(pos, scale, uuid, lv, monType, buffs, false, lane, this.globalSpawnOrder, gameTime);
|
||||
mon.load(pos, scale, uuid, false);
|
||||
}
|
||||
|
||||
/** 视图对象通过 ecs.Entity.remove(ModuleViewComp) 删除组件是触发组件处理自定义释放逻辑 */
|
||||
|
||||
@@ -1,347 +1 @@
|
||||
/**
|
||||
* 肉鸽模式配置脚本 - 增强版 (Wave System)
|
||||
*
|
||||
* 功能说明:
|
||||
* - 采用 15 个小波次(每分钟 1 波)
|
||||
* - 整合进 3 个大的节奏阶段:构筑期、磨合期、极限期
|
||||
* - 废弃动态预算,使用确定性波次配置
|
||||
*
|
||||
* @author 游戏开发团队
|
||||
* @version 3.0 波次重构版
|
||||
* @date 2025-10-19
|
||||
*/
|
||||
|
||||
import { HeroInfo } from "../common/config/heroSet";
|
||||
import { mLogger } from "../common/Logger";
|
||||
|
||||
/**
|
||||
* 怪物类型枚举
|
||||
*/
|
||||
export enum MonType {
|
||||
NORMAL = 0, // 普通怪物
|
||||
ELITE = 1, // 精英怪物
|
||||
BOSS = 2 // Boss怪物
|
||||
}
|
||||
|
||||
/**
|
||||
* 怪物配置接口 (用于生成实例)
|
||||
*/
|
||||
export interface IMonsConfig {
|
||||
uuid: number; // 怪物ID
|
||||
type: MonType; // 怪物类型
|
||||
level: number; // 等级
|
||||
position?: number; // 位置(可选)
|
||||
buffs?: any[]; // buff列表(可选)
|
||||
}
|
||||
|
||||
/**
|
||||
* 怪物属性接口
|
||||
*/
|
||||
export interface MonAttrs {
|
||||
hp: number;
|
||||
ap: number;
|
||||
speed: number;
|
||||
exp?: number;
|
||||
gold?: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* 成长类型枚举
|
||||
*/
|
||||
enum GrowthType {
|
||||
EXPONENTIAL = 1.15, // 指数级 - HP
|
||||
LINEAR = 1.05, // 线性 - AP
|
||||
LOGARITHMIC = 0.3 // 对数级 - Speed
|
||||
}
|
||||
|
||||
/**
|
||||
* 刷怪权重接口
|
||||
*/
|
||||
export interface SpawnWeight {
|
||||
uuid: number;
|
||||
weight: number;
|
||||
type?: MonType; // 默认为 NORMAL
|
||||
}
|
||||
|
||||
/**
|
||||
* 波次配置接口
|
||||
*/
|
||||
export interface WaveConfig {
|
||||
waveId: number; // 波次ID (1-15)
|
||||
name: string; // 波次名称
|
||||
duration: number; // 持续时间 (秒),通常为60
|
||||
spawnInterval: number; // 刷怪间隔 (秒)
|
||||
maxActive: number; // 同屏最大怪物数
|
||||
weights: SpawnWeight[]; // 怪物权重池
|
||||
}
|
||||
|
||||
// 怪物ID映射 (方便阅读)
|
||||
const MON_IDS = {
|
||||
WARRIOR: 5201, // 战士
|
||||
ASSASSIN: 5301, // 斥候
|
||||
TANK: 5401, // 卫士
|
||||
ARCHER: 5501, // 射手
|
||||
BOMBER: 5601, // 自爆兵
|
||||
SUMMONER: 5602, // 召唤师
|
||||
HEALER: 5603, // 祭司
|
||||
TOTEM: 5604, // 图腾师
|
||||
BOSS: 5701 // 首领
|
||||
};
|
||||
|
||||
/**
|
||||
* 全局波次配置表 (15波)
|
||||
*/
|
||||
export const RogueWaves: WaveConfig[] = [
|
||||
// --- 第一阶段:构筑期 (0-5min) ---
|
||||
{
|
||||
waveId: 1, name: "热身", duration: 60, spawnInterval: 2.0, maxActive: 5,
|
||||
weights: [{ uuid: MON_IDS.WARRIOR, weight: 100 }]
|
||||
},
|
||||
{
|
||||
waveId: 2, name: "加速", duration: 60, spawnInterval: 1.8, maxActive: 6,
|
||||
weights: [
|
||||
{ uuid: MON_IDS.WARRIOR, weight: 80 },
|
||||
{ uuid: MON_IDS.ASSASSIN, weight: 20 }
|
||||
]
|
||||
},
|
||||
{
|
||||
waveId: 3, name: "堆叠", duration: 60, spawnInterval: 1.6, maxActive: 7,
|
||||
weights: [
|
||||
{ uuid: MON_IDS.WARRIOR, weight: 60 },
|
||||
{ uuid: MON_IDS.ASSASSIN, weight: 40 }
|
||||
]
|
||||
},
|
||||
{
|
||||
waveId: 4, name: "硬度测试", duration: 60, spawnInterval: 1.5, maxActive: 8,
|
||||
weights: [
|
||||
{ uuid: MON_IDS.WARRIOR, weight: 50 },
|
||||
{ uuid: MON_IDS.ASSASSIN, weight: 30 },
|
||||
{ uuid: MON_IDS.TANK, weight: 20 }
|
||||
]
|
||||
},
|
||||
{
|
||||
waveId: 5, name: "精英首秀", duration: 60, spawnInterval: 1.5, maxActive: 8,
|
||||
weights: [
|
||||
{ uuid: MON_IDS.WARRIOR, weight: 40 },
|
||||
{ uuid: MON_IDS.ASSASSIN, weight: 40 },
|
||||
{ uuid: MON_IDS.TANK, weight: 20 }
|
||||
// 注意:第5分钟会触发固定事件刷精英怪,这里只配普通怪
|
||||
]
|
||||
},
|
||||
|
||||
// --- 第二阶段:磨合期 (5-10min) ---
|
||||
{
|
||||
waveId: 6, name: "远程威胁", duration: 60, spawnInterval: 1.4, maxActive: 10,
|
||||
weights: [
|
||||
{ uuid: MON_IDS.TANK, weight: 30 },
|
||||
{ uuid: MON_IDS.ARCHER, weight: 40 },
|
||||
{ uuid: MON_IDS.WARRIOR, weight: 30 }
|
||||
]
|
||||
},
|
||||
{
|
||||
waveId: 7, name: "铁桶阵", duration: 60, spawnInterval: 1.3, maxActive: 10,
|
||||
weights: [
|
||||
{ uuid: MON_IDS.TANK, weight: 50 },
|
||||
{ uuid: MON_IDS.ARCHER, weight: 50 }
|
||||
]
|
||||
},
|
||||
{
|
||||
waveId: 8, name: "续航干扰", duration: 60, spawnInterval: 1.2, maxActive: 12,
|
||||
weights: [
|
||||
{ uuid: MON_IDS.WARRIOR, weight: 30 },
|
||||
{ uuid: MON_IDS.TANK, weight: 20 },
|
||||
{ uuid: MON_IDS.ARCHER, weight: 30 },
|
||||
{ uuid: MON_IDS.HEALER, weight: 20 }
|
||||
]
|
||||
},
|
||||
{
|
||||
waveId: 9, name: "走位测试", duration: 60, spawnInterval: 1.2, maxActive: 12,
|
||||
weights: [
|
||||
{ uuid: MON_IDS.WARRIOR, weight: 40 },
|
||||
{ uuid: MON_IDS.BOMBER, weight: 30 }, // 自爆兵
|
||||
{ uuid: MON_IDS.ARCHER, weight: 30 }
|
||||
]
|
||||
},
|
||||
{
|
||||
waveId: 10, name: "中场Boss", duration: 60, spawnInterval: 5.0, maxActive: 3,
|
||||
// Boss战期间,只刷少量护卫,Boss由事件触发
|
||||
weights: [
|
||||
{ uuid: MON_IDS.TANK, weight: 100 }
|
||||
]
|
||||
},
|
||||
|
||||
// --- 第三阶段:极限期 (10-15min) ---
|
||||
{
|
||||
waveId: 11, name: "混乱开端", duration: 60, spawnInterval: 1.0, maxActive: 15,
|
||||
weights: [
|
||||
{ uuid: MON_IDS.SUMMONER, weight: 20 },
|
||||
{ uuid: MON_IDS.TOTEM, weight: 20 },
|
||||
{ uuid: MON_IDS.WARRIOR, weight: 30 },
|
||||
{ uuid: MON_IDS.ARCHER, weight: 30 }
|
||||
]
|
||||
},
|
||||
{
|
||||
waveId: 12, name: "全家桶", duration: 60, spawnInterval: 0.9, maxActive: 18,
|
||||
weights: [
|
||||
{ uuid: MON_IDS.WARRIOR, weight: 15 },
|
||||
{ uuid: MON_IDS.ASSASSIN, weight: 15 },
|
||||
{ uuid: MON_IDS.TANK, weight: 15 },
|
||||
{ uuid: MON_IDS.ARCHER, weight: 15 },
|
||||
{ uuid: MON_IDS.BOMBER, weight: 15 },
|
||||
{ uuid: MON_IDS.HEALER, weight: 10 },
|
||||
{ uuid: MON_IDS.SUMMONER, weight: 15 }
|
||||
]
|
||||
},
|
||||
{
|
||||
waveId: 13, name: "精英小队", duration: 60, spawnInterval: 1.0, maxActive: 15,
|
||||
weights: [
|
||||
{ uuid: MON_IDS.TANK, weight: 40 },
|
||||
{ uuid: MON_IDS.ARCHER, weight: 40 },
|
||||
{ uuid: MON_IDS.WARRIOR, weight: 20, type: MonType.ELITE } // 尝试混入精英
|
||||
]
|
||||
},
|
||||
{
|
||||
waveId: 14, name: "绝地求生", duration: 60, spawnInterval: 0.6, maxActive: 20,
|
||||
weights: [
|
||||
{ uuid: MON_IDS.ASSASSIN, weight: 50 },
|
||||
{ uuid: MON_IDS.BOMBER, weight: 50 }
|
||||
]
|
||||
},
|
||||
{
|
||||
waveId: 15, name: "终局", duration: 60, spawnInterval: 3.0, maxActive: 5,
|
||||
// 最终Boss战,只刷少量精英护卫
|
||||
weights: [
|
||||
{ uuid: MON_IDS.TANK, weight: 100, type: MonType.ELITE }
|
||||
]
|
||||
}
|
||||
];
|
||||
|
||||
// 精英怪和Boss刷新时间配置 (时间单位: 秒)
|
||||
// 注意:这里的时间点应与波次结束/开始对应
|
||||
export const SpecialMonsterSchedule = [
|
||||
{ time: 4 * 60 + 50, uuid: MON_IDS.WARRIOR, type: MonType.ELITE, level: 5, desc: "5分钟前夕: 精英战士" },
|
||||
{ time: 9 * 60 + 55, uuid: MON_IDS.BOSS, type: MonType.BOSS, level: 15, desc: "10分钟: 兽人首领" },
|
||||
{ time: 14 * 60 + 55, uuid: MON_IDS.BOSS, type: MonType.BOSS, level: 30, desc: "15分钟: 最终Boss" }
|
||||
];
|
||||
|
||||
/**
|
||||
* 获取当前时间的波次配置
|
||||
* @param timeInSeconds 游戏时间 (秒)
|
||||
*/
|
||||
export function getCurrentWave(timeInSeconds: number): WaveConfig {
|
||||
const waveIndex = Math.min(Math.floor(timeInSeconds / 60), 14);
|
||||
return RogueWaves[waveIndex];
|
||||
}
|
||||
|
||||
/**
|
||||
* 怪物消耗点数配置 (用于经验/金币计算)
|
||||
*/
|
||||
export const MonsterCost: Record<number, number> = {
|
||||
5201: 1, // 兽人战士 (Warrior)
|
||||
5301: 3, // 兽人斥候 (Assassin)
|
||||
5401: 5, // 兽人卫士 (Tank)
|
||||
5501: 4, // 兽人射手 (Remote)
|
||||
5601: 10, // 兽人自爆兵 (Mechanic)
|
||||
5602: 8, // 兽人召唤师
|
||||
5603: 6, // 兽人祭司 (Healer)
|
||||
5604: 6, // 兽人图腾师
|
||||
5701: 50, // 兽人首领 (Elite/Boss)
|
||||
};
|
||||
|
||||
/**
|
||||
* 计算波次因子
|
||||
* @param stage 当前波次
|
||||
* @param timeInSeconds 游戏进行时间(秒)
|
||||
* @returns 波次因子 (0-1之间,15分钟时达到最大)
|
||||
*/
|
||||
function calculateWaveFactor(stage: number, timeInSeconds: number = 0): number {
|
||||
const MAX_GAME_TIME = 15 * 60; // 15分钟 = 900秒
|
||||
const effectiveTime = timeInSeconds || (stage * 60);
|
||||
const factor = Math.min(effectiveTime / MAX_GAME_TIME, 1.0);
|
||||
return factor;
|
||||
}
|
||||
|
||||
/**
|
||||
* 应用成长公式到基础属性
|
||||
*/
|
||||
function applyGrowthFormula(baseStat: number, waveFactor: number, growthType: GrowthType): number {
|
||||
// 基础倍率:15分钟成长约 21 倍 (1 + 1.0 * 20)
|
||||
const TIME_SCALING = 20;
|
||||
const growthMultiplier = Math.pow(1 + waveFactor * TIME_SCALING, growthType);
|
||||
return Math.floor(baseStat * growthMultiplier);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取怪物动态成长属性
|
||||
* @param stage 当前波次 (这里复用为等级或忽略)
|
||||
* @param uuid 怪物ID
|
||||
* @param monType 怪物类型
|
||||
* @param timeInSeconds 游戏进行时间(秒)
|
||||
* @returns 怪物属性
|
||||
*/
|
||||
export function getMonAttr(stage: number, uuid: number, monType: MonType = MonType.NORMAL, timeInSeconds: number = 0): MonAttrs {
|
||||
const baseMonster = HeroInfo[uuid];
|
||||
if (!baseMonster) {
|
||||
mLogger.warn(true, 'RogueConfig', `[RogueConfig] 未找到怪物ID: ${uuid}`);
|
||||
return { hp: 100, ap: 10, speed: 100 };
|
||||
}
|
||||
|
||||
// 计算波次因子
|
||||
const waveFactor = calculateWaveFactor(0, timeInSeconds);
|
||||
|
||||
// 动态质量系数:初始 1.5倍 -> 15分钟 6.0倍
|
||||
// 大幅降低初始强度(原固定5.0),随时间线性增强
|
||||
const qualityRatio = 1.5 + (4.5 * waveFactor);
|
||||
|
||||
// 根据怪物类型应用额外的倍率
|
||||
let typeMultiplier = 1.0;
|
||||
if (monType === MonType.ELITE) {
|
||||
typeMultiplier = 2.0; // 精英怪2倍属性
|
||||
} else if (monType === MonType.BOSS) {
|
||||
typeMultiplier = 5.0; // Boss 5倍属性
|
||||
}
|
||||
|
||||
// 应用不同的成长类型 (应用质量系数)
|
||||
const hp = applyGrowthFormula(baseMonster.hp, waveFactor, GrowthType.EXPONENTIAL) * typeMultiplier * qualityRatio;
|
||||
const ap = applyGrowthFormula(baseMonster.ap, waveFactor, GrowthType.LINEAR) * typeMultiplier * qualityRatio;
|
||||
const speed = applyGrowthFormula(baseMonster.speed, waveFactor, GrowthType.LOGARITHMIC);
|
||||
|
||||
return {
|
||||
hp: Math.floor(hp),
|
||||
ap: Math.floor(ap),
|
||||
speed: Math.floor(speed)
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 无限等级经验配置
|
||||
*/
|
||||
export function getLevelExp(level: number): number {
|
||||
const baseExp = 100;
|
||||
const growthFactor = 1.2;
|
||||
return Math.floor(baseExp * Math.pow(growthFactor, level - 1));
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算怪物掉落金币
|
||||
*/
|
||||
export function calculateMonsterGold(uuid: number, level: number, type: MonType): number {
|
||||
const cost = MonsterCost[uuid] || 1;
|
||||
let danger_ratio = 1 + cost * 0.1;
|
||||
|
||||
let type_ratio = 1;
|
||||
if(type == MonType.BOSS) type_ratio = 10;
|
||||
else if(type == MonType.ELITE) type_ratio = 3;
|
||||
|
||||
const baseGold = 10;
|
||||
let gold = Math.floor((baseGold * type_ratio * danger_ratio + level) * 8);
|
||||
return gold;
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算怪物经验值
|
||||
*/
|
||||
export function calculateMonsterExp(uuid: number, level: number): number {
|
||||
const cost = MonsterCost[uuid] || 1;
|
||||
return Math.max(1, Math.floor(cost * 1.0 * Math.pow(1.15, level - 1) * 8));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user