refactor(missionCard): 重构卡牌池刷新逻辑,改为整池刷新

1.  修改SCardComp的注释,将补卡逻辑改为整池刷新说明
2.  重构MissionCardComp的onCardUsed回调,替换单张补卡为整池刷新
3.  删除buildSingleHeroCard和buildSingleSkillCard两个单张补卡方法
4.  调整注释说明,新增特殊刷新避免重复触发的逻辑
This commit is contained in:
pan
2026-07-21 17:01:35 +08:00
parent fb299f6328
commit db3b5f3649
3 changed files with 329 additions and 107 deletions

View File

@@ -574,14 +574,16 @@ export class MissionCardComp extends CCComp {
}
/**
* 单张卡牌被成功使用后的补卡回调:
* 单张卡牌被成功使用后的整池刷新回调:
* - payload 为该卡槽组件实例CardComp 或 SCardComp
* - 命中英雄卡槽 → 调用 buildSingleHeroCard 补一张英雄/升级卡
* - 命中技能卡槽 → 调用 buildSingleSkillCard 补一张技能卡
* - 未命中任何槽位(如已销毁/未缓存)→ 忽略。
* - 命中英雄卡槽 → 重新构建 3 张英雄池卡牌并分发到所有英雄槽
* - 命中技能卡槽 → 重新构建 3 张技能卡并分发到所有技能槽
* - 未命中任何槽位 → 忽略。
*
* Why: 购买一张卡后立即补充新卡,避免出现空槽,提升抽卡体验
* Why: 购买一张卡后立即刷新整个卡池(不扣金币),让玩家持续从新池中挑选
* 英雄卡池与技能卡池遵循同一逻辑。
* SpecialRefresh 自身效果onUseSpecialCard 中的 tryRefreshHeroCards
* 已是整池刷新,因此 CardComp 对其不派发 CardUsed避免双重刷新。
*/
private onCardUsed(event: string, args: any) {
const source = args;
@@ -589,26 +591,20 @@ export class MissionCardComp extends CCComp {
const heroIdx = this.cardComps.findIndex(c => c === source);
if (heroIdx >= 0) {
const card = this.buildSingleHeroCard();
if (card) {
this.cardComps[heroIdx].applyDrawCard(card);
}
mLogger.log(this.debugMode, "MissionCardComp", "refill hero slot", {
index: heroIdx,
uuid: card?.uuid ?? 0
const cards = this.buildDrawCards();
this.dispatchCardsToSlots(cards);
mLogger.log(this.debugMode, "MissionCardComp", "refresh hero pool after buy", {
triggerSlot: heroIdx
});
return;
}
const skillIdx = this.skillCardComps.findIndex(c => c === source);
if (skillIdx >= 0) {
const card = this.buildSingleSkillCard();
if (card) {
this.skillCardComps[skillIdx].applyDrawCard(card);
}
mLogger.log(this.debugMode, "MissionCardComp", "refill skill slot", {
index: skillIdx,
uuid: card?.uuid ?? 0
const cards = this.buildSkillDrawCards();
this.dispatchCardsToSkillSlots(cards);
mLogger.log(this.debugMode, "MissionCardComp", "refresh skill pool after buy", {
triggerSlot: skillIdx
});
return;
}
@@ -999,58 +995,6 @@ export class MissionCardComp extends CCComp {
return filled;
}
/**
* 构建单张英雄池卡牌,用于购买后补卡。
*
* 规则与 buildDrawCards 保持一致(不含"必出轮询"逻辑):
* 1. 满员且有可升级英雄 → 仅从升级卡池按权重抽 1 张。
* 2. 否则从 升级卡 + 未召唤英雄卡 的混合池按权重抽 1 张。
*
* @returns 卡牌数据;池为空时返回 null
*/
private buildSingleHeroCard(): CardConfig | null {
const upgradeCards = this.buildHeroUpgradeCards();
const aliveHeroCount = this.getAliveHeroCount();
const heroMax = this.getMissionHeroMaxNum();
if (aliveHeroCount >= heroMax && upgradeCards.length > 0) {
return this.weightedPick(upgradeCards);
}
const heroCards = CardPoolList.filter(c => c.type === CardType.Hero);
const aliveHeroUuids = this.getAliveHeroUuids();
const availableHeroCards = heroCards.filter(c => !aliveHeroUuids.has(c.uuid));
const mixedPool: CardConfig[] = [...upgradeCards, ...availableHeroCards];
if (mixedPool.length === 0) return null;
return this.weightedPick(mixedPool);
}
/**
* 构建单张技能卡,用于购买后补卡。
* 规则与 buildSkillDrawCards 对齐(按当前 wave 过滤)。
*
* @returns 卡牌数据;池为空时返回 null
*/
private buildSingleSkillCard(): CardConfig | null {
const currentWave = this.getCurrentWave();
const cards = drawCardsByRule(1, {
count: 1,
type: CardType.Skill,
wave: currentWave,
unique: true
});
if (cards.length > 0) return cards[0];
// 兜底:放宽 wave 限制再尝试
const fallback = drawCardsByRule(1, {
count: 1,
type: CardType.Skill,
unique: true
});
return fallback[0] ?? null;
}
private tryRefreshHeroCards(heroType?: HType): boolean {
const cards = drawCardsByRule(1, {
count: 3,

View File

@@ -109,7 +109,7 @@ export class SCardComp extends CCComp {
this.clearAfterUse();
this.isUsing = false;
oops.message.dispatchEvent(GameEvent.UseSkillCard, used);
// 派发 CardUsed 让 MissionCardComp 立即补一张新技能卡到本槽位
// 派发 CardUsed 让 MissionCardComp 刷新整个技能卡池
oops.message.dispatchEvent(GameEvent.CardUsed, this);
});
return used;