You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
228 lines
9.5 KiB
228 lines
9.5 KiB
import { _decorator, Button, Color, Component, Label, Node, sp, Sprite } from 'cc';
|
|
import { SpriteLoad } from 'db://assets/mx/components/SpriteLoad';
|
|
import { ensureSpineSkeletonDataRuntime } from 'db://assets/mx/module/lang/spineRuntimePatch';
|
|
import { SpineBatch } from 'db://assets/resources/multSpines/MultSpine';
|
|
import { GBundle } from '../../game/ConfigRes';
|
|
import type { IMingjiangkuBagEntry } from '../../manager/EquipDataManager';
|
|
import { RedDotView } from 'db://assets/mx/module/redDot/RedDotView';
|
|
const { ccclass, property } = _decorator;
|
|
|
|
const LOG = '[shenjiangItem]';
|
|
const SPINE_DIM = new Color(0x99, 0x99, 0x99, 255);
|
|
const SPINE_NORMAL = new Color(255, 255, 255, 255);
|
|
const WEAPON_SPINE_ANIM = '待机';
|
|
/** MultSpine 置灰:类型 1 + 插值 0.999(见 MultSpine.ts / Mult-spine.effect) */
|
|
const SPINE_GRAY_SHADER = 1.999;
|
|
/** 武器名不少于该字数时缩小 name 图(含 5 字) */
|
|
const WEAPON_NAME_LONG_LEN = 5;
|
|
/** openNode.name:未超长=1,超长=0.8 */
|
|
const OPEN_NAME_SCALE_NORMAL = 1;
|
|
const OPEN_NAME_SCALE_LONG = 0.8;
|
|
/** suipianNode.name:未超长=0.7,超长=0.56 */
|
|
const SUIPIAN_NAME_SCALE_NORMAL = 0.7;
|
|
const SUIPIAN_NAME_SCALE_LONG = 0.56;
|
|
|
|
type SkelShader = sp.Skeleton & { shaderVar?: number };
|
|
|
|
/**
|
|
* 神将武器库格子
|
|
* quality:icons/weapon/武器底0~4
|
|
* openNode/suipianNode:name=icons/weapon/{name};type1~4 按 Weapon.type 显隐,Spine 皮肤为 Weapon.skin
|
|
*/
|
|
@ccclass('shenjiangItem')
|
|
export class shenjiangItem extends Component {
|
|
|
|
/** 碎片节点(含 type1~4、lb_suipian) */
|
|
@property(Node)
|
|
suipianNode: Node = null;
|
|
|
|
/** 当前格子数据 */
|
|
private _data: IMingjiangkuBagEntry | null = null;
|
|
|
|
/** 当前格子数据 */
|
|
get data(): IMingjiangkuBagEntry | null {
|
|
return this._data;
|
|
}
|
|
|
|
/** 成品拖拽图标节点(openNode 下当前 type 的 Spine) */
|
|
getDragIconNode(): Node | null {
|
|
const openNode = this.node.getChildByName('openNode');
|
|
if (!openNode?.activeInHierarchy) return null;
|
|
const weapon = this._data?.equipId ? gg.equip.getEquip(this._data.equipId) : null;
|
|
const type = Number(weapon?.type) | 0;
|
|
if (type >= 1 && type <= 4) {
|
|
return openNode.getChildByName(`type${type}`) ?? null;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
/** 绑定格子数据并刷新展示 */
|
|
setData(data: IMingjiangkuBagEntry): void {
|
|
this._data = data;
|
|
if (!this.suipianNode) this.suipianNode = this.node.getChildByName('suipianNode');
|
|
const openNode = this.node.getChildByName('openNode');
|
|
const qualityNode = this.node.getChildByName('quality');
|
|
const isFrag = data.kind === 'fragment';
|
|
const weapon = data.equipId > 0 ? gg.equip.getEquip(data.equipId) : null;
|
|
if (!weapon) console.log(LOG, '武器表缺失', data.equipId);
|
|
|
|
const weaponType = Number(weapon?.type) | 0;
|
|
const skin = String(weapon?.skin ?? '').trim();
|
|
const weaponName = String(weapon?.name ?? '').trim();
|
|
if (weaponType < 1 || weaponType > 4) console.warn(LOG, 'type 无效', data.equipId, weaponType);
|
|
if (!skin) console.warn(LOG, 'skin 缺失', data.equipId);
|
|
if (!weaponName) console.warn(LOG, 'name 缺失', data.equipId);
|
|
|
|
if (openNode) openNode.active = !isFrag;
|
|
if (this.suipianNode) this.suipianNode.active = isFrag;
|
|
|
|
const bgIndex = this._equipQualityBgIndex(Number(weapon?.quality), data.equipId);
|
|
this._setSprite(qualityNode, `weapon/武器底${bgIndex}`);
|
|
|
|
const longName = weaponName.length >= WEAPON_NAME_LONG_LEN;
|
|
const openScale = longName ? OPEN_NAME_SCALE_LONG : OPEN_NAME_SCALE_NORMAL;
|
|
const suipianScale = longName ? SUIPIAN_NAME_SCALE_LONG : SUIPIAN_NAME_SCALE_NORMAL;
|
|
|
|
if (!isFrag && openNode) {
|
|
this._setWeaponNameNode(openNode, weaponName, openScale);
|
|
this._applyWeaponSpineGroup(openNode, weaponType, skin, false);
|
|
this._refreshNewWeaponTag(openNode, data.equipId, !isFrag);
|
|
const lbNum = openNode.getChildByName('numBg')?.getChildByName('lb_weaponNum')?.getComponent(Label);
|
|
if (lbNum) lbNum.string = `${Math.max(0, data.count)}`;
|
|
}
|
|
|
|
if (isFrag && this.suipianNode) {
|
|
this._setWeaponNameNode(this.suipianNode, weaponName, suipianScale);
|
|
this._applyWeaponSpineGroup(this.suipianNode, weaponType, skin, true);
|
|
const lbFrag = this.suipianNode.getChildByName('lb_suipian')?.getComponent(Label);
|
|
const need = Number(data.need) > 0 ? Number(data.need) : gg.equip.getComposeNeed(data.equipId);
|
|
if (need <= 0) console.log(LOG, '合成需求缺失', data.equipId);
|
|
if (lbFrag) lbFrag.string = `${data.count}/${Math.max(0, need)}`;
|
|
}
|
|
|
|
const btns = this.node.getComponentsInChildren(Button);
|
|
for (let i = 0; i < btns.length; i++) {
|
|
btns[i].interactable = false;
|
|
btns[i].enabled = false;
|
|
}
|
|
|
|
RedDotView.setLocal(this.node, false);
|
|
}
|
|
|
|
/** 隐藏 openNode 新武器角标 */
|
|
hideNewWeaponTag(): void {
|
|
const openNode = this.node.getChildByName('openNode');
|
|
this._refreshNewWeaponTag(openNode, 0, false);
|
|
}
|
|
|
|
/** openNode/newWeapon:新成品武器角标 */
|
|
private _refreshNewWeaponTag(openNode: Node | null, equipId: number, show: boolean): void {
|
|
const tag = openNode?.getChildByName('newWeapon');
|
|
if (!tag?.isValid) return;
|
|
tag.active = show && gg.equip.isNewWeaponBadgeVisible(equipId);
|
|
}
|
|
|
|
/** 成品可用数量(库存-已穿戴) */
|
|
setCount(count: number): void {
|
|
if (this._data) this._data.count = Math.max(0, count | 0);
|
|
if (this._data?.kind === 'fragment') return;
|
|
const lbNum = this.node.getChildByName('openNode')?.getChildByName('numBg')?.getChildByName('lb_weaponNum')?.getComponent(Label);
|
|
if (lbNum) lbNum.string = `${this._data?.count ?? 0}`;
|
|
}
|
|
|
|
/** 设置武器名图并缩放 name 节点(贴图异步加载完成后会再设一次缩放) */
|
|
private _setWeaponNameNode(parent: Node | null, weaponName: string, scale: number): void {
|
|
const nameNode = parent?.getChildByName('name');
|
|
if (!nameNode?.isValid) return;
|
|
const applyScale = (): void => {
|
|
nameNode.setScale(scale, scale, 1);
|
|
};
|
|
const path = weaponName ? `weapon/${weaponName}` : '';
|
|
if (!path) {
|
|
nameNode.active = false;
|
|
applyScale();
|
|
return;
|
|
}
|
|
nameNode.active = true;
|
|
if (!nameNode.getComponent(Sprite)) nameNode.addComponent(Sprite);
|
|
nameNode.getOrAddComponent(SpriteLoad).setSprite(path, GBundle.Items, () => {
|
|
applyScale();
|
|
});
|
|
applyScale();
|
|
}
|
|
|
|
/** 按武器类型显隐 type1~4,并设置 Spine 皮肤 */
|
|
private _applyWeaponSpineGroup(parent: Node, weaponType: number, skin: string, dimmed: boolean): void {
|
|
let matched = false;
|
|
for (let t = 1; t <= 4; t++) {
|
|
const typeNode = parent.getChildByName(`type${t}`);
|
|
if (!typeNode) continue;
|
|
const show = t === weaponType;
|
|
typeNode.active = show;
|
|
if (!show) continue;
|
|
matched = true;
|
|
this._applyWeaponSpine(typeNode, skin, dimmed);
|
|
}
|
|
if (!matched && weaponType >= 1 && weaponType <= 4) {
|
|
console.log(LOG, 'type 节点缺失', parent.name, weaponType);
|
|
}
|
|
}
|
|
|
|
/** 设置单个武器 Spine 皮肤与待机 */
|
|
private _applyWeaponSpine(typeNode: Node, skin: string, dimmed: boolean): void {
|
|
const skel = typeNode.getComponent(sp.Skeleton) ?? typeNode.getComponentInChildren(sp.Skeleton);
|
|
if (!skel) {
|
|
console.log(LOG, 'Spine 缺失', typeNode.name);
|
|
return;
|
|
}
|
|
if (skel.skeletonData) ensureSpineSkeletonDataRuntime(skel.skeletonData);
|
|
if (skin) {
|
|
try {
|
|
skel.setSkin(skin);
|
|
skel.setSlotsToSetupPose();
|
|
} catch (e) {
|
|
console.log(LOG, 'setSkin 失败', skin, String(e));
|
|
}
|
|
}
|
|
try {
|
|
skel.setAnimation(0, WEAPON_SPINE_ANIM, true);
|
|
} catch (e) {
|
|
console.log(LOG, 'setAnimation 失败', WEAPON_SPINE_ANIM, String(e));
|
|
}
|
|
this._setSpineDimmed(skel, dimmed);
|
|
}
|
|
|
|
/**
|
|
* Spine 置灰:MultSpine 合批走 shaderVar(1.999),否则走 skel.color(同 PanelShenjiang 神将提示)
|
|
*/
|
|
private _setSpineDimmed(skel: sp.Skeleton, dimmed: boolean): void {
|
|
const s = skel as SkelShader;
|
|
if (SpineBatch.active() && typeof s.shaderVar === 'number') {
|
|
s.shaderVar = dimmed ? SPINE_GRAY_SHADER : 0;
|
|
skel.color = SPINE_NORMAL;
|
|
return;
|
|
}
|
|
s.shaderVar = 0;
|
|
skel.color = dimmed ? SPINE_DIM : SPINE_NORMAL;
|
|
}
|
|
|
|
/** 成品品质 → 武器底 0~4(白/绿/蓝/紫/橙) */
|
|
private _equipQualityBgIndex(quality: number, equipId: number): number {
|
|
const q = Number(quality) | 0;
|
|
if (q < 0 || q > 4) {
|
|
console.log(LOG, '品质无效', equipId, q);
|
|
}
|
|
return q;
|
|
}
|
|
|
|
private _setSprite(node: Node | null, path: string): void {
|
|
if (!node?.isValid) return;
|
|
if (!path) {
|
|
node.active = false;
|
|
return;
|
|
}
|
|
node.active = true;
|
|
if (!node.getComponent(Sprite)) node.addComponent(Sprite);
|
|
node.getOrAddComponent(SpriteLoad).setSprite(path, GBundle.Items);
|
|
}
|
|
}
|
|
|