Compare commits
10 Commits
df3ad88c3e
...
oh/0_7_1
| Author | SHA1 | Date | |
|---|---|---|---|
| f359eae788 | |||
| d3ca31fcfa | |||
| 509539760d | |||
| 7a7a6fa02c | |||
| 40c430546c | |||
| b2cc25b32b | |||
| 0692d58e01 | |||
| cdfcf1f8f1 | |||
| dcf739d093 | |||
| bbf8dbb8cb |
File diff suppressed because it is too large
Load Diff
@@ -35,4 +35,64 @@
|
|||||||
冰封: 目标无法移动和攻击(cd继续), 3秒后自动解冻
|
冰封: 目标无法移动和攻击(cd继续), 3秒后自动解冻
|
||||||
沉默: 目标一般技能和必杀技能技能cd清零
|
沉默: 目标一般技能和必杀技能技能cd清零
|
||||||
击晕: 目标无移动和cd暂停
|
击晕: 目标无移动和cd暂停
|
||||||
击退: 后退15像素,cd减少5点,
|
击退: 后退15像素,cd减少5点,
|
||||||
|
|
||||||
|
## 非关键成长三选一(示例池)
|
||||||
|
用于非关键的成长选项,提供小步稳定增益,不抢关键天赋存在感。数值为建议区间,可按实际平衡调整。
|
||||||
|
|
||||||
|
| 组别 | 选项A | 选项B | 选项C | 推荐数值范围 | 阶段建议 | 说明 |
|
||||||
|
| --- | --- | --- | --- | --- | --- | --- |
|
||||||
|
| 基础属性(点数) | 力量 +3 | 智力 +3 | 敏捷 +3 | +3 点 | 全阶段 | 走职业系数转化,稳定推动 HP/AP/MAP/AS 等 |
|
||||||
|
| 攻速系 | 攻速(AS) +10% | 技速(SS) +10% | 移速(SPEED) +8% | +8–12% | 中期 | 普攻/技能循环提速,维持心流 |
|
||||||
|
| 暴击系 | 暴击率(CRITICAL) +10% | 暴伤(CRITICAL_DMG) +15% | 命中(HIT) +8% | +8–15% | 中后期 | 命中稳态配合暴击上限,防过度摇摆 |
|
||||||
|
| 射击系 | 攻击距离(DIS) +10% | 作用范围(AOE) +10% | 穿透(PIERCE) +1 | +8–12% / +1 | 中期 | 影响站位与清杂效率,PIERCE建议≤2 |
|
||||||
|
| 生存上限 | 生命上限(HP_MAX) +10% | 护盾上限(SHIELD_MAX) +12% | 生命回复(HP_REGEN) +15% | +10–15% | 早期 | 提升容错,抗压波次优先出现 |
|
||||||
|
| 防御姿态 | 闪避(DODGE) +8% | 格挡(BLOCK) +10% | 减伤(DMG_RED) +10% | +8–10% | 中期 | 三防不叠加过猛,设软上限 50–60% |
|
||||||
|
| 元素抗性 | 冰抗(ICE_RES) +12% | 火抗(FIRE_RES) +12% | 风抗(WIND_RES) +12% | +10–12% | 中后期 | 元素场景针对性减伤,补短板 |
|
||||||
|
| 元素伤害 | 冰伤(ICE_POWER) +10% | 火伤(FIRE_POWER) +10% | 风伤(WIND_POWER) +10% | +8–10% | 中期 | 与技能元素类型联动,避免单系过度 |
|
||||||
|
| 控制概率 | 眩晕(STUN_CHANCE) +6% | 沉默(SILENCE_CHANCE) +6% | 减速(SLOW_CHANCE) +10% | +6–10% | 中期 | 软控为主,CD/停顿联动合理抑制强控链 |
|
||||||
|
| 妨害状态 | 冻结(FREEZE_CHANCE) +6% | 中毒(POISON_CHANCE) +8% | 燃烧(BURN_CHANCE) +8% | +6–8% | 中期 | 面向清杂、溃散,触发期望受控 |
|
||||||
|
| 蓝量循环 | 蓝上限(MP_MAX) +10% | 蓝回复(MP_REGEN) +15% | 吸蓝(MANASTEAL) +6% | +10–15% | 早中期 | 技能密度稳定来源,支撑法系 |
|
||||||
|
| 续航强化 | 吸血(LIFESTEAL) +6% | 治疗效果(HEAL_EFFECT) +12% | 护盾效果(SHIELD_UP) +12% | +6–12% | 中后期 | 对应不同生存风格,数值递减避免堆满 |
|
||||||
|
| 稳定系 | 命中(HIT) +10% | 控抗(CON_RES) +10% | 暴抗(CRITICAL_RESIST) +10% | +8–10% | 中后期 | 降低波动,克制高暴击/高控敌群 |
|
||||||
|
| 经济成长 | 经验(EXP_GAIN) +10% | 金币(GOLD_GAIN) +10% | 掉落(DROP_CHANCE) +8% | +8–10% | 转场期 | 低战力节点给经济,避免战斗失衡 |
|
||||||
|
| 复活保障 | 复活次数(REVIVE_COUNT) +1 | 无敌时间(INVINCIBLE_TIME) +1s | 复活时间(REVIVE_TIME) -10% | +1 / +1s / -10% | 后期 | 高压波次救命,不与关键天赋冲突 |
|
||||||
|
| 元素对抗 | 物抗(PHYS_RES) +10% | 魔抗(MAGIC_RES) +10% | 物伤加成(PHYS_POWER) +8% | +8–10% | 中后期 | 根据敌群构成动态出现 |
|
||||||
|
| 资源提效 | 技能持续(SKILL_DURATION) +8% | 范围(AOE) +10% | 技速(SS) +8% | +8–10% | 中期 | DOT/场控/召唤类技能收益更佳 |
|
||||||
|
|
||||||
|
## 设计理念
|
||||||
|
- 非关键增益:提供轻量、可叠加的稳定成长,不与关键三选一争夺注意力。
|
||||||
|
- ERG需求:存在(生存)–关系(交互与反馈)–成长(能力提升)均衡覆盖,维持心流。
|
||||||
|
- 小步快跑:每次选择形成可感知的小增量,累计 3–5 次后出现显著体感。
|
||||||
|
- 动态补偿:三选一含“补缺/增强/探索”三类,提高决策质量与多样性。
|
||||||
|
- 软上限与递减:概率类、穿透等设软上限并递减,避免极端堆叠破坏体验。
|
||||||
|
|
||||||
|
## 出现规则与阶段
|
||||||
|
- 频率:每 2–3 波或每升 2 级出现一次,单局给予 3–5 次非关键成长选择。
|
||||||
|
- 阶段:早期主生存与蓝量,中期主效率与控制,后期主稳定与复活保障。
|
||||||
|
- 去重:同池短时间不重复,鼓励构筑分散与策略多样性。
|
||||||
|
- 池权重:根据敌群/技能元素/职业类型动态调整池权重,提升贴合度。
|
||||||
|
|
||||||
|
## 数值与软上限建议
|
||||||
|
- 概率类软上限 50–60%,暴击率软上限 60–70%,穿透 ≤ 2。
|
||||||
|
- 递减系数:同类堆叠每层收益降低 15–30%,维持平衡与选择张力。
|
||||||
|
|
||||||
|
## IAA激励(可选)
|
||||||
|
- 单局一次:允许“刷新一次三选一”或“临时解锁第四备选(低权重强项)”。
|
||||||
|
- 公平性:激励数值较同池低 10–20%,避免破坏对局公平与关键天赋权重。
|
||||||
|
|
||||||
|
## 落地建议
|
||||||
|
- 配置复用:非关键三选一统一走天赋 `BUFF` 模式,即时或升级触发。
|
||||||
|
- 属性枚举:在 TalSet 的 `TalAttrs` 扩充基础属性(HP/MP/AS/SS/CRITICAL/HIT 等)。
|
||||||
|
- 阶段配表:按波次/等级给不同池的权重与范围,避免压制关键天赋。
|
||||||
|
- 上限与递减:对核心概率类与强度类属性设置软上限与递减曲线。
|
||||||
|
|
||||||
|
## 与代码映射(实现参考)
|
||||||
|
- 触发类型:可用升级或初始触发,见 `assets/script/game/common/config/TalSet.ts:7` 枚举。
|
||||||
|
- 效果类型:建议统一使用 `TalEffet.BUFF` + `vType(BType.VALUE/RATIO)`。
|
||||||
|
- 可选属性来源:`assets/script/game/common/config/HeroAttrs.ts:27–113` 定义完整 `Attrs`。
|
||||||
|
- 职业成长差异:`assets/script/game/common/config/HeroAttrs.ts:272–422` 提供成长系数。
|
||||||
|
- 攻速/技速影响CD:`assets/script/game/hero/HeroSkills.ts:139–158`。
|
||||||
|
- 命中/闪避/暴击联动:`assets/script/game/hero/HeroAtkSystem.ts:141–162`。
|
||||||
|
- 元素伤害与抗性修正:`assets/script/game/hero/HeroAtkSystem.ts:295–306`。
|
||||||
|
- 护盾吸收:`assets/script/game/hero/HeroAtkSystem.ts:422–450`。
|
||||||
|
|||||||
@@ -12,10 +12,10 @@ export enum BType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export enum NeAttrs {
|
export enum NeAttrs {
|
||||||
IN_FROST = 0,
|
IN_FROST = 0, // 冰冻状态
|
||||||
IN_STUN = 1,
|
IN_STUN = 1, // 眩晕状态
|
||||||
IN_BURN = 2,
|
IN_BURN = 2, // 灼烧状态
|
||||||
IN_POISON = 3,
|
IN_POISON = 3, // 中毒状态
|
||||||
}
|
}
|
||||||
|
|
||||||
// ========== 属性枚举 ==========
|
// ========== 属性枚举 ==========
|
||||||
@@ -48,7 +48,7 @@ export enum Attrs {
|
|||||||
MDEF = 21, // 魔法防御
|
MDEF = 21, // 魔法防御
|
||||||
DODGE = 22, // 闪避率
|
DODGE = 22, // 闪避率
|
||||||
BLOCK = 23, // 格挡率
|
BLOCK = 23, // 格挡率
|
||||||
DAMAGE_REDUCTION = 24, // 伤害减免
|
DMG_RED = 24, // 伤害减免
|
||||||
THORNS = 25, // 反伤
|
THORNS = 25, // 反伤
|
||||||
CRITICAL_RESIST = 26, // 暴击抗性
|
CRITICAL_RESIST = 26, // 暴击抗性
|
||||||
CON_RES = 27, // 控制抗性
|
CON_RES = 27, // 控制抗性
|
||||||
@@ -102,11 +102,9 @@ export enum Attrs {
|
|||||||
BURN = 75, // 易伤效果
|
BURN = 75, // 易伤效果
|
||||||
WFUNY = 77, // 风怒
|
WFUNY = 77, // 风怒
|
||||||
|
|
||||||
// ========== 生存与恢复相关 (80-89) ==========
|
// ========== 负面状态相关 (80-89) ==========
|
||||||
|
DMG_INVUL = 80, //易伤
|
||||||
// ========== 负面状态相关 (90-99) ==========
|
// ========== 基础属性(影响其他属性) (90-99)==========
|
||||||
|
|
||||||
// ========== 基础属性(影响其他属性)(100-104) ==========
|
|
||||||
STRENGTH = 90, // 力量(影响物理相关)
|
STRENGTH = 90, // 力量(影响物理相关)
|
||||||
INTELLIGENCE = 91, // 智力(影响魔法相关)
|
INTELLIGENCE = 91, // 智力(影响魔法相关)
|
||||||
AGILITY = 92, // 敏捷(影响速度和闪避)
|
AGILITY = 92, // 敏捷(影响速度和闪避)
|
||||||
@@ -173,7 +171,7 @@ export const AttrsType: Record<Attrs, BType> = {
|
|||||||
[Attrs.MDEF]: BType.VALUE, // 魔法防御 - 数值型
|
[Attrs.MDEF]: BType.VALUE, // 魔法防御 - 数值型
|
||||||
[Attrs.DODGE]: BType.RATIO, // 闪避率 - 百分比型
|
[Attrs.DODGE]: BType.RATIO, // 闪避率 - 百分比型
|
||||||
[Attrs.BLOCK]: BType.RATIO, // 格挡率 - 百分比型
|
[Attrs.BLOCK]: BType.RATIO, // 格挡率 - 百分比型
|
||||||
[Attrs.DAMAGE_REDUCTION]: BType.RATIO, // 伤害减免 - 百分比型
|
[Attrs.DMG_RED]: BType.RATIO, // 伤害减免 - 百分比型
|
||||||
[Attrs.THORNS]: BType.RATIO, // 反伤 - 百分比型
|
[Attrs.THORNS]: BType.RATIO, // 反伤 - 百分比型
|
||||||
|
|
||||||
// ========== 暴击与命中属性(百分比型) ==========
|
// ========== 暴击与命中属性(百分比型) ==========
|
||||||
@@ -227,9 +225,9 @@ export const AttrsType: Record<Attrs, BType> = {
|
|||||||
[Attrs.BURN]: BType.RATIO, // 易伤效果 - 百分比型
|
[Attrs.BURN]: BType.RATIO, // 易伤效果 - 百分比型
|
||||||
[Attrs.WFUNY]: BType.RATIO, // 未知特殊属性 - 百分比型
|
[Attrs.WFUNY]: BType.RATIO, // 未知特殊属性 - 百分比型
|
||||||
|
|
||||||
// ========== 生存与恢复相关(混合类型) ==========
|
|
||||||
|
|
||||||
// ========== 负面状态相关(混合类型) ==========
|
// ========== 负面状态相关(混合类型) ==========
|
||||||
|
[Attrs.DMG_INVUL]: BType.RATIO, //易伤
|
||||||
|
|
||||||
// ========== 基础属性(数值型) ==========
|
// ========== 基础属性(数值型) ==========
|
||||||
[Attrs.STRENGTH]: BType.VALUE, // 力量 - 数值型
|
[Attrs.STRENGTH]: BType.VALUE, // 力量 - 数值型
|
||||||
|
|||||||
@@ -158,6 +158,10 @@ export interface SkillConfig {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const SkillSet: Record<number, SkillConfig> = {
|
export const SkillSet: Record<number, SkillConfig> = {
|
||||||
|
5000:{uuid:5000,name:"反伤",sp_name:"thorns",icon:"3036",TGroup:TGroup.Enemy,SType:SType.damage,act:"atk",DTType:DTType.single,DType:DType.ATK,
|
||||||
|
ap:0,map:0,cd:0,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:"反伤",
|
||||||
|
},
|
||||||
// ========== 基础攻击 ========== 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,
|
||||||
|
|||||||
@@ -19,19 +19,24 @@ export enum TriType {
|
|||||||
|
|
||||||
|
|
||||||
export enum TalEffet {
|
export enum TalEffet {
|
||||||
ATK_DMG=1, // 伤害
|
ATK_DMG=1, // 伤害 次数+伤害加成,如额外5次 伤害+20%
|
||||||
SKILL_DMG=2, // 技能伤害
|
SKILL_DMG=2, // 技能伤害 次数+伤害加成,如额外5次 伤害+20%
|
||||||
HP=3, // 回血 百分比
|
DMG_RED=10, // 减伤 次数+减伤加成,如额外5次 伤害-20%
|
||||||
MP=4, //回蓝 百分比
|
THORNS=14, //反伤 百分比 次数+反伤加成,如额外5次 反伤-20%
|
||||||
BUFF = 5, // 暴击率,闪避率等,可叠加的触发后清零
|
///////////////////////////////////////////////////////////////////////
|
||||||
STATS=6, // 状态
|
HP=3, // 回血 百分比 直接触发,回血20%
|
||||||
WFUNY=7, // 风怒
|
MP=4, //回蓝 百分比 直接触发,回蓝20%
|
||||||
D_SKILL=8, //两次技能
|
SHIELD=9, // 护盾 直接触发,获得20%的生命值护盾
|
||||||
SHIELD=9, // 护盾
|
////////////////////////////////////////////////////////////////////////
|
||||||
LDMG=10, // 减伤
|
BUFF = 5, // 数值叠加 触发后清零: 暴击率,闪避率等,触发后效果取消
|
||||||
C_MSKILL=11, // 必杀技能必暴
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
C_ATK=12, // 普工必爆
|
STATS=6, // 状态 待定
|
||||||
C_SKILL=13, // 一般技能必暴
|
|
||||||
|
WFUNY=7, // 风怒 次数 叠加 ,如额外5次 风怒
|
||||||
|
D_SKILL=8, //两次技能 次数 叠加,如额外5次 两次技能
|
||||||
|
C_MSKILL=11, // 必杀技能必暴 次数 叠加 ,如额外5次 必杀技能必暴
|
||||||
|
C_ATK=12, // 普工必爆 次数 叠加 ,如额外5次 普工必爆
|
||||||
|
C_SKILL=13, // 一般技能必暴 次数 叠加 ,如额外5次 一般技能必暴
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum TalTarget {
|
export enum TalTarget {
|
||||||
@@ -47,7 +52,7 @@ export enum TalAttrs {
|
|||||||
SILENCE_CHANCE=Attrs.SILENCE_CHANCE, // 沉默概率
|
SILENCE_CHANCE=Attrs.SILENCE_CHANCE, // 沉默概率
|
||||||
CRITICAL=Attrs.CRITICAL, // 暴击率
|
CRITICAL=Attrs.CRITICAL, // 暴击率
|
||||||
AP=Attrs.AP, // 攻击力
|
AP=Attrs.AP, // 攻击力
|
||||||
MP=Attrs.MAP, // 魔法
|
MP=Attrs.MAP, // 魔法攻击力
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* 天赋配置接口
|
* 天赋配置接口
|
||||||
@@ -111,7 +116,7 @@ export const talConf: Record<number, ItalConf> = {
|
|||||||
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%的生命值护盾"},
|
||||||
7103:{uuid:7103,name:"减伤",triType:TriType.DMG,Trigger:3,count:1,target:TalTarget.ENEMY,effet:TalEffet.LDMG,vType:BType.RATIO, value:50,attrs:TalAttrs.NON,
|
7103:{uuid:7103,name:"减伤",triType:TriType.DMG,Trigger:3,count:1,target:TalTarget.ENEMY,effet:TalEffet.DMG_RED,vType:BType.RATIO, value:50,attrs:TalAttrs.NON,
|
||||||
desc:"被攻击3次后, 下1次伤害减50%"},
|
desc:"被攻击3次后, 下1次伤害减50%"},
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -21,6 +21,9 @@ export interface DamageEvent {
|
|||||||
|
|
||||||
/** 伤害事件ID(用于去重和调试) */
|
/** 伤害事件ID(用于去重和调试) */
|
||||||
eventId: string;
|
eventId: string;
|
||||||
|
|
||||||
|
ext_dmg:number //额外伤害
|
||||||
|
dmg_ratio:number//伤害比例
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -55,7 +58,7 @@ export class DamageQueueComp extends ecs.Comp {
|
|||||||
/**
|
/**
|
||||||
* 添加伤害事件到队列
|
* 添加伤害事件到队列
|
||||||
*/
|
*/
|
||||||
addDamageEvent(attrs: any, caster: HeroViewComp, s_uuid: number): void {
|
addDamageEvent(attrs: any, caster: HeroViewComp, s_uuid: number,ext_dmg:number=0,dmg_ratio:number=1): void {
|
||||||
const timestamp = Date.now();
|
const timestamp = Date.now();
|
||||||
const eventId = `${caster.ent.eid}_${s_uuid}_${timestamp}_${Math.random()}`;
|
const eventId = `${caster.ent.eid}_${s_uuid}_${timestamp}_${Math.random()}`;
|
||||||
|
|
||||||
@@ -64,7 +67,9 @@ export class DamageQueueComp extends ecs.Comp {
|
|||||||
caster: caster,
|
caster: caster,
|
||||||
s_uuid: s_uuid,
|
s_uuid: s_uuid,
|
||||||
timestamp: timestamp,
|
timestamp: timestamp,
|
||||||
eventId: eventId
|
eventId: eventId,
|
||||||
|
ext_dmg:ext_dmg,
|
||||||
|
dmg_ratio:dmg_ratio,
|
||||||
};
|
};
|
||||||
|
|
||||||
this.damageEvents.push(damageEvent);
|
this.damageEvents.push(damageEvent);
|
||||||
@@ -155,7 +160,7 @@ export class DamageQueueHelper {
|
|||||||
* 为实体添加伤害事件
|
* 为实体添加伤害事件
|
||||||
* 如果实体没有伤害队列组件,会自动创建
|
* 如果实体没有伤害队列组件,会自动创建
|
||||||
*/
|
*/
|
||||||
static addDamageToEntity(entity: ecs.Entity, attrs: any, caster: HeroViewComp, s_uuid: number): void {
|
static addDamageToEntity(entity: ecs.Entity, attrs: any, caster: HeroViewComp, s_uuid: number,ext_dmg:number=0,dmg_ratio:number=1): void {
|
||||||
let damageQueue = entity.get(DamageQueueComp);
|
let damageQueue = entity.get(DamageQueueComp);
|
||||||
|
|
||||||
// 如果实体没有伤害队列组件,创建一个
|
// 如果实体没有伤害队列组件,创建一个
|
||||||
@@ -164,7 +169,7 @@ export class DamageQueueHelper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 添加伤害事件到队列
|
// 添加伤害事件到队列
|
||||||
damageQueue.addDamageEvent(attrs, caster, s_uuid);
|
damageQueue.addDamageEvent(attrs, caster, s_uuid,ext_dmg,dmg_ratio);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import { FightSet } from "../common/config/GameSet";
|
|||||||
import { SkillSet, DType } 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 } from "./DamageQueueComp";
|
||||||
import { smc } from "../common/SingletonModuleComp";
|
import { smc } from "../common/SingletonModuleComp";
|
||||||
|
|
||||||
|
|
||||||
@@ -30,7 +30,7 @@ interface FinalData {
|
|||||||
*
|
*
|
||||||
* 重要概念:
|
* 重要概念:
|
||||||
* - damageEvent.Attrs: 施法者属性快照(创建技能时保存)
|
* - damageEvent.Attrs: 施法者属性快照(创建技能时保存)
|
||||||
* - targetAttrs: 被攻击者实时属性
|
* - TAttrsComp: 被攻击者实时属性
|
||||||
* - 属性来源规范:攻击判定用施法者,防御判定用被攻击者
|
* - 属性来源规范:攻击判定用施法者,防御判定用被攻击者
|
||||||
*/
|
*/
|
||||||
@ecs.register('HeroAtkSystem')
|
@ecs.register('HeroAtkSystem')
|
||||||
@@ -51,10 +51,10 @@ export class HeroAtkSystem extends ecs.ComblockSystem implements ecs.ISystemUpd
|
|||||||
*/
|
*/
|
||||||
update(e: ecs.Entity): void {
|
update(e: ecs.Entity): void {
|
||||||
if(!smc.mission.play || smc.mission.pause) return;
|
if(!smc.mission.play || smc.mission.pause) return;
|
||||||
const model = e.get(HeroAttrsComp);
|
const TAttrsComp = e.get(HeroAttrsComp);
|
||||||
const damageQueue = e.get(DamageQueueComp);
|
const damageQueue = e.get(DamageQueueComp);
|
||||||
|
|
||||||
if (!model || !damageQueue || damageQueue.isEmpty()) return;
|
if (!TAttrsComp || !damageQueue || damageQueue.isEmpty()) return;
|
||||||
|
|
||||||
// 标记正在处理
|
// 标记正在处理
|
||||||
damageQueue.isProcessing = true;
|
damageQueue.isProcessing = true;
|
||||||
@@ -66,20 +66,13 @@ export class HeroAtkSystem extends ecs.ComblockSystem implements ecs.ISystemUpd
|
|||||||
if (!damageEvent) break;
|
if (!damageEvent) break;
|
||||||
|
|
||||||
// 处理单个伤害事件
|
// 处理单个伤害事件
|
||||||
const FDData = this.doAttack(e, damageEvent);
|
this.doAttack(e, damageEvent);
|
||||||
processedCount++;
|
processedCount++;
|
||||||
damageQueue.processedCount++;
|
damageQueue.processedCount++;
|
||||||
|
|
||||||
if (this.debugMode) {
|
|
||||||
const casterName = damageEvent.caster?.ent?.get(HeroAttrsComp)?.hero_name || "未知";
|
|
||||||
const casterUuid = damageEvent.caster?.ent?.get(HeroAttrsComp)?.hero_uuid || 0;
|
|
||||||
console.log(`[HeroAtkSystem] 英雄${model.hero_name} (uuid: ${model.hero_uuid}) 受到 ${casterName}(uuid: ${casterUuid})的 伤害 ${FDData.damage},${FDData.isCrit?"暴击":"普通"}攻击,技能ID ${damageEvent.s_uuid}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 如果目标已死亡,停止处理后续伤害
|
// 如果目标已死亡,停止处理后续伤害
|
||||||
if (model.is_dead) {
|
if (TAttrsComp.is_dead) {
|
||||||
if (this.debugMode) {
|
if (this.debugMode) {
|
||||||
console.log(`[HeroAtkSystem] ${model.hero_name} 已死亡,停止处理剩余伤害`);
|
console.log(`[HeroAtkSystem] ${TAttrsComp.hero_name} 已死亡,停止处理剩余伤害`);
|
||||||
}
|
}
|
||||||
damageQueue.clear(); // 清空剩余伤害
|
damageQueue.clear(); // 清空剩余伤害
|
||||||
break;
|
break;
|
||||||
@@ -91,7 +84,7 @@ export class HeroAtkSystem extends ecs.ComblockSystem implements ecs.ISystemUpd
|
|||||||
e.remove(DamageQueueComp);
|
e.remove(DamageQueueComp);
|
||||||
|
|
||||||
if (this.debugMode && processedCount > 0) {
|
if (this.debugMode && processedCount > 0) {
|
||||||
console.log(`[HeroAtkSystem] ${model.hero_name} 伤害队列处理完成,共处理 ${processedCount} 个伤害事件`);
|
console.log(`[HeroAtkSystem] ${TAttrsComp.hero_name} 伤害队列处理完成,共处理 ${processedCount} 个伤害事件`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -109,7 +102,7 @@ export class HeroAtkSystem extends ecs.ComblockSystem implements ecs.ISystemUpd
|
|||||||
* - HIT: 命中率(用于闪避计算)
|
* - HIT: 命中率(用于闪避计算)
|
||||||
* - AP/MAP: 攻击力(基础伤害计算)
|
* - AP/MAP: 攻击力(基础伤害计算)
|
||||||
*
|
*
|
||||||
* ✅ 正确使用被攻击者属性(targetAttrs - 实时):
|
* ✅ 正确使用被攻击者属性(TAttrsComp - 实时):
|
||||||
* - DODGE: 闪避率(用于闪避计算)
|
* - DODGE: 闪避率(用于闪避计算)
|
||||||
* - SHIELD_MAX: 护盾最大值(护盾吸收)
|
* - SHIELD_MAX: 护盾最大值(护盾吸收)
|
||||||
* - hp: 当前生命值(伤害应用)
|
* - hp: 当前生命值(伤害应用)
|
||||||
@@ -124,17 +117,17 @@ export class HeroAtkSystem extends ecs.ComblockSystem implements ecs.ISystemUpd
|
|||||||
* @returns 最终伤害数据(包含伤害值、暴击标记、闪避标记)
|
* @returns 最终伤害数据(包含伤害值、暴击标记、闪避标记)
|
||||||
*/
|
*/
|
||||||
private doAttack(target: ecs.Entity, damageEvent: DamageEvent): FinalData {
|
private doAttack(target: ecs.Entity, damageEvent: DamageEvent): FinalData {
|
||||||
const targetAttrs = target.get(HeroAttrsComp);
|
const TAttrsComp = target.get(HeroAttrsComp);
|
||||||
const targetView = target.get(HeroViewComp);
|
const targetView = target.get(HeroViewComp);
|
||||||
let reDate:FinalData={
|
let reDate:FinalData={
|
||||||
damage:0,
|
damage:0,
|
||||||
isCrit:false,
|
isCrit:false,
|
||||||
isDodge:false,
|
isDodge:false,
|
||||||
}
|
}
|
||||||
if (!targetAttrs || targetAttrs.is_dead) return reDate;
|
if (!TAttrsComp || TAttrsComp.is_dead) return reDate;
|
||||||
|
|
||||||
const caster = damageEvent.caster;
|
const caster = damageEvent.caster;
|
||||||
const attackerModel = caster?.ent?.get(HeroAttrsComp);
|
const CAttrsComp = caster?.ent?.get(HeroAttrsComp);
|
||||||
|
|
||||||
// 获取技能配置
|
// 获取技能配置
|
||||||
const skillConf = SkillSet[damageEvent.s_uuid];
|
const skillConf = SkillSet[damageEvent.s_uuid];
|
||||||
@@ -145,20 +138,20 @@ export class HeroAtkSystem extends ecs.ComblockSystem implements ecs.ISystemUpd
|
|||||||
|
|
||||||
// 闪避判定
|
// 闪避判定
|
||||||
// 闪避成功概率 = 被攻击者闪避率 - 施法者命中率
|
// 闪避成功概率 = 被攻击者闪避率 - 施法者命中率
|
||||||
// targetAttrs.Attrs[Attrs.DODGE]: 被攻击者的实时闪避属性
|
// TAttrsComp.Attrs[Attrs.DODGE]: 被攻击者的实时闪避属性
|
||||||
// damageEvent.Attrs[Attrs.HIT]: 施法者在技能创建时的命中属性快照
|
// damageEvent.Attrs[Attrs.HIT]: 施法者在技能创建时的命中属性快照
|
||||||
const isDodge =this.checkChance((targetAttrs.Attrs[Attrs.DODGE]-damageEvent.Attrs[Attrs.HIT]) || 0);
|
const isDodge =this.checkChance((TAttrsComp.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 快照)
|
// 使用施法者的暴击率属性(damageEvent.Attrs 快照),- 被攻击者的暴击抗性属性TAttrsComp.Attrs[Attrs.CRITICAL_RESIST]
|
||||||
const isCrit = this.checkChance(damageEvent.Attrs[Attrs.CRITICAL]);
|
const isCrit = this.checkChance(damageEvent.Attrs[Attrs.CRITICAL]-TAttrsComp.Attrs[Attrs.CRITICAL_RESIST]);
|
||||||
if (isCrit) attackerModel?.useValueTalByAttr(Attrs.CRITICAL); // 清除施法者的暴击buff
|
// 计算基础伤害
|
||||||
// 计算伤害
|
let damage = this.dmgCount(damageEvent,TAttrsComp);
|
||||||
let damage = this.dmgCount(damageEvent,targetAttrs.Attrs);
|
if (this.debugMode) console.log("[HeroAtkSystem] dmgCount",damage)
|
||||||
if (isCrit) {
|
if (isCrit) {
|
||||||
// 暴击伤害计算
|
// 暴击伤害计算
|
||||||
// 使用施法者的暴击伤害加成属性(damageEvent.Attrs 快照)
|
// 使用施法者的暴击伤害加成属性(damageEvent.Attrs 快照)
|
||||||
@@ -166,20 +159,28 @@ export class HeroAtkSystem extends ecs.ComblockSystem implements ecs.ISystemUpd
|
|||||||
const casterCritDmg = damageEvent.Attrs[Attrs.CRITICAL_DMG] || 0;
|
const casterCritDmg = damageEvent.Attrs[Attrs.CRITICAL_DMG] || 0;
|
||||||
damage = Math.floor(damage * (1 + (FightSet.CRIT_DAMAGE + casterCritDmg) / 100));
|
damage = Math.floor(damage * (1 + (FightSet.CRIT_DAMAGE + casterCritDmg) / 100));
|
||||||
reDate.isCrit=true;
|
reDate.isCrit=true;
|
||||||
|
CAttrsComp?.useValueTalByAttr(Attrs.CRITICAL); // 清除施法者的暴击buff
|
||||||
|
|
||||||
}
|
}
|
||||||
// 伤害计算(考虑易伤等debuff)
|
if (this.debugMode) console.log("[HeroAtkSystem] after crit",damage)
|
||||||
damage = this.calculateDamage(targetAttrs, damage);
|
|
||||||
// 护盾吸收
|
// 护盾吸收
|
||||||
damage =Math.floor(this.absorbShield(targetAttrs, damage))
|
damage =Math.floor(this.absorbShield(TAttrsComp, damage))
|
||||||
|
if (this.debugMode) console.log("[HeroAtkSystem] after shield",damage)
|
||||||
if (damage <= 0) return reDate;
|
if (damage <= 0) return reDate;
|
||||||
// 应用伤害到数据层
|
// 应用伤害到数据层
|
||||||
targetAttrs.hp -= damage;
|
TAttrsComp.hp -= damage;
|
||||||
targetAttrs.atked_count++;
|
if (this.debugMode) {
|
||||||
|
const casterName = damageEvent.caster?.ent?.get(HeroAttrsComp)?.hero_name || "未知";
|
||||||
|
const casterUuid = damageEvent.caster?.ent?.get(HeroAttrsComp)?.hero_uuid || 0;
|
||||||
|
console.log(`[HeroAtkSystem] 英雄${TAttrsComp.hero_name} (uuid: ${TAttrsComp.hero_uuid}) 受到 ${casterName}(uuid: ${casterUuid})的 伤害 ${damage},${isCrit?"暴击":"普通"}攻击,技能ID ${damageEvent.s_uuid}`);
|
||||||
|
}
|
||||||
|
//反伤判定 并应用到施法者
|
||||||
|
this.check_thorns(TAttrsComp, caster?.ent,damage);
|
||||||
// 击退判定
|
// 击退判定
|
||||||
// 使用施法者的击退概率属性(damageEvent.Attrs 快照)
|
// 使用施法者的击退概率属性(damageEvent.Attrs 快照)
|
||||||
// 击退成功后需要清理施法者的相关天赋buff
|
// 击退成功后需要清理施法者的相关天赋buff
|
||||||
const isBack = this.checkChance(damageEvent.Attrs[Attrs.BACK_CHANCE] || 0);
|
const isBack = this.checkChance(damageEvent.Attrs[Attrs.BACK_CHANCE] || 0);
|
||||||
if (isBack) attackerModel?.useValueTalByAttr(Attrs.BACK_CHANCE);
|
if (isBack) CAttrsComp?.useValueTalByAttr(Attrs.BACK_CHANCE);
|
||||||
|
|
||||||
|
|
||||||
// ✅ 触发视图层表现(伤害数字、受击动画、后退)
|
// ✅ 触发视图层表现(伤害数字、受击动画、后退)
|
||||||
@@ -187,7 +188,9 @@ export class HeroAtkSystem extends ecs.ComblockSystem implements ecs.ISystemUpd
|
|||||||
|
|
||||||
|
|
||||||
// 检查死亡
|
// 检查死亡
|
||||||
if (targetAttrs.hp <= 0) {
|
if (TAttrsComp.hp <= 0) {
|
||||||
|
// 增加被击杀计数
|
||||||
|
if (caster) CAttrsComp.Attrs.killed_count++;
|
||||||
this.doDead(target);
|
this.doDead(target);
|
||||||
// ✅ 触发死亡视图表现
|
// ✅ 触发死亡视图表现
|
||||||
if (targetView) {
|
if (targetView) {
|
||||||
@@ -195,13 +198,37 @@ export class HeroAtkSystem extends ecs.ComblockSystem implements ecs.ISystemUpd
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.debugMode) {
|
if (this.debugMode) console.log(`[HeroAtkSystem] ${TAttrsComp.hero_name} 受到 ${damage} 点伤害 (暴击: ${isCrit})`);
|
||||||
console.log(`[HeroAtkSystem] ${targetAttrs.hero_name} 受到 ${damage} 点伤害 (暴击: ${isCrit})`);
|
|
||||||
}
|
|
||||||
|
|
||||||
reDate.damage=damage;
|
reDate.damage=damage;
|
||||||
return reDate;
|
return reDate;
|
||||||
}
|
}
|
||||||
|
check_thorns(TAttrsComp:HeroAttrsComp, caster: ecs.Entity, damage:number) {
|
||||||
|
// 检查目标是否有反伤属性,这里受伤的时时施法者
|
||||||
|
if (!caster||damage<=0) return;
|
||||||
|
let thornsDamage=0;
|
||||||
|
thornsDamage=TAttrsComp.Attrs[Attrs.THORNS]||0+TAttrsComp.useCountValTal(Attrs.THORNS);
|
||||||
|
let CAttrs=caster.get(HeroAttrsComp);
|
||||||
|
// 计算反伤伤害
|
||||||
|
let thornsDmg=Math.floor(thornsDamage*damage/100);
|
||||||
|
// 应用反伤伤害到数据层
|
||||||
|
CAttrs.hp -= thornsDmg;
|
||||||
|
CAttrs.atked_count++;
|
||||||
|
let CView=caster.get(HeroViewComp);
|
||||||
|
// ✅ 触发视图层表现(伤害数字、受击动画、后退)
|
||||||
|
if (CView) CView.do_atked(thornsDmg, false, SkillSet[5000].uuid, false);
|
||||||
|
// 检查死亡
|
||||||
|
if (CAttrs.hp <= 0) {
|
||||||
|
this.doDead(caster);
|
||||||
|
// 增加击杀计数
|
||||||
|
if (caster) TAttrsComp.Attrs.killed_count++;
|
||||||
|
// ✅ 触发死亡视图表现
|
||||||
|
if (CView) {
|
||||||
|
CView.do_dead();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* 详细伤害计算核心方法
|
* 详细伤害计算核心方法
|
||||||
*
|
*
|
||||||
@@ -228,18 +255,21 @@ export class HeroAtkSystem extends ecs.ComblockSystem implements ecs.ISystemUpd
|
|||||||
* - 所有除法和乘法计算后都进行取整操作,确保游戏中的伤害值为整数
|
* - 所有除法和乘法计算后都进行取整操作,确保游戏中的伤害值为整数
|
||||||
* - 元素伤害只应用于魔法伤害部分
|
* - 元素伤害只应用于魔法伤害部分
|
||||||
*/
|
*/
|
||||||
private dmgCount(damageEvent:any,TAttrs:any){
|
private dmgCount(damageEvent:DamageEvent,TAttrsComp:HeroAttrsComp){
|
||||||
// 1. 获取技能配置 - 如果技能不存在,直接返回0伤害
|
// 1. 获取技能配置 - 如果技能不存在,直接返回0伤害
|
||||||
const CAttrs=damageEvent.Attrs;
|
const CAttrs=damageEvent.Attrs;
|
||||||
|
const TAttrs=TAttrsComp.Attrs;
|
||||||
let sConf = SkillSet[damageEvent.s_uuid];
|
let sConf = SkillSet[damageEvent.s_uuid];
|
||||||
if (!sConf) return 0;
|
if (!sConf) return 0;
|
||||||
|
if (this.debugMode) console.log(`[HeroAtkSystem] 伤害处理对象`,CAttrs,TAttrs);
|
||||||
// 2. 计算原始物理伤害和魔法伤害
|
// 2. 计算原始物理伤害和魔法伤害
|
||||||
// 物理伤害基础值 = 技能物理倍率 * (施法者物理攻击力 + 额外物理伤害) / 100 * 伤害比例
|
// 物理伤害基础值 = 技能物理倍率 * (施法者物理攻击力 + 额外伤害) / 100 * 额外伤害比例
|
||||||
let apBase = (sConf.ap||0)*(CAttrs[Attrs.AP]+damageEvent.ext_dmg)/100*damageEvent.dmg_ratio;
|
let apBase = (sConf.ap||0)*(CAttrs[Attrs.AP]+damageEvent.ext_dmg)/100*damageEvent.dmg_ratio;
|
||||||
// 魔法伤害基础值 = 技能魔法倍率 * (施法者魔法攻击力 + 额外魔法伤害) / 100 * 伤害比例
|
// 魔法伤害基础值 = 技能魔法倍率 * (施法者魔法攻击力 + 额外伤害) / 100 * 额外伤害比例
|
||||||
let mapBase = (sConf.map||0)*(CAttrs[Attrs.MAP]+damageEvent.ext_dmg)/100*damageEvent.dmg_ratio;
|
let mapBase = (sConf.map||0)*(CAttrs[Attrs.MAP]+damageEvent.ext_dmg)/100*damageEvent.dmg_ratio;
|
||||||
|
if (this.debugMode) console.log(`[HeroAtkSystem] 物理伤害基础值: ${apBase}, 技能ap=${sConf.ap},施法者物理攻击力: ${CAttrs[Attrs.AP]}, 魔法伤害基础值: ${mapBase}技能map=${sConf.map}
|
||||||
|
额外伤害:${damageEvent.ext_dmg}, 额外伤害比例:${damageEvent.dmg_ratio}`);
|
||||||
|
|
||||||
// 3. 获取目标防御属性
|
// 3. 获取目标防御属性
|
||||||
const def = (TAttrs[Attrs.DEF]||0); // 目标物理防御
|
const def = (TAttrs[Attrs.DEF]||0); // 目标物理防御
|
||||||
const mdef = (TAttrs[Attrs.MDEF]||0); // 目标魔法防御
|
const mdef = (TAttrs[Attrs.MDEF]||0); // 目标魔法防御
|
||||||
@@ -252,12 +282,15 @@ export class HeroAtkSystem extends ecs.ComblockSystem implements ecs.ISystemUpd
|
|||||||
let apAfter = Math.floor(apBase * (1 - apRed)); // 物理伤害 - 防御减免
|
let apAfter = Math.floor(apBase * (1 - apRed)); // 物理伤害 - 防御减免
|
||||||
let mapAfter = Math.floor(mapBase * (1 - mapRed)); // 魔法伤害 - 防御减免
|
let mapAfter = Math.floor(mapBase * (1 - mapRed)); // 魔法伤害 - 防御减免
|
||||||
|
|
||||||
|
if (this.debugMode) console.log(`[HeroAtkSystem] 物理伤害基础值: ${apBase}, 物理伤害 - 防御减免: ${apAfter} 魔法伤害基础值: ${mapBase}, 魔法伤害 - 防御减免: ${mapAfter}`);
|
||||||
|
|
||||||
// 6. 应用物理/魔法攻击力和抗性修正
|
// 6. 应用物理/魔法攻击力和抗性修正
|
||||||
// 物理伤害修正:基础伤害 * (1 + 物理攻击力加成%) * (1 - 目标物理抗性%)
|
// 物理伤害修正:基础伤害 * (1 + 物理攻击力加成%) * (1 - 目标物理抗性%)
|
||||||
apAfter = this.applyPR(apAfter, CAttrs[Attrs.PHYS_POWER]||0, TAttrs[Attrs.PHYS_RES]||0);
|
apAfter = this.applyPR(apAfter, CAttrs[Attrs.PHYS_POWER]||0, TAttrs[Attrs.PHYS_RES]||0);
|
||||||
// 魔法伤害修正:基础伤害 * (1 + 魔法攻击力加成%) * (1 - 目标魔法抗性%)
|
// 魔法伤害修正:基础伤害 * (1 + 魔法攻击力加成%) * (1 - 目标魔法抗性%)
|
||||||
mapAfter = this.applyPR(mapAfter, CAttrs[Attrs.MAGIC_POWER]||0, TAttrs[Attrs.MAGIC_RES]||0);
|
mapAfter = this.applyPR(mapAfter, CAttrs[Attrs.MAGIC_POWER]||0, TAttrs[Attrs.MAGIC_RES]||0);
|
||||||
|
if (this.debugMode) console.log(`[HeroAtkSystem] 物理伤害修正后: ${apAfter} 魔法伤害修正后: ${mapAfter} `);
|
||||||
|
|
||||||
// 7. 根据技能元素类型,应用元素属性加成和抗性修正
|
// 7. 根据技能元素类型,应用元素属性加成和抗性修正
|
||||||
switch (sConf.DType) {
|
switch (sConf.DType) {
|
||||||
case DType.ICE:
|
case DType.ICE:
|
||||||
@@ -273,14 +306,19 @@ export class HeroAtkSystem extends ecs.ComblockSystem implements ecs.ISystemUpd
|
|||||||
mapAfter = this.applyPR(mapAfter, CAttrs[Attrs.WIND_POWER]||0, TAttrs[Attrs.WIND_RES]||0);
|
mapAfter = this.applyPR(mapAfter, CAttrs[Attrs.WIND_POWER]||0, TAttrs[Attrs.WIND_RES]||0);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
if (this.debugMode) console.log(`[HeroAtkSystem] 物理伤害修正后: ${apAfter} 元素伤害修正后: ${mapAfter}`);
|
||||||
|
|
||||||
// 8. 计算最终总伤害(物理伤害 + 魔法伤害)
|
// 8. 计算最终总伤害(物理伤害 + 魔法伤害)
|
||||||
let total = apAfter + mapAfter;
|
let total = apAfter + mapAfter;
|
||||||
|
//9.1 易伤
|
||||||
// 9. 应用最终伤害减免效果(如特殊天赋、buff等提供的减免)
|
let DMG_INVUL = TAttrs[Attrs.DMG_INVUL]||0
|
||||||
total = Math.floor(total * (1 - ((TAttrs[Attrs.DAMAGE_REDUCTION]||0)/100)));
|
//9.2 免伤 属性免伤+天赋免伤
|
||||||
|
let DMG_RED =TAttrs[Attrs.DMG_RED]||0+TAttrsComp.useCountValTal(Attrs.DMG_RED);
|
||||||
// 10. 确保伤害值非负,返回最终伤害
|
// 10. 确保伤害值非负,返回最终伤害
|
||||||
|
total = Math.max(0,total);
|
||||||
|
//11. 易伤减免 免伤属性免伤+天赋免伤
|
||||||
|
total = Math.floor(total * (1 + ((DMG_INVUL-DMG_RED)/100)));
|
||||||
|
if (this.debugMode) console.log(`[HeroAtkSystem] 易伤减免后: ${total}`);
|
||||||
return Math.max(0,total);
|
return Math.max(0,total);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -337,16 +375,16 @@ export class HeroAtkSystem extends ecs.ComblockSystem implements ecs.ISystemUpd
|
|||||||
* 这确保了死亡逻辑的单一性和一致性
|
* 这确保了死亡逻辑的单一性和一致性
|
||||||
*/
|
*/
|
||||||
private doDead(entity: ecs.Entity): void {
|
private doDead(entity: ecs.Entity): void {
|
||||||
const model = entity.get(HeroAttrsComp);
|
const TAttrsComp = entity.get(HeroAttrsComp);
|
||||||
if (!model || model.is_dead) return;
|
if (!TAttrsComp || TAttrsComp.is_dead) return;
|
||||||
|
|
||||||
model.is_dead = true;
|
TAttrsComp.is_dead = true;
|
||||||
|
|
||||||
// 触发死亡事件
|
// 触发死亡事件
|
||||||
this.onDeath(entity);
|
this.onDeath(entity);
|
||||||
|
|
||||||
if (this.debugMode) {
|
if (this.debugMode) {
|
||||||
console.log(`[HeroAtkSystem] ${model.hero_name} 死亡`);
|
console.log(`[HeroAtkSystem] ${TAttrsComp.hero_name} 死亡`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -380,24 +418,6 @@ export class HeroAtkSystem extends ecs.ComblockSystem implements ecs.ISystemUpd
|
|||||||
return r < rate;
|
return r < rate;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 伤害计算(考虑易伤等debuff)
|
|
||||||
*
|
|
||||||
* 预留的伤害计算扩展点,用于处理:
|
|
||||||
* - 被攻击者的易伤状态(增加受到伤害)
|
|
||||||
* - 被攻击者的伤害减免状态(减少受到伤害)
|
|
||||||
* - 元素抗性计算
|
|
||||||
* - 真实伤害/魔法伤害/物理伤害的类型区分
|
|
||||||
*
|
|
||||||
* @param model 被攻击者的属性组件(包含抗性、易伤等状态)
|
|
||||||
* @param baseDamage 基础伤害值
|
|
||||||
* @returns 最终伤害值(经过各种加成和减免后的结果)
|
|
||||||
*/
|
|
||||||
private calculateDamage(model: HeroAttrsComp, baseDamage: number): number {
|
|
||||||
// 这里可以添加易伤等debuff的计算逻辑
|
|
||||||
// 例如:如果目标有易伤buff,增加受到的伤害
|
|
||||||
return baseDamage;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 护盾吸收伤害
|
* 护盾吸收伤害
|
||||||
@@ -407,24 +427,24 @@ export class HeroAtkSystem extends ecs.ComblockSystem implements ecs.ISystemUpd
|
|||||||
* 2. 如果护盾值 < 伤害值:部分吸收,剩余伤害 = 原伤害 - 护盾值
|
* 2. 如果护盾值 < 伤害值:部分吸收,剩余伤害 = 原伤害 - 护盾值
|
||||||
* 3. 护盾被击破时,重置护盾最大值属性
|
* 3. 护盾被击破时,重置护盾最大值属性
|
||||||
*
|
*
|
||||||
* @param model 被攻击者的属性组件(包含当前护盾值)
|
* @param TAttrsComp 被攻击者的属性组件(包含当前护盾值)
|
||||||
* @param damage 原始伤害值
|
* @param damage 原始伤害值
|
||||||
* @returns 剩余伤害值(护盾吸收后的结果)
|
* @returns 剩余伤害值(护盾吸收后的结果)
|
||||||
*/
|
*/
|
||||||
private absorbShield(model: HeroAttrsComp, damage: number): number {
|
private absorbShield(TAttrsComp: HeroAttrsComp, damage: number): number {
|
||||||
if (model.shield <= 0) return damage;
|
if (TAttrsComp.shield <= 0) return damage;
|
||||||
|
|
||||||
if (model.shield >= damage) {
|
if (TAttrsComp.shield >= damage) {
|
||||||
model.shield -= damage;
|
TAttrsComp.shield -= damage;
|
||||||
if (model.shield <= 0) {
|
if (TAttrsComp.shield <= 0) {
|
||||||
model.shield = 0;
|
TAttrsComp.shield = 0;
|
||||||
model.Attrs[Attrs.SHIELD_MAX] = 0;
|
TAttrsComp.Attrs[Attrs.SHIELD_MAX] = 0;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
} else {
|
} else {
|
||||||
const remainingDamage = damage - model.shield;
|
const remainingDamage = damage - TAttrsComp.shield;
|
||||||
model.shield = 0;
|
TAttrsComp.shield = 0;
|
||||||
model.Attrs[Attrs.SHIELD_MAX] = 0;
|
TAttrsComp.Attrs[Attrs.SHIELD_MAX] = 0;
|
||||||
return remainingDamage;
|
return remainingDamage;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -442,11 +462,11 @@ export class HeroAtkSystem extends ecs.ComblockSystem implements ecs.ISystemUpd
|
|||||||
* @todo 当前对怪物实体直接返回,后续可以根据需求扩展怪物的被攻击逻辑
|
* @todo 当前对怪物实体直接返回,后续可以根据需求扩展怪物的被攻击逻辑
|
||||||
*/
|
*/
|
||||||
private onAttacked(entity: ecs.Entity): void {
|
private onAttacked(entity: ecs.Entity): void {
|
||||||
const model = entity.get(HeroAttrsComp);
|
const TAttrsComp = entity.get(HeroAttrsComp);
|
||||||
if (!model || model.is_dead) return;
|
if (!TAttrsComp || TAttrsComp.is_dead) return;
|
||||||
|
TAttrsComp.atked_count++;
|
||||||
// 这里可以添加被攻击时的特殊处理逻辑
|
// 这里可以添加被攻击时的特殊处理逻辑
|
||||||
if (model.fac === FacSet.MON) return;
|
if (TAttrsComp.fac === FacSet.MON) return;
|
||||||
|
|
||||||
// 例如:触发某些天赋效果、反击逻辑等
|
// 例如:触发某些天赋效果、反击逻辑等
|
||||||
}
|
}
|
||||||
@@ -470,13 +490,13 @@ export class HeroAtkSystem extends ecs.ComblockSystem implements ecs.ISystemUpd
|
|||||||
* @important 死亡事件应该幂等,避免重复触发
|
* @important 死亡事件应该幂等,避免重复触发
|
||||||
*/
|
*/
|
||||||
private onDeath(entity: ecs.Entity): void {
|
private onDeath(entity: ecs.Entity): void {
|
||||||
const model = entity.get(HeroAttrsComp);
|
const TAttrsComp = entity.get(HeroAttrsComp);
|
||||||
if (!model) return;
|
if (!TAttrsComp) return;
|
||||||
|
|
||||||
if (model.fac === FacSet.MON) {
|
if (TAttrsComp.fac === FacSet.MON) {
|
||||||
// 怪物死亡处理
|
// 怪物死亡处理
|
||||||
this.scheduleDrop(entity);
|
this.scheduleDrop(entity);
|
||||||
} else if (model.fac === FacSet.HERO) {
|
} else if (TAttrsComp.fac === FacSet.HERO) {
|
||||||
// 英雄死亡处理
|
// 英雄死亡处理
|
||||||
this.scheduleHeroDeath(entity);
|
this.scheduleHeroDeath(entity);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ export class HeroAttrsComp extends ecs.Comp {
|
|||||||
// ==================== 计数统计 ====================
|
// ==================== 计数统计 ====================
|
||||||
atk_count: number = 0; // 攻击次数
|
atk_count: number = 0; // 攻击次数
|
||||||
atked_count: number = 0; // 被攻击次数
|
atked_count: number = 0; // 被攻击次数
|
||||||
|
killed_count:number=0;
|
||||||
// 注意:技能数据已迁移到 HeroSkillsComp,不再存储在这里
|
// 注意:技能数据已迁移到 HeroSkillsComp,不再存储在这里
|
||||||
|
|
||||||
start(){
|
start(){
|
||||||
@@ -441,6 +441,13 @@ export class HeroAttrsComp extends ecs.Comp {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 添加数值型天赋buff 数值会进行累加,count 时叠加层数
|
||||||
|
* @param t_uuid 天赋唯一标识
|
||||||
|
* @param attrIndex 属性索引
|
||||||
|
* @param bType buff类型(VALUE:数值型, RATIO:百分比型)
|
||||||
|
* @param value buff值
|
||||||
|
*/
|
||||||
addValueTal(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];
|
||||||
@@ -452,6 +459,12 @@ export class HeroAttrsComp extends ecs.Comp {
|
|||||||
}
|
}
|
||||||
this.recalculateSingleAttr(attrIndex);
|
this.recalculateSingleAttr(attrIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 添加计数型天赋,每次添加数值已最新额覆盖久的,count为可用次数
|
||||||
|
* @param eff 天赋效果ID
|
||||||
|
* @param value 天赋值
|
||||||
|
*/
|
||||||
addCountTal(eff: number, value: number) {
|
addCountTal(eff: number, value: number) {
|
||||||
const t = this.Talents[eff] || { value: 0, count: 0 };
|
const t = this.Talents[eff] || { value: 0, count: 0 };
|
||||||
t.value = value;
|
t.value = value;
|
||||||
@@ -459,18 +472,34 @@ export class HeroAttrsComp extends ecs.Comp {
|
|||||||
this.Talents[eff] = t;
|
this.Talents[eff] = t;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 使用计数型天赋,如风怒 ,必爆等天赋,只需要返回是否暴击的,使用这个方法
|
||||||
|
* @param eff 天赋效果ID
|
||||||
|
* @returns 是否使用成功
|
||||||
|
*/
|
||||||
useCountTal(eff: number): boolean {
|
useCountTal(eff: number): boolean {
|
||||||
const t = this.Talents[eff];
|
const t = this.Talents[eff];
|
||||||
if (!t || t.count <= 0) return false;
|
if (!t || t.count <= 0) return false;
|
||||||
t.count -= 1;
|
t.count -= 1;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 使用计数型天赋并返回天赋值,如额外5次 伤害+20% ,5次受伤,免伤20% 使用这个方法
|
||||||
|
* @param eff 天赋效果ID
|
||||||
|
* @returns 天赋值
|
||||||
|
*/
|
||||||
useCountValTal(eff: number): number {
|
useCountValTal(eff: number): number {
|
||||||
const t = this.Talents[eff];
|
const t = this.Talents[eff];
|
||||||
if (!t || t.value <= 0) return 0;
|
if (!t || t.value <= 0) return 0;
|
||||||
t.count -= 1;
|
t.count -= 1;
|
||||||
return t.value;
|
return t.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据UUID移除数值型天赋buff
|
||||||
|
* @param t_uuid 天赋唯一标识
|
||||||
|
*/
|
||||||
useValueTalByUuid(t_uuid: number) {
|
useValueTalByUuid(t_uuid: number) {
|
||||||
const buff = this.BUFFS_TAL[t_uuid];
|
const buff = this.BUFFS_TAL[t_uuid];
|
||||||
if (!buff) return;
|
if (!buff) return;
|
||||||
@@ -478,6 +507,11 @@ export class HeroAttrsComp extends ecs.Comp {
|
|||||||
delete this.BUFFS_TAL[t_uuid];
|
delete this.BUFFS_TAL[t_uuid];
|
||||||
this.recalculateSingleAttr(attrIndex);
|
this.recalculateSingleAttr(attrIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据属性索引移除数值型天赋buff
|
||||||
|
* @param attrIndex 属性索引
|
||||||
|
*/
|
||||||
useValueTalByAttr(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) {
|
||||||
@@ -527,6 +561,7 @@ export class HeroAttrsComp extends ecs.Comp {
|
|||||||
this.is_kalami = false;
|
this.is_kalami = false;
|
||||||
this.atk_count = 0;
|
this.atk_count = 0;
|
||||||
this.atked_count = 0;
|
this.atked_count = 0;
|
||||||
|
this.killed_count =0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -26,6 +26,20 @@ export interface BuffInfo {
|
|||||||
@ccclass('HeroViewComp') // 定义Cocos Creator 组件
|
@ccclass('HeroViewComp') // 定义Cocos Creator 组件
|
||||||
@ecs.register('HeroView', false) // 定义ECS 组件
|
@ecs.register('HeroView', false) // 定义ECS 组件
|
||||||
export class HeroViewComp extends CCComp {
|
export class HeroViewComp extends CCComp {
|
||||||
|
private debugMode: boolean = true; // 是否启用调试模式
|
||||||
|
|
||||||
|
// 添加条件日志方法
|
||||||
|
private debugLog(...args: any[]): void {
|
||||||
|
if (this.debugMode) {
|
||||||
|
console.log(...args);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private debugWarn(...args: any[]): void {
|
||||||
|
if (this.debugMode) {
|
||||||
|
console.warn(...args);
|
||||||
|
}
|
||||||
|
}
|
||||||
// ==================== View 层属性(表现相关)====================
|
// ==================== View 层属性(表现相关)====================
|
||||||
as: HeroSpine = null!
|
as: HeroSpine = null!
|
||||||
status:String = "idle"
|
status:String = "idle"
|
||||||
@@ -43,7 +57,7 @@ export class HeroViewComp extends CCComp {
|
|||||||
get model() {
|
get model() {
|
||||||
// 🔥 修复:添加安全检查,防止ent为null时的访问异常
|
// 🔥 修复:添加安全检查,防止ent为null时的访问异常
|
||||||
if (!this.ent) {
|
if (!this.ent) {
|
||||||
console.warn("[HeroViewComp] ent is null, returning null for model");
|
this.debugWarn("[HeroViewComp] ent is null, returning null for model");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return this.ent.get(HeroAttrsComp);
|
return this.ent.get(HeroAttrsComp);
|
||||||
@@ -89,7 +103,8 @@ export class HeroViewComp extends CCComp {
|
|||||||
this.top_node.getChildByName("hp").active = true;
|
this.top_node.getChildByName("hp").active = true;
|
||||||
this.top_node.getChildByName("mp").active = true;
|
this.top_node.getChildByName("mp").active = true;
|
||||||
// 初始隐藏血条(被攻击后才显示)
|
// 初始隐藏血条(被攻击后才显示)
|
||||||
this.top_node.active = false;
|
this.top_node.active = true;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 初始化 UI 节点引用 */
|
/** 初始化 UI 节点引用 */
|
||||||
@@ -136,8 +151,8 @@ export class HeroViewComp extends CCComp {
|
|||||||
|
|
||||||
// ✅ 更新 UI 显示(数据由 HeroAttrSystem 更新)
|
// ✅ 更新 UI 显示(数据由 HeroAttrSystem 更新)
|
||||||
// 移除了每帧调用的 hp_show,改为仅在需要时调用
|
// 移除了每帧调用的 hp_show,改为仅在需要时调用
|
||||||
this.hp_show(this.model.hp, this.model.Attrs[Attrs.HP_MAX]);
|
this.hp_show();
|
||||||
this.mp_show(this.model.mp, this.model.Attrs[Attrs.MP_MAX]);
|
this.mp_show();
|
||||||
this.show_shield(this.model.shield, this.model.Attrs[Attrs.SHIELD_MAX]);
|
this.show_shield(this.model.shield, this.model.Attrs[Attrs.SHIELD_MAX]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -155,20 +170,23 @@ export class HeroViewComp extends CCComp {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** 显示血量 */
|
/** 显示血量 */
|
||||||
private hp_show(hp: number, hp_max: number) {
|
private hp_show() {
|
||||||
// 不再基于血量是否满来决定显示状态,只更新进度条
|
// 不再基于血量是否满来决定显示状态,只更新进度条
|
||||||
if(!this.top_node.active) return;
|
let hp=this.model.hp;
|
||||||
|
let hp_max=this.model.Attrs[Attrs.HP_MAX];
|
||||||
let hp_progress = hp / hp_max;
|
this.debugLog("hp_show",hp,hp_max)
|
||||||
this.top_node.getChildByName("hp").getComponent(ProgressBar).progress = hp_progress;
|
this.top_node.getChildByName("hp").getComponent(ProgressBar).progress = hp / hp_max;;
|
||||||
this.scheduleOnce(() => {
|
this.scheduleOnce(() => {
|
||||||
this.top_node.getChildByName("hp").getChildByName("hpb").getComponent(ProgressBar).progress = hp_progress;
|
this.top_node.getChildByName("hp").getChildByName("hpb").getComponent(ProgressBar).progress = hp / hp_max;;
|
||||||
}, 0.15);
|
}, 0.15);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 显示魔法值 */
|
/** 显示魔法值 */
|
||||||
private mp_show(mp: number, mp_max: number) {
|
private mp_show() {
|
||||||
if(!this.top_node.active) return
|
if(!this.top_node.active) return
|
||||||
|
let mp=this.model.mp;
|
||||||
|
let mp_max=this.model.Attrs[Attrs.MP_MAX];
|
||||||
|
this.debugLog("mp_show",mp,mp_max)
|
||||||
this.top_node.getChildByName("mp").getComponent(ProgressBar).progress = mp / mp_max;
|
this.top_node.getChildByName("mp").getComponent(ProgressBar).progress = mp / mp_max;
|
||||||
this.scheduleOnce(() => {
|
this.scheduleOnce(() => {
|
||||||
this.top_node.getChildByName("mp").getChildByName("mpb").getComponent(ProgressBar).progress = mp / mp_max;
|
this.top_node.getChildByName("mp").getChildByName("mpb").getComponent(ProgressBar).progress = mp / mp_max;
|
||||||
@@ -288,13 +306,13 @@ export class HeroViewComp extends CCComp {
|
|||||||
this.heathed();
|
this.heathed();
|
||||||
this.hp_tip(TooltipTypes.health, hp.toFixed(0));
|
this.hp_tip(TooltipTypes.health, hp.toFixed(0));
|
||||||
this.top_node.active=true
|
this.top_node.active=true
|
||||||
this.hp_show(this.model.hp, this.model.Attrs[Attrs.HP_MAX]);
|
this.hp_show();
|
||||||
}
|
}
|
||||||
mp_add(mp: number = 0) {
|
mp_add(mp: number = 0) {
|
||||||
// 生命值更新由 Model 层处理,这里只负责视图表现
|
// 生命值更新由 Model 层处理,这里只负责视图表现
|
||||||
this.hp_tip(TooltipTypes.addmp, mp.toFixed(0));
|
this.hp_tip(TooltipTypes.addmp, mp.toFixed(0));
|
||||||
this.top_node.active=true
|
this.top_node.active=true
|
||||||
this.mp_show(this.model.mp, this.model.Attrs[Attrs.MP_MAX]);
|
this.mp_show();
|
||||||
}
|
}
|
||||||
|
|
||||||
alive(){
|
alive(){
|
||||||
@@ -326,7 +344,7 @@ export class HeroViewComp extends CCComp {
|
|||||||
realDead(){
|
realDead(){
|
||||||
// 🔥 修复:添加model安全检查,防止实体销毁过程中的空指针异常
|
// 🔥 修复:添加model安全检查,防止实体销毁过程中的空指针异常
|
||||||
if (!this.model) {
|
if (!this.model) {
|
||||||
console.warn("[HeroViewComp] realDead called but model is null, skipping");
|
this.debugWarn("[HeroViewComp] realDead called but model is null, skipping");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if(this.model.fac === FacSet.HERO){
|
if(this.model.fac === FacSet.HERO){
|
||||||
@@ -439,7 +457,7 @@ export class HeroViewComp extends CCComp {
|
|||||||
private showDamageImmediate(damage: number, isCrit: boolean, anm:string="atked") {
|
private showDamageImmediate(damage: number, isCrit: boolean, anm:string="atked") {
|
||||||
if (!this.model) return;
|
if (!this.model) return;
|
||||||
|
|
||||||
this.hp_show(this.model.hp, this.model.Attrs[Attrs.HP_MAX]);
|
this.hp_show();
|
||||||
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));
|
this.hp_tip(TooltipTypes.crit, damage.toFixed(0));
|
||||||
@@ -467,3 +485,8 @@ export class HeroViewComp extends CCComp {
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -208,8 +208,8 @@ export class TalComp extends ecs.Comp {
|
|||||||
case TalEffet.SKILL_DMG:
|
case TalEffet.SKILL_DMG:
|
||||||
heroAttrs.addCountTal(TalEffet.SKILL_DMG, talent.value + talent.value_add);
|
heroAttrs.addCountTal(TalEffet.SKILL_DMG, talent.value + talent.value_add);
|
||||||
break;
|
break;
|
||||||
case TalEffet.LDMG:
|
case TalEffet.DMG_RED:
|
||||||
heroAttrs.addCountTal(TalEffet.LDMG, talent.value + talent.value_add);
|
heroAttrs.addCountTal(TalEffet.DMG_RED, talent.value + talent.value_add);
|
||||||
break;
|
break;
|
||||||
case TalEffet.HP:
|
case TalEffet.HP:
|
||||||
heroAttrs.add_hp(talent.value + talent.value_add,talent.vType == BType.VALUE);
|
heroAttrs.add_hp(talent.value + talent.value_add,talent.vType == BType.VALUE);
|
||||||
|
|||||||
@@ -149,7 +149,9 @@ export class SkillView extends CCComp {
|
|||||||
target.ent,
|
target.ent,
|
||||||
this.sData.Attrs,
|
this.sData.Attrs,
|
||||||
this.sData.caster,
|
this.sData.caster,
|
||||||
this.sData.s_uuid
|
this.sData.s_uuid,
|
||||||
|
this.sData.ext_dmg,
|
||||||
|
this.sData.dmg_ratio,
|
||||||
);
|
);
|
||||||
// 更新技能命中次数
|
// 更新技能命中次数
|
||||||
this.sData.hit_count++
|
this.sData.hit_count++
|
||||||
|
|||||||
Reference in New Issue
Block a user