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.
AdLike2048/assets/script/battle/combat/ExecuteRules.ts

81 lines
3.1 KiB

3 weeks ago
import type { EntityId } from 'db://assets/mx/module/ecs';
import { createAbilityContext } from 'db://assets/mx/module/battle/combat/AbilityContext';
import { EntityTag, HealthComp, TagComp } from 'db://assets/mx/module/battle';
import type { SkillPresentationContext } from '../skill/SkillPresentationTypes';
import { SkillPresentationEnv } from '../skill/SkillPresentationEnv';
/** Boss 不可被秒杀/斩杀 */
export function isBossEntity(entityId: EntityId): boolean {
const session = SkillPresentationEnv.getBattleSession();
if (!session?.world.isAlive(entityId)) return false;
return !!session.world.getComponent(entityId, TagComp)?.tags.includes(EntityTag.Boss);
}
/** 聚合已选词条 skill_special(含普攻 up_type=1) */
export function readSkillSpecialWan(caster: EntityId, specialType: number): number {
let best = 0;
for (const raw of SkillPresentationEnv.getSkillSpecials(caster)) {
for (const seg of String(raw).split(';')) {
const part = seg.trim();
if (!part) continue;
const nums = part.split(',').map(Number);
if ((nums[0] ?? 0) !== specialType || nums.length < 2) continue;
best = Math.max(best, Math.max(0, Number(nums[1]) || 0));
}
}
return best;
}
function dealExecuteDamage(
ctx: SkillPresentationContext,
targetId: EntityId,
damageType: string,
): boolean {
const session = SkillPresentationEnv.getBattleSession();
if (!session?.world.isAlive(targetId)) return false;
const floatPos = SkillPresentationEnv.resolveKillFloaterWorldPos(targetId);
const abilityCtx = createAbilityContext(session, ctx.caster, ctx.abilityId, [targetId]);
abilityCtx.level = ctx.level;
const amount = session.damage.dealToTarget(ctx.caster, targetId, {
percentMaxHpWan: 10000,
scale: 1,
damageType,
skillAtkBuff1: '',
skillAtkBuff2: '',
}, abilityCtx);
if (amount > 0 && floatPos) {
SkillPresentationEnv.playKillFloater(floatPos, damageType);
}
return amount > 0;
}
/** skill_special 类型 10:概率秒杀(Boss 无效) */
export function tryInstantKill(
ctx: SkillPresentationContext,
targetId: EntityId,
killWan: number,
damageType = 'instant_kill',
): boolean {
if (killWan <= 0 || isBossEntity(targetId)) return false;
const rng = SkillPresentationEnv.getBattleRng();
const roll = (rng?.next() ?? Math.random()) * 10000;
if (roll >= killWan) return false;
return dealExecuteDamage(ctx, targetId, damageType);
}
/** skill_special 类型 11:HP 比例斩杀(Boss 无效) */
export function tryExecuteByThreshold(
ctx: SkillPresentationContext,
targetId: EntityId,
thresholdWan: number,
damageType = 'execute',
): boolean {
if (thresholdWan <= 0 || isBossEntity(targetId)) return false;
const session = SkillPresentationEnv.getBattleSession();
if (!session?.world.isAlive(targetId)) return false;
const hp = session.world.getComponent(targetId, HealthComp);
if (!hp || hp.maxHp <= 0) return false;
if (hp.hp / hp.maxHp > thresholdWan / 10000) return false;
return dealExecuteDamage(ctx, targetId, damageType);
}