Compare commits
2 Commits
dc0e873523
...
f0063525da
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f0063525da | ||
|
|
f52488f3fb |
File diff suppressed because it is too large
Load Diff
@@ -16,7 +16,7 @@
|
||||
*
|
||||
* 触发组口径:每个触发槽位(atking/dead/fstart/atked/call/field)整组视为一个技能,
|
||||
* 组内多个 s_uuid / 光环词条合并为一个名称(组内首个自定义名)与一套说明统一展示:
|
||||
* - buildHeroSkillDesc 中每组合并为一行(CHeroComp / HeroBoxComp 等直接消费)
|
||||
* - buildHeroSkillDesc 中每组合并为一行(CHeroComp / HeroMoreCom 等直接消费)
|
||||
* - buildHeroGroupTierLines(heroUuid, slot) 供弹窗按整组分档渲染(SinfoComp)
|
||||
*
|
||||
* 占位符规范(模板作者可用,渲染时数值片段自动绿色高亮):
|
||||
|
||||
@@ -562,7 +562,7 @@ export const HeroInfo: Record<number, heroInfo> = {
|
||||
],
|
||||
},
|
||||
bonus: [
|
||||
{ lv: 12, attrs: {"def":50}, name: "钢铁壁垒", },
|
||||
{ lv: 12, attrs: {"def":50}, name: "钢铁壁垒", icon: "46-Iron-Clad", },
|
||||
],
|
||||
info: "自身强护盾+群体小护盾,强生存",
|
||||
},
|
||||
@@ -588,7 +588,7 @@ export const HeroInfo: Record<number, heroInfo> = {
|
||||
],
|
||||
},
|
||||
bonus: [
|
||||
{ lv: 12, attrs: {"hp":50}, name: "不屈战意", },
|
||||
{ lv: 12, attrs: {"hp":50}, name: "不屈战意", icon: "29-Endure", },
|
||||
],
|
||||
info: "易伤+风怒,近战 dps",
|
||||
},
|
||||
@@ -612,7 +612,7 @@ export const HeroInfo: Record<number, heroInfo> = {
|
||||
{ lv: 4, uuids: [{ uuid: 7005, value: 0.25, name: "大圣神威" }] },
|
||||
],
|
||||
bonus: [
|
||||
{ lv: 12, attrs: {"hp":50}, name: "不屈战意", },
|
||||
{ lv: 12, attrs: {"hp":50}, name: "不屈战意", icon: "29-Endure", },
|
||||
],
|
||||
info: "必晕爆发+暴击光环,近战收割",
|
||||
},
|
||||
@@ -636,7 +636,7 @@ export const HeroInfo: Record<number, heroInfo> = {
|
||||
{ lv: 4, uuids: [{ uuid: 7004, value: 0.12, name: "剑刃风暴" }, { uuid: 7005, value: 0.2, name: "斩魂利刃" }] },
|
||||
],
|
||||
bonus: [
|
||||
{ lv: 12, attrs: {"ap":50}, name: "致命本能", },
|
||||
{ lv: 12, attrs: {"ap":50}, name: "致命本能", icon: "36-Guardian-Stance", },
|
||||
],
|
||||
info: "暴击+暴伤双光环,暴击流刺客",
|
||||
},
|
||||
@@ -660,7 +660,7 @@ export const HeroInfo: Record<number, heroInfo> = {
|
||||
{ lv: 4, uuids: [{ uuid: 7002, value: 10, name: "攻击光环" }] },
|
||||
],
|
||||
bonus: [
|
||||
{ lv: 12, attrs: {"ap":50}, name: "致命本能", },
|
||||
{ lv: 12, attrs: {"ap":50}, name: "致命本能", icon: "36-Guardian-Stance", },
|
||||
],
|
||||
info: "普攻出血+大招群体出血,持续消耗",
|
||||
},
|
||||
@@ -684,7 +684,7 @@ export const HeroInfo: Record<number, heroInfo> = {
|
||||
{ lv: 4, uuids: [{ uuid: 7006, value: 0.15 }] },
|
||||
],
|
||||
bonus: [
|
||||
{ lv: 12, attrs: {"ap":50}, name: "鹰眼锁定", },
|
||||
{ lv: 12, attrs: {"ap":50}, name: "鹰眼锁定", icon: "27-Hawkeye", },
|
||||
],
|
||||
info: "冰冻控场+多重箭,远程控制",
|
||||
},
|
||||
@@ -708,7 +708,7 @@ export const HeroInfo: Record<number, heroInfo> = {
|
||||
{ lv: 4, uuids: [{ uuid: 7002, value: 0.15, name: "深渊威压" }] },
|
||||
],
|
||||
bonus: [
|
||||
{ lv: 12, attrs: {"ap":50}, name: "奥术共鸣", },
|
||||
{ lv: 12, attrs: {"ap":50}, name: "奥术共鸣", icon: "100-Enchant-Magic", },
|
||||
],
|
||||
info: "烈焰击退+易伤光环,法系压场",
|
||||
},
|
||||
@@ -734,7 +734,7 @@ export const HeroInfo: Record<number, heroInfo> = {
|
||||
],
|
||||
},
|
||||
bonus: [
|
||||
{ lv: 12, attrs: {"hp":50}, name: "守护之心", },
|
||||
{ lv: 12, attrs: {"hp":50}, name: "守护之心", icon: "29-Endure", },
|
||||
],
|
||||
info: "全体治疗+攻击附盾,团队续航",
|
||||
},
|
||||
@@ -760,7 +760,7 @@ export const HeroInfo: Record<number, heroInfo> = {
|
||||
],
|
||||
},
|
||||
bonus: [
|
||||
{ lv: 12, attrs: {"def":50}, name: "钢铁壁垒", },
|
||||
{ lv: 12, attrs: {"def":50}, name: "钢铁壁垒", icon: "46-Iron-Clad", },
|
||||
],
|
||||
info: "受击自疗+击退,自愈坦克",
|
||||
},
|
||||
@@ -786,7 +786,7 @@ export const HeroInfo: Record<number, heroInfo> = {
|
||||
],
|
||||
},
|
||||
bonus: [
|
||||
{ lv: 12, attrs: {"ap":50}, name: "鹰眼锁定", },
|
||||
{ lv: 12, attrs: {"ap":50}, name: "鹰眼锁定", icon: "27-Hawkeye", },
|
||||
],
|
||||
info: "万箭齐射+高频击退,远程压制",
|
||||
},
|
||||
@@ -812,7 +812,7 @@ export const HeroInfo: Record<number, heroInfo> = {
|
||||
],
|
||||
},
|
||||
bonus: [
|
||||
{ lv: 12, attrs: {"def":50}, name: "钢铁壁垒", },
|
||||
{ lv: 12, attrs: {"def":50}, name: "钢铁壁垒", icon: "46-Iron-Clad", },
|
||||
],
|
||||
info: "永久和计时生命最大值,控血大师",
|
||||
},
|
||||
@@ -836,7 +836,7 @@ export const HeroInfo: Record<number, heroInfo> = {
|
||||
{ lv: 4, uuids: [{ uuid: 7006, value: 10 }] },
|
||||
],
|
||||
bonus: [
|
||||
{ lv: 12, attrs: {"ap":50}, name: "奥术共鸣", },
|
||||
{ lv: 12, attrs: {"ap":50}, name: "奥术共鸣", icon: "100-Enchant-Magic", },
|
||||
],
|
||||
info: "普攻 大招加速 buff+加速光环,加速大师",
|
||||
},
|
||||
@@ -862,7 +862,7 @@ export const HeroInfo: Record<number, heroInfo> = {
|
||||
],
|
||||
},
|
||||
bonus: [
|
||||
{ lv: 12, attrs: {"hp":50}, name: "守护之心", },
|
||||
{ lv: 12, attrs: {"hp":50}, name: "守护之心", icon: "29-Endure", },
|
||||
],
|
||||
info: "大招全体反伤 普攻暴击 暴击反伤辅助",
|
||||
},
|
||||
@@ -886,10 +886,155 @@ export const HeroInfo: Record<number, heroInfo> = {
|
||||
{ lv: 4, uuids: [{ uuid: 7023, value: 10 }] },
|
||||
],
|
||||
bonus: [
|
||||
{ lv: 12, attrs: {"hp":50}, name: "不屈战意", },
|
||||
{ lv: 12, attrs: {"hp":50}, name: "不屈战意", icon: "29-Endure", },
|
||||
],
|
||||
info: "",
|
||||
},
|
||||
// 5015 毒箭猎手 — 毒伤持续流:普攻淬毒叠层+毒雨铺DoT+攻击光环喂养毒伤
|
||||
5015: {
|
||||
uuid: 5015, name: "毒箭猎手", path: "ha3", fac: FacSet.HERO, rarity: 2, lv: 1, type: HType.Long, grow_type: HGrowType.Archer, role: HRole.Archer, hp: HERO_ROLE_BASE[HRole.Archer].hp + 10, ap: HERO_ROLE_BASE[HRole.Archer].ap, def: HERO_ROLE_BASE[HRole.Archer].def,
|
||||
skills: {
|
||||
6007: { uuid: 6007, name: "淬毒箭", lv: 1, cd: AtkSpeedSet[AtkSpeedLv.Normal].cd, ccd: 0, overrides: {"ap":100}, desc: "射出箭矢,对{target}造成攻击力{ap}%伤害",
|
||||
lv_entries: [
|
||||
{ lv: 2, s_lv: SkillLv.Lv2, overrides: {"timed_buff_id":7005,"buff_value":30,"buff_chance":30}, desc: "普通攻击有{buff_chance}%概率使目标中毒(每0.5秒受到{buff_value}点伤害,持续{dur}秒)" },
|
||||
],
|
||||
},
|
||||
6150: { uuid: 6150, name: "万箭齐发·毒", lv: 1, cd: 8, ccd: 0, overrides: {"ap":150,"timed_buff_id":7005,"buff_value":30,"buff_chance":50,"icon":"4-Apply-Poison"}, desc: "毒箭如雨,对{target}造成攻击力{ap}%伤害,{buff_chance}%概率使目标中毒(每0.5秒受到{buff_value}点伤害,持续{dur}秒)",
|
||||
lv_entries: [
|
||||
{ lv: 8, s_lv: SkillLv.Lv2, overrides: {"ap":200,"buff_value":40,"buff_chance":60} },
|
||||
{ lv: 16, s_lv: SkillLv.Lv3, overrides: {"ap":250,"buff_value":60,"buff_chance":80,"hit_count":2}, desc: "毒箭如雨,对{target}造成攻击力{ap}%伤害,{buff_chance}%概率使目标中毒(每0.5秒受到{buff_value}点伤害,持续{dur}秒),每支箭可命中{hit_count}个目标" },
|
||||
],
|
||||
},
|
||||
},
|
||||
atking: {
|
||||
6007: [
|
||||
{ lv: 4, s_lv: SkillLv.Lv1, name: "蚀骨毒箭", t_num: 3, overrides: {"ap":80,"timed_buff_id":7005,"buff_value":40,"buff_chance":100}, desc: "追加射出蚀骨毒箭,对{target}造成攻击力{ap}%伤害,必定使目标中毒(每0.5秒受到{buff_value}点伤害,持续{dur}秒)" },
|
||||
],
|
||||
},
|
||||
field: [
|
||||
{ lv: 4, uuids: [{ uuid: 7002, value: 0.1, name: "淬毒磨砺" }] },
|
||||
],
|
||||
bonus: [
|
||||
{ lv: 12, attrs: {"ap":50}, name: "剧毒淬炼", icon: "27-Hawkeye", },
|
||||
],
|
||||
info: "淬毒普攻+毒雨叠层,持续消耗型远程毒C",
|
||||
},
|
||||
// 5016 连珠神射 — 暴击连射爆发流:VeryFast极速普攻+概率追射必暴箭+开局团队暴击爆发
|
||||
5016: {
|
||||
uuid: 5016, name: "连珠神射", path: "ha4", fac: FacSet.HERO, rarity: 4, lv: 1, type: HType.Mid, grow_type: HGrowType.Archer, role: HRole.Archer, hp: HERO_ROLE_BASE[HRole.Archer].hp, ap: HERO_ROLE_BASE[HRole.Archer].ap + 10, def: HERO_ROLE_BASE[HRole.Archer].def,
|
||||
skills: {
|
||||
6008: { uuid: 6008, name: "连珠箭", lv: 1, cd: AtkSpeedSet[AtkSpeedLv.VeryFast].cd, ccd: 0, overrides: {"ap":100}, desc: "极速连射,对{target}造成攻击力{ap}%伤害",
|
||||
lv_entries: [
|
||||
{ lv: 2, s_lv: SkillLv.Lv2, overrides: {"crt":20,"proc_skill":{"s_uuid":6007,"chance":20,"overrides":{"crt":100}}}, desc: "普通攻击暴击率提升{crt}%,并有概率触发连射追箭(必定暴击)" },
|
||||
],
|
||||
},
|
||||
6151: { uuid: 6151, name: "裂空箭雨", lv: 1, cd: 8, ccd: 0, overrides: {"ap":150,"crt":30,"summon_count":5}, desc: "箭雨倾泻,对{target}造成攻击力{ap}%伤害,{crt}%概率暴击",
|
||||
lv_entries: [
|
||||
{ lv: 8, s_lv: SkillLv.Lv2, overrides: {"ap":200,"crt":50} },
|
||||
{ lv: 16, s_lv: SkillLv.Lv3, overrides: {"ap":250,"crt":70,"summon_count":6,"hit_count":2}, desc: "箭雨倾泻,对{target}造成攻击力{ap}%伤害,{crt}%概率暴击,每支箭可命中{hit_count}个目标" },
|
||||
],
|
||||
},
|
||||
},
|
||||
fstart: {
|
||||
6504: [
|
||||
{ lv: 4, s_lv: SkillLv.Lv1, name: "猎杀时刻", t_num: 1, overrides: {"buff_value":30}, desc: "战斗开始时释放暴击爆发,全体友方暴击率提升{buff_value}%,持续{dur}秒" },
|
||||
],
|
||||
},
|
||||
field: [
|
||||
{ lv: 4, uuids: [{ uuid: 7004, value: 0.15, name: "猎手集结" }] },
|
||||
],
|
||||
bonus: [
|
||||
{ lv: 12, attrs: {"ap":50}, name: "猎杀直觉", icon: "27-Hawkeye", },
|
||||
],
|
||||
info: "极速连射+暴击追射+开局团队暴击,爆发型射手主C",
|
||||
},
|
||||
// 5017 碎甲术士 — 破甲减防法师:fstart先手/普攻概率/大招必定三通道施加破甲7008+穿透光环,团队物理增伤位
|
||||
5017: {
|
||||
uuid: 5017, name: "碎甲术士", path: "hm3", fac: FacSet.HERO, rarity: 3, lv: 1, type: HType.Long, grow_type: HGrowType.Mage, role: HRole.Mage, hp: HERO_ROLE_BASE[HRole.Mage].hp, ap: HERO_ROLE_BASE[HRole.Mage].ap + 10, def: HERO_ROLE_BASE[HRole.Mage].def,
|
||||
skills: {
|
||||
6012: { uuid: 6012, name: "蚀甲酸瓶", lv: 1, cd: AtkSpeedSet[AtkSpeedLv.Normal].cd, ccd: 0, overrides: {"ap":100}, desc: "掷出酸瓶,对{target}造成攻击力{ap}%伤害",
|
||||
lv_entries: [
|
||||
{ lv: 2, s_lv: SkillLv.Lv2, overrides: {"timed_buff_id":7008,"buff_chance":30}, desc: "普通攻击有{buff_chance}%概率使目标破甲(防御降低,持续{dur}秒)" },
|
||||
],
|
||||
},
|
||||
6203: { uuid: 6203, name: "碎甲能量波", lv: 1, cd: 8, ccd: 0, overrides: {"ap":150,"timed_buff_id":7008}, desc: "释放碎甲能量波,对{target}造成攻击力{ap}%伤害,并使目标破甲(防御降低,持续{dur}秒)",
|
||||
lv_entries: [
|
||||
{ lv: 8, s_lv: SkillLv.Lv2, overrides: {"ap":200} },
|
||||
{ lv: 16, s_lv: SkillLv.Lv3, overrides: {"ap":250,"buff_value":-70}, desc: "释放碎甲能量波,对{target}造成攻击力{ap}%伤害,并使目标破甲加深(防御大幅降低,持续{dur}秒)" },
|
||||
],
|
||||
},
|
||||
},
|
||||
fstart: {
|
||||
6012: [
|
||||
{ lv: 4, s_lv: SkillLv.Lv1, name: "先手蚀甲", t_num: 1, overrides: {"ap":150,"timed_buff_id":7008}, desc: "战斗开始时掷出蚀甲酸瓶,对{target}造成攻击力{ap}%伤害,并必定使其破甲(防御降低,持续{dur}秒)" },
|
||||
],
|
||||
},
|
||||
field: [
|
||||
{ lv: 4, uuids: [{ uuid: 7009, value: 0.1, name: "锐矛之赐" }] },
|
||||
],
|
||||
bonus: [
|
||||
{ lv: 12, attrs: {"ap":50}, name: "奥术共鸣", icon: "100-Enchant-Magic", },
|
||||
],
|
||||
info: "先手破甲+概率蚀甲+穿透光环,物理队核心增伤位",
|
||||
},
|
||||
// 5018 雷暴领主 — 雷暴AOE爆发+麻痹控场:先手雷击+高倍率能量波
|
||||
5018: {
|
||||
uuid: 5018, name: "雷暴领主", path: "hm4", fac: FacSet.HERO, rarity: 5, lv: 1, type: HType.Long, grow_type: HGrowType.Mage, role: HRole.Mage, hp: HERO_ROLE_BASE[HRole.Mage].hp - 10, ap: HERO_ROLE_BASE[HRole.Mage].ap + 20, def: HERO_ROLE_BASE[HRole.Mage].def,
|
||||
skills: {
|
||||
6009: { uuid: 6009, name: "雷霆弹", lv: 1, cd: AtkSpeedSet[AtkSpeedLv.Fast].cd, ccd: 0, overrides: {"ap":100}, desc: "掷出雷霆弹,对{target}造成攻击力{ap}%伤害",
|
||||
lv_entries: [
|
||||
{ lv: 2, s_lv: SkillLv.Lv2, overrides: {"para":15}, desc: "普通攻击有{para}%概率麻痹敌人,减缓其技能冷却恢复" },
|
||||
],
|
||||
},
|
||||
6203: { uuid: 6203, name: "雷霆裂空", lv: 1, cd: 8, ccd: 0, overrides: {"ap":200,"para":40}, desc: "释放雷霆裂空波,对{target}造成攻击力{ap}%伤害,{para}%概率麻痹敌人",
|
||||
lv_entries: [
|
||||
{ lv: 8, s_lv: SkillLv.Lv2, overrides: {"ap":250,"para":60}, desc: "释放雷霆裂空波,对{target}造成攻击力{ap}%伤害,{para}%概率麻痹敌人" },
|
||||
{ lv: 16, s_lv: SkillLv.Lv3, overrides: {"ap":300,"para":80,"hit_count":3}, desc: "释放雷霆裂空波,对{target}造成攻击力{ap}%伤害,可多次命中,{para}%概率麻痹敌人" },
|
||||
],
|
||||
},
|
||||
},
|
||||
fstart: {
|
||||
6203: [
|
||||
{ lv: 4, s_lv: SkillLv.Lv1, name: "雷击先手", t_num: 1, overrides: {"ap":150,"para":30,"icon":"100-Enchant-Magic"}, desc: "战斗开始释放雷击,对{target}造成攻击力{ap}%伤害,{para}%概率麻痹敌人" },
|
||||
],
|
||||
},
|
||||
field: [
|
||||
{ lv: 4, uuids: [{ uuid: 7003, value: 10, name: "雷云领域" }] },
|
||||
],
|
||||
bonus: [
|
||||
{ lv: 12, attrs: {"ap":50}, name: "奥术共鸣", icon: "100-Enchant-Magic", },
|
||||
],
|
||||
info: "雷暴爆发+麻痹控场,法系主C",
|
||||
},
|
||||
// 5019 圣盾贤者 — 护盾反伤生存法:全队圣盾+荆棘反伤+受击荆棘
|
||||
5019: {
|
||||
uuid: 5019, name: "圣盾贤者", path: "hm5", fac: FacSet.HERO, rarity: 2, lv: 1, type: HType.Long, grow_type: HGrowType.Mage, role: HRole.Mage, hp: HERO_ROLE_BASE[HRole.Mage].hp + 20, ap: HERO_ROLE_BASE[HRole.Mage].ap - 5, def: HERO_ROLE_BASE[HRole.Mage].def + 5,
|
||||
skills: {
|
||||
6011: { uuid: 6011, name: "圣光飞瓶", lv: 1, cd: AtkSpeedSet[AtkSpeedLv.Normal].cd, ccd: 0, overrides: {"ap":100}, desc: "掷出圣光飞瓶,对{target}造成攻击力{ap}%伤害",
|
||||
lv_entries: [
|
||||
{ lv: 2, s_lv: SkillLv.Lv2, overrides: {"proc_skill":{"s_uuid":6516,"chance":20,"overrides":{"timed_buff_id":7028,"buff_value":10}}}, desc: "普通攻击概率凝聚荆棘护体(受击时反弹{buff_value}%所受伤害,持续{dur}秒)" },
|
||||
],
|
||||
},
|
||||
6301: { uuid: 6301, name: "奥术圣壁", lv: 1, cd: 8, ccd: 0, overrides: {"TGroup": TGroup.Ally,"ap":20,"timed_buff_id":7027,"buff_value":10}, desc: "为全体友方施加生命最大值{ap}%的护盾,并附加荆棘(受击时反弹{buff_value}点伤害,持续{dur}秒)",
|
||||
lv_entries: [
|
||||
{ lv: 8, s_lv: SkillLv.Lv2, overrides: {"ap":30,"buff_value":15}, desc: "为全体友方施加生命最大值{ap}%的护盾,并附加荆棘(受击时反弹{buff_value}点伤害,持续{dur}秒)" },
|
||||
{ lv: 16, s_lv: SkillLv.Lv3, overrides: {"ap":40,"buff_value":20}, desc: "为全体友方施加生命最大值{ap}%的护盾,并附加荆棘(受击时反弹{buff_value}点伤害,持续{dur}秒)" },
|
||||
],
|
||||
},
|
||||
},
|
||||
atked: {
|
||||
6516: [
|
||||
{ lv: 4, s_lv: SkillLv.Lv1, name: "荆棘回应", t_num: 3, overrides: {"timed_buff_id":7028,"buff_value":10,"icon":"75-Shield-Stun"}, desc: "凝聚荆棘护体,受击时反弹{buff_value}%所受伤害,持续{dur}秒" },
|
||||
],
|
||||
},
|
||||
field: [
|
||||
{ lv: 4, uuids: [{ uuid: 7022, value: 8, name: "荆棘领域" }] },
|
||||
],
|
||||
bonus: [
|
||||
{ lv: 12, attrs: {"hp":50}, name: "守护之心", icon: "29-Endure", },
|
||||
],
|
||||
info: "全队护盾+荆棘反伤,生存反击法",
|
||||
},
|
||||
// @hero-setup:heroes-end
|
||||
|
||||
/*
|
||||
@@ -969,9 +1114,9 @@ export const HeroInfo: Record<number, heroInfo> = {
|
||||
};
|
||||
|
||||
export const HeroList: number[] = [
|
||||
// 编辑器导出自动同步(共 14 个)
|
||||
// 编辑器导出自动同步(共 19 个)
|
||||
5001, 5002, 5003, 5004, 5005, 5006, 5007, 5008, 5009, 5010,
|
||||
5011, 5012, 5013, 5014,
|
||||
5011, 5012, 5013, 5014, 5015, 5016, 5017, 5018, 5019,
|
||||
];
|
||||
// @hero-setup:region-end
|
||||
|
||||
|
||||
@@ -1,676 +0,0 @@
|
||||
/**
|
||||
* @file HeroBoxComp.ts
|
||||
* @description 英雄面板单个英雄盒组件(UI 视图层)
|
||||
*
|
||||
* 职责:
|
||||
* 1. 同步显示一个已登场英雄的基础信息(图标 / 名称 / 等级 / AP / HP)。
|
||||
* 2. 长按英雄盒同步实例化信息面板(more.prefab),展示次级属性与技能描述;放开手指销毁。
|
||||
* 3. 由 MissionCardComp 实例化到 herosBoxNode 下,最多 3 个,与场上英雄一一对应。
|
||||
* 4. 英雄卖出 / 死亡后槽位保留,通过 applyEmpty() 显示为空英雄信息。
|
||||
*
|
||||
* 依赖:
|
||||
* - HeroAttrsComp —— 英雄属性数据模型
|
||||
* - HeroInfo(heroSet)—— 英雄静态配置
|
||||
*/
|
||||
import { mLogger } from "../common/Logger";
|
||||
import { _decorator, Node, Sprite, Label, resources, AnimationClip, SpriteFrame, NodeEventType, EventTouch, Tween, tween, Vec3, Color, Prefab, instantiate, director, find } from "cc";
|
||||
import { ecs } from "../../../../extensions/oops-plugin-framework/assets/libs/ecs/ECS";
|
||||
import { CCComp } from "../../../../extensions/oops-plugin-framework/assets/module/common/CCComp";
|
||||
import { oops } from "db://oops-framework/core/Oops";
|
||||
import { GameEvent } from "../common/config/GameEvent";
|
||||
import { HeroInfo, calcGrowBonus } from "../common/config/heroSet";
|
||||
import { HeroAttrsComp } from "../hero/HeroAttrsComp";
|
||||
import { Hero } from "../hero/Hero";
|
||||
import { FacSet, FightSet, getLvColor, NumberFormatter } from "../common/config/GameSet";
|
||||
import { buildHeroSkillDesc } from "../common/HeroSkillText";
|
||||
import { MissionEconomy } from "./MissionEconomy";
|
||||
import { UIID } from "../common/config/GameUIConfig";
|
||||
import { HeroMoreCom } from "./HeroMoreCom";
|
||||
|
||||
const { ccclass, property } = _decorator;
|
||||
|
||||
/**
|
||||
* HeroBoxComp —— 英雄面板单个英雄信息盒
|
||||
*
|
||||
* 与场上英雄一一绑定(eid),英雄移除后显示空状态。
|
||||
*/
|
||||
@ccclass('HeroBoxComp')
|
||||
@ecs.register('HeroBoxComp', false)
|
||||
export class HeroBoxComp extends CCComp {
|
||||
private debugMode: boolean = false;
|
||||
|
||||
/** 金币不足时升级费用标红色(暗红,区别于正常白色) */
|
||||
private static readonly INSUFFICIENT_COLOR: Color = new Color(231, 76, 60);
|
||||
|
||||
// ======================== 编辑器绑定节点 ========================
|
||||
|
||||
|
||||
|
||||
/** 英雄图标节点 */
|
||||
@property({ type: Node })
|
||||
private icon_node: Node = null;
|
||||
/** 背景节点 */
|
||||
@property({ type: Node })
|
||||
private bg_node: Node = null;
|
||||
/** 英雄名称 */
|
||||
@property(Label)
|
||||
private name_label: Label = null;
|
||||
/** 等级标签 */
|
||||
@property(Label)
|
||||
private level_label: Label = null;
|
||||
|
||||
/** 空槽位标识节点(未绑定英雄时激活,点击打开英雄卡池) */
|
||||
@property(Node)
|
||||
private noHero: Node = null;
|
||||
|
||||
/** 出售按钮(绑定英雄时激活,点击出售该英雄) */
|
||||
@property(Node)
|
||||
private sell_btn: Node = null;
|
||||
|
||||
/** 升级按钮(绑定英雄时激活,点击弹出升级预览确认框) */
|
||||
@property(Node)
|
||||
private upgrade_btn: Node = null;
|
||||
|
||||
/** 出售价格标签(按英雄等级显示当前卖价,含驻场加成) */
|
||||
@property(Label)
|
||||
private sell_price_label: Label = null;
|
||||
|
||||
/** 升级费用标签(按当前等级显示升级消耗金币,满级时隐藏) */
|
||||
@property(Label)
|
||||
private upgrade_price_label: Label = null;
|
||||
|
||||
// ======================== 战斗信息标签(总值 + 附加值) ========================
|
||||
|
||||
/** 攻击总值 */
|
||||
@property(Label)
|
||||
private ap_all_label: Label = null;
|
||||
/** 攻击附加值 */
|
||||
@property(Label)
|
||||
private ap_plus_label: Label = null;
|
||||
/** 生命总值 */
|
||||
@property(Label)
|
||||
private hp_all_label: Label = null;
|
||||
/** 生命附加值 */
|
||||
@property(Label)
|
||||
private hp_plus_label: Label = null;
|
||||
|
||||
/** 英雄信息弹窗预制体(长按英雄盒时同步实例化展示,绕开 oops.gui 异步加载) */
|
||||
@property(Prefab)
|
||||
private morePrefab: Prefab = null;
|
||||
|
||||
// ======================== 运行时状态 ========================
|
||||
|
||||
/** 绑定的英雄实体 ID(0 表示空槽位) */
|
||||
private eid: number = 0;
|
||||
/** 绑定的英雄属性数据模型引用 */
|
||||
private model: HeroAttrsComp | null = null;
|
||||
/** 图标视觉令牌(异步加载竞态保护) */
|
||||
private iconVisualToken: number = 0;
|
||||
/** 当前显示的英雄 UUID(避免相同 UUID 重复加载动画) */
|
||||
private iconHeroUuid: number = 0;
|
||||
|
||||
/** 当前已弹出的英雄信息面板节点(null 表示未弹出) */
|
||||
private moreNode: Node | null = null;
|
||||
|
||||
/** 长按判定:当前按下触摸 ID(-1 表示无) */
|
||||
private longPressTouchId: number = -1;
|
||||
/** 长按判定:按下起点 UI 坐标 */
|
||||
private longPressStartX: number = 0;
|
||||
private longPressStartY: number = 0;
|
||||
/** 长按触发时长(秒) */
|
||||
private static readonly LONG_PRESS_DURATION = 0.5;
|
||||
/** 长按最大位移容差(像素),超出则取消判定 */
|
||||
private static readonly LONG_PRESS_SLOP = 30;
|
||||
|
||||
// ======================== 生命周期 ========================
|
||||
|
||||
onLoad() {
|
||||
// 长按英雄盒任意区域实例化信息面板(more.prefab);出售/升级按钮上的触摸不触发
|
||||
this.node.on(NodeEventType.TOUCH_START, this.onBoxTouchStart, this);
|
||||
this.node.on(NodeEventType.TOUCH_MOVE, this.onBoxTouchMove, this);
|
||||
this.node.on(NodeEventType.TOUCH_END, this.onBoxTouchEnd, this);
|
||||
this.node.on(NodeEventType.TOUCH_CANCEL, this.onBoxTouchCancel, this);
|
||||
// 空槽位点击 → 打开英雄卡池
|
||||
this.noHero?.on(NodeEventType.TOUCH_END, this.onNoHeroClick, this);
|
||||
// 出售按钮点击 → 出售当前绑定英雄
|
||||
this.sell_btn?.on(NodeEventType.TOUCH_END, this.onSellHeroClick, this);
|
||||
// 升级按钮点击 → 弹出升级预览确认框
|
||||
this.upgrade_btn?.on(NodeEventType.TOUCH_END, this.onUpgradeHeroClick, this);
|
||||
}
|
||||
|
||||
onDestroy() {
|
||||
if (this.node && this.node.isValid) {
|
||||
this.node.off(NodeEventType.TOUCH_START, this.onBoxTouchStart, this);
|
||||
this.node.off(NodeEventType.TOUCH_MOVE, this.onBoxTouchMove, this);
|
||||
this.node.off(NodeEventType.TOUCH_END, this.onBoxTouchEnd, this);
|
||||
this.node.off(NodeEventType.TOUCH_CANCEL, this.onBoxTouchCancel, this);
|
||||
}
|
||||
if (this.noHero && this.noHero.isValid) {
|
||||
this.noHero.off(NodeEventType.TOUCH_END, this.onNoHeroClick, this);
|
||||
}
|
||||
if (this.sell_btn && this.sell_btn.isValid) {
|
||||
this.sell_btn.off(NodeEventType.TOUCH_END, this.onSellHeroClick, this);
|
||||
}
|
||||
if (this.upgrade_btn && this.upgrade_btn.isValid) {
|
||||
this.upgrade_btn.off(NodeEventType.TOUCH_END, this.onUpgradeHeroClick, this);
|
||||
}
|
||||
// 销毁时一并清理已弹出的信息面板
|
||||
this.closeMoreNode();
|
||||
}
|
||||
|
||||
/**
|
||||
* 升级按钮点击:构建升级后新能力预览,弹出公共确认框。
|
||||
* Why: 升级消耗金币不可逆,需展示收益并二次确认。
|
||||
*/
|
||||
private onUpgradeHeroClick() {
|
||||
if (!this.eid || !this.model) return;
|
||||
const heroLv = Math.max(1, Math.floor(this.model.lv ?? 1));
|
||||
// 无限升级:不再拦截满级
|
||||
oops.audio.playEffect("music/button");
|
||||
|
||||
const nextLv = heroLv + 1;
|
||||
const cost = MissionEconomy.getUpgradeCost(heroLv);
|
||||
// 金币不足:smalltip 气泡提示(挂载金币节点),不弹确认框
|
||||
if (MissionEconomy.getCoin() < cost) {
|
||||
oops.message.dispatchEvent(GameEvent.ShowSmallTip, { type: "buy_coin", text: "金币不足" });
|
||||
return;
|
||||
}
|
||||
const preview = this.buildUpgradePreview(heroLv, nextLv);
|
||||
|
||||
// oops.gui 公共确认窗口(自定义 CommonPrompt:内容支持富文本高亮)
|
||||
oops.gui.open(UIID.Window, {
|
||||
title: `升级英雄`,
|
||||
content: preview,
|
||||
okWord: "升级",
|
||||
cancelWord: "取消",
|
||||
needCancel: true,
|
||||
okFunc: () => this.executeUpgradeHero()
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行升级:校验状态后派发 HeroUpgrade 事件,由 MissionCardComp 扣费并应用等级。
|
||||
* Why: 扣费/属性重算统一走 MissionCardComp(与升级卡共用 tryUpgradeHeroByEid),
|
||||
* 本组件仅负责 UI 交互与预览,保证单一数据源。
|
||||
*/
|
||||
private executeUpgradeHero() {
|
||||
// 确认窗口打开期间英雄可能已死亡/被移除,需二次校验
|
||||
if (!this.eid || !this.model) return;
|
||||
oops.message.dispatchEvent(GameEvent.HeroUpgrade, { eid: this.eid });
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建升级前后对比富文本(当前属性/能力 vs 升级后属性/能力)。
|
||||
* 技能描述统一按局外等级口径渲染(buildHeroSkillDesc),与英雄信息弹窗同一套
|
||||
* 文案规则;战斗内升级不改变局外等级,故技能段前后一致,仅属性段随等级变化。
|
||||
*
|
||||
* @param heroLv 当前英雄等级
|
||||
* @param nextLv 目标等级
|
||||
* @returns 多行富文本:当前属性→升级后属性 + 当前技能 vs 升级后技能
|
||||
*/
|
||||
private buildUpgradePreview(heroLv: number, nextLv: number): string {
|
||||
const hero = HeroInfo[this.model?.hero_uuid ?? 0];
|
||||
if (!hero) return "";
|
||||
|
||||
// ---- 属性成长(固定基础值 + 成长类型指数递增 + 一次性加成) ----
|
||||
const attrLine = (lv: number): string => {
|
||||
const grow = calcGrowBonus(hero, lv);
|
||||
const ap = Math.floor(hero.ap + grow.ap + HeroBoxComp.sumBonusPct(hero.ap + grow.ap, hero.bonus, 'ap', lv));
|
||||
const hp = Math.floor(hero.hp + grow.hp + HeroBoxComp.sumBonusPct(hero.hp + grow.hp, hero.bonus, 'hp', lv));
|
||||
return `攻击 <color=#27AE60>${ap}</color> 生命 <color=#27AE60>${hp}</color>`;
|
||||
};
|
||||
|
||||
// ---- 升级前后能力对比(局外等级口径,战斗内升级技能段不变) ----
|
||||
const skillDesc = buildHeroSkillDesc(hero.uuid);
|
||||
const curDesc = skillDesc;
|
||||
const nextDesc = skillDesc;
|
||||
|
||||
return `<outline color=#000000 width=2>` + [
|
||||
`<b>当前 Lv.${heroLv}:</b>`,
|
||||
attrLine(heroLv),
|
||||
curDesc,
|
||||
``,
|
||||
`<b>升级后 Lv.${nextLv}:</b>`,
|
||||
attrLine(nextLv),
|
||||
nextDesc,
|
||||
].filter(s => s !== undefined).join("\n") + `</outline>`;
|
||||
}
|
||||
|
||||
/** 累加等级额外加成(≤目标等级的所有档位) */
|
||||
/** 累加 bonus 中某百分比键的档位总量,并按"基础+成长"快照换算为固定增量(≤目标等级的所有档位) */
|
||||
private static sumBonusPct(snap: number, entries: HeroInfo[number]['bonus'], key: 'hp' | 'ap' | 'def', lv: number): number {
|
||||
if (!entries) return 0;
|
||||
let pct = 0;
|
||||
for (const e of entries) { if (e.lv <= lv) pct += e.attrs[key] ?? 0; }
|
||||
return Math.round(snap * pct / 100);
|
||||
}
|
||||
|
||||
/**
|
||||
* 出售按钮点击:弹出公共确认窗口,确认后再执行出售。
|
||||
* Why: 出售不可逆,需二次确认防止误触。
|
||||
*/
|
||||
private onSellHeroClick() {
|
||||
if (!this.eid || !this.model) return;
|
||||
// 场上仅剩 1 个英雄时不允许出售:复用英雄栏 smalltip 气泡提示(与满员同一挂载点)
|
||||
if (HeroBoxComp.getAliveHeroCount() <= 1) {
|
||||
oops.message.dispatchEvent(GameEvent.ShowSmallTip, { type: "hero_full", text: "至少保留 1 个英雄" });
|
||||
return;
|
||||
}
|
||||
oops.audio.playEffect("music/button");
|
||||
|
||||
const heroName = this.model.hero_name ?? "";
|
||||
const heroLv = Math.max(1, Math.floor(this.model.lv ?? 1));
|
||||
const gold = MissionEconomy.getSellGold(heroLv);
|
||||
|
||||
// oops.gui 公共确认窗口(自定义 CommonPrompt:内容支持富文本高亮)
|
||||
oops.gui.open(UIID.Window, {
|
||||
title: "出售英雄",
|
||||
content: `确定出售 <color=#C0392B>${heroName}</color>(Lv.${heroLv})吗?\n出售后获得 <color=#1E8449>${gold}</color> 金币`,
|
||||
okWord: "出售",
|
||||
cancelWord: "取消",
|
||||
needCancel: true,
|
||||
okFunc: () => this.executeSellHero()
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行出售:移除英雄实体、按等级结算金币并派发 HeroSell 事件。
|
||||
* MissionCardComp 监听该事件后会刷新槽位,本盒自动切为空状态。
|
||||
*/
|
||||
private executeSellHero() {
|
||||
// 确认窗口打开期间英雄可能已死亡/被移除,需二次校验
|
||||
if (!this.eid || !this.model) return;
|
||||
const heroLv = Math.max(1, Math.floor(this.model.lv ?? 1));
|
||||
// 移除 ECS 实体失败(实体已失效)则不做后续结算
|
||||
if (!Hero.removeByEid(this.eid)) return;
|
||||
|
||||
// 统一经济管理入口:按等级计算卖价并加金币
|
||||
const gold = MissionEconomy.executeSellHero(heroLv);
|
||||
mLogger.log(this.debugMode, "HeroBoxComp", "executeSellHero", { eid: this.eid, heroLv, gold });
|
||||
|
||||
// 通知 MissionCardComp 更新场上英雄数量并刷新英雄盒槽位
|
||||
oops.message.dispatchEvent(GameEvent.HeroSell, { eid: this.eid });
|
||||
}
|
||||
|
||||
/**
|
||||
* 空槽位点击:播放主节点点击动画,并派发事件通知 MissionCardComp 展示英雄卡池。
|
||||
*/
|
||||
private onNoHeroClick() {
|
||||
oops.audio.playEffect("music/button");
|
||||
this.playClickAnim();
|
||||
oops.message.dispatchEvent(GameEvent.HeroBoxEmptyClick);
|
||||
}
|
||||
|
||||
/** 主节点点击动画:缩放按下 → 回弹 */
|
||||
private playClickAnim() {
|
||||
if (!this.node || !this.node.isValid) return;
|
||||
Tween.stopAllByTarget(this.node);
|
||||
this.node.setScale(1, 1, 1);
|
||||
tween(this.node)
|
||||
.to(0.06, { scale: new Vec3(0.94, 0.94, 1) })
|
||||
.to(0.1, { scale: new Vec3(1, 1, 1) })
|
||||
.start();
|
||||
}
|
||||
|
||||
/** 刷新计时累计(降频刷新实时属性) */
|
||||
private refreshElapsed: number = 0;
|
||||
/** 实时刷新间隔(秒) */
|
||||
private static readonly REFRESH_INTERVAL = 0.25;
|
||||
|
||||
/**
|
||||
* 帧更新:绑定英雄后按固定间隔实时刷新面板信息。
|
||||
* Why: AP/HP/暴击等属性受 buff/光环影响实时变化,需降频轮询同步;
|
||||
* 实体失效时 refresh 会自动切换为空状态。
|
||||
*/
|
||||
update(dt: number) {
|
||||
if (!this.model) return;
|
||||
this.refreshElapsed += dt;
|
||||
if (this.refreshElapsed < HeroBoxComp.REFRESH_INTERVAL) return;
|
||||
this.refreshElapsed = 0;
|
||||
this.refresh();
|
||||
}
|
||||
|
||||
/**
|
||||
* 英雄盒按下:记录起点并启动长按判定。
|
||||
* 出售/升级按钮上的触摸不触发长按(按钮有各自的 TOUCH_END 行为)。
|
||||
*/
|
||||
private onBoxTouchStart(event: EventTouch) {
|
||||
if (!this.hasHero) return;
|
||||
const target = event.target as Node | null;
|
||||
if (this.isNodeWithin(target, this.sell_btn) || this.isNodeWithin(target, this.upgrade_btn)) return;
|
||||
this.longPressTouchId = event.touch?.getID() ?? -1;
|
||||
const pos = event.getUILocation();
|
||||
this.longPressStartX = pos.x;
|
||||
this.longPressStartY = pos.y;
|
||||
this.scheduleOnce(this.onLongPressFired, HeroBoxComp.LONG_PRESS_DURATION);
|
||||
}
|
||||
|
||||
/** 英雄盒拖动:位移超出容差取消长按判定 */
|
||||
private onBoxTouchMove(event: EventTouch) {
|
||||
if (this.longPressTouchId < 0) return;
|
||||
if ((event.touch?.getID() ?? -1) !== this.longPressTouchId) return;
|
||||
const pos = event.getUILocation();
|
||||
const dx = pos.x - this.longPressStartX;
|
||||
const dy = pos.y - this.longPressStartY;
|
||||
if (dx * dx + dy * dy > HeroBoxComp.LONG_PRESS_SLOP * HeroBoxComp.LONG_PRESS_SLOP) {
|
||||
this.cancelLongPress();
|
||||
}
|
||||
}
|
||||
|
||||
/** 英雄盒抬起:取消未触发的长按判定;若长按已弹出信息面板则立即关闭 */
|
||||
private onBoxTouchEnd(event: EventTouch) {
|
||||
if (this.longPressTouchId < 0) return;
|
||||
if ((event.touch?.getID() ?? -1) !== this.longPressTouchId) return;
|
||||
this.cancelLongPress();
|
||||
// 直接销毁已弹出的信息面板(同步 destroy,无竞态)
|
||||
this.closeMoreNode();
|
||||
}
|
||||
|
||||
/** 英雄盒触摸被系统打断:取消长按判定;若已弹窗则一并关闭 */
|
||||
private onBoxTouchCancel(event: EventTouch) {
|
||||
this.onBoxTouchEnd(event);
|
||||
}
|
||||
|
||||
/** 取消长按判定(复位触摸 ID 并移除定时) */
|
||||
private cancelLongPress() {
|
||||
this.longPressTouchId = -1;
|
||||
this.unschedule(this.onLongPressFired);
|
||||
}
|
||||
|
||||
/** 长按触发:同步实例化英雄信息面板(more.prefab,展示次级属性与技能描述) */
|
||||
private onLongPressFired() {
|
||||
// 不重置 longPressTouchId:保留以便 onBoxTouchEnd 能识别同一触摸并销毁弹窗
|
||||
if (!this.hasHero || !(this.model as any)?.ent) return;
|
||||
if (!this.morePrefab) {
|
||||
mLogger.warn(true, "HeroBoxComp", "onLongPressFired morePrefab 未绑定,请在编辑器拖入 more.prefab");
|
||||
return;
|
||||
}
|
||||
oops.audio.playEffect("music/button");
|
||||
// 同步实例化:避开 oops.gui 首次异步加载窗口期,确保放开时能立即 destroy
|
||||
this.closeMoreNode();
|
||||
this.moreNode = instantiate(this.morePrefab);
|
||||
// more.prefab 是全屏遮罩弹窗,必须挂到 Canvas 根节点,避免被英雄盒父节点的 Mask 裁剪或坐标系错位
|
||||
const canvas = find("Canvas") || director.getScene()?.getChildByName("Canvas");
|
||||
(canvas ?? this.node.parent)?.addChild(this.moreNode);
|
||||
// 整体上移 100 像素(弹窗相对英雄盒偏上展示)
|
||||
this.moreNode.setPosition(this.moreNode.position.x, this.moreNode.position.y + 100, this.moreNode.position.z);
|
||||
this.moreNode.getComponent(HeroMoreCom)?.init(this.eid);
|
||||
}
|
||||
|
||||
/** 关闭并清理已弹出的英雄信息面板(同步 destroy) */
|
||||
private closeMoreNode() {
|
||||
if (this.moreNode && this.moreNode.isValid) {
|
||||
this.moreNode.destroy();
|
||||
}
|
||||
this.moreNode = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断触摸目标节点是否位于指定祖先节点(含自身)之内。
|
||||
* @param target 触摸命中的节点(可能为空)
|
||||
* @param ancestor 祖先节点(可能为空,空时返回 false)
|
||||
* @returns 命中节点是否为 ancestor 的后代或自身
|
||||
*/
|
||||
private isNodeWithin(target: Node | null, ancestor: Node | null): boolean {
|
||||
if (!target || !ancestor || !ancestor.isValid) return false;
|
||||
let cur: Node | null = target;
|
||||
while (cur) {
|
||||
if (cur === ancestor) return true;
|
||||
if (cur === this.node) break;
|
||||
cur = cur.parent;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/** ECS 组件移除时销毁节点 */
|
||||
reset() {
|
||||
if (this.node && this.node.isValid) {
|
||||
this.node.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
// ======================== 数据绑定 ========================
|
||||
|
||||
/** 当前槽位是否绑定了英雄 */
|
||||
public get hasHero(): boolean {
|
||||
return this.eid > 0 && !!this.model;
|
||||
}
|
||||
|
||||
/** 当前绑定的英雄实体 ID */
|
||||
public get bindEid(): number {
|
||||
return this.eid;
|
||||
}
|
||||
|
||||
/**
|
||||
* 绑定场上英雄并刷新显示。
|
||||
* @param eid 英雄 ECS 实体 ID
|
||||
* @param model 英雄属性组件
|
||||
*/
|
||||
public bindHero(eid: number, model: HeroAttrsComp) {
|
||||
this.eid = eid;
|
||||
this.model = model;
|
||||
this.node.active = true;
|
||||
if (this.noHero && this.noHero.isValid) {
|
||||
this.noHero.active = false;
|
||||
}
|
||||
if (this.sell_btn && this.sell_btn.isValid) {
|
||||
this.sell_btn.active = true;
|
||||
}
|
||||
if (this.upgrade_btn && this.upgrade_btn.isValid) {
|
||||
this.upgrade_btn.active = true;
|
||||
}
|
||||
this.refresh();
|
||||
}
|
||||
|
||||
/** 清空槽位,显示空英雄信息 */
|
||||
public applyEmpty() {
|
||||
this.eid = 0;
|
||||
this.model = null;
|
||||
this.iconHeroUuid = 0;
|
||||
this.iconVisualToken += 1;
|
||||
|
||||
if (this.noHero && this.noHero.isValid) {
|
||||
this.noHero.active = true;
|
||||
}
|
||||
|
||||
if (this.sell_btn && this.sell_btn.isValid) {
|
||||
this.sell_btn.active = false;
|
||||
}
|
||||
if (this.upgrade_btn && this.upgrade_btn.isValid) {
|
||||
this.upgrade_btn.active = false;
|
||||
}
|
||||
if (this.sell_price_label && this.sell_price_label.isValid) {
|
||||
this.sell_price_label.string = "";
|
||||
}
|
||||
if (this.upgrade_price_label && this.upgrade_price_label.isValid) {
|
||||
this.upgrade_price_label.string = "";
|
||||
}
|
||||
|
||||
if (this.name_label && this.name_label.isValid) {
|
||||
this.name_label.string = "";
|
||||
}
|
||||
if (this.level_label && this.level_label.isValid) {
|
||||
this.level_label.string = "";
|
||||
}
|
||||
if (this.icon_node && this.icon_node.isValid) {
|
||||
const sprite = this.icon_node.getComponent(Sprite) || this.icon_node.getComponentInChildren(Sprite);
|
||||
if (sprite) sprite.spriteFrame = null;
|
||||
}
|
||||
this.clearStatRow(this.ap_all_label, this.ap_plus_label);
|
||||
this.clearStatRow(this.hp_all_label, this.hp_plus_label);
|
||||
}
|
||||
|
||||
/**
|
||||
* 刷新显示:同步英雄等级、名称、AP / HP 与图标(次级属性与技能描述已分离至 HeroMoreCom 弹窗)。
|
||||
* 绑定的英雄实体已失效时自动切换为空状态。
|
||||
*/
|
||||
public refresh() {
|
||||
if (!this.model || !(this.model as any).ent) {
|
||||
this.applyEmpty();
|
||||
return;
|
||||
}
|
||||
|
||||
const heroUuid = this.model.hero_uuid ?? 0;
|
||||
const hero = HeroInfo[heroUuid];
|
||||
|
||||
// ---- 背景(按 rarity 切换 bg_node 颜色子节点) ----
|
||||
this.updateBgNode(hero?.rarity ?? 1);
|
||||
|
||||
// ---- 名称 ----
|
||||
if (this.name_label && this.name_label.isValid) {
|
||||
this.name_label.string = this.model.hero_name ?? "";
|
||||
}
|
||||
|
||||
// ---- 等级 ----
|
||||
if (this.level_label && this.level_label.isValid) {
|
||||
const lv = this.model.lv ?? 1;
|
||||
this.level_label.string = `Lv.${lv}`;
|
||||
this.level_label.color = getLvColor(lv);
|
||||
}
|
||||
|
||||
// ---- 出售价格(按等级计算) ----
|
||||
if (this.sell_price_label && this.sell_price_label.isValid) {
|
||||
const lv = Math.max(1, Math.floor(this.model.lv ?? 1));
|
||||
this.sell_price_label.string = `${MissionEconomy.getSellGold(lv)}`;
|
||||
}
|
||||
|
||||
// ---- 升级费用(无限升级:始终显示;金币不足时标红提示) ----
|
||||
if (this.upgrade_price_label && this.upgrade_price_label.isValid) {
|
||||
const lv = Math.max(1, Math.floor(this.model.lv ?? 1));
|
||||
const cost = MissionEconomy.getUpgradeCost(lv);
|
||||
this.upgrade_price_label.string = `${cost}`;
|
||||
// 金币不足标红,足够恢复默认色,给玩家直观的可升级反馈
|
||||
this.upgrade_price_label.color = MissionEconomy.getCoin() >= cost ? Color.WHITE : HeroBoxComp.INSUFFICIENT_COLOR;
|
||||
}
|
||||
|
||||
// ---- AP / HP ----
|
||||
// plus(附加值)= 最终值 - 当前等级基础值;基础值 = 1 级原始 base + 等级成长 + bonus 百分比加成。
|
||||
// Why: base_ap/base_hp 是不含任何等级增长的原始值,直接用 final-base 会把升级带来的
|
||||
// 属性增长也计入增量。这里补齐等级增长作为基准,使 plus 仅反映 buff/光环等临时增益。
|
||||
const lv = Math.max(1, Math.floor(this.model.lv ?? 1));
|
||||
const grow = hero ? calcGrowBonus(hero, lv) : { ap: 0, hp: 0 };
|
||||
|
||||
const finalAp = Math.max(0, Math.floor(this.model.getFinalAp()));
|
||||
const lvBaseAp = Math.max(0, Math.floor((this.model.base_ap ?? 0) + grow.ap + HeroBoxComp.sumBonusPct((this.model.base_ap ?? 0) + grow.ap, hero?.bonus, 'ap', lv)));
|
||||
this.setStatRow(this.ap_all_label, this.ap_plus_label, finalAp, finalAp - lvBaseAp);
|
||||
|
||||
const finalHp = Math.max(0, Math.floor(this.model.getFinalHpMax()));
|
||||
const lvBaseHp = Math.max(0, Math.floor((this.model.base_hp ?? 0) + grow.hp + HeroBoxComp.sumBonusPct((this.model.base_hp ?? 0) + grow.hp, hero?.bonus, 'hp', lv)));
|
||||
this.setStatRow(this.hp_all_label, this.hp_plus_label, finalHp, finalHp - lvBaseHp);
|
||||
|
||||
// ---- 图标(UUID 变化时重新加载首帧动画) ----
|
||||
if (hero && heroUuid !== this.iconHeroUuid) {
|
||||
this.iconHeroUuid = heroUuid;
|
||||
this.iconVisualToken += 1;
|
||||
this.updateHeroIcon(hero.path, heroUuid, this.iconVisualToken);
|
||||
}
|
||||
}
|
||||
|
||||
// ======================== 内部工具 ========================
|
||||
|
||||
/**
|
||||
* 根据 rarity 切换 bg_node 下的颜色子节点显示。
|
||||
* 等级与颜色对应关系:
|
||||
* rarity 1 → green
|
||||
* rarity 2 → blue
|
||||
* rarity 3 → purple
|
||||
* rarity 4 → red
|
||||
* rarity 5 → yellow
|
||||
* @param rarity 英雄卡牌等级(HeroInfo.rarity,缺省按 1 处理)
|
||||
*/
|
||||
private updateBgNode(rarity: number) {
|
||||
if (!this.bg_node || !this.bg_node.isValid) return;
|
||||
const lvToColor: Record<number, string> = {
|
||||
1: "green",
|
||||
2: "blue",
|
||||
3: "purple",
|
||||
4: "red",
|
||||
5: "yellow",
|
||||
};
|
||||
const targetColor = lvToColor[rarity] ?? lvToColor[1];
|
||||
this.bg_node.children.forEach(child => {
|
||||
child.active = (child.name === targetColor);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 统计场上存活英雄数量(与 MissionCardComp.getAliveHeroCount 口径一致)。
|
||||
*/
|
||||
private static getAliveHeroCount(): number {
|
||||
let count = 0;
|
||||
ecs.query(ecs.allOf(HeroAttrsComp)).forEach((entity: ecs.Entity) => {
|
||||
const model = entity.get(HeroAttrsComp);
|
||||
if (model && model.fac === FacSet.HERO) {
|
||||
count++;
|
||||
}
|
||||
});
|
||||
return count;
|
||||
}
|
||||
|
||||
/**
|
||||
* 写入一行战斗信息(总值 + 附加值)。
|
||||
* 总值始终显示(0 不隐藏);附加值为 0 时隐藏,正/负分别显示 (+x) / (x)。
|
||||
*
|
||||
* @param allLabel 总值标签(可为空,空时跳过)
|
||||
* @param plusLabel 附加值标签(可为空)
|
||||
* @param total 总数值(最终生效值)
|
||||
* @param bonus 附加数值(最终值 - 基础值)
|
||||
* @param suffix 数值后缀(如 "%")
|
||||
* @param decimals 保留小数位数(默认 0,取整)
|
||||
*/
|
||||
private setStatRow(allLabel: Label | null, plusLabel: Label | null, total: number, bonus: number, suffix: string = "", decimals: number = 0) {
|
||||
// 整数数值统一走 NumberFormatter 千分位缩写(如 12.3k),避免大数值溢出标签
|
||||
const fmt = (v: number) => decimals > 0 ? v.toFixed(decimals) : NumberFormatter.formatNumber(Math.floor(v));
|
||||
if (allLabel && allLabel.isValid) {
|
||||
allLabel.string = `${fmt(total)}${suffix}`;
|
||||
}
|
||||
if (plusLabel && plusLabel.isValid) {
|
||||
if (bonus !== 0) {
|
||||
plusLabel.string = bonus > 0 ? `(+${fmt(bonus)}${suffix})` : `(${fmt(bonus)}${suffix})`;
|
||||
} else {
|
||||
plusLabel.string = "";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** 清空一行战斗信息(空槽位时使用) */
|
||||
private clearStatRow(allLabel: Label | null, plusLabel: Label | null) {
|
||||
if (allLabel && allLabel.isValid) allLabel.string = "";
|
||||
if (plusLabel && plusLabel.isValid) plusLabel.string = "";
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载英雄 idle 动画首帧作为静态图标。
|
||||
* @param path 英雄美术资源名(HeroInfo.path)
|
||||
* @param uuid 英雄 UUID(竞态校验用)
|
||||
* @param token 视觉令牌(竞态保护)
|
||||
*/
|
||||
private updateHeroIcon(path: string, uuid: number, token: number) {
|
||||
if (!this.icon_node || !this.icon_node.isValid) return;
|
||||
const sprite = this.icon_node.getComponent(Sprite) || this.icon_node.getComponentInChildren(Sprite);
|
||||
if (sprite) sprite.spriteFrame = null;
|
||||
|
||||
resources.load(`game/heros/hero/${path}/idle`, AnimationClip, (err, clip) => {
|
||||
if (err || !clip) return;
|
||||
// 异步加载期间槽位可能已被复用 / 清空
|
||||
if (token !== this.iconVisualToken) return;
|
||||
if (this.iconHeroUuid !== uuid) return;
|
||||
if (!this.icon_node || !this.icon_node.isValid) return;
|
||||
const target = this.icon_node.getComponent(Sprite) || this.icon_node.getComponentInChildren(Sprite);
|
||||
if (!target || !target.isValid) return;
|
||||
// 帧动画数据存于 spriteFrame 轨道的 _channel._curve._values(裸 SpriteFrame 数组)
|
||||
let firstFrame: SpriteFrame | undefined;
|
||||
for (const track of clip.tracks) {
|
||||
const curve = (track as unknown as { channel?: { curve?: { _values?: unknown[] } } }).channel?.curve;
|
||||
const frame = curve?._values?.[0];
|
||||
if (frame instanceof SpriteFrame) {
|
||||
firstFrame = frame;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (firstFrame) {
|
||||
target.spriteFrame = firstFrame;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
{"ver":"4.0.24","importer":"typescript","imported":true,"uuid":"518b8ddd-3a02-40d8-bbfd-d61182b7414d","files":[],"subMetas":{},"userData":{}}
|
||||
@@ -3,11 +3,10 @@
|
||||
* @description 英雄信息弹窗组件(UI 视图层)
|
||||
*
|
||||
* 职责:
|
||||
* 1. 展示单个英雄的次级属性(攻速/击晕/暴击/爆伤/冰冻/击退/穿透/风怒)与技能描述,
|
||||
* 展示内容由原 HeroBoxComp 分离而来,计算口径与其完全一致。
|
||||
* 2. 由 HeroBoxComp 长按英雄盒时同步实例化(instantiate more.prefab)并调用 init(eid)。
|
||||
* 1. 展示单个英雄的次级属性(攻速/击晕/暴击/爆伤/冰冻/击退/穿透/风怒)与技能描述。
|
||||
* 2. 由调用方同步实例化(instantiate more.prefab)并调用 init(eid)。
|
||||
* 3. 属性受 buff/光环影响实时变化,打开期间按固定间隔降频刷新;英雄死亡/被卖出自动关闭。
|
||||
* 4. 点击弹窗内任意位置(含全屏透明遮罩)或 HeroBoxComp 放开手指时由调用方 destroy。
|
||||
* 4. 点击弹窗内任意位置(含全屏透明遮罩)时由调用方 destroy。
|
||||
*
|
||||
* 依赖:
|
||||
* - HeroAttrsComp —— 英雄属性数据模型
|
||||
@@ -110,7 +109,7 @@ export class HeroMoreCom extends Component {
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化并渲染英雄信息(由 HeroBoxComp 在 instantiate 后同步调用)。
|
||||
* 初始化并渲染英雄信息(由调用方在 instantiate 后同步调用)。
|
||||
* @param eid 英雄 ECS 实体 ID;实体不存在时立即销毁
|
||||
*/
|
||||
public init(eid: number) {
|
||||
@@ -155,7 +154,7 @@ export class HeroMoreCom extends Component {
|
||||
|
||||
/**
|
||||
* 刷新显示:8 行次级属性(总值 + 附加值)+ 技能描述富文本。
|
||||
* 附加 = 最终生效值 - 基础配置值,与原 HeroBoxComp 口径一致。
|
||||
* 附加 = 最终生效值 - 基础配置值。
|
||||
*/
|
||||
private refresh() {
|
||||
if (!this.model) return;
|
||||
@@ -230,7 +229,7 @@ export class HeroMoreCom extends Component {
|
||||
|
||||
// ======================== 交互 ========================
|
||||
|
||||
/** 点击面板任意处(含遮罩)关闭(备用交互,主路径由 HeroBoxComp 放开手指 destroy) */
|
||||
/** 点击面板任意处(含遮罩)关闭(备用交互,主路径由调用方 destroy) */
|
||||
private onTouchEndClose() {
|
||||
oops.audio.playEffect("music/button");
|
||||
this.closeSelf();
|
||||
|
||||
@@ -47,7 +47,6 @@ import { drawItemCards } from "../common/config/ICardSet";
|
||||
import { drawSkillCards } from "../common/config/SCardSet";
|
||||
import { CHeroComp } from "./CHeroComp";
|
||||
import { EquipListComp } from "./EquipListComp";
|
||||
import { HeroBoxComp } from "./HeroBoxComp";
|
||||
import { SCardComp } from "./SCardComp";
|
||||
import { MissEquipComp } from "./MissEquipComp";
|
||||
import { MissSkillsComp } from "./MissSkillsComp";
|
||||
@@ -109,8 +108,6 @@ export class MissionCardComp extends CCComp {
|
||||
showHeros: Node = null!
|
||||
@property(Node)
|
||||
herosPanNode: Node = null!
|
||||
@property(Node)
|
||||
herosBoxNode: Node = null!
|
||||
/** 英雄抽卡面板开启金币费用显示节点 */
|
||||
@property(Node)
|
||||
showHerosCost: Node = null!
|
||||
@@ -189,8 +186,6 @@ export class MissionCardComp extends CCComp {
|
||||
|
||||
/** 三个槽位对应的 CHeroComp 控制器缓存(有序数组) */
|
||||
private cardComps: CHeroComp[] = [];
|
||||
/** 英雄面板 HeroBoxComp 控制器缓存(与场上英雄一一对应,最多 3 个) */
|
||||
private heroBoxComps: HeroBoxComp[] = [];
|
||||
/** 装备卡槽控制器缓存 */
|
||||
private equipCardComps: EquipListComp[] = [];
|
||||
/** 技能卡槽控制器缓存 */
|
||||
@@ -266,7 +261,6 @@ export class MissionCardComp extends CCComp {
|
||||
onLoad() {
|
||||
this.bindEvents();
|
||||
this.cacheCardComps();
|
||||
this.hideAllHeroBoxSlots();
|
||||
this.initCardsPanelPos();
|
||||
this.initPanelLayout();
|
||||
// 初始即永久隐藏手动插卡按钮,任何阶段都不再激活
|
||||
@@ -360,9 +354,6 @@ export class MissionCardComp extends CCComp {
|
||||
this.hasCalledHero = false;
|
||||
this.updatePanelButtonsInteractable();
|
||||
|
||||
// 初始化英雄信息盒(3 个空槽位)
|
||||
// 暂不启用 herobox 同步显示英雄信息(后续可能恢复),保留代码备查
|
||||
// this.refreshHeroBoxSlots();
|
||||
|
||||
// 重置开局免费三选一次数与选择计数,随后立即弹出第 1 组三选一
|
||||
this.openingFreePicks = MissionCardComp.OPENING_FREE_PICK_COUNT;
|
||||
@@ -378,17 +369,12 @@ export class MissionCardComp extends CCComp {
|
||||
mLogger.log(this.debugMode, "MissionCardComp", "mission start");
|
||||
}
|
||||
|
||||
/** 任务结束:清空 3 槽 + 装备商店 + 技能卡槽 + 英雄面板并隐藏整个节点 */
|
||||
/** 任务结束:清空 3 槽 + 装备商店 + 技能卡槽并隐藏整个节点 */
|
||||
onMissionEnd() {
|
||||
this.clearAllCards();
|
||||
this.clearEquipments();
|
||||
this.clearSkillCards();
|
||||
this.clearShopItems();
|
||||
for (const comp of this.heroBoxComps) {
|
||||
if (comp && comp.node && comp.node.isValid) {
|
||||
comp.applyEmpty();
|
||||
}
|
||||
}
|
||||
// 任务结束清理:停止新手卡牌引导动画
|
||||
this.stopCardsGuideAnim();
|
||||
this.unscheduleAllCallbacks();
|
||||
@@ -439,8 +425,6 @@ export class MissionCardComp extends CCComp {
|
||||
oops.message.on(GameEvent.UseSpecialCard, this.onUseSpecialCard, this);
|
||||
oops.message.on(GameEvent.ShowSmallTip, this.onShowSmallTip, this);
|
||||
oops.message.on(GameEvent.CardUsed, this.onCardUsed, this);
|
||||
oops.message.on(GameEvent.HeroBoxEmptyClick, this.onHeroBoxEmptyClick, this);
|
||||
oops.message.on(GameEvent.HeroUpgrade, this.onHeroUpgrade, this);
|
||||
|
||||
/** 按钮触控事件:抽卡 */
|
||||
this.cards_refresh?.on(NodeEventType.TOUCH_START, this.onDrawTouchStart, this);
|
||||
@@ -698,8 +682,6 @@ export class MissionCardComp extends CCComp {
|
||||
oops.message.off(GameEvent.UseSpecialCard, this.onUseSpecialCard, this);
|
||||
oops.message.off(GameEvent.ShowSmallTip, this.onShowSmallTip, this);
|
||||
oops.message.off(GameEvent.CardUsed, this.onCardUsed, this);
|
||||
oops.message.off(GameEvent.HeroBoxEmptyClick, this.onHeroBoxEmptyClick, this);
|
||||
oops.message.off(GameEvent.HeroUpgrade, this.onHeroUpgrade, this);
|
||||
if (this.cards_refresh && this.cards_refresh.isValid) {
|
||||
this.cards_refresh.off(NodeEventType.TOUCH_START, this.onDrawTouchStart, this);
|
||||
this.cards_refresh.off(NodeEventType.TOUCH_END, this.onDrawTouchEnd, this);
|
||||
@@ -756,56 +738,20 @@ export class MissionCardComp extends CCComp {
|
||||
this.hasCalledHero = true;
|
||||
this.updatePanelButtonsInteractable();
|
||||
}
|
||||
|
||||
|
||||
|
||||
// 英雄登场后同步英雄信息盒
|
||||
// 暂不启用 herobox 同步(后续可能恢复)
|
||||
// this.refreshHeroBoxSlots();
|
||||
}
|
||||
|
||||
/** 英雄死亡事件回调:刷新面板列表并更新英雄数量 UI */
|
||||
/** 英雄死亡事件回调:更新英雄数量 UI */
|
||||
private onHeroDead() {
|
||||
this.updateHeroNumUI(true, false);
|
||||
// 暂不启用 herobox 同步(后续可能恢复)
|
||||
// this.refreshHeroBoxSlots();
|
||||
}
|
||||
|
||||
/** 英雄被出售事件回调:更新英雄数量 UI 并清空对应英雄信息盒 */
|
||||
/** 英雄被出售事件回调:更新英雄数量 UI */
|
||||
private onHeroSell() {
|
||||
this.updateHeroNumUI(true, false);
|
||||
// 暂不启用 herobox 同步(后续可能恢复)
|
||||
// this.refreshHeroBoxSlots();
|
||||
}
|
||||
|
||||
/**
|
||||
* 英雄面板升级请求回调(由 HeroBoxComp 确认弹窗后派发)。
|
||||
* 扣费成功后按 eid 精确升级;金币不足或不可升级时 toast 提示。
|
||||
*/
|
||||
private onHeroUpgrade(event: string, args: any) {
|
||||
const payload = args ?? event;
|
||||
const eid: number = payload?.eid ?? 0;
|
||||
if (!eid) return;
|
||||
const actor = this.queryAliveHeroActors().find(item => item.eid === eid);
|
||||
if (!actor) return;
|
||||
// 无限升级:不再拦截满级,仅校验金币
|
||||
// 统一经济管理入口:按当前等级扣费
|
||||
if (!MissionEconomy.executeUpgradeCost(actor.model.lv)) {
|
||||
oops.gui.toast(`金币不足`);
|
||||
return;
|
||||
}
|
||||
this.tryUpgradeHeroByEid(eid);
|
||||
}
|
||||
|
||||
/** 英雄升级事件回调:刷新英雄信息盒显示 */
|
||||
/** 英雄升级事件回调 */
|
||||
private onHeroLvUp() {
|
||||
// 暂不启用 herobox 同步(后续可能恢复)
|
||||
// this.refreshHeroBoxSlots();
|
||||
}
|
||||
|
||||
/** 英雄面板空槽位点击回调:展示英雄卡池选择界面 */
|
||||
private onHeroBoxEmptyClick() {
|
||||
this.onShowCardsClick();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1169,76 +1115,6 @@ export class MissionCardComp extends CCComp {
|
||||
this.showHeros.active = false;
|
||||
}
|
||||
|
||||
// ======================== 英雄信息盒(herosBoxNode) ========================
|
||||
|
||||
/**
|
||||
* 同步英雄信息盒槽位与场上英雄:
|
||||
* 1. 刷新 herosBoxNode 下 HeroBoxComp 槽位缓存(编辑器已预放 3 个)。
|
||||
* 2. 查询当前存活英雄列表,按序绑定到槽位(bindHero 内部激活节点)。
|
||||
* 3. 多余槽位清空数据并隐藏(默认全部隐藏,召唤一个激活一个)。
|
||||
*
|
||||
* Why: 英雄召唤 / 死亡 / 卖出 / 升级后调用,保证面板与场上一一对应。
|
||||
*
|
||||
* 备注:当前版本暂不启用 herobox 同步显示英雄信息(后续可能恢复),
|
||||
* 方法体已整体注释,所有调用点也已注释。恢复时取消方法体与调用点注释。
|
||||
*/
|
||||
private refreshHeroBoxSlots() {
|
||||
/* 暂不启用 herobox 同步,保留实现备查
|
||||
if (!this.herosBoxNode || !this.herosBoxNode.isValid) return;
|
||||
|
||||
this.ensureHeroBoxSlots();
|
||||
|
||||
// 查询场上存活英雄(含复活中的实体,按 eid 升序保证稳定顺序)
|
||||
const actors: Array<{ eid: number, model: HeroAttrsComp }> = [];
|
||||
ecs.query(ecs.allOf(HeroAttrsComp)).forEach((entity: ecs.Entity) => {
|
||||
const model = entity.get(HeroAttrsComp);
|
||||
if (!model) return;
|
||||
if (model.fac !== FacSet.HERO) return;
|
||||
if (model.is_dead) return;
|
||||
actors.push({ eid: entity.eid, model });
|
||||
});
|
||||
actors.sort((a, b) => a.eid - b.eid);
|
||||
|
||||
for (let i = 0; i < this.heroBoxComps.length; i++) {
|
||||
const comp = this.heroBoxComps[i];
|
||||
if (!comp || !comp.node || !comp.node.isValid) continue;
|
||||
const actor = actors[i];
|
||||
if (actor) {
|
||||
comp.bindHero(actor.eid, actor.model);
|
||||
} else {
|
||||
// 空槽位默认隐藏:召唤一个英雄才激活一个槽位
|
||||
comp.applyEmpty();
|
||||
comp.node.active = false;
|
||||
}
|
||||
}
|
||||
|
||||
// 列表高度只按可见槽位(存活英雄数)计算,空槽位已隐藏不再占位
|
||||
this.resizeListBox(this.herosBoxNode, actors.length);
|
||||
*/
|
||||
}
|
||||
|
||||
/**
|
||||
* 缓存英雄信息盒槽位组件引用。
|
||||
* 槽位已在编辑器中预先放置(herosBoxNode 下挂 HeroBoxComp),
|
||||
* 运行时仅刷新缓存,不再动态实例化。
|
||||
*/
|
||||
private ensureHeroBoxSlots() {
|
||||
if (!this.herosBoxNode || !this.herosBoxNode.isValid) return;
|
||||
this.heroBoxComps = this.herosBoxNode.children
|
||||
.map(node => node.getComponent(HeroBoxComp))
|
||||
.filter((comp): comp is HeroBoxComp => !!comp);
|
||||
}
|
||||
|
||||
/** 英雄信息盒槽位默认全部隐藏,召唤一个英雄再激活一个 */
|
||||
private hideAllHeroBoxSlots() {
|
||||
this.ensureHeroBoxSlots();
|
||||
for (const comp of this.heroBoxComps) {
|
||||
if (comp && comp.node && comp.node.isValid) {
|
||||
comp.node.active = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 支付抽卡面板开启费用:
|
||||
* 金币足够则扣除当前费用,并将该面板费用递增 PANEL_OPEN_COST_STEP;
|
||||
@@ -2316,7 +2192,6 @@ export class MissionCardComp extends CCComp {
|
||||
|
||||
// 关键:在 reset/销毁 时将 Map 置空,彻底切断引用
|
||||
this.cardComps = [];
|
||||
this.heroBoxComps = [];
|
||||
this.skillCardComps = [];
|
||||
|
||||
if (this.node && this.node.isValid) {
|
||||
|
||||
@@ -101,7 +101,8 @@
|
||||
"attrs": {
|
||||
"def": 50
|
||||
},
|
||||
"name": "钢铁壁垒"
|
||||
"name": "钢铁壁垒",
|
||||
"icon": "46-Iron-Clad"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -202,7 +203,8 @@
|
||||
"attrs": {
|
||||
"hp": 50
|
||||
},
|
||||
"name": "不屈战意"
|
||||
"name": "不屈战意",
|
||||
"icon": "29-Endure"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -300,7 +302,8 @@
|
||||
"attrs": {
|
||||
"hp": 50
|
||||
},
|
||||
"name": "不屈战意"
|
||||
"name": "不屈战意",
|
||||
"icon": "29-Endure"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -400,7 +403,8 @@
|
||||
"attrs": {
|
||||
"ap": 50
|
||||
},
|
||||
"name": "致命本能"
|
||||
"name": "致命本能",
|
||||
"icon": "36-Guardian-Stance"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -501,7 +505,8 @@
|
||||
"attrs": {
|
||||
"ap": 50
|
||||
},
|
||||
"name": "致命本能"
|
||||
"name": "致命本能",
|
||||
"icon": "36-Guardian-Stance"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -600,7 +605,8 @@
|
||||
"attrs": {
|
||||
"ap": 50
|
||||
},
|
||||
"name": "鹰眼锁定"
|
||||
"name": "鹰眼锁定",
|
||||
"icon": "27-Hawkeye"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -699,7 +705,8 @@
|
||||
"attrs": {
|
||||
"ap": 50
|
||||
},
|
||||
"name": "奥术共鸣"
|
||||
"name": "奥术共鸣",
|
||||
"icon": "100-Enchant-Magic"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -795,7 +802,8 @@
|
||||
"attrs": {
|
||||
"hp": 50
|
||||
},
|
||||
"name": "守护之心"
|
||||
"name": "守护之心",
|
||||
"icon": "29-Endure"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -898,7 +906,8 @@
|
||||
"attrs": {
|
||||
"def": 50
|
||||
},
|
||||
"name": "钢铁壁垒"
|
||||
"name": "钢铁壁垒",
|
||||
"icon": "46-Iron-Clad"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -999,7 +1008,8 @@
|
||||
"attrs": {
|
||||
"ap": 50
|
||||
},
|
||||
"name": "鹰眼锁定"
|
||||
"name": "鹰眼锁定",
|
||||
"icon": "27-Hawkeye"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -1103,7 +1113,8 @@
|
||||
"attrs": {
|
||||
"def": 50
|
||||
},
|
||||
"name": "钢铁壁垒"
|
||||
"name": "钢铁壁垒",
|
||||
"icon": "46-Iron-Clad"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -1226,7 +1237,8 @@
|
||||
"attrs": {
|
||||
"ap": 50
|
||||
},
|
||||
"name": "奥术共鸣"
|
||||
"name": "奥术共鸣",
|
||||
"icon": "100-Enchant-Magic"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -1334,7 +1346,8 @@
|
||||
"attrs": {
|
||||
"hp": 50
|
||||
},
|
||||
"name": "守护之心"
|
||||
"name": "守护之心",
|
||||
"icon": "29-Endure"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -1440,9 +1453,611 @@
|
||||
"attrs": {
|
||||
"hp": 50
|
||||
},
|
||||
"name": "不屈战意"
|
||||
"name": "不屈战意",
|
||||
"icon": "29-Endure"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"uuid": 5015,
|
||||
"name": "毒箭猎手",
|
||||
"comment": "毒伤持续流:普攻淬毒叠层+毒雨铺DoT+攻击光环喂养毒伤",
|
||||
"path": "ha3",
|
||||
"rarity": 2,
|
||||
"roleKey": "Archer",
|
||||
"growKey": "Archer",
|
||||
"typeKey": "Long",
|
||||
"statBase": {
|
||||
"hp": 10,
|
||||
"ap": 0,
|
||||
"def": 0
|
||||
},
|
||||
"dis": null,
|
||||
"speed": null,
|
||||
"dodge": null,
|
||||
"accuracy": null,
|
||||
"skills": [
|
||||
{
|
||||
"uuid": 6007,
|
||||
"name": "淬毒箭",
|
||||
"cd": 1.05,
|
||||
"cdExpr": "AtkSpeedSet[AtkSpeedLv.Normal].cd",
|
||||
"overrides": {
|
||||
"ap": 100
|
||||
},
|
||||
"desc": "射出箭矢,对{target}造成攻击力{ap}%伤害",
|
||||
"lv_entries": [
|
||||
{
|
||||
"lv": 2,
|
||||
"s_lv": 2,
|
||||
"overrides": {
|
||||
"timed_buff_id": 7005,
|
||||
"buff_value": 30,
|
||||
"buff_chance": 30
|
||||
},
|
||||
"desc": "普通攻击有{buff_chance}%概率使目标中毒(每0.5秒受到{buff_value}点伤害,持续{dur}秒)"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"uuid": 6150,
|
||||
"name": "万箭齐发·毒",
|
||||
"cd": 8,
|
||||
"cdExpr": null,
|
||||
"overrides": {
|
||||
"ap": 150,
|
||||
"timed_buff_id": 7005,
|
||||
"buff_value": 30,
|
||||
"buff_chance": 50,
|
||||
"icon": "4-Apply-Poison"
|
||||
},
|
||||
"desc": "毒箭如雨,对{target}造成攻击力{ap}%伤害,{buff_chance}%概率使目标中毒(每0.5秒受到{buff_value}点伤害,持续{dur}秒)",
|
||||
"lv_entries": [
|
||||
{
|
||||
"lv": 8,
|
||||
"s_lv": 2,
|
||||
"overrides": {
|
||||
"ap": 200,
|
||||
"buff_value": 40,
|
||||
"buff_chance": 60
|
||||
},
|
||||
"desc": ""
|
||||
},
|
||||
{
|
||||
"lv": 16,
|
||||
"s_lv": 3,
|
||||
"overrides": {
|
||||
"ap": 250,
|
||||
"buff_value": 60,
|
||||
"buff_chance": 80,
|
||||
"hit_count": 2
|
||||
},
|
||||
"desc": "毒箭如雨,对{target}造成攻击力{ap}%伤害,{buff_chance}%概率使目标中毒(每0.5秒受到{buff_value}点伤害,持续{dur}秒),每支箭可命中{hit_count}个目标"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"atking": {
|
||||
"6007": [
|
||||
{
|
||||
"lv": 4,
|
||||
"s_lv": 1,
|
||||
"name": "蚀骨毒箭",
|
||||
"t_num": 3,
|
||||
"overrides": {
|
||||
"ap": 80,
|
||||
"timed_buff_id": 7005,
|
||||
"buff_value": 40,
|
||||
"buff_chance": 100
|
||||
},
|
||||
"desc": "追加射出蚀骨毒箭,对{target}造成攻击力{ap}%伤害,必定使目标中毒(每0.5秒受到{buff_value}点伤害,持续{dur}秒)"
|
||||
}
|
||||
]
|
||||
},
|
||||
"atked": {},
|
||||
"fstart": {},
|
||||
"dead": {},
|
||||
"field": [
|
||||
{
|
||||
"lv": 4,
|
||||
"uuids": [
|
||||
{
|
||||
"uuid": 7002,
|
||||
"value": 0.1,
|
||||
"name": "淬毒磨砺"
|
||||
}
|
||||
],
|
||||
"desc": ""
|
||||
}
|
||||
],
|
||||
"info": "淬毒普攻+毒雨叠层,持续消耗型远程毒C",
|
||||
"bonus": [
|
||||
{
|
||||
"lv": 12,
|
||||
"attrs": {
|
||||
"ap": 50
|
||||
},
|
||||
"name": "剧毒淬炼",
|
||||
"icon": "27-Hawkeye"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"uuid": 5016,
|
||||
"name": "连珠神射",
|
||||
"comment": "暴击连射爆发流:VeryFast极速普攻+概率追射必暴箭+开局团队暴击爆发",
|
||||
"path": "ha4",
|
||||
"rarity": 4,
|
||||
"roleKey": "Archer",
|
||||
"growKey": "Archer",
|
||||
"typeKey": "Mid",
|
||||
"statBase": {
|
||||
"hp": 0,
|
||||
"ap": 10,
|
||||
"def": 0
|
||||
},
|
||||
"dis": null,
|
||||
"speed": null,
|
||||
"dodge": null,
|
||||
"accuracy": null,
|
||||
"skills": [
|
||||
{
|
||||
"uuid": 6008,
|
||||
"name": "连珠箭",
|
||||
"cd": 0.75,
|
||||
"cdExpr": "AtkSpeedSet[AtkSpeedLv.VeryFast].cd",
|
||||
"overrides": {
|
||||
"ap": 100
|
||||
},
|
||||
"desc": "极速连射,对{target}造成攻击力{ap}%伤害",
|
||||
"lv_entries": [
|
||||
{
|
||||
"lv": 2,
|
||||
"s_lv": 2,
|
||||
"overrides": {
|
||||
"crt": 20,
|
||||
"proc_skill": {
|
||||
"s_uuid": 6007,
|
||||
"chance": 20,
|
||||
"overrides": {
|
||||
"crt": 100
|
||||
}
|
||||
}
|
||||
},
|
||||
"desc": "普通攻击暴击率提升{crt}%,并有概率触发连射追箭(必定暴击)"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"uuid": 6151,
|
||||
"name": "裂空箭雨",
|
||||
"cd": 8,
|
||||
"cdExpr": null,
|
||||
"overrides": {
|
||||
"ap": 150,
|
||||
"crt": 30,
|
||||
"summon_count": 5
|
||||
},
|
||||
"desc": "箭雨倾泻,对{target}造成攻击力{ap}%伤害,{crt}%概率暴击",
|
||||
"lv_entries": [
|
||||
{
|
||||
"lv": 8,
|
||||
"s_lv": 2,
|
||||
"overrides": {
|
||||
"ap": 200,
|
||||
"crt": 50
|
||||
},
|
||||
"desc": ""
|
||||
},
|
||||
{
|
||||
"lv": 16,
|
||||
"s_lv": 3,
|
||||
"overrides": {
|
||||
"ap": 250,
|
||||
"crt": 70,
|
||||
"summon_count": 6,
|
||||
"hit_count": 2
|
||||
},
|
||||
"desc": "箭雨倾泻,对{target}造成攻击力{ap}%伤害,{crt}%概率暴击,每支箭可命中{hit_count}个目标"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"atking": {},
|
||||
"atked": {},
|
||||
"fstart": {
|
||||
"6504": [
|
||||
{
|
||||
"lv": 4,
|
||||
"s_lv": 1,
|
||||
"name": "猎杀时刻",
|
||||
"t_num": 1,
|
||||
"overrides": {
|
||||
"buff_value": 30
|
||||
},
|
||||
"desc": "战斗开始时释放暴击爆发,全体友方暴击率提升{buff_value}%,持续{dur}秒"
|
||||
}
|
||||
]
|
||||
},
|
||||
"dead": {},
|
||||
"field": [
|
||||
{
|
||||
"lv": 4,
|
||||
"uuids": [
|
||||
{
|
||||
"uuid": 7004,
|
||||
"value": 0.15,
|
||||
"name": "猎手集结"
|
||||
}
|
||||
],
|
||||
"desc": ""
|
||||
}
|
||||
],
|
||||
"info": "极速连射+暴击追射+开局团队暴击,爆发型射手主C",
|
||||
"bonus": [
|
||||
{
|
||||
"lv": 12,
|
||||
"attrs": {
|
||||
"ap": 50
|
||||
},
|
||||
"name": "猎杀直觉",
|
||||
"icon": "27-Hawkeye"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"uuid": 5017,
|
||||
"name": "碎甲术士",
|
||||
"comment": "破甲减防法师:fstart先手/普攻概率/大招必定三通道施加破甲7008+穿透光环,团队物理增伤位",
|
||||
"path": "hm3",
|
||||
"rarity": 3,
|
||||
"roleKey": "Mage",
|
||||
"growKey": "Mage",
|
||||
"typeKey": "Long",
|
||||
"statBase": {
|
||||
"hp": 0,
|
||||
"ap": 10,
|
||||
"def": 0
|
||||
},
|
||||
"dis": null,
|
||||
"speed": null,
|
||||
"dodge": null,
|
||||
"accuracy": null,
|
||||
"skills": [
|
||||
{
|
||||
"uuid": 6012,
|
||||
"name": "蚀甲酸瓶",
|
||||
"cd": 1.05,
|
||||
"cdExpr": "AtkSpeedSet[AtkSpeedLv.Normal].cd",
|
||||
"overrides": {
|
||||
"ap": 100
|
||||
},
|
||||
"desc": "掷出酸瓶,对{target}造成攻击力{ap}%伤害",
|
||||
"lv_entries": [
|
||||
{
|
||||
"lv": 2,
|
||||
"s_lv": 2,
|
||||
"overrides": {
|
||||
"timed_buff_id": 7008,
|
||||
"buff_chance": 30
|
||||
},
|
||||
"desc": "普通攻击有{buff_chance}%概率使目标破甲(防御降低,持续{dur}秒)"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"uuid": 6203,
|
||||
"name": "碎甲能量波",
|
||||
"cd": 8,
|
||||
"cdExpr": null,
|
||||
"overrides": {
|
||||
"ap": 150,
|
||||
"timed_buff_id": 7008
|
||||
},
|
||||
"desc": "释放碎甲能量波,对{target}造成攻击力{ap}%伤害,并使目标破甲(防御降低,持续{dur}秒)",
|
||||
"lv_entries": [
|
||||
{
|
||||
"lv": 8,
|
||||
"s_lv": 2,
|
||||
"overrides": {
|
||||
"ap": 200
|
||||
},
|
||||
"desc": ""
|
||||
},
|
||||
{
|
||||
"lv": 16,
|
||||
"s_lv": 3,
|
||||
"overrides": {
|
||||
"ap": 250,
|
||||
"buff_value": -70
|
||||
},
|
||||
"desc": "释放碎甲能量波,对{target}造成攻击力{ap}%伤害,并使目标破甲加深(防御大幅降低,持续{dur}秒)"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"atking": {},
|
||||
"atked": {},
|
||||
"fstart": {
|
||||
"6012": [
|
||||
{
|
||||
"lv": 4,
|
||||
"s_lv": 1,
|
||||
"name": "先手蚀甲",
|
||||
"t_num": 1,
|
||||
"overrides": {
|
||||
"ap": 150,
|
||||
"timed_buff_id": 7008
|
||||
},
|
||||
"desc": "战斗开始时掷出蚀甲酸瓶,对{target}造成攻击力{ap}%伤害,并必定使其破甲(防御降低,持续{dur}秒)"
|
||||
}
|
||||
]
|
||||
},
|
||||
"dead": {},
|
||||
"field": [
|
||||
{
|
||||
"lv": 4,
|
||||
"uuids": [
|
||||
{
|
||||
"uuid": 7009,
|
||||
"value": 0.1,
|
||||
"name": "锐矛之赐"
|
||||
}
|
||||
],
|
||||
"desc": ""
|
||||
}
|
||||
],
|
||||
"info": "先手破甲+概率蚀甲+穿透光环,物理队核心增伤位",
|
||||
"bonus": [
|
||||
{
|
||||
"lv": 12,
|
||||
"attrs": {
|
||||
"ap": 50
|
||||
},
|
||||
"name": "奥术共鸣",
|
||||
"icon": "100-Enchant-Magic"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"uuid": 5018,
|
||||
"name": "雷暴领主",
|
||||
"comment": "雷暴AOE爆发+麻痹控场:先手雷击+高倍率能量波",
|
||||
"path": "hm4",
|
||||
"rarity": 5,
|
||||
"roleKey": "Mage",
|
||||
"growKey": "Mage",
|
||||
"typeKey": "Long",
|
||||
"statBase": {
|
||||
"hp": -10,
|
||||
"ap": 20,
|
||||
"def": 0
|
||||
},
|
||||
"dis": null,
|
||||
"speed": null,
|
||||
"dodge": null,
|
||||
"accuracy": null,
|
||||
"skills": [
|
||||
{
|
||||
"uuid": 6009,
|
||||
"name": "雷霆弹",
|
||||
"cd": 0.9,
|
||||
"cdExpr": "AtkSpeedSet[AtkSpeedLv.Fast].cd",
|
||||
"overrides": {
|
||||
"ap": 100
|
||||
},
|
||||
"desc": "掷出雷霆弹,对{target}造成攻击力{ap}%伤害",
|
||||
"lv_entries": [
|
||||
{
|
||||
"lv": 2,
|
||||
"s_lv": 2,
|
||||
"overrides": {
|
||||
"para": 15
|
||||
},
|
||||
"desc": "普通攻击有{para}%概率麻痹敌人,减缓其技能冷却恢复"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"uuid": 6203,
|
||||
"name": "雷霆裂空",
|
||||
"cd": 8,
|
||||
"cdExpr": null,
|
||||
"overrides": {
|
||||
"ap": 200,
|
||||
"para": 40
|
||||
},
|
||||
"desc": "释放雷霆裂空波,对{target}造成攻击力{ap}%伤害,{para}%概率麻痹敌人",
|
||||
"lv_entries": [
|
||||
{
|
||||
"lv": 8,
|
||||
"s_lv": 2,
|
||||
"overrides": {
|
||||
"ap": 250,
|
||||
"para": 60
|
||||
},
|
||||
"desc": "释放雷霆裂空波,对{target}造成攻击力{ap}%伤害,{para}%概率麻痹敌人"
|
||||
},
|
||||
{
|
||||
"lv": 16,
|
||||
"s_lv": 3,
|
||||
"overrides": {
|
||||
"ap": 300,
|
||||
"para": 80,
|
||||
"hit_count": 3
|
||||
},
|
||||
"desc": "释放雷霆裂空波,对{target}造成攻击力{ap}%伤害,可多次命中,{para}%概率麻痹敌人"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"atking": {},
|
||||
"atked": {},
|
||||
"fstart": {
|
||||
"6203": [
|
||||
{
|
||||
"lv": 4,
|
||||
"s_lv": 1,
|
||||
"name": "雷击先手",
|
||||
"t_num": 1,
|
||||
"overrides": {
|
||||
"ap": 150,
|
||||
"para": 30,
|
||||
"icon": "100-Enchant-Magic"
|
||||
},
|
||||
"desc": "战斗开始释放雷击,对{target}造成攻击力{ap}%伤害,{para}%概率麻痹敌人"
|
||||
}
|
||||
]
|
||||
},
|
||||
"dead": {},
|
||||
"field": [
|
||||
{
|
||||
"lv": 4,
|
||||
"uuids": [
|
||||
{
|
||||
"uuid": 7003,
|
||||
"value": 10,
|
||||
"name": "雷云领域"
|
||||
}
|
||||
],
|
||||
"desc": ""
|
||||
}
|
||||
],
|
||||
"info": "雷暴爆发+麻痹控场,法系主C",
|
||||
"bonus": [
|
||||
{
|
||||
"lv": 12,
|
||||
"attrs": {
|
||||
"ap": 50
|
||||
},
|
||||
"name": "奥术共鸣",
|
||||
"icon": "100-Enchant-Magic"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"uuid": 5019,
|
||||
"name": "圣盾贤者",
|
||||
"comment": "护盾反伤生存法:全队圣盾+荆棘反伤+受击荆棘",
|
||||
"path": "hm5",
|
||||
"rarity": 2,
|
||||
"roleKey": "Mage",
|
||||
"growKey": "Mage",
|
||||
"typeKey": "Long",
|
||||
"statBase": {
|
||||
"hp": 20,
|
||||
"ap": -5,
|
||||
"def": 5
|
||||
},
|
||||
"dis": null,
|
||||
"speed": null,
|
||||
"dodge": null,
|
||||
"accuracy": null,
|
||||
"skills": [
|
||||
{
|
||||
"uuid": 6011,
|
||||
"name": "圣光飞瓶",
|
||||
"cd": 1.05,
|
||||
"cdExpr": "AtkSpeedSet[AtkSpeedLv.Normal].cd",
|
||||
"overrides": {
|
||||
"ap": 100
|
||||
},
|
||||
"desc": "掷出圣光飞瓶,对{target}造成攻击力{ap}%伤害",
|
||||
"lv_entries": [
|
||||
{
|
||||
"lv": 2,
|
||||
"s_lv": 2,
|
||||
"overrides": {
|
||||
"proc_skill": {
|
||||
"s_uuid": 6516,
|
||||
"chance": 20,
|
||||
"overrides": {
|
||||
"timed_buff_id": 7028,
|
||||
"buff_value": 10
|
||||
}
|
||||
}
|
||||
},
|
||||
"desc": "普通攻击概率凝聚荆棘护体(受击时反弹{buff_value}%所受伤害,持续{dur}秒)"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"uuid": 6301,
|
||||
"name": "奥术圣壁",
|
||||
"cd": 8,
|
||||
"cdExpr": null,
|
||||
"overrides": {
|
||||
"TGroup": "Ally",
|
||||
"ap": 20,
|
||||
"timed_buff_id": 7027,
|
||||
"buff_value": 10
|
||||
},
|
||||
"desc": "为全体友方施加生命最大值{ap}%的护盾,并附加荆棘(受击时反弹{buff_value}点伤害,持续{dur}秒)",
|
||||
"lv_entries": [
|
||||
{
|
||||
"lv": 8,
|
||||
"s_lv": 2,
|
||||
"overrides": {
|
||||
"ap": 30,
|
||||
"buff_value": 15
|
||||
},
|
||||
"desc": "为全体友方施加生命最大值{ap}%的护盾,并附加荆棘(受击时反弹{buff_value}点伤害,持续{dur}秒)"
|
||||
},
|
||||
{
|
||||
"lv": 16,
|
||||
"s_lv": 3,
|
||||
"overrides": {
|
||||
"ap": 40,
|
||||
"buff_value": 20
|
||||
},
|
||||
"desc": "为全体友方施加生命最大值{ap}%的护盾,并附加荆棘(受击时反弹{buff_value}点伤害,持续{dur}秒)"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"atking": {},
|
||||
"atked": {
|
||||
"6516": [
|
||||
{
|
||||
"lv": 4,
|
||||
"s_lv": 1,
|
||||
"name": "荆棘回应",
|
||||
"t_num": 3,
|
||||
"overrides": {
|
||||
"timed_buff_id": 7028,
|
||||
"buff_value": 10,
|
||||
"icon": "75-Shield-Stun"
|
||||
},
|
||||
"desc": "凝聚荆棘护体,受击时反弹{buff_value}%所受伤害,持续{dur}秒"
|
||||
}
|
||||
]
|
||||
},
|
||||
"fstart": {},
|
||||
"dead": {},
|
||||
"field": [
|
||||
{
|
||||
"lv": 4,
|
||||
"uuids": [
|
||||
{
|
||||
"uuid": 7022,
|
||||
"value": 8,
|
||||
"name": "荆棘领域"
|
||||
}
|
||||
],
|
||||
"desc": ""
|
||||
}
|
||||
],
|
||||
"info": "全队护盾+荆棘反伤,生存反击法",
|
||||
"bonus": [
|
||||
{
|
||||
"lv": 12,
|
||||
"attrs": {
|
||||
"hp": 50
|
||||
},
|
||||
"name": "守护之心",
|
||||
"icon": "29-Endure"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user