feat(技能): 新增驻场技能系统并集成到游戏机制中
- 在英雄配置中增加驻场技能字段,支持八种全局加成类型 - 实现驻场技能数值计算,影响召唤/死亡/战斗开始结束技能触发次数 - 集成驻场技能到金币收益系统,提升每回合和卖出英雄的金币获取 - 为战斗结束治疗添加驻场技能加成,增强队伍恢复效果
This commit is contained in:
@@ -299,3 +299,33 @@ export const SkillSet: Record<number, SkillConfig> = {
|
|||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export enum FieldSkillType {
|
||||||
|
SummonCount = 1, // 召唤触发技能次数提升
|
||||||
|
DeadCount = 2, // 死亡触发技能次数提升
|
||||||
|
StartCount = 3, // 战斗开始触发技能次数提升
|
||||||
|
EndCount = 4, // 战斗结束触发技能次数提升
|
||||||
|
WaveGold = 5, // 每回合金币收益提升
|
||||||
|
SellGold = 6, // 卖出英雄金币提升
|
||||||
|
WaveHeal = 7, // 战斗结束生命回复量提升
|
||||||
|
HeroAtk = 8, // 英雄攻击力加成
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface FieldSkillConfig {
|
||||||
|
uuid: number;
|
||||||
|
name: string;
|
||||||
|
type: FieldSkillType;
|
||||||
|
value: number; // 提升的数值
|
||||||
|
info: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const FieldSkillSet: Record<number, FieldSkillConfig> = {
|
||||||
|
7001: { uuid: 7001, name: "召唤精通", type: FieldSkillType.SummonCount, value: 1, info: "场上所有友方召唤触发技能触发次数+1" },
|
||||||
|
7002: { uuid: 7002, name: "亡灵统御", type: FieldSkillType.DeadCount, value: 1, info: "场上所有友方死亡触发技能触发次数+1" },
|
||||||
|
7003: { uuid: 7003, name: "先发制人", type: FieldSkillType.StartCount, value: 1, info: "场上所有友方战斗开始触发技能触发次数+1" },
|
||||||
|
7004: { uuid: 7004, name: "余音绕梁", type: FieldSkillType.EndCount, value: 1, info: "场上所有友方战斗结束触发技能触发次数+1" },
|
||||||
|
7005: { uuid: 7005, name: "理财专家", type: FieldSkillType.WaveGold, value: 10, info: "每回合结束时金币收益提升10" },
|
||||||
|
7006: { uuid: 7006, name: "商业大亨", type: FieldSkillType.SellGold, value: 5, info: "卖出英雄时金币收益提升5" },
|
||||||
|
7007: { uuid: 7007, name: "神圣恢复", type: FieldSkillType.WaveHeal, value: 0.3, info: "战斗结束时全队恢复效果+30%" },
|
||||||
|
7008: { uuid: 7008, name: "战鼓激昂", type: FieldSkillType.HeroAtk, value: 0.2, info: "场上所有友方攻击力提升20%" },
|
||||||
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -67,6 +67,7 @@ export interface heroInfo {
|
|||||||
dead?:number[]; // 死亡后触发的技能uuid列表
|
dead?:number[]; // 死亡后触发的技能uuid列表
|
||||||
fstart?:number[]; // 战斗开始时释放的技能uuid列表
|
fstart?:number[]; // 战斗开始时释放的技能uuid列表
|
||||||
fend?:number[]; // 战斗结束时释放的技能uuid列表
|
fend?:number[]; // 战斗结束时释放的技能uuid列表
|
||||||
|
field?:number[]; // 驻场技能uuid列表,英雄在场时对全局生效
|
||||||
atking?:{s_uuid:number, t_num:number}[]; // 普通攻击后触发的技能配置,s_uuid: 技能id, t_num: 触发所需的普攻次数
|
atking?:{s_uuid:number, t_num:number}[]; // 普通攻击后触发的技能配置,s_uuid: 技能id, t_num: 触发所需的普攻次数
|
||||||
atked?:{s_uuid:number, t_num:number}[]; // 受击后触发的技能配置,s_uuid: 技能id, t_num: 触发所需的受击次数
|
atked?:{s_uuid:number, t_num:number}[]; // 受击后触发的技能配置,s_uuid: 技能id, t_num: 触发所需的受击次数
|
||||||
// dis: number; // 攻击距离(像素)
|
// dis: number; // 攻击距离(像素)
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import { GameEvent } from "../common/config/GameEvent";
|
|||||||
import { Attrs} from "../common/config/HeroAttrs";
|
import { Attrs} from "../common/config/HeroAttrs";
|
||||||
import { MoveComp } from "./MoveComp";
|
import { MoveComp } from "./MoveComp";
|
||||||
import { mLogger } from "../common/Logger";
|
import { mLogger } from "../common/Logger";
|
||||||
|
import { FieldSkillType } from "../common/config/SkillSet";
|
||||||
/** 英雄实体:负责英雄节点创建、属性初始化、入场动画与销毁流程 */
|
/** 英雄实体:负责英雄节点创建、属性初始化、入场动画与销毁流程 */
|
||||||
@ecs.register(`Hero`)
|
@ecs.register(`Hero`)
|
||||||
|
|
||||||
@@ -200,14 +201,19 @@ export class Hero extends ecs.Entity {
|
|||||||
|
|
||||||
// 落地后触发 call 技能
|
// 落地后触发 call 技能
|
||||||
if (model && model.call && model.call.length > 0) {
|
if (model && model.call && model.call.length > 0) {
|
||||||
model.call.forEach(uuid => {
|
let triggerCount = 1 + HeroAttrsComp.getFieldSkillTotalValue(FieldSkillType.SummonCount);
|
||||||
oops.message.dispatchEvent(GameEvent.TriggerSkill, {
|
triggerCount = Math.max(1, Math.floor(triggerCount));
|
||||||
s_uuid: uuid,
|
|
||||||
heroAttrs: model,
|
for (let i = 0; i < triggerCount; i++) {
|
||||||
heroView: view,
|
model.call.forEach(uuid => {
|
||||||
triggerType: 'call'
|
oops.message.dispatchEvent(GameEvent.TriggerSkill, {
|
||||||
|
s_uuid: uuid,
|
||||||
|
heroAttrs: model,
|
||||||
|
heroView: view,
|
||||||
|
triggerType: 'call'
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.start();
|
.start();
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import { smc } from "../common/SingletonModuleComp";
|
|||||||
import { HeroInfo } from "../common/config/heroSet";
|
import { HeroInfo } from "../common/config/heroSet";
|
||||||
import { oops } from "db://oops-framework/core/Oops";
|
import { oops } from "db://oops-framework/core/Oops";
|
||||||
import { GameEvent } from "../common/config/GameEvent";
|
import { GameEvent } from "../common/config/GameEvent";
|
||||||
|
import { FieldSkillType } from "../common/config/SkillSet";
|
||||||
|
|
||||||
import { mLogger } from "../common/Logger";
|
import { mLogger } from "../common/Logger";
|
||||||
|
|
||||||
@@ -276,14 +277,19 @@ export class HeroAtkSystem extends ecs.ComblockSystem implements ecs.ISystemUpd
|
|||||||
if (TAttrsComp.dead && TAttrsComp.dead.length > 0) {
|
if (TAttrsComp.dead && TAttrsComp.dead.length > 0) {
|
||||||
const view = entity.get(HeroViewComp);
|
const view = entity.get(HeroViewComp);
|
||||||
if (view) {
|
if (view) {
|
||||||
TAttrsComp.dead.forEach((uuid: number) => {
|
let triggerCount = 1 + HeroAttrsComp.getFieldSkillTotalValue(FieldSkillType.DeadCount);
|
||||||
oops.message.dispatchEvent(GameEvent.TriggerSkill, {
|
triggerCount = Math.max(1, Math.floor(triggerCount));
|
||||||
s_uuid: uuid,
|
|
||||||
heroAttrs: TAttrsComp,
|
for (let i = 0; i < triggerCount; i++) {
|
||||||
heroView: view,
|
TAttrsComp.dead.forEach((uuid: number) => {
|
||||||
triggerType: 'dead'
|
oops.message.dispatchEvent(GameEvent.TriggerSkill, {
|
||||||
|
s_uuid: uuid,
|
||||||
|
heroAttrs: TAttrsComp,
|
||||||
|
heroView: view,
|
||||||
|
triggerType: 'dead'
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
import { ecs } from "../../../../extensions/oops-plugin-framework/assets/libs/ecs/ECS";
|
import { ecs } from "../../../../extensions/oops-plugin-framework/assets/libs/ecs/ECS";
|
||||||
import { HeroDisVal, HSkillInfo, HType } from "../common/config/heroSet";
|
import { HeroDisVal, HeroInfo, HSkillInfo, HType } from "../common/config/heroSet";
|
||||||
import { mLogger } from "../common/Logger";
|
import { mLogger } from "../common/Logger";
|
||||||
import { Timer } from "db://oops-framework/core/common/timer/Timer";
|
import { Timer } from "db://oops-framework/core/common/timer/Timer";
|
||||||
import { FightSet } from "../common/config/GameSet";
|
import { FacSet, FightSet } from "../common/config/GameSet";
|
||||||
|
import { FieldSkillSet, FieldSkillType } from "../common/config/SkillSet";
|
||||||
@ecs.register('HeroAttrs')
|
@ecs.register('HeroAttrs')
|
||||||
export class HeroAttrsComp extends ecs.Comp {
|
export class HeroAttrsComp extends ecs.Comp {
|
||||||
public debugMode: boolean = false;
|
public debugMode: boolean = false;
|
||||||
@@ -279,8 +280,24 @@ export class HeroAttrsComp extends ecs.Comp {
|
|||||||
this.dirty_shield = false;
|
this.dirty_shield = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** 获取指定驻场技能类型的总加成值(只计算存活的英雄) */
|
||||||
|
public static getFieldSkillTotalValue(type: FieldSkillType): number {
|
||||||
|
let total = 0;
|
||||||
|
ecs.query(ecs.allOf(HeroAttrsComp)).forEach((entity: ecs.Entity) => {
|
||||||
|
const model = entity.get(HeroAttrsComp);
|
||||||
|
if (!model || model.is_dead || model.fac !== FacSet.HERO) return;
|
||||||
|
const heroConfig = HeroInfo[model.hero_uuid];
|
||||||
|
if (heroConfig && heroConfig.field) {
|
||||||
|
for (const skillUuid of heroConfig.field) {
|
||||||
|
const skillConfig = FieldSkillSet[skillUuid];
|
||||||
|
if (skillConfig && skillConfig.type === type) {
|
||||||
|
total += skillConfig.value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return total;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ecs.register('HeroBuffSystem')
|
@ecs.register('HeroBuffSystem')
|
||||||
|
|||||||
@@ -25,6 +25,8 @@ import { CCComp } from "../../../../extensions/oops-plugin-framework/assets/modu
|
|||||||
import { HeroInfo } from "../common/config/heroSet";
|
import { HeroInfo } from "../common/config/heroSet";
|
||||||
import { HeroAttrsComp } from "../hero/HeroAttrsComp";
|
import { HeroAttrsComp } from "../hero/HeroAttrsComp";
|
||||||
import { Hero } from "../hero/Hero";
|
import { Hero } from "../hero/Hero";
|
||||||
|
import { FieldSkillType } from "../common/config/SkillSet";
|
||||||
|
import { GameEvent } from "../common/config/GameEvent";
|
||||||
import { oops } from "db://oops-framework/core/Oops";
|
import { oops } from "db://oops-framework/core/Oops";
|
||||||
import { UIID } from "../common/config/GameUIConfig";
|
import { UIID } from "../common/config/GameUIConfig";
|
||||||
import { mLogger } from "../common/Logger";
|
import { mLogger } from "../common/Logger";
|
||||||
@@ -251,6 +253,13 @@ export class HInfoComp extends CCComp {
|
|||||||
removed
|
removed
|
||||||
});
|
});
|
||||||
if (!removed) return;
|
if (!removed) return;
|
||||||
|
|
||||||
|
// 卖出英雄金币收益
|
||||||
|
const baseSellGold = 1; // 基础卖出金币
|
||||||
|
const goldBoost = HeroAttrsComp.getFieldSkillTotalValue(FieldSkillType.SellGold);
|
||||||
|
const totalSellGold = baseSellGold + goldBoost;
|
||||||
|
oops.message.dispatchEvent(GameEvent.CoinAdd, { delta: totalSellGold });
|
||||||
|
|
||||||
oops.gui.remove(UIID.IBox);
|
oops.gui.remove(UIID.IBox);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -45,6 +45,7 @@ import { Skill } from "../skill/Skill";
|
|||||||
import { Tooltip } from "../skill/Tooltip";
|
import { Tooltip } from "../skill/Tooltip";
|
||||||
import { CardInitCoins } from "../common/config/CardSet";
|
import { CardInitCoins } from "../common/config/CardSet";
|
||||||
import { Timer } from "db://oops-framework/core/common/timer/Timer";
|
import { Timer } from "db://oops-framework/core/common/timer/Timer";
|
||||||
|
import { FieldSkillType } from "../common/config/SkillSet";
|
||||||
const { ccclass, property } = _decorator;
|
const { ccclass, property } = _decorator;
|
||||||
|
|
||||||
/** 任务(关卡)生命周期阶段 */
|
/** 任务(关卡)生命周期阶段 */
|
||||||
@@ -466,20 +467,30 @@ export class MissionComp extends CCComp {
|
|||||||
* @param isStart 是否为战斗开始
|
* @param isStart 是否为战斗开始
|
||||||
*/
|
*/
|
||||||
private triggerHeroBattleSkills(isStart: boolean) {
|
private triggerHeroBattleSkills(isStart: boolean) {
|
||||||
|
let triggerCount = 1;
|
||||||
|
if (isStart) {
|
||||||
|
triggerCount += HeroAttrsComp.getFieldSkillTotalValue(FieldSkillType.StartCount);
|
||||||
|
} else {
|
||||||
|
triggerCount += HeroAttrsComp.getFieldSkillTotalValue(FieldSkillType.EndCount);
|
||||||
|
}
|
||||||
|
triggerCount = Math.max(1, Math.floor(triggerCount));
|
||||||
|
|
||||||
ecs.query(this.heroAttrsMatcher).forEach(entity => {
|
ecs.query(this.heroAttrsMatcher).forEach(entity => {
|
||||||
const attrs = entity.get(HeroAttrsComp);
|
const attrs = entity.get(HeroAttrsComp);
|
||||||
const view = entity.get(HeroViewComp);
|
const view = entity.get(HeroViewComp);
|
||||||
if (!attrs || !view || attrs.is_dead || attrs.fac !== FacSet.HERO) return;
|
if (!attrs || !view || attrs.is_dead || attrs.fac !== FacSet.HERO) return;
|
||||||
const skillUuids = isStart ? attrs.fstart : attrs.fend;
|
const skillUuids = isStart ? attrs.fstart : attrs.fend;
|
||||||
if (skillUuids && skillUuids.length > 0) {
|
if (skillUuids && skillUuids.length > 0) {
|
||||||
skillUuids.forEach(uuid => {
|
for (let i = 0; i < triggerCount; i++) {
|
||||||
oops.message.dispatchEvent(GameEvent.TriggerSkill, {
|
skillUuids.forEach(uuid => {
|
||||||
s_uuid: uuid,
|
oops.message.dispatchEvent(GameEvent.TriggerSkill, {
|
||||||
heroAttrs: attrs,
|
s_uuid: uuid,
|
||||||
heroView: view,
|
heroAttrs: attrs,
|
||||||
triggerType: isStart ? 'fstart' : 'fend'
|
heroView: view,
|
||||||
|
triggerType: isStart ? 'fstart' : 'fend'
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -488,13 +499,16 @@ export class MissionComp extends CCComp {
|
|||||||
* 战斗结束阶段治疗所有英雄(包括墓地英雄),恢复70%最大生命值
|
* 战斗结束阶段治疗所有英雄(包括墓地英雄),恢复70%最大生命值
|
||||||
*/
|
*/
|
||||||
private healAllHeroes() {
|
private healAllHeroes() {
|
||||||
|
const healRateBoost = HeroAttrsComp.getFieldSkillTotalValue(FieldSkillType.WaveHeal);
|
||||||
|
const finalHealRate = Math.min(1, FightSet.WAVE_HEAL_RATE + healRateBoost);
|
||||||
|
|
||||||
ecs.query(this.heroAttrsMatcher).forEach(entity => {
|
ecs.query(this.heroAttrsMatcher).forEach(entity => {
|
||||||
const attrs = entity.get(HeroAttrsComp);
|
const attrs = entity.get(HeroAttrsComp);
|
||||||
const view = entity.get(HeroViewComp);
|
const view = entity.get(HeroViewComp);
|
||||||
if (!attrs || !view || attrs.fac !== FacSet.HERO) return;
|
if (!attrs || !view || attrs.fac !== FacSet.HERO) return;
|
||||||
|
|
||||||
// 计算恢复量:基于配置的百分比(如 70%)的最大生命值
|
// 计算恢复量:基于配置的百分比(如 70%)的最大生命值
|
||||||
const healAmount = Math.floor(attrs.hp_max * FightSet.WAVE_HEAL_RATE);
|
const healAmount = Math.floor(attrs.hp_max * finalHealRate);
|
||||||
|
|
||||||
// 应用恢复量,不超过最大生命值
|
// 应用恢复量,不超过最大生命值
|
||||||
attrs.hp = Math.min(attrs.hp_max, attrs.hp + healAmount);
|
attrs.hp = Math.min(attrs.hp_max, attrs.hp + healAmount);
|
||||||
@@ -649,7 +663,12 @@ export class MissionComp extends CCComp {
|
|||||||
const base = Math.max(0, Math.floor(this.prepareBaseCoinReward));
|
const base = Math.max(0, Math.floor(this.prepareBaseCoinReward));
|
||||||
const grow = Math.max(0, Math.floor(this.prepareCoinWaveGrow));
|
const grow = Math.max(0, Math.floor(this.prepareCoinWaveGrow));
|
||||||
const cap = Math.max(0, Math.floor(this.prepareCoinRewardCap));
|
const cap = Math.max(0, Math.floor(this.prepareCoinRewardCap));
|
||||||
const reward = Math.min(cap, base + (wave - 1) * grow);
|
let reward = Math.min(cap, base + (wave - 1) * grow);
|
||||||
|
|
||||||
|
// 增加驻场技能金币收益
|
||||||
|
const goldBoost = HeroAttrsComp.getFieldSkillTotalValue(FieldSkillType.WaveGold);
|
||||||
|
reward += goldBoost;
|
||||||
|
|
||||||
if (reward <= 0) {
|
if (reward <= 0) {
|
||||||
this.lastPrepareCoinWave = wave;
|
this.lastPrepareCoinWave = wave;
|
||||||
return;
|
return;
|
||||||
@@ -657,7 +676,8 @@ export class MissionComp extends CCComp {
|
|||||||
smc.vmdata.mission_data.coin = Math.max(0, Math.floor((smc.vmdata.mission_data.coin ?? 0) + reward));
|
smc.vmdata.mission_data.coin = Math.max(0, Math.floor((smc.vmdata.mission_data.coin ?? 0) + reward));
|
||||||
this.lastPrepareCoinWave = wave;
|
this.lastPrepareCoinWave = wave;
|
||||||
oops.message.dispatchEvent(GameEvent.CoinAdd, { delta: reward, syncOnly: true });
|
oops.message.dispatchEvent(GameEvent.CoinAdd, { delta: reward, syncOnly: true });
|
||||||
mLogger.log(this.debugMode, 'MissionComp', "prepare coin reward", { wave, reward, coin: smc.vmdata.mission_data.coin });
|
|
||||||
|
mLogger.log(this.debugMode, "MissionComp", "grantPrepareCoinByWave", { wave, reward, boost: goldBoost, coin: smc.vmdata.mission_data.coin });
|
||||||
}
|
}
|
||||||
|
|
||||||
// ======================== 怪物数量管理 ========================
|
// ======================== 怪物数量管理 ========================
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ import { HeroAttrsComp } from "../hero/HeroAttrsComp";
|
|||||||
import { FacSet, FightSet, BoxSet } from "../common/config/GameSet";
|
import { FacSet, FightSet, BoxSet } from "../common/config/GameSet";
|
||||||
import { oneCom } from "../skill/oncend";
|
import { oneCom } from "../skill/oncend";
|
||||||
import { HeroViewComp } from "../hero/HeroViewComp";
|
import { HeroViewComp } from "../hero/HeroViewComp";
|
||||||
|
import { FieldSkillSet, FieldSkillType } from "../common/config/SkillSet";
|
||||||
const { ccclass } = _decorator;
|
const { ccclass } = _decorator;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -252,6 +253,26 @@ export class MissionHeroCompComp extends CCComp {
|
|||||||
return heroes;
|
return heroes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** 获取指定驻场技能类型的总加成值(只计算存活的英雄) */
|
||||||
|
public getFieldSkillTotalValue(type: FieldSkillType): number {
|
||||||
|
let total = 0;
|
||||||
|
const heroes = this.getAllHeroes();
|
||||||
|
for (const hero of heroes) {
|
||||||
|
const model = hero.get(HeroAttrsComp);
|
||||||
|
if (!model || model.is_dead) continue;
|
||||||
|
const heroConfig = HeroInfo[model.hero_uuid];
|
||||||
|
if (heroConfig && heroConfig.field) {
|
||||||
|
for (const skillUuid of heroConfig.field) {
|
||||||
|
const skillConfig = FieldSkillSet[skillUuid];
|
||||||
|
if (skillConfig && skillConfig.type === type) {
|
||||||
|
total += skillConfig.value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return total;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 从存活英雄中挑选可参与本次合成的英雄组。
|
* 从存活英雄中挑选可参与本次合成的英雄组。
|
||||||
*
|
*
|
||||||
|
|||||||
Reference in New Issue
Block a user