feat(hero&skill): 新增击晕控制相关技能与属性支持

1. 新增击晕率属性计算与驻场加成逻辑
2. 重构冰冻相关英雄为击晕控制英雄
3. 完善技能描述显示与配置参数
4. 更新UI预制体 sprite 配置(仅为资源变更)
This commit is contained in:
panFD
2026-06-12 22:12:35 +08:00
parent 8fca560efd
commit 092d0e4371
7 changed files with 49 additions and 35 deletions

View File

@@ -351,18 +351,18 @@
"_dstBlendFactor": 4, "_dstBlendFactor": 4,
"_color": { "_color": {
"__type__": "cc.Color", "__type__": "cc.Color",
"r": 0, "r": 255,
"g": 0, "g": 255,
"b": 0, "b": 255,
"a": 88 "a": 255
}, },
"_spriteFrame": { "_spriteFrame": {
"__uuid__": "cb93c900-b440-4571-91d1-7da1636e3d73@1be8d", "__uuid__": "cb93c900-b440-4571-91d1-7da1636e3d73@b9538",
"__expectedType__": "cc.SpriteFrame" "__expectedType__": "cc.SpriteFrame"
}, },
"_type": 0, "_type": 0,
"_fillType": 0, "_fillType": 0,
"_sizeMode": 1, "_sizeMode": 0,
"_fillCenter": { "_fillCenter": {
"__type__": "cc.Vec2", "__type__": "cc.Vec2",
"x": 0, "x": 0,
@@ -372,7 +372,10 @@
"_fillRange": 0, "_fillRange": 0,
"_isTrimmedMode": true, "_isTrimmedMode": true,
"_useGrayscale": false, "_useGrayscale": false,
"_atlas": null, "_atlas": {
"__uuid__": "cb93c900-b440-4571-91d1-7da1636e3d73",
"__expectedType__": "cc.SpriteAtlas"
},
"_id": "" "_id": ""
}, },
{ {

View File

@@ -72,6 +72,7 @@ function buildEffectDesc(skill: ReturnType<typeof mergeSkillParams>): string {
if (skill.crt) parts.push(`暴击+${skill.crt}%`); if (skill.crt) parts.push(`暴击+${skill.crt}%`);
// 附加冰冻概率 // 附加冰冻概率
if (skill.frz) parts.push(`冰冻+${skill.frz}%`); if (skill.frz) parts.push(`冰冻+${skill.frz}%`);
if (skill.stun) parts.push(`击晕+${skill.stun}%`);
// 附加击退概率 // 附加击退概率
if (skill.bck) parts.push(`击退+${skill.bck}%`); if (skill.bck) parts.push(`击退+${skill.bck}%`);
} }
@@ -109,7 +110,7 @@ export function buildSkillDesc(hero: heroInfo): string {
// 通过 s_uuid 查找技能基础配置 // 通过 s_uuid 查找技能基础配置
const base = SkillSet[item.s_uuid]; const base = SkillSet[item.s_uuid];
if (!base) continue; if (!base) continue;
// 合并 overrides 得到实际技能参数ap/hit_count/crt/frz/bck 等可能被覆盖) // 合并 overrides 得到实际技能参数ap/hit_count/crt/frz/stun/bck 等可能被覆盖)
const skill = mergeSkillParams(base, item.overrides); const skill = mergeSkillParams(base, item.overrides);
// 将模板中的 "n" 替换为实际触发次数 // 将模板中的 "n" 替换为实际触发次数
const trigger = tpl.replace("n", String(item.t_num)); const trigger = tpl.replace("n", String(item.t_num));

View File

@@ -150,6 +150,7 @@ export interface SkillConfig {
kind?: SkillKind, // 主效果类型 kind?: SkillKind, // 主效果类型
crt?: number, // 额外暴击率 crt?: number, // 额外暴击率
frz?: number, // 额外冰冻概率 frz?: number, // 额外冰冻概率
stun?: number, // 额外击晕概率
bck?: number, // 额外击退概率 bck?: number, // 额外击退概率
buff_type?: Attrs, // Buff 类型 (单一职责) buff_type?: Attrs, // Buff 类型 (单一职责)
call_hero?: number, // 召唤技能召唤英雄id(可选) call_hero?: number, // 召唤技能召唤英雄id(可选)
@@ -164,8 +165,10 @@ export interface SkillOverrides {
hitcd?: number; hitcd?: number;
crt?: number; crt?: number;
frz?: number; frz?: number;
stun?: number;
bck?: number; bck?: number;
buff_type?: Attrs; buff_type?: Attrs;
call_hero?: number;
} }
/** /**
@@ -183,7 +186,7 @@ export function mergeSkillParams(config: SkillConfig, overrides?: SkillOverrides
} }
export const SkillUpList = { export const SkillUpList = {
1001: { ap: 0, hit_count: 0, buff_ap: 0, buff_hp: 0, bck: 0, frz: 0, crt: 0, num: 0 } 1001: { ap: 0, hit_count: 0, buff_ap: 0, buff_hp: 0, bck: 0, frz: 0, stun: 0, crt: 0, num: 0 }
} }
/****** /******
@@ -249,7 +252,7 @@ export const SkillSet: Record<number, SkillConfig> = {
6101: { 6101: {
uuid: 6101, name: "火球", sp_name: "ball_fire", icon: "1126", TGroup: TGroup.Enemy, readyAnm: "", endAnm: "", act: "atk", uuid: 6101, name: "火球", sp_name: "ball_fire", icon: "1126", TGroup: TGroup.Enemy, readyAnm: "", endAnm: "", act: "atk",
DTType: DTType.single, frz: 0, ap: 100, hit_count: 1, hitcd: 0.3, speed: 720, with: 90, ready: 0.2, EAnm: 0, DAnm: "", IType: IType.remote, DTType: DTType.single, stun: 0, ap: 100, hit_count: 1, hitcd: 0.3, speed: 720, with: 90, ready: 0.2, EAnm: 0, DAnm: "", IType: IType.remote,
RType: RType.linear, EType: EType.collision, info: "造成攻击力100%的伤害,一定几率暴击,高阶技能", RType: RType.linear, EType: EType.collision, info: "造成攻击力100%的伤害,一定几率暴击,高阶技能",
}, },
6102: { 6102: {
@@ -269,14 +272,14 @@ export const SkillSet: Record<number, SkillConfig> = {
RType: RType.linear, EType: EType.collision, info: "射出强力箭矢最多穿透6个敌人附带20%额外暴击率", RType: RType.linear, EType: EType.collision, info: "射出强力箭矢最多穿透6个敌人附带20%额外暴击率",
}, },
6105: { 6105: {
uuid: 6105, name: "冰刺", sp_name: "ice_up", icon: "1173", TGroup: TGroup.Enemy, readyAnm: "blues", endAnm: "", act: "max", uuid: 6105, name: "雷爆", sp_name: "ice_up", icon: "1173", TGroup: TGroup.Enemy, readyAnm: "blues", endAnm: "", act: "max",
DTType: DTType.range, frz: 0, ap: 150, hit_count: 6, hitcd: 0.2, speed: 720, with: 0, ready: 0.2, EAnm: 0, DAnm: "", IType: IType.remote, DTType: DTType.range, stun: 0, ap: 150, hit_count: 6, hitcd: 0.2, speed: 720, with: 0, ready: 0.2, EAnm: 0, DAnm: "", IType: IType.remote,
RType: RType.fixedEnd, EType: EType.animationEnd, info: "召唤冰刺攻击一排的敌人,有概率冰冻", RType: RType.fixedEnd, EType: EType.animationEnd, info: "召唤雷爆攻击一排的敌人,有概率击晕",
}, },
6106: { 6106: {
uuid: 6106, name: "冰推", sp_name: "ice_t", icon: "1173", TGroup: TGroup.Enemy, readyAnm: "blues", endAnm: "", act: "max", uuid: 6106, name: "雷墙", sp_name: "ice_t", icon: "1173", TGroup: TGroup.Enemy, readyAnm: "blues", endAnm: "", act: "max",
DTType: DTType.range, frz: 0, ap: 150, hit_count: 6, hitcd: 0.2, speed: 720, with: 0, ready: 0.2, EAnm: 0, DAnm: "", IType: IType.remote, DTType: DTType.range, stun: 0, ap: 150, hit_count: 6, hitcd: 0.2, speed: 720, with: 0, ready: 0.2, EAnm: 0, DAnm: "", IType: IType.remote,
RType: RType.fixed, EType: EType.animationEnd, info: "召唤墙阻挡敌人,有概率冰冻", RType: RType.fixed, EType: EType.animationEnd, info: "召唤墙阻挡敌人,有概率击晕",
}, },
6107: { 6107: {
uuid: 6107, name: "陨石", sp_name: "fire_yuns", icon: "1173", TGroup: TGroup.Enemy, readyAnm: "reds", endAnm: "", act: "max", uuid: 6107, name: "陨石", sp_name: "fire_yuns", icon: "1173", TGroup: TGroup.Enemy, readyAnm: "reds", endAnm: "", act: "max",
@@ -322,9 +325,9 @@ export const SkillSet: Record<number, SkillConfig> = {
RType: RType.fixed, EType: EType.animationEnd, buff_type: Attrs.critical_damage, info: "全体友方暴击伤害提升20%持续1次", RType: RType.fixed, EType: EType.animationEnd, buff_type: Attrs.critical_damage, info: "全体友方暴击伤害提升20%持续1次",
}, },
6405: { 6405: {
uuid: 6405, name: "冰冻强化", sp_name: "buff_wind", icon: "1255", TGroup: TGroup.Team, readyAnm: "up_blue", endAnm: "", act: "atk", uuid: 6405, name: "击晕强化", sp_name: "buff_wind", icon: "1255", TGroup: TGroup.Team, readyAnm: "up_blue", endAnm: "", act: "atk",
DTType: DTType.single, kind: SkillKind.Support, ap: 1, hit_count: 1, hitcd: 0.2, speed: 720, with: 0, ready: 0.2, EAnm: 0, DAnm: "", IType: IType.support, DTType: DTType.single, kind: SkillKind.Support, ap: 1, hit_count: 1, hitcd: 0.2, speed: 720, with: 0, ready: 0.2, EAnm: 0, DAnm: "", IType: IType.support,
RType: RType.fixed, EType: EType.animationEnd, buff_type: Attrs.freeze_chance, info: "全体友方冰冻概率提升10%持续1次", RType: RType.fixed, EType: EType.animationEnd, buff_type: Attrs.stun_chance, info: "全体友方击晕概率提升10%持续1次",
}, },
6406: { 6406: {
uuid: 6406, name: "击退强化", sp_name: "buff_wind", icon: "1255", TGroup: TGroup.Team, readyAnm: "up_blue", endAnm: "", act: "atk", uuid: 6406, name: "击退强化", sp_name: "buff_wind", icon: "1255", TGroup: TGroup.Team, readyAnm: "up_blue", endAnm: "", act: "atk",
@@ -363,7 +366,7 @@ export enum FieldSkillType {
SellGold = 6, // 卖出英雄金币提升 SellGold = 6, // 卖出英雄金币提升
WaveHeal = 7, // 战斗结束生命回复量提升 WaveHeal = 7, // 战斗结束生命回复量提升
HeroAtk = 8, // 英雄攻击力加成 HeroAtk = 8, // 英雄攻击力加成
HeroFrost = 9, // 英雄冰冻加成 HeroStun = 9, // 英雄击晕加成
HeroCrit = 10, // 英雄暴击加成 HeroCrit = 10, // 英雄暴击加成
HeroCritDamage = 11, // 英雄暴击伤害加成 HeroCritDamage = 11, // 英雄暴击伤害加成
HeroSpeed = 12, // 英雄攻击速度加成 HeroSpeed = 12, // 英雄攻击速度加成
@@ -393,7 +396,7 @@ export const FieldSkillSet: Record<number, FieldSkillConfig> = {
7006: { uuid: 7006, name: "出售强化", type: FieldSkillType.SellGold, value: 5, info: "卖出英雄金币+5" }, 7006: { uuid: 7006, name: "出售强化", type: FieldSkillType.SellGold, value: 5, info: "卖出英雄金币+5" },
7007: { uuid: 7007, name: "战后恢复", type: FieldSkillType.WaveHeal, value: 0.3, info: "战斗结束生命回复量+30%" }, 7007: { uuid: 7007, name: "战后恢复", type: FieldSkillType.WaveHeal, value: 0.3, info: "战斗结束生命回复量+30%" },
7008: { uuid: 7008, name: "攻击加成", type: FieldSkillType.HeroAtk, value: 0.2, info: "英雄攻击力+20%" }, 7008: { uuid: 7008, name: "攻击加成", type: FieldSkillType.HeroAtk, value: 0.2, info: "英雄攻击力+20%" },
7009: { uuid: 7009, name: "冰冻加成", type: FieldSkillType.HeroFrost, value: 0.1, info: "英雄冰冻概率+10%" }, 7009: { uuid: 7009, name: "击晕加成", type: FieldSkillType.HeroStun, value: 0.1, info: "英雄击晕概率+10%" },
7010: { uuid: 7010, name: "暴击加成", type: FieldSkillType.HeroCrit, value: 0.1, info: "英雄暴击率+10%" }, 7010: { uuid: 7010, name: "暴击加成", type: FieldSkillType.HeroCrit, value: 0.1, info: "英雄暴击率+10%" },
7011: { uuid: 7011, name: "暴伤加成", type: FieldSkillType.HeroCritDamage, value: 0.5, info: "英雄暴击伤害+50%" }, 7011: { uuid: 7011, name: "暴伤加成", type: FieldSkillType.HeroCritDamage, value: 0.5, info: "英雄暴击伤害+50%" },
7012: { uuid: 7012, name: "攻速加成", type: FieldSkillType.HeroSpeed, value: 0.2, info: "英雄攻击速度+20%" }, 7012: { uuid: 7012, name: "攻速加成", type: FieldSkillType.HeroSpeed, value: 0.2, info: "英雄攻击速度+20%" },

View File

@@ -268,33 +268,33 @@ export const HeroInfo: Record<number, heroInfo> = {
info:"驻场提供攻击力光环每2次攻击为全队叠加攻击力"}, info:"驻场提供攻击力光环每2次攻击为全队叠加攻击力"},
// ========== 冰冻控制流 (新加) ========== // ========== 击晕控制流 (新加) ==========
5106:{uuid:5106,name:"寒冰学徒",path:"hm3", fac:FacSet.HERO,pool_lv:1,lv:1,type:HType.Long, 5106:{uuid:5106,name:"雷爆学徒",path:"hm3", fac:FacSet.HERO,pool_lv:1,lv:1,type:HType.Long,
hp:130,ap:50, hp:130,ap:50,
skills:{6007:{uuid:6007,lv:1,cd:AtkSpeedSet[AtkSpeedLv.Slow1].cd,ccd:0}}, skills:{6007:{uuid:6007,lv:1,cd:AtkSpeedSet[AtkSpeedLv.Slow1].cd,ccd:0}},
field:[6405], field:[6405],
atking:[{s_uuid:6405,t_num:2}], atking:[{s_uuid:6405,t_num:2}],
evolve:{ evolve:{
2:{atking:[{s_uuid:6105,t_num:3,overrides:{ap:100,frz:20}}]}, 2:{atking:[{s_uuid:6105,t_num:3,overrides:{ap:100,stun:20}}]},
3:{skill:{s_uuid:6105,overrides:{frz:15,hit_count:6}}, 3:{skill:{s_uuid:6105,overrides:{stun:15,hit_count:6}},
atking:[{s_uuid:6105,t_num:1,overrides:{ap:150,frz:35,hit_count:8}}], atking:[{s_uuid:6105,t_num:1,overrides:{ap:150,stun:35,hit_count:8}}],
ap_bonus:30}, ap_bonus:30},
}, },
info:"驻场提供冰冻光环每2次普攻叠加冰冻概率"}, info:"驻场提供击晕光环每2次普攻叠加击晕概率"},
5107:{uuid:5107,name:"霜寒法师",path:"hm5", fac:FacSet.HERO,pool_lv:2,lv:1,type:HType.Long, 5107:{uuid:5107,name:"雷霆法师",path:"hm5", fac:FacSet.HERO,pool_lv:2,lv:1,type:HType.Long,
hp:160,ap:80, hp:160,ap:80,
skills:{6007:{uuid:6007,lv:1,cd:AtkSpeedSet[AtkSpeedLv.Normal3].cd,ccd:0}}, skills:{6007:{uuid:6007,lv:1,cd:AtkSpeedSet[AtkSpeedLv.Normal3].cd,ccd:0}},
field:[6405], field:[6405],
atking:[{s_uuid:6105,t_num:2,overrides:{ap:120,frz:25}}], atking:[{s_uuid:6105,t_num:2,overrides:{ap:120,stun:25}}],
info:"驻场冰冻光环每2次攻击触发冰刺AOE25%冰冻概率住一排敌人"}, info:"驻场击晕光环每2次攻击触发雷爆AOE25%击晕概率住一排敌人"},
5108:{uuid:5108,name:"永冬贤者",path:"hm4", fac:FacSet.HERO,pool_lv:3,lv:1,type:HType.Long, 5108:{uuid:5108,name:"风暴贤者",path:"hm4", fac:FacSet.HERO,pool_lv:3,lv:1,type:HType.Long,
hp:250,ap:110, hp:250,ap:110,
skills:{6007:{uuid:6007,lv:1,cd:AtkSpeedSet[AtkSpeedLv.Slow3].cd,ccd:0}}, skills:{6007:{uuid:6007,lv:1,cd:AtkSpeedSet[AtkSpeedLv.Slow3].cd,ccd:0}},
field:[6405], field:[6405],
atking:[{s_uuid:6105,t_num:1,overrides:{ap:150,frz:35,hit_count:8}}], atking:[{s_uuid:6105,t_num:1,overrides:{ap:150,stun:35,hit_count:8}}],
info:"驻场强力冰冻光环,每次攻击释放冰刺35%冰冻概率"}, info:"驻场强力击晕光环,每次攻击释放雷爆35%击晕概率"},
// ========== 辅助英雄 (保留 5301, 5302) ========== // ========== 辅助英雄 (保留 5301, 5302) ==========

View File

@@ -273,7 +273,13 @@ export class HeroAttrsComp extends ecs.Comp {
/** 英雄实时冰冻率 = 基础冰冻率 + 驻场冰冻率。 */ /** 英雄实时冰冻率 = 基础冰冻率 + 驻场冰冻率。 */
public getRuntimeFreezeChance(): number { public getRuntimeFreezeChance(): number {
if (this.fac !== FacSet.HERO) return this.freeze_chance; if (this.fac !== FacSet.HERO) return this.freeze_chance;
return this.freeze_chance + HeroAttrsComp.getFieldPercentValue(FieldSkillType.HeroFrost); return this.freeze_chance;
}
/** 英雄实时击晕率 = 基础击晕率 + 驻场击晕率。 */
public getRuntimeStunChance(): number {
if (this.fac !== FacSet.HERO) return this.stun_chance;
return this.stun_chance + HeroAttrsComp.getFieldPercentValue(FieldSkillType.HeroStun);
} }
/** 英雄实时风怒概率 = 基础风怒 + 驻场风怒。 */ /** 英雄实时风怒概率 = 基础风怒 + 驻场风怒。 */

View File

@@ -483,7 +483,7 @@ export class SCastSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate
if (config.buff_type === Attrs.ap) upgradeValue = sUp.buff_ap || 0; if (config.buff_type === Attrs.ap) upgradeValue = sUp.buff_ap || 0;
else if (config.buff_type === Attrs.hp_max) upgradeValue = sUp.buff_hp || 0; else if (config.buff_type === Attrs.hp_max) upgradeValue = sUp.buff_hp || 0;
else if (config.buff_type === Attrs.critical) upgradeValue = sUp.crt || 0; else if (config.buff_type === Attrs.critical) upgradeValue = sUp.crt || 0;
// 如果后续有冰冻等,在这里加上对应的 sUp 字段即可,如 sUp.frz // 如果后续有冰冻、击晕等,在这里加上对应的 sUp 字段即可,如 sUp.frz / sUp.stun
const totalBuffValue = baseValue + upgradeValue; const totalBuffValue = baseValue + upgradeValue;

View File

@@ -206,13 +206,14 @@ export class Skill extends ecs.Entity {
const SUp=SkillUpList[s_uuid] ? SkillUpList[s_uuid]:SkillUpList[1001]; const SUp=SkillUpList[s_uuid] ? SkillUpList[s_uuid]:SkillUpList[1001];
const sCrt = (config.crt ?? 0)+(SUp.crt*skill_lv); const sCrt = (config.crt ?? 0)+(SUp.crt*skill_lv);
const sFrz = (config.frz ?? 0)+(SUp.frz*skill_lv); const sFrz = (config.frz ?? 0)+(SUp.frz*skill_lv);
const sStun = (config.stun ?? 0)+(SUp.stun*skill_lv);
const sAp =config.ap+(SUp.ap*skill_lv); const sAp =config.ap+(SUp.ap*skill_lv);
const sHit=config.hit_count+(SUp.hit_count*skill_lv); const sHit=config.hit_count+(SUp.hit_count*skill_lv);
sDataCom.Attrs[Attrs.ap] = Math.floor(cAttrsComp.ap*sAp/100); //技能的ap是百分值 需要/100 而且需要再最终计算总ap时再/100不然会出现ap为90%变0 sDataCom.Attrs[Attrs.ap] = Math.floor(cAttrsComp.ap*sAp/100); //技能的ap是百分值 需要/100 而且需要再最终计算总ap时再/100不然会出现ap为90%变0
sDataCom.Attrs[Attrs.critical] = cAttrsComp.getRuntimeCritical() + sCrt; sDataCom.Attrs[Attrs.critical] = cAttrsComp.getRuntimeCritical() + sCrt;
sDataCom.Attrs[Attrs.critical_damage] = cAttrsComp.getRuntimeCritDamageBonus(); sDataCom.Attrs[Attrs.critical_damage] = cAttrsComp.getRuntimeCritDamageBonus();
sDataCom.Attrs[Attrs.freeze_chance] = cAttrsComp.getRuntimeFreezeChance() + sFrz; sDataCom.Attrs[Attrs.freeze_chance] = cAttrsComp.getRuntimeFreezeChance() + sFrz;
sDataCom.Attrs[Attrs.stun_chance] = cAttrsComp.stun_chance || 0; sDataCom.Attrs[Attrs.stun_chance] = cAttrsComp.getRuntimeStunChance() + sStun;
sDataCom.Attrs[Attrs.knockback_chance] = cAttrsComp.knockback_chance || 0; sDataCom.Attrs[Attrs.knockback_chance] = cAttrsComp.knockback_chance || 0;
sDataCom.Attrs[Attrs.knockback_distance] = cAttrsComp.knockback_distance || 0; sDataCom.Attrs[Attrs.knockback_distance] = cAttrsComp.knockback_distance || 0;
sDataCom.Attrs[Attrs.puncture_chance] = cAttrsComp.getRuntimePunctureChance(); // 初始化携带施法者的穿透概率 sDataCom.Attrs[Attrs.puncture_chance] = cAttrsComp.getRuntimePunctureChance(); // 初始化携带施法者的穿透概率