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.
176 lines
6.2 KiB
176 lines
6.2 KiB
import type { EntityId, World } from 'db://assets/mx/module/ecs';
|
|
import { GridOccupancyComp, TagComp, UnitMetaComp } from 'db://assets/mx/module/battle/ecs/Components';
|
|
import { TableNames } from '../../game/ConfigTableData';
|
|
import { PEACH_TREE_WEAPON2_ID } from '../bag/BagPrepConfig';
|
|
import { isNonCombatWeapon1 } from '../heros/HeroActorRes';
|
|
|
|
/** 塔 unitDefId 前缀 */
|
|
const TOWER_DEF_PREFIX = 'tower_w1_';
|
|
/** 塔 Hero 标签前缀 */
|
|
const WEAPON1_TAG_PREFIX = 'weapon1_';
|
|
|
|
/** 英雄组成文字 id 列表(Hero.text) */
|
|
export function heroCharacterIds(hero: ITableHero): readonly number[] {
|
|
return hero.text ?? [];
|
|
}
|
|
|
|
/** 指定合成等级对应的普攻技能 id */
|
|
export function heroNormalSkillId(hero: ITableHero, composeLevel: number): number {
|
|
return _skillIdAtLevel(hero.atk_id, composeLevel);
|
|
}
|
|
|
|
/** 指定合成等级对应的英雄主动技能 id(0=无) */
|
|
export function heroUltSkillId(hero: ITableHero | null | undefined, composeLevel = 1): number {
|
|
if (!hero) return 0;
|
|
return _skillIdAtLevel(hero.act_skill, composeLevel);
|
|
}
|
|
|
|
/** 是否基础单字英雄 */
|
|
export function isBasicHero(hero: ITableHero): boolean {
|
|
return Number(hero.herotype) === 1;
|
|
}
|
|
|
|
/**
|
|
* 单字落下即可攻击来敌(刀/枪/棍/弓)。
|
|
* 不含营、铲、桃、组合碎字。
|
|
* @param textId Text.id
|
|
*/
|
|
export function isAttackGlyph(textId: number): boolean {
|
|
const id = Number(textId);
|
|
if (!(id > 0)) return false;
|
|
const heroes = gg.data.table.getTableList<ITableHero>(TableNames.Hero) ?? [];
|
|
for (let i = 0; i < heroes.length; i++) {
|
|
const hero = heroes[i];
|
|
const texts = hero.text ?? [];
|
|
if (texts.length !== 1 || Number(texts[0]) !== id) continue;
|
|
if (!isBasicHero(hero) || isNonCombatWeapon1(Number(hero.id))) return false;
|
|
return heroNormalSkillId(hero, 1) > 0;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/** 是否多格组合英雄 */
|
|
export function isComboHero(hero: ITableHero): boolean {
|
|
return Number(hero.herotype) === 2;
|
|
}
|
|
|
|
/** 是否五行数字英雄(herotype 1–5) */
|
|
export function isElementHero(hero: ITableHero | null | undefined): boolean {
|
|
if (!hero) return false;
|
|
const t = Math.floor(Number(hero.herotype));
|
|
return t >= 1 && t <= 5;
|
|
}
|
|
|
|
/**
|
|
* Hero.id 是否为五行战斗单位(有普攻)。
|
|
* @param heroId Hero.id
|
|
*/
|
|
export function isElementCombatHeroId(heroId: number): boolean {
|
|
const id = Math.floor(Number(heroId) || 0);
|
|
if (!(id > 0)) return false;
|
|
const hero = gg.data.table.getTableData<ITableHero>(TableNames.Hero, id);
|
|
if (!isElementHero(hero) || isNonCombatWeapon1(id)) return false;
|
|
return heroNormalSkillId(hero!, 1) > 0;
|
|
}
|
|
|
|
/**
|
|
* 从塔实体解析 Hero.id(unitDefId / weapon1_ 标签)。
|
|
* @param world 战斗世界
|
|
* @param entityId 实体
|
|
*/
|
|
export function resolveTowerHeroId(world: World, entityId: EntityId): number {
|
|
const defId = world.getComponent(entityId, UnitMetaComp)?.unitDefId ?? '';
|
|
if (defId.startsWith(TOWER_DEF_PREFIX)) {
|
|
const id = Number(defId.slice(TOWER_DEF_PREFIX.length));
|
|
if (id > 0) return id;
|
|
}
|
|
const tags = world.getComponent(entityId, TagComp)?.tags;
|
|
if (tags) {
|
|
for (let i = 0; i < tags.length; i++) {
|
|
const t = tags[i];
|
|
if (!t.startsWith(WEAPON1_TAG_PREFIX)) continue;
|
|
const id = Number(t.slice(WEAPON1_TAG_PREFIX.length));
|
|
if (id > 0) return id;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* 从塔实体解析 Hero 行。
|
|
* @param world 战斗世界
|
|
* @param entityId 实体
|
|
*/
|
|
function resolveTowerHero(world: World, entityId: EntityId): ITableHero | null {
|
|
const heroId = resolveTowerHeroId(world, entityId);
|
|
if (!(heroId > 0)) return null;
|
|
const hero = gg.data.table.getTableData<ITableHero>(TableNames.Hero, heroId);
|
|
if (!hero) {
|
|
console.log('[BattleHeroTable] Hero 缺失', heroId);
|
|
return null;
|
|
}
|
|
return hero;
|
|
}
|
|
|
|
/**
|
|
* 怪物技能 target_stage=1 的默认敌人:敌方阵营、非组合武将(herotype≠2)、非多格组合字。
|
|
* @param world 战斗世界
|
|
* @param entityId 候选目标
|
|
*/
|
|
export function isMonsterDefaultEnemyTarget(world: World, entityId: EntityId): boolean {
|
|
const hero = resolveTowerHero(world, entityId);
|
|
if (hero == null || Number(hero.herotype) === 2) return false;
|
|
const cells = world.getComponent(entityId, GridOccupancyComp)?.cells;
|
|
return !(cells && cells.length > 1);
|
|
}
|
|
|
|
/**
|
|
* 是否蟠桃树塔(Hero/Text id=102,herotype=3)。
|
|
* @param world 战斗世界
|
|
* @param entityId 候选目标
|
|
*/
|
|
export function isPeachTreeTower(world: World, entityId: EntityId): boolean {
|
|
return resolveTowerHeroId(world, entityId) === PEACH_TREE_WEAPON2_ID;
|
|
}
|
|
|
|
/**
|
|
* atk_buff1 类型 12:只锁基础字(herotype=1),不含组合字。
|
|
* 损毁态由调用方用 TowerRuinHost 判定,本表不反向依赖战斗宿主。
|
|
* @param world 战斗世界
|
|
* @param entityId 候选目标
|
|
*/
|
|
export function isMonsterBasicHeroTarget(world: World, entityId: EntityId): boolean {
|
|
if (!isMonsterDefaultEnemyTarget(world, entityId)) return false;
|
|
const hero = resolveTowerHero(world, entityId);
|
|
return hero != null && isBasicHero(hero);
|
|
}
|
|
|
|
/**
|
|
* atk_type=9:Hero.weapon 等于将 id(1刀 2枪 3棍 4弓),含组合武将。
|
|
* @param world 战斗世界
|
|
* @param entityId 候选目标
|
|
* @param weaponType Hero.weapon
|
|
*/
|
|
export function isHeroWeaponTarget(world: World, entityId: EntityId, weaponType: number): boolean {
|
|
if (!(weaponType > 0)) return false;
|
|
const hero = resolveTowerHero(world, entityId);
|
|
return hero != null && Number(hero.weapon) === weaponType;
|
|
}
|
|
|
|
/** 文字块展示/资源名 */
|
|
export function textIconName(text: ITableText): string {
|
|
return text.icon ?? '';
|
|
}
|
|
|
|
/** 文字块显示名 */
|
|
export function textDisplayName(text: ITableText): string {
|
|
const g = text.group?.trim();
|
|
return g || textIconName(text);
|
|
}
|
|
|
|
/** 数组按下标取技能 id;composeLevel 从 1 起,越界 clamp */
|
|
function _skillIdAtLevel(ids: readonly number[] | null | undefined, composeLevel: number): number {
|
|
if (!ids || ids.length <= 0) return 0;
|
|
const idx = Math.max(0, Math.min(composeLevel - 1, ids.length - 1));
|
|
return ids[idx] ?? 0;
|
|
}
|
|
|