Compare commits
2 Commits
3386ccc68c
...
58ac41feb0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
58ac41feb0 | ||
|
|
e846e6408c |
@@ -54,18 +54,18 @@
|
|||||||
],
|
],
|
||||||
"_active": true,
|
"_active": true,
|
||||||
"_components": [
|
"_components": [
|
||||||
{
|
|
||||||
"__id__": 444
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"__id__": 446
|
"__id__": 446
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"__id__": 448
|
"__id__": 448
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"__id__": 450
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"_prefab": {
|
"_prefab": {
|
||||||
"__id__": 450
|
"__id__": 452
|
||||||
},
|
},
|
||||||
"_lpos": {
|
"_lpos": {
|
||||||
"__type__": "cc.Vec3",
|
"__type__": "cc.Vec3",
|
||||||
@@ -9594,18 +9594,18 @@
|
|||||||
],
|
],
|
||||||
"_active": true,
|
"_active": true,
|
||||||
"_components": [
|
"_components": [
|
||||||
{
|
|
||||||
"__id__": 437
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"__id__": 439
|
"__id__": 439
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"__id__": 441
|
"__id__": 441
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"__id__": 443
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"_prefab": {
|
"_prefab": {
|
||||||
"__id__": 443
|
"__id__": 445
|
||||||
},
|
},
|
||||||
"_lpos": {
|
"_lpos": {
|
||||||
"__type__": "cc.Vec3",
|
"__type__": "cc.Vec3",
|
||||||
@@ -9827,10 +9827,13 @@
|
|||||||
"_components": [
|
"_components": [
|
||||||
{
|
{
|
||||||
"__id__": 434
|
"__id__": 434
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"__id__": 436
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"_prefab": {
|
"_prefab": {
|
||||||
"__id__": 436
|
"__id__": 438
|
||||||
},
|
},
|
||||||
"_lpos": {
|
"_lpos": {
|
||||||
"__type__": "cc.Vec3",
|
"__type__": "cc.Vec3",
|
||||||
@@ -9889,6 +9892,74 @@
|
|||||||
"__type__": "cc.CompPrefabInfo",
|
"__type__": "cc.CompPrefabInfo",
|
||||||
"fileId": "e5AR/R3blDqZJioB55xQMd"
|
"fileId": "e5AR/R3blDqZJioB55xQMd"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"__type__": "cc.Label",
|
||||||
|
"_name": "",
|
||||||
|
"_objFlags": 0,
|
||||||
|
"__editorExtras__": {},
|
||||||
|
"node": {
|
||||||
|
"__id__": 433
|
||||||
|
},
|
||||||
|
"_enabled": true,
|
||||||
|
"__prefab": {
|
||||||
|
"__id__": 437
|
||||||
|
},
|
||||||
|
"_customMaterial": null,
|
||||||
|
"_srcBlendFactor": 2,
|
||||||
|
"_dstBlendFactor": 4,
|
||||||
|
"_color": {
|
||||||
|
"__type__": "cc.Color",
|
||||||
|
"r": 255,
|
||||||
|
"g": 255,
|
||||||
|
"b": 255,
|
||||||
|
"a": 255
|
||||||
|
},
|
||||||
|
"_string": "label",
|
||||||
|
"_horizontalAlign": 0,
|
||||||
|
"_verticalAlign": 1,
|
||||||
|
"_actualFontSize": 21,
|
||||||
|
"_fontSize": 20,
|
||||||
|
"_fontFamily": "Arial",
|
||||||
|
"_lineHeight": 40,
|
||||||
|
"_overflow": 2,
|
||||||
|
"_enableWrapText": true,
|
||||||
|
"_font": null,
|
||||||
|
"_isSystemFontUsed": true,
|
||||||
|
"_spacingX": 0,
|
||||||
|
"_isItalic": false,
|
||||||
|
"_isBold": true,
|
||||||
|
"_isUnderline": false,
|
||||||
|
"_underlineHeight": 2,
|
||||||
|
"_cacheMode": 0,
|
||||||
|
"_enableOutline": true,
|
||||||
|
"_outlineColor": {
|
||||||
|
"__type__": "cc.Color",
|
||||||
|
"r": 0,
|
||||||
|
"g": 0,
|
||||||
|
"b": 0,
|
||||||
|
"a": 255
|
||||||
|
},
|
||||||
|
"_outlineWidth": 2,
|
||||||
|
"_enableShadow": false,
|
||||||
|
"_shadowColor": {
|
||||||
|
"__type__": "cc.Color",
|
||||||
|
"r": 0,
|
||||||
|
"g": 0,
|
||||||
|
"b": 0,
|
||||||
|
"a": 255
|
||||||
|
},
|
||||||
|
"_shadowOffset": {
|
||||||
|
"__type__": "cc.Vec2",
|
||||||
|
"x": 2,
|
||||||
|
"y": 2
|
||||||
|
},
|
||||||
|
"_shadowBlur": 2,
|
||||||
|
"_id": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"__type__": "cc.CompPrefabInfo",
|
||||||
|
"fileId": "a4aoaDD+FBU6Rtemm9p9yx"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"__type__": "cc.PrefabInfo",
|
"__type__": "cc.PrefabInfo",
|
||||||
"root": {
|
"root": {
|
||||||
@@ -9912,7 +9983,7 @@
|
|||||||
},
|
},
|
||||||
"_enabled": true,
|
"_enabled": true,
|
||||||
"__prefab": {
|
"__prefab": {
|
||||||
"__id__": 438
|
"__id__": 440
|
||||||
},
|
},
|
||||||
"_contentSize": {
|
"_contentSize": {
|
||||||
"__type__": "cc.Size",
|
"__type__": "cc.Size",
|
||||||
@@ -9940,7 +10011,7 @@
|
|||||||
},
|
},
|
||||||
"_enabled": true,
|
"_enabled": true,
|
||||||
"__prefab": {
|
"__prefab": {
|
||||||
"__id__": 440
|
"__id__": 442
|
||||||
},
|
},
|
||||||
"_alignFlags": 0,
|
"_alignFlags": 0,
|
||||||
"_target": null,
|
"_target": null,
|
||||||
@@ -9976,7 +10047,7 @@
|
|||||||
},
|
},
|
||||||
"_enabled": false,
|
"_enabled": false,
|
||||||
"__prefab": {
|
"__prefab": {
|
||||||
"__id__": 442
|
"__id__": 444
|
||||||
},
|
},
|
||||||
"_resizeMode": 1,
|
"_resizeMode": 1,
|
||||||
"_layoutType": 3,
|
"_layoutType": 3,
|
||||||
@@ -10027,7 +10098,7 @@
|
|||||||
},
|
},
|
||||||
"_enabled": true,
|
"_enabled": true,
|
||||||
"__prefab": {
|
"__prefab": {
|
||||||
"__id__": 445
|
"__id__": 447
|
||||||
},
|
},
|
||||||
"_contentSize": {
|
"_contentSize": {
|
||||||
"__type__": "cc.Size",
|
"__type__": "cc.Size",
|
||||||
@@ -10055,7 +10126,7 @@
|
|||||||
},
|
},
|
||||||
"_enabled": true,
|
"_enabled": true,
|
||||||
"__prefab": {
|
"__prefab": {
|
||||||
"__id__": 447
|
"__id__": 449
|
||||||
},
|
},
|
||||||
"icon_node": {
|
"icon_node": {
|
||||||
"__id__": 105
|
"__id__": 105
|
||||||
@@ -10100,7 +10171,7 @@
|
|||||||
},
|
},
|
||||||
"_enabled": true,
|
"_enabled": true,
|
||||||
"__prefab": {
|
"__prefab": {
|
||||||
"__id__": 449
|
"__id__": 451
|
||||||
},
|
},
|
||||||
"_alignFlags": 44,
|
"_alignFlags": 44,
|
||||||
"_target": null,
|
"_target": null,
|
||||||
|
|||||||
142
assets/script/game/common/config/HeroSkillDesc.ts
Normal file
142
assets/script/game/common/config/HeroSkillDesc.ts
Normal file
@@ -0,0 +1,142 @@
|
|||||||
|
/**
|
||||||
|
* @file HeroSkillDesc.ts
|
||||||
|
* @description 英雄技能描述生成器
|
||||||
|
*
|
||||||
|
* 职责:
|
||||||
|
* 将英雄配置(heroInfo)中的特殊触发技能转换为可读的描述文本,
|
||||||
|
* 供 HInfoComp 的 info_node 显示。每行一个技能,用换行符连接。
|
||||||
|
*
|
||||||
|
* 生成格式:
|
||||||
|
* {触发条件} → {技能名} {效果描述}
|
||||||
|
* 例: "受击2次 → 护盾 护盾2次"
|
||||||
|
* 例: "攻击1次 → 攻击强化 全体友方攻击力提升5点,持续1次"
|
||||||
|
* 例: "场上存活 → 攻击加成 英雄攻击力+20%"
|
||||||
|
*
|
||||||
|
* 依赖:
|
||||||
|
* - heroSet → SkillTriggerDesc(触发条件模板)、SkillTriggerType(触发类型枚举)、heroInfo
|
||||||
|
* - SkillSet → SkillSet(技能基础配置)、mergeSkillParams(合并覆盖参数)、SkillKind(技能类型枚举)
|
||||||
|
* - FieldSkillSet(驻场技能配置)
|
||||||
|
*/
|
||||||
|
import { heroInfo, SkillTriggerDesc, SkillTriggerType } from "./heroSet";
|
||||||
|
import { FieldSkillSet, mergeSkillParams, SkillKind, SkillOverrides, SkillSet } from "./SkillSet";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 需要遍历的触发技能类型列表(不含 Field 和 Revive,这两者结构不同需单独处理)
|
||||||
|
* Field → number[](驻场技能 uuid 列表)
|
||||||
|
* Revive → { s_uuid, r_num, upr }(单个对象)
|
||||||
|
*/
|
||||||
|
const TRIGGER_KEYS: SkillTriggerType[] = [
|
||||||
|
SkillTriggerType.Call, // 召唤时触发
|
||||||
|
SkillTriggerType.Dead, // 死亡时触发
|
||||||
|
SkillTriggerType.FStart, // 战斗开始时触发
|
||||||
|
SkillTriggerType.FEnd, // 战斗结束时触发
|
||||||
|
SkillTriggerType.Atking, // 攻击后触发
|
||||||
|
SkillTriggerType.Atked, // 受击后触发
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据合并后的技能配置生成效果描述文本
|
||||||
|
*
|
||||||
|
* 按 SkillKind 分类输出:
|
||||||
|
* - Heal → "治疗伙伴{ap}"
|
||||||
|
* - Shield → "护盾{ap}次"(ap 表示可抵挡次数)
|
||||||
|
* - Gold → "金币+{gold}"
|
||||||
|
* - Support → 直接使用技能自身的 info 字段(如"全体友方攻击力提升5点,持续1次")
|
||||||
|
* - Damage → "伤害{ap}%" + 可选的暴击/冰冻/击退/多段附加描述
|
||||||
|
*
|
||||||
|
* @param skill 经过 mergeSkillParams 合并 overrides 后的完整技能配置
|
||||||
|
* @returns 效果描述字符串,各部分用空格连接
|
||||||
|
*/
|
||||||
|
function buildEffectDesc(skill: ReturnType<typeof mergeSkillParams>): string {
|
||||||
|
const parts: string[] = [];
|
||||||
|
const kind = skill.kind;
|
||||||
|
|
||||||
|
if (kind === SkillKind.Heal) {
|
||||||
|
// 治疗类:ap 为治疗量
|
||||||
|
parts.push(`治疗伙伴${skill.ap}`);
|
||||||
|
} else if (kind === SkillKind.Shield) {
|
||||||
|
// 护盾类:ap 为可抵挡的攻击次数
|
||||||
|
parts.push(`护盾${skill.ap}次`);
|
||||||
|
} else if (kind === SkillKind.Gold) {
|
||||||
|
// 金币类:gold 为获取金币数
|
||||||
|
parts.push(`金币+${skill.gold ?? 0}`);
|
||||||
|
} else if (kind === SkillKind.Support) {
|
||||||
|
// 辅助类(buff):直接使用技能的 info 描述文案
|
||||||
|
parts.push(String(skill.info));
|
||||||
|
} else if (kind === SkillKind.Damage || kind === undefined) {
|
||||||
|
// 伤害类(含无 kind 的默认技能):ap 为攻击力百分比
|
||||||
|
parts.push(`伤害${skill.ap}%`);
|
||||||
|
// 多段伤害
|
||||||
|
if (skill.hit_count > 1) parts.push(`${skill.hit_count}段`);
|
||||||
|
// 附加暴击率
|
||||||
|
if (skill.crt) parts.push(`暴击+${skill.crt}%`);
|
||||||
|
// 附加冰冻概率
|
||||||
|
if (skill.frz) parts.push(`冰冻+${skill.frz}%`);
|
||||||
|
// 附加击退概率
|
||||||
|
if (skill.bck) parts.push(`击退+${skill.bck}%`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return parts.join(" ");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将英雄的特殊触发技能配置转换为可读描述文本
|
||||||
|
*
|
||||||
|
* 处理流程:
|
||||||
|
* 1. 遍历 6 种触发类型(call/dead/fstart/fend/atking/atked),从 hero[key] 取出
|
||||||
|
* {s_uuid, t_num, overrides?}[],通过 s_uuid 查 SkillSet 获取技能基础配置,
|
||||||
|
* 用 mergeSkillParams 合并 overrides 得到实际参数,再拼成一行描述。
|
||||||
|
* 2. 单独处理 field(驻场技能):从 FieldSkillSet 查找配置,输出光环效果。
|
||||||
|
* 3. 单独处理 revive(复活技能):结构与上述不同,是单个对象而非数组。
|
||||||
|
*
|
||||||
|
* 输出示例(5006 疾风刺客):
|
||||||
|
* "攻击1次 → 攻击强化 全体友方攻击力提升5点,持续1次
|
||||||
|
* 死亡时 → 攻击强化 全体友方攻击力提升8点,持续1次"
|
||||||
|
*
|
||||||
|
* @param hero 英雄静态配置(HeroInfo 中的条目)
|
||||||
|
* @returns 多行技能描述文本,每行一个技能,用 \n 分隔
|
||||||
|
*/
|
||||||
|
export function buildSkillDesc(hero: heroInfo): string {
|
||||||
|
const lines: string[] = [];
|
||||||
|
|
||||||
|
// ---- 第一步:处理 6 种标准触发技能(结构均为 {s_uuid, t_num, overrides?}[]) ----
|
||||||
|
for (const key of TRIGGER_KEYS) {
|
||||||
|
const arr = hero[key] as { s_uuid: number; t_num: number; overrides?: SkillOverrides }[] | undefined;
|
||||||
|
if (!arr?.length) continue;
|
||||||
|
// 从 SkillTriggerDesc 取模板,如 "攻击n次"、"受击n次"、"召唤时" 等
|
||||||
|
const tpl = SkillTriggerDesc[key] ?? key;
|
||||||
|
for (const item of arr) {
|
||||||
|
// 通过 s_uuid 查找技能基础配置
|
||||||
|
const base = SkillSet[item.s_uuid];
|
||||||
|
if (!base) continue;
|
||||||
|
// 合并 overrides 得到实际技能参数(ap/hit_count/crt/frz/bck 等可能被覆盖)
|
||||||
|
const skill = mergeSkillParams(base, item.overrides);
|
||||||
|
// 将模板中的 "n" 替换为实际触发次数
|
||||||
|
const trigger = tpl.replace("n", String(item.t_num));
|
||||||
|
lines.push(`${trigger} → ${base.name} ${buildEffectDesc(skill)}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---- 第二步:处理驻场技能(field)—— 结构为 number[],uuid 指向 FieldSkillSet ----
|
||||||
|
const fieldUuids = hero[SkillTriggerType.Field] as number[] | undefined;
|
||||||
|
if (fieldUuids?.length) {
|
||||||
|
const tpl = SkillTriggerDesc[SkillTriggerType.Field] ?? "场上存活";
|
||||||
|
for (const uuid of fieldUuids) {
|
||||||
|
const fs = FieldSkillSet[uuid];
|
||||||
|
if (fs) lines.push(`${tpl} → ${fs.name} ${fs.info}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---- 第三步:处理复活技能(revive)—— 结构为 {s_uuid, r_num, upr} 单个对象 ----
|
||||||
|
const revive = hero[SkillTriggerType.Revive] as { s_uuid: number; r_num: number; upr: number } | undefined;
|
||||||
|
if (revive) {
|
||||||
|
const base = SkillSet[revive.s_uuid];
|
||||||
|
if (base) {
|
||||||
|
const skill = mergeSkillParams(base);
|
||||||
|
const tpl = SkillTriggerDesc[SkillTriggerType.Revive] ?? "复活时";
|
||||||
|
lines.push(`${tpl} : ${base.name} ${buildEffectDesc(skill)}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return lines.join("\n");
|
||||||
|
}
|
||||||
9
assets/script/game/common/config/HeroSkillDesc.ts.meta
Normal file
9
assets/script/game/common/config/HeroSkillDesc.ts.meta
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"ver": "4.0.24",
|
||||||
|
"importer": "typescript",
|
||||||
|
"imported": true,
|
||||||
|
"uuid": "de462338-a674-4ccf-b621-bb67d0d9b901",
|
||||||
|
"files": [],
|
||||||
|
"subMetas": {},
|
||||||
|
"userData": {}
|
||||||
|
}
|
||||||
@@ -100,14 +100,14 @@ export const SkillTriggerName = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const SkillTriggerDesc = {
|
export const SkillTriggerDesc = {
|
||||||
[SkillTriggerType.Call]: "召唤时:",
|
[SkillTriggerType.Call]: "召唤时",
|
||||||
[SkillTriggerType.Dead]: "死亡时:",
|
[SkillTriggerType.Dead]: "死亡时",
|
||||||
[SkillTriggerType.FStart]: "战斗开始时:",
|
[SkillTriggerType.FStart]: "战斗开始时",
|
||||||
[SkillTriggerType.FEnd]: "战斗结束时:",
|
[SkillTriggerType.FEnd]: "战斗结束时",
|
||||||
[SkillTriggerType.Field]: "驻场时:",
|
[SkillTriggerType.Field]: "场上存活",
|
||||||
[SkillTriggerType.Atking]: "攻击后时:",
|
[SkillTriggerType.Atking]: "攻击n次",
|
||||||
[SkillTriggerType.Atked]: "受击后时:",
|
[SkillTriggerType.Atked]: "受击n次",
|
||||||
[SkillTriggerType.Revive]: "复活时:",
|
[SkillTriggerType.Revive]: "复活时",
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ import { smc } from "../common/SingletonModuleComp";
|
|||||||
import { TalentType } from "../common/config/TalentSet";
|
import { TalentType } from "../common/config/TalentSet";
|
||||||
import { Hero } from "../hero/Hero";
|
import { Hero } from "../hero/Hero";
|
||||||
import { FieldSkillType } from "../common/config/SkillSet";
|
import { FieldSkillType } from "../common/config/SkillSet";
|
||||||
|
import { buildSkillDesc } from "../common/config/HeroSkillDesc";
|
||||||
import { GameEvent } from "../common/config/GameEvent";
|
import { GameEvent } from "../common/config/GameEvent";
|
||||||
import { oops } from "db://oops-framework/core/Oops";
|
import { oops } from "db://oops-framework/core/Oops";
|
||||||
import { UIID } from "../common/config/GameUIConfig";
|
import { UIID } from "../common/config/GameUIConfig";
|
||||||
@@ -176,6 +177,10 @@ export class HInfoComp extends CCComp {
|
|||||||
this.hpLabel.string = `${hp}`;
|
this.hpLabel.string = `${hp}`;
|
||||||
if (this.hpPlusLabel) this.hpPlusLabel.node.active = false;
|
if (this.hpPlusLabel) this.hpPlusLabel.node.active = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.infoLabel) {
|
||||||
|
this.infoLabel.string = buildSkillDesc(hero);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 是否正在关闭中,防止重复调用 remove */
|
/** 是否正在关闭中,防止重复调用 remove */
|
||||||
@@ -277,7 +282,7 @@ export class HInfoComp extends CCComp {
|
|||||||
// ---- 技能信息标签 ----
|
// ---- 技能信息标签 ----
|
||||||
if (this.infoLabel) {
|
if (this.infoLabel) {
|
||||||
const heroData = HeroInfo[heroUuid];
|
const heroData = HeroInfo[heroUuid];
|
||||||
this.infoLabel.string = heroData?.info ?? "";
|
this.infoLabel.string = heroData ? buildSkillDesc(heroData) : "";
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---- 数值标签 ----
|
// ---- 数值标签 ----
|
||||||
@@ -327,7 +332,16 @@ export class HInfoComp extends CCComp {
|
|||||||
this.nameLabel = this.Name_node.getComponent(Label) || this.Name_node.getComponentInChildren(Label);
|
this.nameLabel = this.Name_node.getComponent(Label) || this.Name_node.getComponentInChildren(Label);
|
||||||
}
|
}
|
||||||
if (!this.infoLabel && this.info_node) {
|
if (!this.infoLabel && this.info_node) {
|
||||||
this.infoLabel = this.info_node.getComponent(Label) || this.info_node.getComponentInChildren(Label);
|
this.infoLabel = this.info_node.getComponentInChildren(Label);
|
||||||
|
if (!this.infoLabel) {
|
||||||
|
const child = this.info_node.children[0] || this.info_node;
|
||||||
|
this.infoLabel = child.getComponent(Label) || child.addComponent(Label);
|
||||||
|
this.infoLabel.fontSize = 20;
|
||||||
|
this.infoLabel.lineHeight = 28;
|
||||||
|
this.infoLabel.overflow = Label.Overflow.SHRINK;
|
||||||
|
this.infoLabel.horizontalAlign = Label.HorizontalAlign.LEFT;
|
||||||
|
this.infoLabel.verticalAlign = Label.VerticalAlign.TOP;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (!this.apLabel && this.ap_node) {
|
if (!this.apLabel && this.ap_node) {
|
||||||
this.apLabel = this.ap_node.getChildByName("val")?.getComponent(Label) || null;
|
this.apLabel = this.ap_node.getChildByName("val")?.getComponent(Label) || null;
|
||||||
|
|||||||
Reference in New Issue
Block a user