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/manager/battleBuff/BattleBuffPassiveSkillUtil.ts

675 lines
25 KiB

3 weeks ago
import { DailyShopDataManager } from '../DailyShopDataManager';
import type { DailyShopParsed } from '../DailyShopTypes';
import { BattleBuffFunctionType, passiveBuffUsesBattleGameCd } from './BattleBuffTypes';
export { passiveBuffUsesBattleGameCd };
import {
parseBattleBuffBaseThunderConfig,
parseBattleBuffKillPeachConfig,
parseFunctionParNums,
type BattleBuffBaseThunderConfig,
} from './BattleBuffParamParse';
/** 召神令被动建池结果 */
export type BattleBuffHeroSummonRatePoolAdjust = {
/** 是否携带 functiontype=8 被动 */
active: boolean;
/** 去重后 functionpar 偏移累加 */
offset: number;
};
/** 行军速度被动汇总结果 */
export type BattleBuffMoveSpeedAdjust = {
/** 是否携带 functiontype=12 被动 */
active: boolean;
/** 去重 buffId 后 functionpar 万分比累加 */
bonusWan: number;
};
/** 兵将血量被动汇总结果 */
export type BattleBuffUnitHpAdjust = {
/** 是否携带 functiontype=15 被动 */
active: boolean;
/** 去重 buffId 后 functionpar 万分比累加 */
bonusWan: number;
};
/** 攻击单位攻速被动汇总结果 */
export type BattleBuffUnitAttackSpeedAdjust = {
/** 是否携带 functiontype=27 被动 */
active: boolean;
/** 去重 buffId 后 functionpar 万分比累加 */
bonusWan: number;
};
/** 敌军移速降低被动汇总结果 */
export type BattleBuffEnemySlowAdjust = {
/** 是否携带 functiontype=23 被动 */
active: boolean;
/** 去重 buffId 后降低比例万分比累加 */
slowWan: number;
};
/** 召唤消耗降低被动汇总结果 */
export type BattleBuffSummonCostAdjust = {
/** 是否携带 functiontype=26 被动 */
active: boolean;
/** 去重 buffId 后降低比例万分比累加 */
reduceWan: number;
};
/** 基地血量被动汇总结果 */
export type BattleBuffBaseHpAdjust = {
/** 是否携带 functiontype=6 被动 */
active: boolean;
/** 去重 buffId 后 functionpar 上限值累加 */
bonusHp: number;
};
/** 还魂丹被动汇总结果 */
export type BattleBuffReviveAdjust = {
/** 是否携带 functiontype=14 被动 */
active: boolean;
/** 去重 buffId 后触发概率万分比累加(上限 10000) */
probWan: number;
};
/** 九霄神雷被动汇总结果 */
export type BattleBuffBaseThunderAdjust = {
/** 是否携带 functiontype=20 被动 */
active: boolean;
/** 单局最多触发次数(不同 buffId 累加) */
maxTriggers: number;
/** 小怪伤害比例万分比(取携带中最大值) */
smallDmgWan: number;
/** Boss 伤害比例万分比(取携带中最大值) */
bossDmgWan: number;
/** 触发距离格数(取携带中最大值) */
triggerCells: number;
/** 生效距离格数(从锚点向出怪口后退,取携带中最大值) */
effectCells: number;
};
/** 打断 Boss 施法被动汇总结果 */
export type BattleBuffBossInterruptAdjust = {
/** 是否携带 functiontype=21 被动 */
active: boolean;
/** 去重 buffId 后激活概率万分比累加(上限 10000) */
probWan: number;
/** 去重 buffId 后伤害比例万分比累加 */
dmgWan: number;
};
/** 还魂丹复活后实体 Tag:再次死亡无桃、不再触发还魂 */
export const BATTLE_BUFF_PASSIVE_REVIVED_TAG = 'buff_passive_revived';
/** 读取被动 buff 局内 CD 秒数(functionpar 首段;无 CD 类型返回 0) */
export function readBattleBuffPassiveCdSec(row: ITableBattlebuff | null | undefined): number {
if (!row) return 0;
const ft = Number(row.functiontype) || 0;
if (!passiveBuffUsesBattleGameCd(ft)) return 0;
const nums = parseFunctionParNums(row.functionpar);
if (nums.length < 1) {
console.log('[BattleBuff] 被动 buff functionpar 缺少 CD', row.id, row.functionpar);
return 0;
}
return Math.max(0, Math.floor(nums[0]));
}
/** 是否被动「召神令」(functiontype=8) */
export function isBattleBuffPassiveHeroSummonRate(row: ITableBattlebuff | null | undefined): boolean {
if (!row) return false;
return Number(row.functiontype) === BattleBuffFunctionType.HeroSummonRate;
}
/** 读取召神令 number 档偏移(functionpar 首段) */
export function readBattleBuffHeroSummonRateOffset(row: ITableBattlebuff | null | undefined): number {
if (!isBattleBuffPassiveHeroSummonRate(row)) return 0;
const nums = parseFunctionParNums(row!.functionpar);
if (nums.length < 1) {
console.log('[BattleBuff] 召神令 functionpar 缺少偏移', row!.id, row!.functionpar);
return 0;
}
const offset = Math.floor(nums[0]);
return offset > 0 ? offset : 0;
}
/**
* 汇总携带被动中召神令偏移:不同 buffId 叠加,相同 buffId 只计一次。
* @param passives 当前携带被动
*/
export function resolveCarriedHeroSummonRatePoolAdjust(passives: readonly DailyShopParsed[]): BattleBuffHeroSummonRatePoolAdjust {
let offset = 0;
let active = false;
const seenIds: number[] = [];
for (let i = 0; i < passives.length; i++) {
const row = passives[i].row;
if (!isBattleBuffPassiveHeroSummonRate(row)) continue;
active = true;
const buffId = Number(row.id) || 0;
if (buffId <= 0) continue;
let duplicated = false;
for (let j = 0; j < seenIds.length; j++) {
if (seenIds[j] === buffId) {
duplicated = true;
break;
}
}
if (duplicated) continue;
seenIds.push(buffId);
offset += readBattleBuffHeroSummonRateOffset(row);
}
return { active, offset };
}
/** 是否被动「行军速度」(functiontype=12) */
export function isBattleBuffPassiveMoveSpeed(row: ITableBattlebuff | null | undefined): boolean {
if (!row) return false;
return Number(row.functiontype) === BattleBuffFunctionType.MoveSpeed;
}
/** 读取行军速度被动加成万分比(functionpar 首段) */
export function readBattleBuffMoveSpeedBonusWan(row: ITableBattlebuff | null | undefined): number {
if (!isBattleBuffPassiveMoveSpeed(row)) return 0;
const nums = parseFunctionParNums(row!.functionpar);
if (nums.length < 1) {
console.log('[BattleBuff] 行军速度 functionpar 缺少万分比', row!.id, row!.functionpar);
return 0;
}
return Math.max(0, Math.floor(nums[0]));
}
/**
* 汇总携带被动中行军速度加成:不同 buffId 万分比相加,相同 buffId 只计一次。
* @param passives 当前携带被动;省略时读 DailyShop
*/
export function resolveCarriedMoveSpeedBonusWan(passives?: readonly DailyShopParsed[]): BattleBuffMoveSpeedAdjust {
const list = passives ?? DailyShopDataManager.getOwnedPassive();
let bonusWan = 0;
let active = false;
const seenIds: number[] = [];
for (let i = 0; i < list.length; i++) {
const row = list[i].row;
if (!isBattleBuffPassiveMoveSpeed(row)) continue;
active = true;
const buffId = Number(row.id) || 0;
if (buffId <= 0) continue;
let duplicated = false;
for (let j = 0; j < seenIds.length; j++) {
if (seenIds[j] === buffId) {
duplicated = true;
break;
}
}
if (duplicated) continue;
seenIds.push(buffId);
bonusWan += readBattleBuffMoveSpeedBonusWan(row);
}
return { active, bonusWan };
}
/** 是否被动「基地加血」(functiontype=6) */
export function isBattleBuffPassiveBaseHp(row: ITableBattlebuff | null | undefined): boolean {
if (!row) return false;
return Number(row.functiontype) === BattleBuffFunctionType.BaseHp;
}
/** 读取基地加血被动上限增加值(functionpar 首段) */
export function readBattleBuffBaseHpBonus(row: ITableBattlebuff | null | undefined): number {
if (!isBattleBuffPassiveBaseHp(row)) return 0;
const nums = parseFunctionParNums(row!.functionpar);
if (nums.length < 1) {
console.log('[BattleBuff] 基地加血 functionpar 缺少上限值', row!.id, row!.functionpar);
return 0;
}
return Math.max(0, Math.floor(nums[0]));
}
/**
* 汇总携带被动中基地加血:不同 buffId 上限值相加,相同 buffId 只计一次。
* @param passives 当前携带被动;省略时读 DailyShop
*/
export function resolveCarriedBaseHpBonus(passives?: readonly DailyShopParsed[]): BattleBuffBaseHpAdjust {
const list = passives ?? DailyShopDataManager.getOwnedPassive();
let bonusHp = 0;
let active = false;
const seenIds: number[] = [];
for (let i = 0; i < list.length; i++) {
const row = list[i].row;
if (!isBattleBuffPassiveBaseHp(row)) continue;
active = true;
const buffId = Number(row.id) || 0;
if (buffId <= 0) continue;
let duplicated = false;
for (let j = 0; j < seenIds.length; j++) {
if (seenIds[j] === buffId) {
duplicated = true;
break;
}
}
if (duplicated) continue;
seenIds.push(buffId);
bonusHp += readBattleBuffBaseHpBonus(row);
}
return { active, bonusHp };
}
/** 是否被动「还魂丹」(functiontype=14) */
export function isBattleBuffPassiveRevive(row: ITableBattlebuff | null | undefined): boolean {
if (!row) return false;
return Number(row.functiontype) === BattleBuffFunctionType.Revive;
}
/** 读取还魂丹被动触发概率万分比(functionpar 首段) */
export function readBattleBuffReviveProbWan(row: ITableBattlebuff | null | undefined): number {
if (!isBattleBuffPassiveRevive(row)) return 0;
const nums = parseFunctionParNums(row!.functionpar);
if (nums.length < 1) {
console.log('[BattleBuff] 还魂丹 functionpar 缺少万分比', row!.id, row!.functionpar);
return 0;
}
return Math.max(0, Math.floor(nums[0]));
}
/**
* 汇总携带被动中还魂丹触发概率:不同 buffId 万分比相加,相同 buffId 只计一次。
* @param passives 当前携带被动;省略时读 DailyShop
*/
export function resolveCarriedReviveProbWan(passives?: readonly DailyShopParsed[]): BattleBuffReviveAdjust {
const list = passives ?? DailyShopDataManager.getOwnedPassive();
let probWan = 0;
let active = false;
const seenIds: number[] = [];
for (let i = 0; i < list.length; i++) {
const row = list[i].row;
if (!isBattleBuffPassiveRevive(row)) continue;
active = true;
const buffId = Number(row.id) || 0;
if (buffId <= 0) continue;
let duplicated = false;
for (let j = 0; j < seenIds.length; j++) {
if (seenIds[j] === buffId) {
duplicated = true;
break;
}
}
if (duplicated) continue;
seenIds.push(buffId);
probWan += readBattleBuffReviveProbWan(row);
}
probWan = Math.min(10000, probWan);
return { active, probWan };
}
/**
* 还魂丹:按汇总概率掷骰是否触发原地复活。
* @param passives 省略时读 DailyShop 当前携带被动
*/
export function rollCarriedPassiveRevive(passives?: readonly DailyShopParsed[]): boolean {
const adjust = resolveCarriedReviveProbWan(passives);
if (!adjust.active || adjust.probWan <= 0) return false;
const roll = Math.floor(Math.random() * 10000);
return roll < adjust.probWan;
}
/** 是否被动「九霄神雷」(functiontype=20) */
export function isBattleBuffPassiveBaseThunder(row: ITableBattlebuff | null | undefined): boolean {
if (!row) return false;
return Number(row.functiontype) === BattleBuffFunctionType.BaseThunder;
}
/** 读取九霄神雷被动配置 */
export function readBattleBuffBaseThunderConfig(row: ITableBattlebuff | null | undefined): BattleBuffBaseThunderConfig | null {
if (!isBattleBuffPassiveBaseThunder(row)) return null;
return parseBattleBuffBaseThunderConfig(row!.functionpar);
}
/**
* 汇总携带被动中九霄神雷:单局次数不同 buffId 累加;伤害/距离取最大值。
* @param passives 当前携带被动;省略时读 DailyShop
*/
export function resolveCarriedBaseThunderConfig(passives?: readonly DailyShopParsed[]): BattleBuffBaseThunderAdjust {
const list = passives ?? DailyShopDataManager.getOwnedPassive();
let maxTriggers = 0;
let smallDmgWan = 0;
let bossDmgWan = 0;
let triggerCells = 0;
let effectCells = 0;
let active = false;
const seenIds: number[] = [];
for (let i = 0; i < list.length; i++) {
const row = list[i].row;
if (!isBattleBuffPassiveBaseThunder(row)) continue;
active = true;
const cfg = readBattleBuffBaseThunderConfig(row);
if (!cfg) continue;
const buffId = Number(row.id) || 0;
if (buffId > 0) {
let duplicated = false;
for (let j = 0; j < seenIds.length; j++) {
if (seenIds[j] === buffId) {
duplicated = true;
break;
}
}
if (!duplicated) {
seenIds.push(buffId);
maxTriggers += cfg.maxTriggers;
}
}
if (cfg.smallDmgWan > smallDmgWan) smallDmgWan = cfg.smallDmgWan;
if (cfg.bossDmgWan > bossDmgWan) bossDmgWan = cfg.bossDmgWan;
if (cfg.triggerCells > triggerCells) triggerCells = cfg.triggerCells;
if (cfg.effectCells > effectCells) effectCells = cfg.effectCells;
}
return { active, maxTriggers, smallDmgWan, bossDmgWan, triggerCells, effectCells };
}
/** 是否被动「打断 Boss 施法」(functiontype=21) */
export function isBattleBuffPassiveBossInterrupt(row: ITableBattlebuff | null | undefined): boolean {
if (!row) return false;
return Number(row.functiontype) === BattleBuffFunctionType.BossInterrupt;
}
/**
* 读取打断 Boss 施法被动参数。
* functionpar:激活概率万分比,伤害比例万分比
*/
export function readBattleBuffBossInterruptConfig(row: ITableBattlebuff | null | undefined): { probWan: number; dmgWan: number } | null {
if (!isBattleBuffPassiveBossInterrupt(row)) return null;
const nums = parseFunctionParNums(row!.functionpar);
if (nums.length < 2) {
console.log('[BattleBuff] 打断 Boss 施法 functionpar 缺少概率/伤害', row!.id, row!.functionpar);
return null;
}
const probWan = Math.max(0, Math.floor(nums[0]));
const dmgWan = Math.max(0, Math.floor(nums[1]));
if (probWan <= 0 && dmgWan <= 0) return null;
return { probWan, dmgWan };
}
/**
* 汇总携带被动中打断 Boss 施法:不同 buffId 概率与伤害万分比相加,相同 buffId 只计一次。
* @param passives 当前携带被动;省略时读 DailyShop
*/
export function resolveCarriedBossInterruptConfig(passives?: readonly DailyShopParsed[]): BattleBuffBossInterruptAdjust {
const list = passives ?? DailyShopDataManager.getOwnedPassive();
let probWan = 0;
let dmgWan = 0;
let active = false;
const seenIds: number[] = [];
for (let i = 0; i < list.length; i++) {
const row = list[i].row;
if (!isBattleBuffPassiveBossInterrupt(row)) continue;
active = true;
const buffId = Number(row.id) || 0;
if (buffId <= 0) continue;
let duplicated = false;
for (let j = 0; j < seenIds.length; j++) {
if (seenIds[j] === buffId) {
duplicated = true;
break;
}
}
if (duplicated) continue;
seenIds.push(buffId);
const cfg = readBattleBuffBossInterruptConfig(row);
if (!cfg) continue;
probWan += cfg.probWan;
dmgWan += cfg.dmgWan;
}
probWan = Math.min(10000, probWan);
return { active, probWan, dmgWan };
}
/**
* 打断 Boss 施法:按汇总概率掷骰是否触发。
* @param passives 省略时读 DailyShop 当前携带被动
*/
export function rollCarriedBossInterrupt(passives?: readonly DailyShopParsed[]): boolean {
const adjust = resolveCarriedBossInterruptConfig(passives);
if (!adjust.active || adjust.probWan <= 0) return false;
const roll = Math.floor(Math.random() * 10000);
return roll < adjust.probWan;
}
/** 是否被动「兵将血量」(functiontype=15) */
export function isBattleBuffPassiveUnitHp(row: ITableBattlebuff | null | undefined): boolean {
if (!row) return false;
return Number(row.functiontype) === BattleBuffFunctionType.UnitHp;
}
/** 读取兵将血量被动上限加成万分比(functionpar 首段) */
export function readBattleBuffUnitHpBonusWan(row: ITableBattlebuff | null | undefined): number {
if (!isBattleBuffPassiveUnitHp(row)) return 0;
const nums = parseFunctionParNums(row!.functionpar);
if (nums.length < 1) {
console.log('[BattleBuff] 兵将血量 functionpar 缺少万分比', row!.id, row!.functionpar);
return 0;
}
return Math.max(0, Math.floor(nums[0]));
}
/**
* 汇总携带被动中兵将血量加成:不同 buffId 万分比相加,相同 buffId 只计一次。
* @param passives 当前携带被动;省略时读 DailyShop
*/
export function resolveCarriedUnitHpBonusWan(passives?: readonly DailyShopParsed[]): BattleBuffUnitHpAdjust {
const list = passives ?? DailyShopDataManager.getOwnedPassive();
let bonusWan = 0;
let active = false;
const seenIds: number[] = [];
for (let i = 0; i < list.length; i++) {
const row = list[i].row;
if (!isBattleBuffPassiveUnitHp(row)) continue;
active = true;
const buffId = Number(row.id) || 0;
if (buffId <= 0) continue;
let duplicated = false;
for (let j = 0; j < seenIds.length; j++) {
if (seenIds[j] === buffId) {
duplicated = true;
break;
}
}
if (duplicated) continue;
seenIds.push(buffId);
bonusWan += readBattleBuffUnitHpBonusWan(row);
}
return { active, bonusWan };
}
/** 是否被动「攻击单位攻速」(functiontype=27) */
export function isBattleBuffPassiveUnitAttackSpeed(row: ITableBattlebuff | null | undefined): boolean {
if (!row) return false;
return Number(row.functiontype) === BattleBuffFunctionType.UnitAttackSpeed;
}
/** 读取攻击单位攻速被动加成万分比(functionpar 首段) */
export function readBattleBuffUnitAttackSpeedBonusWan(row: ITableBattlebuff | null | undefined): number {
if (!isBattleBuffPassiveUnitAttackSpeed(row)) return 0;
const nums = parseFunctionParNums(row!.functionpar);
if (nums.length < 1) {
console.log('[BattleBuff] 攻击单位攻速 functionpar 缺少万分比', row!.id, row!.functionpar);
return 0;
}
return Math.max(0, Math.floor(nums[0]));
}
/**
* 汇总携带被动中攻击单位攻速加成:不同 buffId 万分比相加,相同 buffId 只计一次。
* @param passives 当前携带被动;省略时读 DailyShop
*/
export function resolveCarriedUnitAttackSpeedBonusWan(passives?: readonly DailyShopParsed[]): BattleBuffUnitAttackSpeedAdjust {
const list = passives ?? DailyShopDataManager.getOwnedPassive();
let bonusWan = 0;
let active = false;
const seenIds: number[] = [];
for (let i = 0; i < list.length; i++) {
const row = list[i].row;
if (!isBattleBuffPassiveUnitAttackSpeed(row)) continue;
active = true;
const buffId = Number(row.id) || 0;
if (buffId <= 0) continue;
let duplicated = false;
for (let j = 0; j < seenIds.length; j++) {
if (seenIds[j] === buffId) {
duplicated = true;
break;
}
}
if (duplicated) continue;
seenIds.push(buffId);
bonusWan += readBattleBuffUnitAttackSpeedBonusWan(row);
}
return { active, bonusWan };
}
/** 是否被动「敌军移速降低」(functiontype=23) */
export function isBattleBuffPassiveEnemySlow(row: ITableBattlebuff | null | undefined): boolean {
if (!row) return false;
return Number(row.functiontype) === BattleBuffFunctionType.EnemySlow;
}
/** 读取敌军移速降低被动比例万分比(functionpar 首段) */
export function readBattleBuffEnemySlowWan(row: ITableBattlebuff | null | undefined): number {
if (!isBattleBuffPassiveEnemySlow(row)) return 0;
const nums = parseFunctionParNums(row!.functionpar);
if (nums.length < 1) {
console.log('[BattleBuff] 敌军移速降低 functionpar 缺少万分比', row!.id, row!.functionpar);
return 0;
}
return Math.max(0, Math.floor(nums[0]));
}
/**
* 汇总携带被动中敌军移速降低:不同 buffId 万分比相加,相同 buffId 只计一次。
* @param passives 当前携带被动;省略时读 DailyShop
*/
export function resolveCarriedEnemySlowWan(passives?: readonly DailyShopParsed[]): BattleBuffEnemySlowAdjust {
const list = passives ?? DailyShopDataManager.getOwnedPassive();
let slowWan = 0;
let active = false;
const seenIds: number[] = [];
for (let i = 0; i < list.length; i++) {
const row = list[i].row;
if (!isBattleBuffPassiveEnemySlow(row)) continue;
active = true;
const buffId = Number(row.id) || 0;
if (buffId <= 0) continue;
let duplicated = false;
for (let j = 0; j < seenIds.length; j++) {
if (seenIds[j] === buffId) {
duplicated = true;
break;
}
}
if (duplicated) continue;
seenIds.push(buffId);
slowWan += readBattleBuffEnemySlowWan(row);
}
return { active, slowWan };
}
/** 是否被动「召唤消耗降低」(functiontype=26) */
export function isBattleBuffPassiveSummonCost(row: ITableBattlebuff | null | undefined): boolean {
if (!row) return false;
return Number(row.functiontype) === BattleBuffFunctionType.SummonCost;
}
/** 读取召唤消耗降低被动比例万分比(functionpar 首段) */
export function readBattleBuffSummonCostReduceWan(row: ITableBattlebuff | null | undefined): number {
if (!isBattleBuffPassiveSummonCost(row)) return 0;
const nums = parseFunctionParNums(row!.functionpar);
if (nums.length < 1) {
console.log('[BattleBuff] 召唤消耗降低 functionpar 缺少万分比', row!.id, row!.functionpar);
return 0;
}
return Math.max(0, Math.floor(nums[0]));
}
/**
* 汇总携带被动中召唤消耗降低:不同 buffId 万分比相加,相同 buffId 只计一次。
* @param passives 当前携带被动;省略时读 DailyShop
*/
export function resolveCarriedSummonCostReduceWan(passives?: readonly DailyShopParsed[]): BattleBuffSummonCostAdjust {
const list = passives ?? DailyShopDataManager.getOwnedPassive();
let reduceWan = 0;
let active = false;
const seenIds: number[] = [];
for (let i = 0; i < list.length; i++) {
const row = list[i].row;
if (!isBattleBuffPassiveSummonCost(row)) continue;
active = true;
const buffId = Number(row.id) || 0;
if (buffId <= 0) continue;
let duplicated = false;
for (let j = 0; j < seenIds.length; j++) {
if (seenIds[j] === buffId) {
duplicated = true;
break;
}
}
if (duplicated) continue;
seenIds.push(buffId);
reduceWan += readBattleBuffSummonCostReduceWan(row);
}
reduceWan = Math.min(10000, reduceWan);
return { active, reduceWan };
}
/** 是否被动「击杀额外蟠桃」(functiontype=25) */
export function isBattleBuffPassiveKillPeach(row: ITableBattlebuff | null | undefined): boolean {
if (!row) return false;
return Number(row.functiontype) === BattleBuffFunctionType.KillPeach;
}
/**
* 击杀小怪:按携带被动 functionpar 概率掷骰,累加成功 buff 的蟠桃数量。
* 不同 buffId 各自掷骰;相同 buffId 只计一次。
* @param passives 省略时读 DailyShop 当前携带被动
* @returns 本次击杀额外蟠桃总数;未触发时 0
*/
export function rollCarriedKillPeachBonus(passives?: readonly DailyShopParsed[]): number {
const list = passives ?? DailyShopDataManager.getOwnedPassive();
let total = 0;
const seenIds: number[] = [];
for (let i = 0; i < list.length; i++) {
const row = list[i].row;
if (!isBattleBuffPassiveKillPeach(row)) continue;
const buffId = Number(row.id) || 0;
if (buffId > 0) {
let duplicated = false;
for (let j = 0; j < seenIds.length; j++) {
if (seenIds[j] === buffId) {
duplicated = true;
break;
}
}
if (duplicated) continue;
seenIds.push(buffId);
}
const cfg = parseBattleBuffKillPeachConfig(row.functionpar);
if (!cfg) {
console.log('[BattleBuff] 击杀额外蟠桃 functionpar 无效', row.id, row.functionpar);
continue;
}
const roll = Math.floor(Math.random() * 10000);
if (roll < cfg.probWan) {
total += cfg.count;
}
}
return total;
}
/** 读取被动 buff 产字 weapon2Id(functionpar 第二段) */
export function readBattleBuffPassiveSpawnWeapon2Id(row: ITableBattlebuff | null | undefined): number {
if (!row) return 0;
const nums = parseFunctionParNums(row.functionpar);
if (nums.length < 2) {
console.log('[BattleBuff] 被动产字 functionpar 缺少文字 id', row?.id, row?.functionpar);
return 0;
}
return Math.max(0, Math.floor(nums[1]));
}