14 Commits

Author SHA1 Message Date
b965c88961 feat(英雄属性): 添加HP/MP基础属性管理方法并移除health方法冗余参数
添加add_hp、add_mp和add_shield方法用于管理英雄基础属性
移除HeroViewComp.health方法中不再使用的is_num参数
恢复TalComp中HP和MP天赋效果的处理逻辑
2025-11-25 16:45:05 +08:00
b73d756106 refactor(hero): 移除怒气值相关属性和逻辑,修改hp显示逻辑
移除英雄属性组件中的怒气值(pow)属性及相关配置
删除英雄视图组件中怒气值显示和使用的逻辑
简化资源管理,移除不再使用的代码
2025-11-25 16:35:35 +08:00
3edc69deff refactor(skill): 移除溅射伤害设定,溅射以后有特定技能触发
清理不再使用的溅射伤害功能,包括移除SDataCom中的splash字段、Skill和SACastSystem中的相关参数,
以及删除TalSet中的溅射天赋配置
2025-11-25 15:24:38 +08:00
03a8a41980 feat(战斗系统): 添加伤害比例属性并应用到伤害计算
在SDataCom中添加dmg_ratio属性用于调整伤害比例
修改HeroAtkSystem中的伤害计算公式,将dmg_ratio纳入计算
2025-11-24 16:58:13 +08:00
91c18004eb feat(技能系统): 添加额外伤害和溅射伤害功能
在技能组件中新增ext_dmg和splash字段用于处理额外伤害和溅射伤害
修改技能创建和伤害计算逻辑以支持新功能
2025-11-24 16:58:04 +08:00
6df4abadd1 feat(战斗系统): 添加必杀技能类型并优化天赋触发逻辑
- 在TriType枚举中添加MAX类型用于必杀技能触发
- 重构SACastSystem中的技能处理逻辑,将普通攻击、技能和必杀技能分开处理
- 优化天赋触发条件判断,确保不同类型技能触发正确的天赋效果
- 调整技能动画播放和伤害计算逻辑,使风怒和双技能天赋能正确生效
2025-11-24 15:52:28 +08:00
8d2ec76b01 feat(战斗系统): 实现攻击和技能伤害加成天赋效果
添加ATK_DMG和SKILL_DMG天赋类型,支持在普通攻击和技能释放时应用额外伤害
修改SACastSystem以处理不同类型的伤害加成
重构TalEffet枚举并更新相关配置
2025-11-24 15:39:05 +08:00
4ed531e100 refactor(hero): 重命名天赋相关方法以区分计数型和数值型
将计数型天赋操作方法从addTalent/consumeTalent重命名为addCountTal/useCountTal
将数值型天赋操作方法从addTalBuff/clearTalBuff重命名为addValueTal/useValueTalByUuid
更新相关文档和调用代码以保持一致性
2025-11-24 10:27:38 +08:00
aefe3d6d06 refactor(战斗系统): 重构伤害计算逻辑并完善注释
重构 HeroAtkSystem 中的伤害计算方法,将基础伤害计算升级为详细的伤害计算流程
新增 applyPR 方法的详细注释,说明其计算公式和使用场景
优化代码结构,添加计算步骤的注释说明
2025-11-21 10:36:54 +08:00
2dc43b5b81 refactor(HeroAtkSystem): 重构伤害计算逻辑以提高可维护性
将原有的伤害计算逻辑拆分为更清晰的步骤,引入applyPR方法统一处理伤害加成和抗性计算
根据技能类型(DType)应用对应的元素伤害计算
使用防御和魔防的百分比减免公式替代原有的固定值减免
2025-11-21 10:28:14 +08:00
58fa6527ee feat(战斗系统): 扩展战斗属性配置和元素伤害类型
- 在GameSet.ts中添加物理和魔法防御常数
- 在SkillSet.ts中细化元素伤害类型并移除冗余字段
- 在HeroAttrs.ts中重构抗性和伤害加成属性,增加物理和魔法相关属性
2025-11-21 10:24:39 +08:00
df23e3787d feat(战斗系统): 完善伤害计算逻辑并添加元素伤害支持
修改 HeroAtkSystem 的 dmgCount 方法,增加目标属性参数并实现完整的伤害计算逻辑,包括物理/魔法伤害区分、防御减免和元素伤害计算。同时在 SkillSet 配置中新增 map 属性和元素伤害配置,支持冰/火/风三种元素伤害类型。
2025-11-21 10:23:35 +08:00
8a0cfb78dd refactor(combat): 重构战斗系统伤害计算逻辑并完善文档
- 将getNeAttrs函数移动到更合理的位置
- 重构伤害计算逻辑,明确区分施法者和被攻击者属性使用
- 完善接口和核心方法的文档注释
- 修正暴击伤害计算错误,使用施法者暴击伤害属性
- 优化闪避判定公式,考虑施法者命中率
2025-11-21 09:18:49 +08:00
3990799046 refactor: 移除废弃脚本并迁移ECS文档至assets目录
删除不再使用的update-oops-plugin-framework.bat脚本
将ecs.md文档从根目录迁移至assets/script目录并更新内容
2025-11-20 16:54:15 +08:00
16 changed files with 487 additions and 158 deletions

11
assets/script/ecs.md.meta Normal file
View File

@@ -0,0 +1,11 @@
{
"ver": "1.0.1",
"importer": "text",
"imported": true,
"uuid": "1f3ba9b7-02ad-406f-86b3-895009bcb3e7",
"files": [
".json"
],
"subMetas": {},
"userData": {}
}

View File

