feat(英雄系统): 实现英雄升级和经验系统
- 在 HeroViewComp 中扩展怪物死亡事件数据,包含等级和类型信息 - 在 SingletonModuleComp 中实现完整的经验计算和升级逻辑 - 在 MissionComp 中添加经验获取和升级事件处理 - 在 RogueConfig 中添加经验计算公式和怪物经验配置 - 添加等级同步机制防止ECS数据覆盖
This commit is contained in:
@@ -9,6 +9,7 @@ import * as exp from "constants";
|
||||
import { HeroAttrsComp } from "../hero/HeroAttrsComp";
|
||||
import { Attrs } from "./config/HeroAttrs";
|
||||
import { time } from "console";
|
||||
import { getLevelExp } from "../map/RogueConfig";
|
||||
/**
|
||||
* 用远程数据覆盖本地数据(统一方法)
|
||||
* @param remoteData 远程数据(云端或本地调试)
|
||||
@@ -89,6 +90,40 @@ export class SingletonModuleComp extends ecs.Comp {
|
||||
},
|
||||
gold: 200, // 金币数据(MVVM绑定字段)
|
||||
};
|
||||
|
||||
/**
|
||||
* 更新英雄经验
|
||||
* @param exp 获得的经验值
|
||||
*/
|
||||
updateHeroExp(exp: number) {
|
||||
if (!this.vmdata.hero) return;
|
||||
|
||||
this.vmdata.hero.exp += exp;
|
||||
// console.log('[smc] 英雄升级 经验:' + this.vmdata.hero.exp + ' 等级:' + this.vmdata.hero.lv + ' 上限:' + this.vmdata.hero.exp_max);
|
||||
// 确保 exp_max 初始化
|
||||
if (this.vmdata.hero.exp_max <= 0) {
|
||||
this.vmdata.hero.exp_max = getLevelExp(this.vmdata.hero.lv || 1);
|
||||
}
|
||||
|
||||
while (this.vmdata.hero.exp >= this.vmdata.hero.exp_max) {
|
||||
this.vmdata.hero.exp -= this.vmdata.hero.exp_max;
|
||||
this.vmdata.hero.lv++;
|
||||
|
||||
// 更新下一级所需经验
|
||||
this.vmdata.hero.exp_max = getLevelExp(this.vmdata.hero.lv);
|
||||
|
||||
// 触发升级事件
|
||||
oops.message.dispatchEvent(GameEvent.CanUpdateLv, { lv: this.vmdata.hero.lv });
|
||||
}
|
||||
|
||||
// 更新进度条显示 (0-1)
|
||||
if (this.vmdata.hero.exp_max > 0) {
|
||||
this.vmdata.hero.exp_pre = Math.floor(this.vmdata.hero.exp / this.vmdata.hero.exp_max * 100);
|
||||
} else {
|
||||
this.vmdata.hero.exp_pre = 0;
|
||||
}
|
||||
}
|
||||
|
||||
vmAdd() {
|
||||
VM.add(this.vmdata, "data");
|
||||
}
|
||||
@@ -225,7 +260,16 @@ export class SingletonModuleComp extends ecs.Comp {
|
||||
// 基础信息
|
||||
h.name = heroAttrs.hero_name;
|
||||
h.type = heroAttrs.type;
|
||||
h.lv = heroAttrs.lv;
|
||||
|
||||
// 防止 ECS 旧数据覆盖 VM 新数据 (如果 VM 里的等级更高,说明刚升级还没同步到 ECS)
|
||||
if (heroAttrs.lv > h.lv) {
|
||||
h.lv = heroAttrs.lv;
|
||||
} else if (h.lv > heroAttrs.lv) {
|
||||
// 此时应该反向同步?或者等待 CanUpdateLv 事件处理
|
||||
// 这里暂时保持 VM 的高等级,不被 ECS 覆盖
|
||||
} else {
|
||||
h.lv = heroAttrs.lv;
|
||||
}
|
||||
|
||||
// 动态属性
|
||||
h.hp = Math.floor(heroAttrs.hp);
|
||||
@@ -241,10 +285,6 @@ export class SingletonModuleComp extends ecs.Comp {
|
||||
h.crt = Math.floor(heroAttrs.Attrs[Attrs.CRITICAL] || 0);
|
||||
h.as = Math.floor(heroAttrs.Attrs[Attrs.AS] || 0);
|
||||
}
|
||||
updateHeroExp(exp:number){
|
||||
this.vmdata.hero.exp += exp;
|
||||
this.vmdata.hero.exp_pre =Math.floor(this.vmdata.hero.exp/this.vmdata.hero.exp_max)
|
||||
}
|
||||
error(){
|
||||
oops.gui.toast("数据处理异常,请重试或重新登录")
|
||||
}
|
||||
|
||||
@@ -404,7 +404,10 @@ export class HeroViewComp extends CCComp {
|
||||
// 根据阵营触发不同事件
|
||||
if(this.model.fac === FacSet.MON){
|
||||
oops.message.dispatchEvent(GameEvent.MonDead, {
|
||||
hero_uuid: this.model.hero_uuid,
|
||||
uuid: this.model.hero_uuid,
|
||||
lv: this.model.lv,
|
||||
is_boss: this.model.is_boss,
|
||||
is_elite: this.model.is_big_boss, // 暂时映射 is_big_boss 为 elite,或者由 MissionComp 二次判断
|
||||
position: this.node.position
|
||||
});
|
||||
}
|
||||
|
||||
@@ -3,11 +3,13 @@ import { ecs } from "../../../../extensions/oops-plugin-framework/assets/libs/ec
|
||||
import { CCComp } from "../../../../extensions/oops-plugin-framework/assets/module/common/CCComp";
|
||||
import { smc } from "../common/SingletonModuleComp";
|
||||
import { oops } from "../../../../extensions/oops-plugin-framework/assets/core/Oops";
|
||||
import { FightSet} from "../common/config/GameSet";
|
||||
import { HeroAttrsComp } from "../hero/HeroAttrsComp";
|
||||
import { getLevelExp, getMonsterExp, MonsterCost, MonType } from "./RogueConfig";
|
||||
import { GameEvent } from "../common/config/GameEvent";
|
||||
import { HeroViewComp } from "../hero/HeroViewComp";
|
||||
import { UIID } from "../common/config/GameUIConfig";
|
||||
import { SkillView } from "../skill/SkillView";
|
||||
import { FightSet } from "../common/config/GameSet";
|
||||
const { ccclass, property } = _decorator;
|
||||
|
||||
|
||||
@@ -33,7 +35,7 @@ export class MissionComp extends CCComp {
|
||||
this.on(GameEvent.FightEnd,this.fight_end,this)
|
||||
this.on(GameEvent.MissionEnd,this.mission_end,this)
|
||||
this.on(GameEvent.DO_AD_BACK,this.do_ad,this)
|
||||
// this.on(GameEvent.CanUpdateLv,this.show_uplv_button,this)
|
||||
this.on(GameEvent.CanUpdateLv,this.onLevelUp,this)
|
||||
}
|
||||
protected update(dt: number): void {
|
||||
if(!smc.mission.play||smc.mission.pause){
|
||||
@@ -45,6 +47,28 @@ export class MissionComp extends CCComp {
|
||||
}
|
||||
}
|
||||
|
||||
// 升级奖励触发
|
||||
onLevelUp(event: string, args: any) {
|
||||
console.log(`[MissionComp] 英雄升级到 ${args.lv} 级!`);
|
||||
|
||||
// 同步等级到 ECS 组件,防止被 updateHeroInfo 覆盖回旧值
|
||||
ecs.query(ecs.allOf(HeroAttrsComp)).forEach(e => {
|
||||
const attrs = e.get(HeroAttrsComp);
|
||||
if (attrs && attrs.is_master) {
|
||||
attrs.lv = args.lv;
|
||||
// 这里可以扩展:更新英雄属性,如 HP 上限等
|
||||
}
|
||||
});
|
||||
|
||||
// 触发奖励选择界面 (暂时留空)
|
||||
this.showLevelUpReward();
|
||||
}
|
||||
|
||||
showLevelUpReward() {
|
||||
// TODO: 显示三选一技能/属性奖励界面
|
||||
console.log("[MissionComp] 显示升级奖励界面 (TODO)");
|
||||
}
|
||||
|
||||
//奖励发放
|
||||
do_reward(){
|
||||
// 奖励发放
|
||||
@@ -56,7 +80,31 @@ export class MissionComp extends CCComp {
|
||||
do_mon_dead(event:any,data:any){
|
||||
// console.log("[MissionComp] do_mon_dead",event,data)
|
||||
smc.vmdata.mission_data.mon_num--
|
||||
|
||||
|
||||
// 计算并增加经验
|
||||
// data 应该是怪物组件或包含怪物信息的对象
|
||||
if (data && data.uuid) {
|
||||
// 默认值处理
|
||||
const level = data.lv || 1;
|
||||
|
||||
// 类型推断
|
||||
let type = MonType.NORMAL;
|
||||
if (data.is_boss) {
|
||||
type = MonType.BOSS;
|
||||
} else if (data.is_elite) {
|
||||
type = MonType.ELITE;
|
||||
} else {
|
||||
// 兜底策略:根据Cost判断是否为精英怪
|
||||
const cost = MonsterCost[data.uuid] || 1;
|
||||
if (cost >= 10) {
|
||||
type = MonType.ELITE;
|
||||
}
|
||||
}
|
||||
|
||||
// 获取怪物经验
|
||||
const exp = getMonsterExp(data.uuid, level, type);
|
||||
smc.updateHeroExp(exp);
|
||||
}
|
||||
}
|
||||
|
||||
do_hero_dead(event:any,data:any){
|
||||
|
||||
@@ -65,182 +65,6 @@ enum GrowthType {
|
||||
LOGARITHMIC = 0.5 // 对数级 - Speed
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算波次因子
|
||||
* @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 * 30); // 如果没有时间数据,用波次估算(每波30秒)
|
||||
const factor = Math.min(effectiveTime / MAX_GAME_TIME, 1.0);
|
||||
return factor;
|
||||
}
|
||||
|
||||
/**
|
||||
* 应用成长公式到基础属性
|
||||
* @param baseStat 基础属性值
|
||||
* @param waveFactor 波次因子 (0-1)
|
||||
* @param growthType 成长类型
|
||||
* @returns 成长后的属性值
|
||||
*/
|
||||
function applyGrowthFormula(baseStat: number, waveFactor: number, growthType: GrowthType): number {
|
||||
// 公式: Current_Stat = Base_Stat * (1 + waveFactor * 0.15) ^ Growth_Type
|
||||
const growthMultiplier = Math.pow(1 + waveFactor * 0.15, 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) {
|
||||
console.warn(`[RogueConfig] 未找到怪物ID: ${uuid}`);
|
||||
return { hp: 100, mp: 100, ap: 10, def: 0, speed: 100 };
|
||||
}
|
||||
|
||||
// 计算波次因子
|
||||
const waveFactor = calculateWaveFactor(stage, timeInSeconds);
|
||||
|
||||
// 根据怪物类型应用额外的倍率
|
||||
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;
|
||||
const ap = applyGrowthFormula(baseMonster.ap, waveFactor, GrowthType.LINEAR) * typeMultiplier;
|
||||
const speed = applyGrowthFormula(baseMonster.speed, waveFactor, GrowthType.LOGARITHMIC);
|
||||
|
||||
// MP和DEF使用线性成长
|
||||
const mp = applyGrowthFormula(baseMonster.mp, waveFactor, GrowthType.LINEAR);
|
||||
const def = applyGrowthFormula(baseMonster.def, waveFactor, GrowthType.LINEAR) * typeMultiplier;
|
||||
|
||||
return {
|
||||
hp: Math.floor(hp),
|
||||
mp: Math.floor(mp),
|
||||
ap: Math.floor(ap),
|
||||
def: Math.floor(def),
|
||||
speed: Math.floor(speed)
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据波次生成怪物配置
|
||||
* @param stage 当前波次
|
||||
* @returns IMonsConfig数组
|
||||
*/
|
||||
export function getStageMonConfigs(stage: number): IMonsConfig[] {
|
||||
const monsterConfigs: IMonsConfig[] = [];
|
||||
|
||||
// 基础怪物列表(从heroset.ts中获取)
|
||||
const normalMons = [5201, 5301, 5401, 5501, 5601, 5602, 5603, 5604];
|
||||
const eliteMons = [5701];
|
||||
|
||||
// 根据波次生成怪物配置
|
||||
// 波次越高,怪物数量越多,精英怪物出现概率越高
|
||||
const baseCount = 5 + Math.floor(stage / 2); // 基础数量每2波增加1
|
||||
const eliteChance = Math.min(stage * 0.05, 0.3); // 精英怪概率最高30%
|
||||
const bossWave = stage % 10 === 0; // 每10波出Boss
|
||||
|
||||
if (bossWave && stage > 0) {
|
||||
// Boss波
|
||||
monsterConfigs.push({
|
||||
uuid: 5701,
|
||||
type: MonType.BOSS,
|
||||
level: stage
|
||||
});
|
||||
} else {
|
||||
// 普通波
|
||||
for (let i = 0; i < baseCount; i++) {
|
||||
// 随机决定是否生成精英怪
|
||||
const isElite = Math.random() < eliteChance;
|
||||
const monList = isElite ? eliteMons : normalMons;
|
||||
const randomUuid = monList[Math.floor(Math.random() * monList.length)];
|
||||
|
||||
monsterConfigs.push({
|
||||
uuid: randomUuid,
|
||||
type: isElite ? MonType.ELITE : MonType.NORMAL,
|
||||
level: stage,
|
||||
position: i % 5
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return monsterConfigs;
|
||||
}
|
||||
|
||||
// ==========================================
|
||||
// 新增:基于威胁点数(Threat Budget)的刷怪系统
|
||||
// ==========================================
|
||||
|
||||
// 怪物消耗点数配置
|
||||
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)
|
||||
};
|
||||
|
||||
// 刷怪权重接口
|
||||
interface SpawnWeight {
|
||||
uuid: number;
|
||||
weight: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据游戏时间获取刷怪权重
|
||||
* @param timeInSeconds 游戏时间(秒)
|
||||
*/
|
||||
function getSpawnWeights(timeInSeconds: number): SpawnWeight[] {
|
||||
const minutes = timeInSeconds / 60;
|
||||
|
||||
if (minutes < 2) {
|
||||
// 0-2min: 匀速群落 - 100% 战士
|
||||
return [{ uuid: 5201, weight: 100 }];
|
||||
} else if (minutes < 5) {
|
||||
// 2-5min: 快速干扰 - 70% 战士, 30% 刺客
|
||||
return [
|
||||
{ uuid: 5201, weight: 70 },
|
||||
{ uuid: 5301, weight: 30 }
|
||||
];
|
||||
} else if (minutes < 10) {
|
||||
// 5-10min: 阵地博弈 - 50% 战士, 40% 刺客, 10% 攻城/治疗
|
||||
return [
|
||||
{ uuid: 5201, weight: 50 },
|
||||
{ uuid: 5301, weight: 40 },
|
||||
{ uuid: 5401, weight: 5 }, // 攻城
|
||||
{ uuid: 5603, weight: 5 } // 治疗
|
||||
];
|
||||
} else if (minutes < 14) {
|
||||
// 10-14min: 极限生存 - 30% 战士, 50% 刺客, 20% 机制/精英
|
||||
return [
|
||||
{ uuid: 5201, weight: 30 },
|
||||
{ uuid: 5301, weight: 50 },
|
||||
{ uuid: 5601, weight: 10 }, // 机制怪
|
||||
{ uuid: 5701, weight: 10 } // 精英
|
||||
];
|
||||
} else {
|
||||
// 15min: 剧情杀/决战 - 100% Boss
|
||||
return [{ uuid: 5701, weight: 100 }];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 全局刷怪配置接口
|
||||
@@ -384,3 +208,220 @@ export function generateMonstersFromBudget(timeInSeconds: number, heroHpRatio: n
|
||||
|
||||
return monsters;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 计算波次因子
|
||||
* @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 * 30); // 如果没有时间数据,用波次估算(每波30秒)
|
||||
const factor = Math.min(effectiveTime / MAX_GAME_TIME, 1.0);
|
||||
return factor;
|
||||
}
|
||||
|
||||
/**
|
||||
* 应用成长公式到基础属性
|
||||
* @param baseStat 基础属性值
|
||||
* @param waveFactor 波次因子 (0-1)
|
||||
* @param growthType 成长类型
|
||||
* @returns 成长后的属性值
|
||||
*/
|
||||
function applyGrowthFormula(baseStat: number, waveFactor: number, growthType: GrowthType): number {
|
||||
// 公式: Current_Stat = Base_Stat * (1 + waveFactor * 0.15) ^ Growth_Type
|
||||
const growthMultiplier = Math.pow(1 + waveFactor * 0.15, 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) {
|
||||
console.warn(`[RogueConfig] 未找到怪物ID: ${uuid}`);
|
||||
return { hp: 100, mp: 100, ap: 10, def: 0, speed: 100 };
|
||||
}
|
||||
|
||||
// 计算波次因子
|
||||
const waveFactor = calculateWaveFactor(stage, timeInSeconds);
|
||||
|
||||
// 根据怪物类型应用额外的倍率
|
||||
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;
|
||||
const ap = applyGrowthFormula(baseMonster.ap, waveFactor, GrowthType.LINEAR) * typeMultiplier;
|
||||
const speed = applyGrowthFormula(baseMonster.speed, waveFactor, GrowthType.LOGARITHMIC);
|
||||
|
||||
// MP和DEF使用线性成长
|
||||
const mp = applyGrowthFormula(baseMonster.mp, waveFactor, GrowthType.LINEAR);
|
||||
const def = applyGrowthFormula(baseMonster.def, waveFactor, GrowthType.LINEAR) * typeMultiplier;
|
||||
|
||||
return {
|
||||
hp: Math.floor(hp),
|
||||
mp: Math.floor(mp),
|
||||
ap: Math.floor(ap),
|
||||
def: Math.floor(def),
|
||||
speed: Math.floor(speed)
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据波次生成怪物配置
|
||||
* @param stage 当前波次
|
||||
* @returns IMonsConfig数组
|
||||
*/
|
||||
export function getStageMonConfigs(stage: number): IMonsConfig[] {
|
||||
const monsterConfigs: IMonsConfig[] = [];
|
||||
|
||||
// 基础怪物列表(从heroset.ts中获取)
|
||||
const normalMons = [5201, 5301, 5401, 5501, 5601, 5602, 5603, 5604];
|
||||
const eliteMons = [5701];
|
||||
|
||||
// 根据波次生成怪物配置
|
||||
// 波次越高,怪物数量越多,精英怪物出现概率越高
|
||||
const baseCount = 5 + Math.floor(stage / 2); // 基础数量每2波增加1
|
||||
const eliteChance = Math.min(stage * 0.05, 0.3); // 精英怪概率最高30%
|
||||
const bossWave = stage % 10 === 0; // 每10波出Boss
|
||||
|
||||
if (bossWave && stage > 0) {
|
||||
// Boss波
|
||||
monsterConfigs.push({
|
||||
uuid: 5701,
|
||||
type: MonType.BOSS,
|
||||
level: stage
|
||||
});
|
||||
} else {
|
||||
// 普通波
|
||||
for (let i = 0; i < baseCount; i++) {
|
||||
// 随机决定是否生成精英怪
|
||||
const isElite = Math.random() < eliteChance;
|
||||
const monList = isElite ? eliteMons : normalMons;
|
||||
const randomUuid = monList[Math.floor(Math.random() * monList.length)];
|
||||
|
||||
monsterConfigs.push({
|
||||
uuid: randomUuid,
|
||||
type: isElite ? MonType.ELITE : MonType.NORMAL,
|
||||
level: stage,
|
||||
position: i % 5
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return monsterConfigs;
|
||||
}
|
||||
|
||||
/**
|
||||
* 无限等级经验配置
|
||||
* @param level 当前等级
|
||||
* @returns 升级所需经验值
|
||||
*/
|
||||
export function getLevelExp(level: number): number {
|
||||
// 基础经验
|
||||
const baseExp = 100;
|
||||
// 增长因子 (每级增加20%)
|
||||
const growthFactor = 1.2;
|
||||
|
||||
// 公式: Exp = Base * (Factor ^ (Level - 1))
|
||||
// 1级: 100
|
||||
// 2级: 120
|
||||
// 3级: 144
|
||||
// 10级: ~515
|
||||
// 20级: ~3194
|
||||
return Math.floor(baseExp * Math.pow(growthFactor, level - 1));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取怪物掉落经验
|
||||
* @param monsterUuid 怪物ID
|
||||
* @param monsterLevel 怪物等级
|
||||
* @param monsterType 怪物类型
|
||||
*/
|
||||
export function getMonsterExp(monsterUuid: number, monsterLevel: number, monsterType: MonType): number {
|
||||
// 基础掉落经验 (可以从 MonsterCost 推导,或者单独配置)
|
||||
const baseDrop = MonsterCost[monsterUuid] ? MonsterCost[monsterUuid] * 5 : 5;
|
||||
|
||||
// 类型加成
|
||||
let typeMultiplier = 1.0;
|
||||
if (monsterType === MonType.ELITE) typeMultiplier = 3.0;
|
||||
if (monsterType === MonType.BOSS) typeMultiplier = 10.0;
|
||||
|
||||
// 等级加成 (每级增加10%)
|
||||
const levelMultiplier = 1 + (monsterLevel - 1) * 0.1;
|
||||
|
||||
return Math.floor(baseDrop * typeMultiplier * levelMultiplier);
|
||||
}
|
||||
|
||||
// 怪物消耗点数配置
|
||||
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)
|
||||
};
|
||||
|
||||
// 刷怪权重接口
|
||||
interface SpawnWeight {
|
||||
uuid: number;
|
||||
weight: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据游戏时间获取刷怪权重
|
||||
* @param timeInSeconds 游戏时间(秒)
|
||||
*/
|
||||
function getSpawnWeights(timeInSeconds: number): SpawnWeight[] {
|
||||
const minutes = timeInSeconds / 60;
|
||||
|
||||
if (minutes < 2) {
|
||||
// 0-2min: 匀速群落 - 100% 战士
|
||||
return [{ uuid: 5201, weight: 100 }];
|
||||
} else if (minutes < 5) {
|
||||
// 2-5min: 快速干扰 - 70% 战士, 30% 刺客
|
||||
return [
|
||||
{ uuid: 5201, weight: 70 },
|
||||
{ uuid: 5301, weight: 30 }
|
||||
];
|
||||
} else if (minutes < 10) {
|
||||
// 5-10min: 阵地博弈 - 50% 战士, 40% 刺客, 10% 攻城/治疗
|
||||
return [
|
||||
{ uuid: 5201, weight: 50 },
|
||||
{ uuid: 5301, weight: 40 },
|
||||
{ uuid: 5401, weight: 5 }, // 攻城
|
||||
{ uuid: 5603, weight: 5 } // 治疗
|
||||
];
|
||||
} else if (minutes < 14) {
|
||||
// 10-14min: 极限生存 - 30% 战士, 50% 刺客, 20% 机制/精英
|
||||
return [
|
||||
{ uuid: 5201, weight: 30 },
|
||||
{ uuid: 5301, weight: 50 },
|
||||
{ uuid: 5601, weight: 10 }, // 机制怪
|
||||
{ uuid: 5701, weight: 10 } // 精英
|
||||
];
|
||||
} else {
|
||||
// 15min: 剧情杀/决战 - 100% Boss
|
||||
return [{ uuid: 5701, weight: 100 }];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user