feat: add Holo-work tracking, teams and board bonuses
Publish GitHub Pages output / publish (push) Successful in 30s

This commit is contained in:
2026-09-12 15:16:30 +09:00
parent cfea24f5f5
commit dd37f59565
25 changed files with 1237 additions and 33 deletions
+38
View File
@@ -142,6 +142,44 @@ export type MemberBoardEffectSummary = {
}[];
};
export type HoloWorkBoardBonus = { lesson: number; cube: number; training: number };
const emptyWorkBonus = (): HoloWorkBoardBonus => ({ lesson: 0, cube: 0, training: 0 });
/** Percent bonuses provided when each board's owner participates in Holo-work. */
export function calculateHoloWorkBoardBonuses(
summary: BoardSummarySource,
memberBoards: Readonly<Record<string, readonly string[]>>,
connections?: BoardConnections | null
): Record<string, HoloWorkBoardBonus> {
const multipliers = connectionMultipliers(summary, memberBoards, connections);
return Object.fromEntries(Object.entries(memberBoards).map(([memberId, nodes]) => {
const bonus = emptyWorkBonus();
for (const groupId of new Set(nodes)) {
const effect = nodeForMember(summary, groupId, memberId)?.effect;
if (effect?.trigger !== 'work' || effect.type !== 'work_reward_quantity_up_permil_up'
|| effect.targetId !== 'skill_tree_effect_target-skill_tree_character' || effect.value === null) continue;
// Stable resource suffixes from the official SkillTreeEffect IDs distinguish reward categories.
const category = effect.id?.endsWith('-work-item-item-card_level_up') ? 'lesson'
: effect.id?.endsWith('-work-item-item-skill_tree_card-1') ? 'cube'
: effect.id?.endsWith('-work-item-item-card_limit_break-attribute_1-1') ? 'training' : null;
if (category) bonus[category] += effect.value * (multipliers[memberId]?.[groupId] ?? 1) / 10;
}
return [memberId, bonus];
}));
}
export function sumHoloWorkBoardBonuses(bonuses: Readonly<Record<string, HoloWorkBoardBonus>>, memberIds: readonly string[]): HoloWorkBoardBonus {
const total = emptyWorkBonus();
for (const id of new Set(memberIds)) {
const bonus = bonuses[id];
if (!bonus) continue;
total.lesson += bonus.lesson;
total.cube += bonus.cube;
total.training += bonus.training;
}
return total;
}
/** Saved-board overview, without assuming a leader or a song. Conditional effects stay in the detail rows. */
export function summarizeMemberBoardEffects(
summary: BoardSummarySource,