@@ -89,6 +89,8 @@ export enum FightSet {
ATK_ADD_COUNT=4,//伙伴攻击力增加 ATK_ADD_COUNT=4,//伙伴攻击力增加
ATK_ADD_GLOD=1,//金币增加 ATK_ADD_GLOD=1,//金币增加
CRIT_DAMAGE=50,//暴击伤害 CRIT_DAMAGE=50,//暴击伤害
DEF_C=100,//物理防御常数C
MDEF_C=100,//魔法防御常数C
DOUBLE_ATK_RATE=100,//额外攻击默认概率 DOUBLE_ATK_RATE=100,//额外攻击默认概率
GREEN_GOLD=1,//绿色金币 GREEN_GOLD=1,//绿色金币
BLUE_GOLD=2,//蓝色金币 BLUE_GOLD=2,//蓝色金币

View File

@@ -17,18 +17,7 @@ export enum NeAttrs {
IN_BURN = 2, IN_BURN = 2,
IN_POISON = 3, IN_POISON = 3,
} }
export const getNeAttrs = () => {
let reAttrs = {};
Object.keys(NeAttrs).forEach(key => {
if (!isNaN(Number(key))) {
reAttrs[Number(key)] = {
value: 0,
time: 0,
};
}
});
return reAttrs;
}
// ========== 属性枚举 ========== // ========== 属性枚举 ==========
/** /**
* 英雄属性枚举 * 英雄属性枚举
@@ -43,8 +32,6 @@ export enum Attrs {
HP_REGEN = 3, // 生命回复 HP_REGEN = 3, // 生命回复
MP_REGEN = 4, // 魔法回复 MP_REGEN = 4, // 魔法回复
HEAL_EFFECT = 5, // 治疗效果 HEAL_EFFECT = 5, // 治疗效果
POW_MAX = 6, // 最大怒气值
POW_REGEN = 7, // 怒气值回复
// ========== 攻击属性 (10-19) ========== // ========== 攻击属性 (10-19) ==========
AP = 10, // 攻击力 AP = 10, // 攻击力
@@ -65,7 +52,6 @@ export enum Attrs {
THORNS = 25, // 反伤 THORNS = 25, // 反伤
CRITICAL_RESIST = 26, // 暴击抗性 CRITICAL_RESIST = 26, // 暴击抗性
CON_RES = 27, // 控制抗性 CON_RES = 27, // 控制抗性
MAGIC_RES = 28, // 魔法抗性
// ========== 暴击与命中属性 (30-39) ========== // ========== 暴击与命中属性 (30-39) ==========
CRITICAL = 30, // 暴击率 CRITICAL = 30, // 暴击率
@@ -76,9 +62,13 @@ export enum Attrs {
ICE_RES = 40, // 冰冻抗性 ICE_RES = 40, // 冰冻抗性
FIRE_RES = 41, // 火焰抗性 FIRE_RES = 41, // 火焰抗性
WIND_RES = 42, // 自然抗性 WIND_RES = 42, // 自然抗性
ICE_POWER = 43, // 冰冻伤害加成 PHYS_RES = 43, // 物理抗性
FIRE_POWER = 44, // 火焰伤害加成 MAGIC_RES = 44, // 魔法抗性
WIND_POWER = 45, // 自然伤害加成 ICE_POWER = 45, // 冰冻伤害加成
FIRE_POWER = 46, // 火焰伤害加成
WIND_POWER = 47, // 自然伤害加成
PHYS_POWER = 48, // 物理伤害加成
MAGIC_POWER= 49,
// ========== 特殊效果属性 (50-59) ========== // ========== 特殊效果属性 (50-59) ==========
@@ -140,6 +130,18 @@ export const getAttrs = () => {
return reAttrs; return reAttrs;
} }
export const getNeAttrs = () => {
let reAttrs = {};
Object.keys(NeAttrs).forEach(key => {
if (!isNaN(Number(key))) {
reAttrs[Number(key)] = {
value: 0,
time: 0,
};
}
});
return reAttrs;
}
/** /**
* 属性类型配置表 * 属性类型配置表
* 用于区分每个属性是数值型还是百分比型 * 用于区分每个属性是数值型还是百分比型
@@ -154,8 +156,6 @@ export const AttrsType: Record<Attrs, BType> = {
[Attrs.SHIELD_MAX]: BType.VALUE, // 最大护盾值 - 数值型 [Attrs.SHIELD_MAX]: BType.VALUE, // 最大护盾值 - 数值型
[Attrs.HP_REGEN]: BType.VALUE, // 生命回复 - 数值型 [Attrs.HP_REGEN]: BType.VALUE, // 生命回复 - 数值型
[Attrs.MP_REGEN]: BType.VALUE, // 魔法回复 - 数值型 [Attrs.MP_REGEN]: BType.VALUE, // 魔法回复 - 数值型
[Attrs.POW_MAX]: BType.VALUE, // 最大怒气值 - 数值型
[Attrs.POW_REGEN]: BType.VALUE, // 怒气值回复 - 数值型
[Attrs.HEAL_EFFECT]: BType.RATIO, // 治疗效果 - 百分比型 [Attrs.HEAL_EFFECT]: BType.RATIO, // 治疗效果 - 百分比型
// ========== 攻击属性(数值型) ========== // ========== 攻击属性(数值型) ==========
@@ -182,15 +182,19 @@ export const AttrsType: Record<Attrs, BType> = {
[Attrs.HIT]: BType.RATIO, // 命中率 - 百分比型 [Attrs.HIT]: BType.RATIO, // 命中率 - 百分比型
[Attrs.CRITICAL_RESIST]: BType.RATIO, // 暴击抗性 - 百分比型 [Attrs.CRITICAL_RESIST]: BType.RATIO, // 暴击抗性 - 百分比型
[Attrs.CON_RES]: BType.RATIO, // 控制抗性 - 百分比型 [Attrs.CON_RES]: BType.RATIO, // 控制抗性 - 百分比型
[Attrs.MAGIC_RES]: BType.RATIO, // 魔法抗性 - 百分比型
// ========== 元素属性(百分比型) ========== // ========== 元素属性(百分比型) ==========
[Attrs.ICE_RES]: BType.RATIO, // 冰冻抗性 - 百分比型 [Attrs.ICE_RES]: BType.RATIO, // 冰冻抗性 - 百分比型
[Attrs.FIRE_RES]: BType.RATIO, // 火焰抗性 - 百分比型 [Attrs.FIRE_RES]: BType.RATIO, // 火焰抗性 - 百分比型
[Attrs.WIND_RES]: BType.RATIO, // 风抗性 - 百分比型 [Attrs.WIND_RES]: BType.RATIO, // 风抗性 - 百分比型
[Attrs.PHYS_RES]: BType.RATIO, // 物理抗性 - 百分比型
[Attrs.MAGIC_RES]:BType.RATIO,
[Attrs.ICE_POWER]: BType.RATIO, // 冰冻伤害加成 - 百分比型 [Attrs.ICE_POWER]: BType.RATIO, // 冰冻伤害加成 - 百分比型
[Attrs.FIRE_POWER]: BType.RATIO, // 火焰伤害加成 - 百分比型 [Attrs.FIRE_POWER]: BType.RATIO, // 火焰伤害加成 - 百分比型
[Attrs.WIND_POWER]: BType.RATIO, // 风伤害加成 - 百分比型 [Attrs.WIND_POWER]: BType.RATIO, // 风伤害加成 - 百分比型
[Attrs.PHYS_POWER]: BType.RATIO, // 物理伤害加成 - 百分比型
[Attrs.MAGIC_POWER]: BType.RATIO, // 物理伤害加成 - 百分比型
// ========== 特殊效果属性(百分比型) ========== // ========== 特殊效果属性(百分比型) ==========
[Attrs.LIFESTEAL]: BType.RATIO, // 吸血比率 - 百分比型 [Attrs.LIFESTEAL]: BType.RATIO, // 吸血比率 - 百分比型

View File

@@ -81,7 +81,6 @@ export enum EType {
//debuff类型 //debuff类型
/* /*
=== 技能配置系统使用说明 === === 技能配置系统使用说明 ===
@@ -115,7 +114,9 @@ export enum EType {
*/ */
export enum DType { export enum DType {
ATK= 0, // 物理 ATK= 0, // 物理
MAGE=1, // 魔法 ICE=1, // 冰元素
FIRE=2, // 火元素
WIND=3, // 风元素
} }
export const HeroSkillList = [6001,6001,6001,6001,6001,6001] export const HeroSkillList = [6001,6001,6001,6001,6001,6001]
@@ -152,7 +153,7 @@ interface IEndAnm {
// 技能配置接口 - 按照6001格式排列 // 技能配置接口 - 按照6001格式排列
export interface SkillConfig { export interface SkillConfig {
uuid:number,name:string,sp_name:string,icon:string,TGroup:TGroup,SType:SType,act:string,DTType:DTType,DType:DType, uuid:number,name:string,sp_name:string,icon:string,TGroup:TGroup,SType:SType,act:string,DTType:DTType,DType:DType,
ap:number,cd:number,t_num:number,hit_num:number,hit:number,hitcd:number,speed:number,cost:number,with:number,dis:Number,ready:number,EAnm:number,DAnm:number,RType:RType,EType:EType, ap:number,map:number,cd:number,t_num:number,hit_num:number,hit:number,hitcd:number,speed:number,cost:number,with:number,dis:Number,ready:number,EAnm:number,DAnm:number,RType:RType,EType:EType,
buffs:BuffConf[],neAttrs:NeAttrsConf[],info:string,hero?:number , buffs:BuffConf[],neAttrs:NeAttrsConf[],info:string,hero?:number ,
} }
@@ -160,18 +161,18 @@ export const SkillSet: Record<number, SkillConfig> = {
// ========== 基础攻击 ========== 6001-6099 // ========== 基础攻击 ========== 6001-6099
6001: { 6001: {
uuid:6001,name:"挥击",sp_name:"atk_s1",icon:"3036",TGroup:TGroup.Enemy,SType:SType.damage,act:"atk",DTType:DTType.single,DType:DType.ATK, uuid:6001,name:"挥击",sp_name:"atk_s1",icon:"3036",TGroup:TGroup.Enemy,SType:SType.damage,act:"atk",DTType:DTType.single,DType:DType.ATK,
ap:100,cd:1,t_num:1,hit_num:1,hit:1,hitcd:0.2,speed:720,cost:0,with:0,dis:80,ready:0,EAnm:0,DAnm:9001,RType:RType.fixed,EType:EType.animationEnd, ap:100,map:0,cd:1,t_num:1,hit_num:1,hit:1,hitcd:0.2,speed:720,cost:0,with:0,dis:80,ready:0,EAnm:0,DAnm:9001,RType:RType.fixed,EType:EType.animationEnd,
buffs:[],neAttrs:[],info:"向最前方敌人扔出石斧,造成100%攻击的伤害", buffs:[],neAttrs:[],info:"向最前方敌人扔出石斧,造成100%攻击的伤害",
}, },
6002: { 6002: {
uuid:6002,name:"挥砍",sp_name:"atk_s4",icon:"3036",TGroup:TGroup.Enemy,SType:SType.damage,act:"atk",DTType:DTType.single,DType:DType.ATK, uuid:6002,name:"挥砍",sp_name:"atk_s4",icon:"3036",TGroup:TGroup.Enemy,SType:SType.damage,act:"atk",DTType:DTType.single,DType:DType.ATK,
ap:100,cd:1,t_num:1,hit_num:1,hit:1,hitcd:0.2,speed:720,cost:0,with:0,dis:80,ready:0,EAnm:0,DAnm:9001,RType:RType.fixed,EType:EType.animationEnd, ap:100,map:0,cd:1,t_num:1,hit_num:1,hit:1,hitcd:0.2,speed:720,cost:0,with:0,dis:80,ready:0,EAnm:0,DAnm:9001,RType:RType.fixed,EType:EType.animationEnd,
buffs:[],neAttrs:[],info:"向最前方敌人扔出石斧,造成100%攻击的伤害", buffs:[],neAttrs:[],info:"向最前方敌人扔出石斧,造成100%攻击的伤害",
}, },
6005: { 6005: {
uuid:6005,name:"水球",sp_name:"m_water_ball_1",icon:"3039",TGroup:TGroup.Enemy,SType:SType.damage,act:"atk",DTType:DTType.single,DType:DType.MAGE, uuid:6005,name:"水球",sp_name:"m_water_ball_1",icon:"3039",TGroup:TGroup.Enemy,SType:SType.damage,act:"atk",DTType:DTType.single,DType:DType.ICE,
ap:100,cd:5,t_num:1,hit_num:1,hit:2,hitcd:0.3,speed:720,cost:0,with:90,dis:360,ready:8001,EAnm:0,DAnm:9001,RType:RType.linear,EType:EType.collision, ap:0,map:100,cd:5,t_num:1,hit_num:1,hit:2,hitcd:0.3,speed:720,cost:0,with:90,dis:360,ready:8001,EAnm:0,DAnm:9001,RType:RType.linear,EType:EType.collision,
buffs:[],neAttrs:[],info:"召唤大火球攻击前方所有敌人,造成300%攻击的伤害,有一定几率施加灼烧", buffs:[],neAttrs:[],info:"召唤球攻击前方敌人,造成100%魔法攻击的伤害",
}, },
}; };

View File

@@ -9,28 +9,29 @@ export enum TriType {
ATK = 2, //普通攻击触发 ATK = 2, //普通攻击触发
DMG = 3, // 受伤触发 DMG = 3, // 受伤触发
SKILL = 4, // 技能触发 SKILL = 4, // 技能触发
HPL = 5, // 失去生命值触发 MAX = 5, // 必杀触发
HPA = 6, // 获得生命值触发 HPL = 6, // 失去生命值触发
INIT = 7, // 初始触发,如:多1个技能 HPA = 7, // 获得生命值触发
DEAD = 8 // 基于死亡触发 INIT = 8, // 初始触发,如:多1个技能
DEAD = 9, // 基于死亡触发
} }
export enum TalEffet { export enum TalEffet {
DMG=1, // 伤害 ATK_DMG=1, // 伤害
HP=2, // 回血 百分比 SKILL_DMG=2, // 技能伤害
MP=3, //回蓝 百分比 HP=3, // 回血 百分比
BUFF = 4, // 暴击率,闪避率等,可叠加的触发后清零 MP=4, //回蓝 百分比
STATS=5, // 状态 BUFF = 5, // 暴击率,闪避率等,可叠加的触发后清零
WFUNY=6, // 风怒 STATS=6, // 状态
SPLASH=7, // 溅射 WFUNY=7, // 风怒
D_SKILL=8, //两次技能 D_SKILL=8, //两次技能
SHIELD=9, // 护盾 SHIELD=9, // 护盾
LDMG=10, // 减伤 LDMG=10, // 减伤
C_ATK=11, // 普工必爆 C_MSKILL=11, // 必杀技能必暴
C_SKILL=12, // 一般技能必暴 C_ATK=12, // 普工必爆
C_MSKILL=13, // 必杀技能必暴 C_SKILL=13, // 一般技能必暴
} }
export enum TalTarget { export enum TalTarget {
@@ -87,8 +88,7 @@ export const talConf: Record<number, ItalConf> = {
/*** 普通攻击触发 ***/ /*** 普通攻击触发 ***/
7001:{uuid:7001,name:"风怒",triType:TriType.ATK,Trigger:3,count:1,target:TalTarget.ENEMY,effet:TalEffet.WFUNY,vType:BType.RATIO, value:50,attrs:TalAttrs.NON, 7001:{uuid:7001,name:"风怒",triType:TriType.ATK,Trigger:3,count:1,target:TalTarget.ENEMY,effet:TalEffet.WFUNY,vType:BType.RATIO, value:50,attrs:TalAttrs.NON,
desc:"普通攻击3次后, 立即给与目标150%伤害的额外打击"}, desc:"普通攻击3次后, 立即给与目标150%伤害的额外打击"},
7002:{uuid:7002,name:"溅射",triType:TriType.ATK,Trigger:3,count:1,target:TalTarget.ENEMY,effet:TalEffet.SPLASH,vType:BType.RATIO, value:50,attrs:TalAttrs.NON,
desc:"普通攻击3次后, 会对目标100码内的敌人造成30%伤害"},
7003:{uuid:7003,name:"回血",triType:TriType.ATK,Trigger:3,count:1,target:TalTarget.SELF,effet:TalEffet.HP,vType:BType.RATIO, value:1,attrs:TalAttrs.NON, 7003:{uuid:7003,name:"回血",triType:TriType.ATK,Trigger:3,count:1,target:TalTarget.SELF,effet:TalEffet.HP,vType:BType.RATIO, value:1,attrs:TalAttrs.NON,
desc:"普通攻击3次后, 会回复10%的生命值"}, desc:"普通攻击3次后, 会回复10%的生命值"},
7004:{uuid:7004,name:"回蓝",triType:TriType.ATK,Trigger:3,count:1,target:TalTarget.SELF,effet:TalEffet.MP,vType:BType.RATIO, value:1,attrs:TalAttrs.NON, 7004:{uuid:7004,name:"回蓝",triType:TriType.ATK,Trigger:3,count:1,target:TalTarget.SELF,effet:TalEffet.MP,vType:BType.RATIO, value:1,attrs:TalAttrs.NON,
@@ -107,7 +107,7 @@ export const talConf: Record<number, ItalConf> = {
desc:"普通攻击10次后, 下次一般技能额外释放1次,伤害100%"}, desc:"普通攻击10次后, 下次一般技能额外释放1次,伤害100%"},
/*** 受伤触发 ***/ /*** 受伤触发 ***/
7101:{uuid:7101,name:"反击",triType:TriType.DMG,Trigger:3,count:1,target:TalTarget.ENEMY,effet:TalEffet.DMG,vType:BType.RATIO, value:50,attrs:TalAttrs.NON, 7101:{uuid:7101,name:"反击",triType:TriType.DMG,Trigger:3,count:1,target:TalTarget.ENEMY,effet:TalEffet.ATK_DMG,vType:BType.RATIO, value:50,attrs:TalAttrs.NON,
desc:"被攻击3次后, 给于目标50%的伤害"}, desc:"被攻击3次后, 给于目标50%的伤害"},
7102:{uuid:7102,name:"护盾",triType:TriType.DMG,Trigger:3,count:1,target:TalTarget.SELF,effet:TalEffet.SHIELD,vType:BType.RATIO, value:20,attrs:TalAttrs.NON, 7102:{uuid:7102,name:"护盾",triType:TriType.DMG,Trigger:3,count:1,target:TalTarget.SELF,effet:TalEffet.SHIELD,vType:BType.RATIO, value:20,attrs:TalAttrs.NON,
desc:"被攻击3次后, 获得20%的生命值护盾"}, desc:"被攻击3次后, 获得20%的生命值护盾"},

View File

@@ -2,20 +2,37 @@ import { ecs } from "../../../../extensions/oops-plugin-framework/assets/libs/ec
import { FacSet } from "../common/config/GameSet"; import { FacSet } from "../common/config/GameSet";
import { Attrs } from "../common/config/HeroAttrs"; import { Attrs } from "../common/config/HeroAttrs";
import { FightSet } from "../common/config/GameSet"; import { FightSet } from "../common/config/GameSet";
import { SkillSet } from "../common/config/SkillSet"; import { SkillSet, DType } from "../common/config/SkillSet";
import { HeroAttrsComp } from "./HeroAttrsComp"; import { HeroAttrsComp } from "./HeroAttrsComp";
import { HeroViewComp } from "./HeroViewComp"; import { HeroViewComp } from "./HeroViewComp";
import { DamageQueueComp, DamageEvent, DamageQueueHelper } from "./DamageQueueComp"; import { DamageQueueComp, DamageEvent, DamageQueueHelper } from "./DamageQueueComp";
import { smc } from "../common/SingletonModuleComp"; import { smc } from "../common/SingletonModuleComp";
/** 最终伤害数据接口 */ /** 最终伤害数据接口
* 用于封装一次攻击计算的所有结果数据
* @property damage - 最终造成的伤害值(已考虑所有加成和减免)
* @property isCrit - 是否为暴击攻击
* @property isDodge - 是否被闪避闪避时damage为0
*/
interface FinalData { interface FinalData {
damage: number; damage: number;
isCrit: boolean; isCrit: boolean;
isDodge: boolean; isDodge: boolean;
} }
/** 业务层业务逻辑处理对象 伤害处理系统 */ /**
* 英雄攻击系统 - 伤害处理核心系统
*
* 职责:
* 1. 处理所有伤害事件的计算和分发
* 2. 管理伤害队列的处理流程
* 3. 协调视图层的表现更新
*
* 重要概念:
* - damageEvent.Attrs: 施法者属性快照(创建技能时保存)
* - targetAttrs: 被攻击者实时属性
* - 属性来源规范:攻击判定用施法者,防御判定用被攻击者
*/
@ecs.register('HeroAtkSystem') @ecs.register('HeroAtkSystem')
export class HeroAtkSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate { export class HeroAtkSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate {
@@ -81,10 +98,30 @@ export class HeroAtkSystem extends ecs.ComblockSystem implements ecs.ISystemUpd
/** /**
* 执行攻击计算 * 执行攻击计算 - 核心伤害计算逻辑
* @param target 目标实体 *
* @param damageEvent 伤害事件数据 * 属性使用规范(重要!):
* @returns 最终伤害数据 *
* ✅ 正确使用施法者属性damageEvent.Attrs - 快照):
* - CRITICAL: 暴击率判定
* - CRITICAL_DMG: 暴击伤害加成
* - BACK_CHANCE: 击退概率
* - HIT: 命中率(用于闪避计算)
* - AP/MAP: 攻击力(基础伤害计算)
*
* ✅ 正确使用被攻击者属性targetAttrs - 实时):
* - DODGE: 闪避率(用于闪避计算)
* - SHIELD_MAX: 护盾最大值(护盾吸收)
* - hp: 当前生命值(伤害应用)
* - 各种抗性属性(预留扩展)
*
* ❌ 错误使用案例(已修复):
* - 不要混用施法者和被攻击者的属性进行同一计算
* - 暴击伤害应该基于施法者的暴击伤害属性
*
* @param target 目标实体(被攻击者)
* @param damageEvent 伤害事件数据(包含施法者信息和属性快照)
* @returns 最终伤害数据(包含伤害值、暴击标记、闪避标记)
*/ */
private doAttack(target: ecs.Entity, damageEvent: DamageEvent): FinalData { private doAttack(target: ecs.Entity, damageEvent: DamageEvent): FinalData {
const targetAttrs = target.get(HeroAttrsComp); const targetAttrs = target.get(HeroAttrsComp);
@@ -107,19 +144,27 @@ export class HeroAtkSystem extends ecs.ComblockSystem implements ecs.ISystemUpd
this.onAttacked(target); this.onAttacked(target);
// 闪避判定 // 闪避判定
const isDodge =this.checkChance(targetAttrs.Attrs[Attrs.DODGE] || 0); // 闪避成功概率 = 被攻击者闪避率 - 施法者命中率
// targetAttrs.Attrs[Attrs.DODGE]: 被攻击者的实时闪避属性
// damageEvent.Attrs[Attrs.HIT]: 施法者在技能创建时的命中属性快照
const isDodge =this.checkChance((targetAttrs.Attrs[Attrs.DODGE]-damageEvent.Attrs[Attrs.HIT]) || 0);
if (isDodge) { if (isDodge) {
// TODO: 触发闪避视图表现 // TODO: 触发闪避视图表现
reDate.isDodge=true; reDate.isDodge=true;
return reDate; return reDate;
} }
// 暴击判定 // 暴击判定
// 使用施法者的暴击率属性damageEvent.Attrs 快照)
const isCrit = this.checkChance(damageEvent.Attrs[Attrs.CRITICAL]); const isCrit = this.checkChance(damageEvent.Attrs[Attrs.CRITICAL]);
if (isCrit) attackerModel?.clearTalBuffByAttr(Attrs.CRITICAL); if (isCrit) attackerModel?.useValueTalByAttr(Attrs.CRITICAL); // 清除施法者的暴击buff
// 计算伤害 // 计算伤害
let damage = this.dmgCount(damageEvent.Attrs,damageEvent.s_uuid); let damage = this.dmgCount(damageEvent,targetAttrs.Attrs);
if (isCrit) { if (isCrit) {
damage = Math.floor(damage * (1 + (FightSet.CRIT_DAMAGE + targetAttrs.Attrs[Attrs.CRITICAL_DMG]) / 100)); // 暴击伤害计算
// 使用施法者的暴击伤害加成属性damageEvent.Attrs 快照)
// 公式:最终伤害 = 基础伤害 * (1 + 系统暴击倍率 + 施法者暴击伤害加成)
const casterCritDmg = damageEvent.Attrs[Attrs.CRITICAL_DMG] || 0;
damage = Math.floor(damage * (1 + (FightSet.CRIT_DAMAGE + casterCritDmg) / 100));
reDate.isCrit=true; reDate.isCrit=true;
} }
// 伤害计算考虑易伤等debuff // 伤害计算考虑易伤等debuff
@@ -130,9 +175,11 @@ export class HeroAtkSystem extends ecs.ComblockSystem implements ecs.ISystemUpd
// 应用伤害到数据层 // 应用伤害到数据层
targetAttrs.hp -= damage; targetAttrs.hp -= damage;
targetAttrs.atked_count++; targetAttrs.atked_count++;
//击退判定 // 击退判定
// 使用施法者的击退概率属性damageEvent.Attrs 快照)
// 击退成功后需要清理施法者的相关天赋buff
const isBack = this.checkChance(damageEvent.Attrs[Attrs.BACK_CHANCE] || 0); const isBack = this.checkChance(damageEvent.Attrs[Attrs.BACK_CHANCE] || 0);
if (isBack) attackerModel?.clearTalBuffByAttr(Attrs.BACK_CHANCE); if (isBack) attackerModel?.useValueTalByAttr(Attrs.BACK_CHANCE);
// ✅ 触发视图层表现(伤害数字、受击动画、后退) // ✅ 触发视图层表现(伤害数字、受击动画、后退)
@@ -155,15 +202,139 @@ export class HeroAtkSystem extends ecs.ComblockSystem implements ecs.ISystemUpd
reDate.damage=damage; reDate.damage=damage;
return reDate; return reDate;
} }
//伤害计算,暂时简单计算 /**
private dmgCount(CAttrs:any,s_uuid:number){ * 详细伤害计算核心方法
let sConf = SkillSet[s_uuid]; *
* 这是整个战斗系统中最核心的伤害计算方法,负责根据施法者属性、目标属性和技能配置
* 计算最终的基础伤害值。该方法采用多阶段的伤害计算公式,综合考虑了物理和魔法伤害
* 以及各种属性加成和抗性减免。
*
* 计算流程:
* 1. 获取技能配置
* 2. 计算原始物理伤害和魔法伤害
* 3. 应用防御减免
* 4. 应用物理/魔法攻击力和抗性修正
* 5. 应用元素属性加成和抗性修正
* 6. 应用最终伤害减免
* 7. 确保伤害值非负
*
* @param CAttrs 施法者属性快照对象,包含所有攻击力、属性加成等战斗属性
* @param TAttrs 目标属性对象,包含所有防御力、抗性等防御属性
* @param s_uuid 技能ID用于获取技能配置信息和伤害类型
* @returns 经过完整计算后的最终伤害值(未考虑暴击)
*
* @important 注意事项:
* - 此方法计算的是基础伤害,暴击计算在外部处理
* - 所有除法和乘法计算后都进行取整操作,确保游戏中的伤害值为整数
* - 元素伤害只应用于魔法伤害部分
*/
private dmgCount(damageEvent:any,TAttrs:any){
// 1. 获取技能配置 - 如果技能不存在直接返回0伤害
const CAttrs=damageEvent.Attrs;
let sConf = SkillSet[damageEvent.s_uuid];
if (!sConf) return 0; if (!sConf) return 0;
let AP = sConf.ap*CAttrs[Attrs.AP]/100;
return AP; // 2. 计算原始物理伤害和魔法伤害
// 物理伤害基础值 = 技能物理倍率 * (施法者物理攻击力 + 额外物理伤害) / 100 * 伤害比例
let apBase = (sConf.ap||0)*(CAttrs[Attrs.AP]+damageEvent.ext_dmg)/100*damageEvent.dmg_ratio;
// 魔法伤害基础值 = 技能魔法倍率 * (施法者魔法攻击力 + 额外魔法伤害) / 100 * 伤害比例
let mapBase = (sConf.map||0)*(CAttrs[Attrs.MAP]+damageEvent.ext_dmg)/100*damageEvent.dmg_ratio;
// 3. 获取目标防御属性
const def = (TAttrs[Attrs.DEF]||0); // 目标物理防御
const mdef = (TAttrs[Attrs.MDEF]||0); // 目标魔法防御
// 4. 计算防御减免系数(采用公式:防御/(防御+常数)确保防御值不会导致伤害减到0
const apRed = def / (def + FightSet.DEF_C); // 物理防御减免系数
const mapRed = mdef / (mdef + FightSet.MDEF_C); // 魔法防御减免系数
// 5. 应用防御减免到基础伤害,向下取整
let apAfter = Math.floor(apBase * (1 - apRed)); // 物理伤害 - 防御减免
let mapAfter = Math.floor(mapBase * (1 - mapRed)); // 魔法伤害 - 防御减免
// 6. 应用物理/魔法攻击力和抗性修正
// 物理伤害修正:基础伤害 * (1 + 物理攻击力加成%) * (1 - 目标物理抗性%)
apAfter = this.applyPR(apAfter, CAttrs[Attrs.PHYS_POWER]||0, TAttrs[Attrs.PHYS_RES]||0);
// 魔法伤害修正:基础伤害 * (1 + 魔法攻击力加成%) * (1 - 目标魔法抗性%)
mapAfter = this.applyPR(mapAfter, CAttrs[Attrs.MAGIC_POWER]||0, TAttrs[Attrs.MAGIC_RES]||0);
// 7. 根据技能元素类型,应用元素属性加成和抗性修正
switch (sConf.DType) {
case DType.ICE:
// 冰系伤害修正:魔法伤害 * (1 + 冰系攻击力加成%) * (1 - 目标冰系抗性%)
mapAfter = this.applyPR(mapAfter, CAttrs[Attrs.ICE_POWER]||0, TAttrs[Attrs.ICE_RES]||0);
break;
case DType.FIRE:
// 火系伤害修正:魔法伤害 * (1 + 火系攻击力加成%) * (1 - 目标火系抗性%)
mapAfter = this.applyPR(mapAfter, CAttrs[Attrs.FIRE_POWER]||0, TAttrs[Attrs.FIRE_RES]||0);
break;
case DType.WIND:
// 风系伤害修正:魔法伤害 * (1 + 风系攻击力加成%) * (1 - 目标风系抗性%)
mapAfter = this.applyPR(mapAfter, CAttrs[Attrs.WIND_POWER]||0, TAttrs[Attrs.WIND_RES]||0);
break;
}
// 8. 计算最终总伤害(物理伤害 + 魔法伤害)
let total = apAfter + mapAfter;
// 9. 应用最终伤害减免效果如特殊天赋、buff等提供的减免
total = Math.floor(total * (1 - ((TAttrs[Attrs.DAMAGE_REDUCTION]||0)/100)));
// 10. 确保伤害值非负,返回最终伤害
return Math.max(0,total);
}
/**
* 应用攻击力加成和抗性减免的通用计算方法
*
* 这是一个核心的伤害修正计算方法,用于处理各种类型的攻击力加成和抗性减免。
* 该方法采用乘法叠加的方式,分别应用攻击者的加成属性和目标的抗性属性。
*
* 计算公式:
* 最终值 = 基础值 × (1 + 攻击力加成% / 100) × (1 - 抗性% / 100)
*
* 适用场景:
* - 物理攻击力加成和物理抗性减免
* - 魔法攻击力加成和魔法抗性减免
* - 元素攻击力加成和元素抗性减免
* - 其他需要同时考虑加成和减免的属性修正
*
* 计算逻辑说明:
* 1. 首先将百分比转换为小数形式除以100
* 2. 应用攻击者的加成:基础值 × (1 + 加成系数)
* 3. 应用目标的抗性:上一步结果 × (1 - 抗性系数)
* 4. 向下取整,确保结果为整数
*
* @param base 基础值(通常是经过防御减免后的伤害值)
* @param power 攻击者的攻击力加成值百分比形式如50表示50%
* @param res 目标的抗性值百分比形式如30表示30%
* @returns 经过攻击力加成和抗性减免后的最终值(向下取整)
*
* @important 注意事项:
* - 当抗性值大于100时可能导致最终值为负数或零
* - 所有计算结果会向下取整,确保游戏中的数值为整数
* - 此方法可以被多次调用,以叠加不同类型的加成和减免
*/
private applyPR(base: number, power: number, res: number): number {
// 计算公式:基础值 × (1 + 攻击力加成%) × (1 - 抗性%)
// 1. 将百分比转换为小数power/100 和 res/100
// 2. 应用攻击力加成1 + (power/100)
// 3. 应用抗性减免1 - (res/100)
// 4. 最终计算并向下取整
return Math.floor(base * (1 + (power/100)) * (1 - (res/100)));
} }
/** /**
* 处理角色死亡 * 处理角色死亡
*
* 死亡处理流程:
* 1. 标记死亡状态is_dead = true
* 2. 触发死亡事件onDeath
* 3. 记录调试信息(如启用调试模式)
*
* @param entity 死亡的实体
*
* @important 死亡状态一旦设置,该实体将不再处理新的伤害事件
* 这确保了死亡逻辑的单一性和一致性
*/ */
private doDead(entity: ecs.Entity): void { private doDead(entity: ecs.Entity): void {
const model = entity.get(HeroAttrsComp); const model = entity.get(HeroAttrsComp);
@@ -182,7 +353,26 @@ export class HeroAtkSystem extends ecs.ComblockSystem implements ecs.ISystemUpd
/** /**
* 暴击判定 * 统一概率判定方法
*
* 用于所有概率相关的判定:
* - 暴击率判定
* - 闪避率判定
* - 击退概率判定
* - 其他特殊效果概率
*
* @param rate 概率值0-100的百分比
* @returns true-判定成功false-判定失败
*
* @example
* ```typescript
* // 10%概率触发
* if (this.checkChance(10)) {
* // 触发特殊效果
* }
* ```
*
* @important 概率为0或负数时直接返回false避免不必要的随机数计算
*/ */
private checkChance(rate: number): boolean { private checkChance(rate: number): boolean {
if (rate <= 0) return false; if (rate <= 0) return false;
@@ -192,6 +382,16 @@ export class HeroAtkSystem extends ecs.ComblockSystem implements ecs.ISystemUpd
/** /**
* 伤害计算考虑易伤等debuff * 伤害计算考虑易伤等debuff
*
* 预留的伤害计算扩展点,用于处理:
* - 被攻击者的易伤状态(增加受到伤害)
* - 被攻击者的伤害减免状态(减少受到伤害)
* - 元素抗性计算
* - 真实伤害/魔法伤害/物理伤害的类型区分
*
* @param model 被攻击者的属性组件(包含抗性、易伤等状态)
* @param baseDamage 基础伤害值
* @returns 最终伤害值(经过各种加成和减免后的结果)
*/ */
private calculateDamage(model: HeroAttrsComp, baseDamage: number): number { private calculateDamage(model: HeroAttrsComp, baseDamage: number): number {
// 这里可以添加易伤等debuff的计算逻辑 // 这里可以添加易伤等debuff的计算逻辑
@@ -201,6 +401,15 @@ export class HeroAtkSystem extends ecs.ComblockSystem implements ecs.ISystemUpd
/** /**
* 护盾吸收伤害 * 护盾吸收伤害
*
* 护盾吸收逻辑:
* 1. 如果护盾值 >= 伤害值完全吸收剩余伤害为0
* 2. 如果护盾值 < 伤害值:部分吸收,剩余伤害 = 原伤害 - 护盾值
* 3. 护盾被击破时,重置护盾最大值属性
*
* @param model 被攻击者的属性组件(包含当前护盾值)
* @param damage 原始伤害值
* @returns 剩余伤害值(护盾吸收后的结果)
*/ */
private absorbShield(model: HeroAttrsComp, damage: number): number { private absorbShield(model: HeroAttrsComp, damage: number): number {
if (model.shield <= 0) return damage; if (model.shield <= 0) return damage;
@@ -222,6 +431,15 @@ export class HeroAtkSystem extends ecs.ComblockSystem implements ecs.ISystemUpd
/** /**
* 被攻击时触发的事件 * 被攻击时触发的事件
*
* 预留的扩展点,用于处理被攻击时的特殊逻辑:
* - 触发反伤效果(荆棘光环等)
* - 触发被攻击天赋(如受击回血、受击反击等)
* - 触发特殊状态(如受伤狂暴、受伤护盾等)
*
* @param entity 被攻击的实体
*
* @todo 当前对怪物实体直接返回,后续可以根据需求扩展怪物的被攻击逻辑
*/ */
private onAttacked(entity: ecs.Entity): void { private onAttacked(entity: ecs.Entity): void {
const model = entity.get(HeroAttrsComp); const model = entity.get(HeroAttrsComp);
@@ -235,6 +453,21 @@ export class HeroAtkSystem extends ecs.ComblockSystem implements ecs.ISystemUpd
/** /**
* 死亡时触发的事件 * 死亡时触发的事件
*
* 根据实体阵营类型处理不同的死亡逻辑:
*
* - FacSet.MON怪物触发掉落逻辑
* - 延迟执行掉落,避免阻塞主逻辑
* - 可以扩展:经验值计算、任务进度等
*
* - FacSet.HERO英雄触发英雄死亡特殊处理
* - 游戏结束判定
* - 复活机制检查
* - 死亡惩罚/奖励
*
* @param entity 死亡的实体
*
* @important 死亡事件应该幂等,避免重复触发
*/ */
private onDeath(entity: ecs.Entity): void { private onDeath(entity: ecs.Entity): void {
const model = entity.get(HeroAttrsComp); const model = entity.get(HeroAttrsComp);
@@ -251,6 +484,19 @@ export class HeroAtkSystem extends ecs.ComblockSystem implements ecs.ISystemUpd
/** /**
* 延迟执行掉落逻辑 * 延迟执行掉落逻辑
*
* 采用延迟执行的原因:
* 1. 避免在伤害计算过程中阻塞主线程
* 2. 给死亡动画播放留出时间
* 3. 可以批量处理多个掉落,优化性能
*
* @param entity 死亡的怪物实体
*
* @todo 具体实现可以包括:
* - 根据怪物等级计算基础掉落
* - 幸运值影响掉落品质
* - 特殊事件(双倍掉落、稀有掉落等)
* - 掉落物在场景中的生成位置计算
*/ */
private scheduleDrop(entity: ecs.Entity): void { private scheduleDrop(entity: ecs.Entity): void {
// 这里可以添加掉落逻辑 // 这里可以添加掉落逻辑
@@ -259,6 +505,19 @@ export class HeroAtkSystem extends ecs.ComblockSystem implements ecs.ISystemUpd
/** /**
* 延迟执行英雄死亡逻辑 * 延迟执行英雄死亡逻辑
*
* 英雄死亡的特殊处理,比普通怪物复杂:
*
* 处理内容包括:
* - 检查复活次数和复活条件
* - 触发游戏结束界面(如适用)
* - 记录死亡统计信息
* - 处理死亡惩罚(经验损失、装备损坏等)
*
* @param entity 死亡的英雄实体
*
* @important 英雄死亡通常需要玩家交互,所以必须延迟处理
* 给玩家足够的反馈时间和操作空间
*/ */
private scheduleHeroDeath(entity: ecs.Entity): void { private scheduleHeroDeath(entity: ecs.Entity): void {
// 这里可以添加英雄死亡的特殊处理 // 这里可以添加英雄死亡的特殊处理

View File

@@ -2,7 +2,7 @@
"ver": "4.0.24", "ver": "4.0.24",
"importer": "typescript", "importer": "typescript",
"imported": true, "imported": true,
"uuid": "85d8a2e5-f2a1-49b0-9439-fe9e1e98b7d9", "uuid": "bffb52f1-1843-437d-82ef-88d2d7ee2ec5",
"files": [], "files": [],
"subMetas": {}, "subMetas": {},
"userData": {} "userData": {}

View File

@@ -3,6 +3,7 @@ import { Attrs, AttrsType, BType, NeAttrs } from "../common/config/HeroAttrs";
import { BuffConf } from "../common/config/SkillSet"; import { BuffConf } from "../common/config/SkillSet";
import { HeroInfo, AttrSet } from "../common/config/heroSet"; import { HeroInfo, AttrSet } from "../common/config/heroSet";
import { HeroSkillsComp } from "./HeroSkills"; import { HeroSkillsComp } from "./HeroSkills";
import { HeroViewComp } from "./HeroViewComp";
interface talTrigger{ interface talTrigger{
@@ -31,11 +32,12 @@ export class HeroAttrsComp extends ecs.Comp {
// ==================== 动态属性值 ==================== // ==================== 动态属性值 ====================
hp: number = 100; // 当前血量 hp: number = 100; // 当前血量
mp: number = 100; // 当前魔法值 mp: number = 100; // 当前魔法值
pow: number = 0; // 当前怒气值
shield: number = 0; // 当前护盾 shield: number = 0; // 当前护盾
Attrs: any = []; // 最终属性数组经过Buff计算后 Attrs: any = []; // 最终属性数组经过Buff计算后
NeAttrs: any = []; // 负面状态数组 NeAttrs: any = []; // 负面状态数组
//计数型天赋buff
Talents: Record<number, talTrigger> = {}; Talents: Record<number, talTrigger> = {};
//数值型天赋buff
BUFFS_TAL: Record<number, {count:number,BType:BType,attrIndex:number,value: number}> = {}; BUFFS_TAL: Record<number, {count:number,BType:BType,attrIndex:number,value: number}> = {};
// ==================== 技能距离缓存 ==================== // ==================== 技能距离缓存 ====================
@@ -116,7 +118,33 @@ export class HeroAttrsComp extends ecs.Comp {
} }
} }
} }
/*******************基础属性管理********************/
add_hp(value:number,isValue:boolean){
let addValue = value;
if(!isValue){
addValue = value * this.Attrs[Attrs.HP_MAX];
}
let heroView = this.ent.get(HeroViewComp);
if(heroView){
heroView.health(addValue);
}
this.hp += addValue;
this.hp = Math.max(0, Math.min(this.hp, this.Attrs[Attrs.HP_MAX]));
}
add_mp(value:number,isValue:boolean){
let addValue = value;
if(!isValue){
addValue = value * this.Attrs[Attrs.MP_MAX];
}
this.mp += addValue;
this.mp = Math.max(0, Math.min(this.mp, this.Attrs[Attrs.MP_MAX]));
}
add_shield(value:number,isValue:boolean){
let addValue = value;
this.shield += addValue;
this.shield = Math.max(0, Math.min(this.shield, this.Attrs[Attrs.HP_MAX]));
}
// ==================== BUFF 管理 ==================== // ==================== BUFF 管理 ====================
/** /**
* 添加 buff 效果(支持多次叠加) * 添加 buff 效果(支持多次叠加)
@@ -148,6 +176,8 @@ export class HeroAttrsComp extends ecs.Comp {
this.recalculateSingleAttr(attrIndex); this.recalculateSingleAttr(attrIndex);
} }
// ==================== 属性计算系统 ==================== // ==================== 属性计算系统 ====================
/** /**
* 重新计算单个属性 * 重新计算单个属性
@@ -407,7 +437,7 @@ export class HeroAttrsComp extends ecs.Comp {
} }
addTalBuff(t_uuid: number, attrIndex?: number, bType?: BType, value: number = 0) { addValueTal(t_uuid: number, attrIndex?: number, bType?: BType, value: number = 0) {
if (attrIndex === undefined || bType === undefined) return; if (attrIndex === undefined || bType === undefined) return;
const buff = this.BUFFS_TAL[t_uuid]; const buff = this.BUFFS_TAL[t_uuid];
if (!buff) { if (!buff) {
@@ -418,14 +448,33 @@ export class HeroAttrsComp extends ecs.Comp {
} }
this.recalculateSingleAttr(attrIndex); this.recalculateSingleAttr(attrIndex);
} }
clearTalBuff(t_uuid: number) { addCountTal(eff: number, value: number) {
const t = this.Talents[eff] || { value: 0, count: 0 };
t.value = value;
t.count += 1;
this.Talents[eff] = t;
}
useCountTal(eff: number): boolean {
const t = this.Talents[eff];
if (!t || t.count <= 0) return false;
t.count -= 1;
return true;
}
useCountValTal(eff: number): number {
const t = this.Talents[eff];
if (!t || t.value <= 0) return 0;
t.count -= 1;
return t.value;
}
useValueTalByUuid(t_uuid: number) {
const buff = this.BUFFS_TAL[t_uuid]; const buff = this.BUFFS_TAL[t_uuid];
if (!buff) return; if (!buff) return;
const attrIndex = buff.attrIndex; const attrIndex = buff.attrIndex;
delete this.BUFFS_TAL[t_uuid]; delete this.BUFFS_TAL[t_uuid];
this.recalculateSingleAttr(attrIndex); this.recalculateSingleAttr(attrIndex);
} }
clearTalBuffByAttr(attrIndex: number) { useValueTalByAttr(attrIndex: number) {
let changed = false; let changed = false;
for (const key in this.BUFFS_TAL) { for (const key in this.BUFFS_TAL) {
const b = this.BUFFS_TAL[Number(key)]; const b = this.BUFFS_TAL[Number(key)];
@@ -437,19 +486,6 @@ export class HeroAttrsComp extends ecs.Comp {
if (changed) this.recalculateSingleAttr(attrIndex); if (changed) this.recalculateSingleAttr(attrIndex);
} }
addTalent(eff: number, value: number) {
const t = this.Talents[eff] || { value: 0, count: 0 };
t.value = value;
t.count += 1;
this.Talents[eff] = t;
}
consumeTalent(eff: number): boolean {
const t = this.Talents[eff];
if (!t || t.count <= 0) return false;
t.count -= 1;
return true;
}
reset() { reset() {
// 重置为初始状态 // 重置为初始状态
this.hero_uuid = 1001; this.hero_uuid = 1001;

View File

@@ -31,8 +31,6 @@ export class HeroViewComp extends CCComp {
status:String = "idle" status:String = "idle"
scale: number = 1; // 显示方向 scale: number = 1; // 显示方向
box_group:number = BoxSet.HERO; // 碰撞组 box_group:number = BoxSet.HERO; // 碰撞组
usePower:boolean = false;
useMp:boolean = false;
realDeadTime:number=10 realDeadTime:number=10
deadCD:number=0 deadCD:number=0
// 血条显示相关 // 血条显示相关
@@ -89,10 +87,7 @@ export class HeroViewComp extends CCComp {
// } // }
/* 显示角色血*/ /* 显示角色血*/
this.top_node.getChildByName("hp").active = true; this.top_node.getChildByName("hp").active = true;
this.usePower=HeroInfo[this.model.hero_uuid].type==HType.warrior||HeroInfo[this.model.hero_uuid].type==HType.assassin; this.top_node.getChildByName("mp").active = true;
this.useMp=HeroInfo[this.model.hero_uuid].type==HType.mage||HeroInfo[this.model.hero_uuid].type==HType.remote||HeroInfo[this.model.hero_uuid].type==HType.support;
this.top_node.getChildByName("pow").active = this.usePower;
this.top_node.getChildByName("mp").active = this.useMp;
// 初始隐藏血条(被攻击后才显示) // 初始隐藏血条(被攻击后才显示)
this.top_node.active = false; this.top_node.active = false;
} }
@@ -140,9 +135,9 @@ export class HeroViewComp extends CCComp {
this.processDamageQueue(); // 伤害数字显示队列 this.processDamageQueue(); // 伤害数字显示队列
// ✅ 更新 UI 显示(数据由 HeroAttrSystem 更新) // ✅ 更新 UI 显示(数据由 HeroAttrSystem 更新)
// 移除了每帧调用的 hp_show改为仅在需要时调用
this.hp_show(this.model.hp, this.model.Attrs[Attrs.HP_MAX]); this.hp_show(this.model.hp, this.model.Attrs[Attrs.HP_MAX]);
if(this.useMp) this.mp_show(this.model.mp, this.model.Attrs[Attrs.MP_MAX]); this.mp_show(this.model.mp, this.model.Attrs[Attrs.MP_MAX]);
if(this.usePower) this.pow_show(this.model.pow, this.model.Attrs[Attrs.POW_MAX]);
this.show_shield(this.model.shield, this.model.Attrs[Attrs.SHIELD_MAX]); this.show_shield(this.model.shield, this.model.Attrs[Attrs.SHIELD_MAX]);
} }
@@ -294,12 +289,13 @@ export class HeroViewComp extends CCComp {
if(this.model && this.model.shield>0) this.show_shield(this.model.shield, this.model.Attrs[Attrs.SHIELD_MAX]); if(this.model && this.model.shield>0) this.show_shield(this.model.shield, this.model.Attrs[Attrs.SHIELD_MAX]);
} }
health(hp: number = 0, is_num:boolean=true) { health(hp: number = 0) {
// 生命值更新由 Model 层处理,这里只负责视图表现 // 生命值更新由 Model 层处理,这里只负责视图表现
this.heathed(); this.heathed();
if(this.model) { this.hp_tip(TooltipTypes.health, hp.toFixed(0));
this.hp_show(hp, this.model.Attrs[Attrs.HP_MAX]); this.top_node.active=true
} this.hp_show(this.model.hp, this.model.Attrs[Attrs.HP_MAX]);
} }
alive(){ alive(){
@@ -390,17 +386,6 @@ export class HeroViewComp extends CCComp {
} }
// 伤害计算和战斗逻辑已迁移到 HeroBattleSystem // 伤害计算和战斗逻辑已迁移到 HeroBattleSystem
/** 死亡触发器(预留,用于天赋/特殊效果) */
do_dead_trigger(){
if(!this.model || this.model.is_dead || this.model.fac === FacSet.MON) return;
// 预留:天赋触发、复活检查等
}
/** 受击触发器(预留,用于天赋/特殊效果) */
do_atked_trigger(){
if(!this.model || this.model.is_dead || this.model.fac === FacSet.MON) return;
// 预留:反击、护盾触发等
}
@@ -415,7 +400,7 @@ export class HeroViewComp extends CCComp {
switch(skill.act){ switch(skill.act){
case "max": case "max":
this.as.max() this.as.max()
this.tooltip(TooltipTypes.skill, skill.name, skill_id) this.tooltip(TooltipTypes.skill, skill.name)
break break
case "atk": case "atk":
this.as.atk() this.as.atk()
@@ -458,9 +443,9 @@ export class HeroViewComp extends CCComp {
this.hp_show(this.model.hp, this.model.Attrs[Attrs.HP_MAX]); this.hp_show(this.model.hp, this.model.Attrs[Attrs.HP_MAX]);
this.in_atked(anm, this.model.fac==FacSet.HERO?1:-1); this.in_atked(anm, this.model.fac==FacSet.HERO?1:-1);
if (isCrit) { if (isCrit) {
this.hp_tip(TooltipTypes.crit, damage.toFixed(0), damage); this.hp_tip(TooltipTypes.crit, damage.toFixed(0));
} else { } else {
this.hp_tip(TooltipTypes.life, damage.toFixed(0), damage); this.hp_tip(TooltipTypes.life, damage.toFixed(0));
} }
} }
reset() { reset() {

View File

@@ -143,11 +143,12 @@ export class SACastSystem extends ecs.ComblockSystem implements ecs.ISystemUpdat
// 1. 播放施法动画 // 1. 播放施法动画
heroView.playSkillEffect(s_uuid); heroView.playSkillEffect(s_uuid);
/**********************天赋处理*************************************************************************/ /**********************天赋处理*************************************************************************/
// 2. 更新攻击类型的天赋触发值 // 2. 更新攻击类型的天赋触发值,技能和必杀级
if(casterEntity.has(TalComp)){ if(casterEntity.has(TalComp)){
const talComp = casterEntity.get(TalComp); const talComp = casterEntity.get(TalComp);
if (hset === HSSet.atk) talComp.updateCur(TriType.ATK); if (hset === HSSet.atk) talComp.updateCur(TriType.ATK);
if (hset != HSSet.atk) talComp.updateCur(TriType.SKILL); if (hset === HSSet.skill) talComp.updateCur(TriType.SKILL);
if (hset === HSSet.max) talComp.updateCur(TriType.MAX);
} }
/**********************天赋处理*************************************************************************/ /**********************天赋处理*************************************************************************/
// 获取目标位置 // 获取目标位置
@@ -156,33 +157,54 @@ export class SACastSystem extends ecs.ComblockSystem implements ecs.ISystemUpdat
console.warn("[SACastSystem] 没有找到有效目标"); console.warn("[SACastSystem] 没有找到有效目标");
return false; return false;
} }
// 2. 延迟创建技能实体(等待动画) // 2.1 普通攻击逻辑
const delay = 0.3 if (hset === HSSet.atk){
heroView.scheduleOnce(() => { let delay = 0.3
this.createSkill(s_uuid, heroView,targets); let ext_dmg = heroAttrs.useCountValTal(TalEffet.ATK_DMG);
}, delay); heroView.scheduleOnce(() => {
this.createSkill(s_uuid, heroView,targets,ext_dmg);
//风怒wfuny 只针对 普通攻击起效 }, delay);
if (hset === HSSet.atk && heroAttrs.consumeTalent(TalEffet.WFUNY)){ //风怒wfuny 只针对 普通攻击起效
heroView.playSkillEffect(s_uuid); if (heroAttrs.useCountTal(TalEffet.WFUNY)){
//需要再添加 风怒动画 let ext2_dmg = heroAttrs.useCountValTal(TalEffet.ATK_DMG);
this.createSkill(s_uuid, heroView,targets); let delay = 0.3
} heroView.playSkillEffect(s_uuid);
// 双技能 只针对 技能起效 //需要再添加 风怒动画
if(hset === HSSet.skill && heroAttrs.consumeTalent(TalEffet.D_SKILL)){ heroView.scheduleOnce(() => {
targets = this.sTargets(heroView, s_uuid); this.createSkill(s_uuid, heroView,targets,ext2_dmg);
if (targets.length === 0) { },delay);
console.warn("[SACastSystem] 没有找到有效目标");
return false;
} }
}
// 2.2 技能攻击逻辑
if(hset === HSSet.skill){
let delay = 0.3
let ext_dmg = heroAttrs.useCountValTal(TalEffet.SKILL_DMG);
heroView.scheduleOnce(() => {
this.createSkill(s_uuid, heroView,targets,ext_dmg);
}, delay);
// 双技能 只针对 技能起效
if(heroAttrs.useCountTal(TalEffet.D_SKILL)){
let ext2_dmg = heroAttrs.useCountValTal(TalEffet.SKILL_DMG);
let delay = 0.3
heroView.playSkillEffect(s_uuid);
//需要再添加 双技能动画
heroView.scheduleOnce(() => {
this.createSkill(s_uuid, heroView,targets,ext2_dmg);
},delay);
}
}
// 2.3 必杀技能逻辑
if(hset === HSSet.max){
let delay = 0.3
heroView.playSkillEffect(s_uuid); heroView.playSkillEffect(s_uuid);
//需要再添加 双技能动画 //需要再添加 最大伤害动画
heroView.scheduleOnce(() => { heroView.scheduleOnce(() => {
this.createSkill(s_uuid, heroView,targets); this.createSkill(s_uuid, heroView,targets);
}, delay); },delay);
} }
return true; return true;
} }

View File

@@ -189,6 +189,10 @@ export class TalComp extends ecs.Comp {
} }
} }
//执行天赋触发效果 //执行天赋触发效果
// 功能:
// - 根据天赋类型执行相应的效果
// - 支持计数型和数值型天赋
// --heroAttrs.addTalent 是计数型天赋buff heroAttrs.addTalBuff 是数值型天赋buff
doTriggerTal(uuid: number) { doTriggerTal(uuid: number) {
// 检查天赋是否存在 // 检查天赋是否存在
if (!this.Tals[uuid]) { if (!this.Tals[uuid]) {
@@ -198,23 +202,38 @@ export class TalComp extends ecs.Comp {
const talent = this.Tals[uuid]; const talent = this.Tals[uuid];
const heroAttrs=this.ent.get(HeroAttrsComp); const heroAttrs=this.ent.get(HeroAttrsComp);
switch(talent.effet){ switch(talent.effet){
case TalEffet.ATK_DMG:
heroAttrs.addCountTal(TalEffet.ATK_DMG, talent.value + talent.value_add);
break;
case TalEffet.SKILL_DMG:
heroAttrs.addCountTal(TalEffet.SKILL_DMG, talent.value + talent.value_add);
break;
case TalEffet.LDMG:
heroAttrs.addCountTal(TalEffet.LDMG, talent.value + talent.value_add);
break;
case TalEffet.HP:
heroAttrs.add_hp(talent.value + talent.value_add,talent.vType == BType.VALUE);
break;
case TalEffet.MP:
heroAttrs.add_mp(talent.value + talent.value_add,talent.vType == BType.VALUE);
break;
case TalEffet.WFUNY: case TalEffet.WFUNY:
heroAttrs.addTalent(TalEffet.WFUNY, talent.value + talent.value_add); heroAttrs.addCountTal(TalEffet.WFUNY, talent.value + talent.value_add);
break; break;
case TalEffet.D_SKILL: case TalEffet.D_SKILL:
heroAttrs.addTalent(TalEffet.D_SKILL, talent.value + talent.value_add); heroAttrs.addCountTal(TalEffet.D_SKILL, talent.value + talent.value_add);
break; break;
case TalEffet.C_ATK: case TalEffet.C_ATK:
heroAttrs.addTalent(TalEffet.C_ATK, talent.value + talent.value_add); heroAttrs.addCountTal(TalEffet.C_ATK, talent.value + talent.value_add);
break; break;
case TalEffet.C_SKILL: case TalEffet.C_SKILL:
heroAttrs.addTalent(TalEffet.C_SKILL, talent.value + talent.value_add); heroAttrs.addCountTal(TalEffet.C_SKILL, talent.value + talent.value_add);
break; break;
case TalEffet.C_MSKILL: case TalEffet.C_MSKILL:
heroAttrs.addTalent(TalEffet.C_MSKILL, talent.value + talent.value_add); heroAttrs.addCountTal(TalEffet.C_MSKILL, talent.value + talent.value_add);
break; break;
case TalEffet.BUFF: case TalEffet.BUFF:
heroAttrs.addTalBuff(talent.uuid, talent.attrs, talent.vType, talent.value + talent.value_add); heroAttrs.addValueTal(talent.uuid, talent.attrs, talent.vType, talent.value + talent.value_add);
break; break;
} }
} }

View File

@@ -12,6 +12,8 @@ export class SDataCom extends ecs.Comp {
group:BoxSet=BoxSet.HERO group:BoxSet=BoxSet.HERO
fac: number = 0; // 0:hero 1:monster fac: number = 0; // 0:hero 1:monster
s_uuid:number=0 s_uuid:number=0
ext_dmg:number=0 //额外伤害
dmg_ratio:number=1 //伤害比例
hit_count:number=0 //击中数量 hit_count:number=0 //击中数量
reset() { reset() {
this.Attrs=null this.Attrs=null
@@ -20,6 +22,8 @@ export class SDataCom extends ecs.Comp {
this.s_uuid=0 this.s_uuid=0
this.caster=null this.caster=null
this.hit_count=0 this.hit_count=0
this.ext_dmg=0
this.dmg_ratio=1
} }
} }

View File

@@ -93,6 +93,7 @@ export class Skill extends ecs.Entity {
sDataCom.Attrs={...cAttrsComp.Attrs} sDataCom.Attrs={...cAttrsComp.Attrs}
sDataCom.s_uuid=s_uuid sDataCom.s_uuid=s_uuid
sDataCom.fac=cAttrsComp.fac sDataCom.fac=cAttrsComp.fac
sDataCom.ext_dmg=ext_dmg
} }
/** 模块资源释放 */ /** 模块资源释放 */

View File

@@ -201,10 +201,10 @@ console.log("道具1001数量:", itemInfo.result.data.count);
const talents = await WxCloudApi.getTalents(); const talents = await WxCloudApi.getTalents();
// 添加天赋点 // 添加天赋点
const result = await WxCloudApi.addTalent(1001, 1); const result = await WxCloudApi.addCountTal(1001, 1);
// 消耗天赋点 // 消耗天赋点
const result = await WxCloudApi.consumeTalent(1001, 1); const result = await WxCloudApi.useCountTal(1001, 1);
``` ```
### 装备操作 ### 装备操作

View File

@@ -1,15 +0,0 @@
md extensions
cd extensions
IF EXIST oops-plugin-framework (
goto update
) ELSE (
goto clone
)
:clone
git clone -b master https://gitee.com/dgflash/oops-plugin-framework.git
:update
cd oops-plugin-framework
git pull