From e4e0e0779c47e0eb959755baa5d2b45815bff647 Mon Sep 17 00:00:00 2001 From: Wickedness Date: Sun, 5 Jul 2026 16:11:46 +0900 Subject: [PATCH] Validate camp reward bond links --- scripts/verify-camp-reward-data.mjs | 31 ++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/scripts/verify-camp-reward-data.mjs b/scripts/verify-camp-reward-data.mjs index ff4da0c..47198b1 100644 --- a/scripts/verify-camp-reward-data.mjs +++ b/scripts/verify-camp-reward-data.mjs @@ -29,6 +29,9 @@ try { const campBondReferences = validateCampBondReferences(dialogueEvents, 'campDialogues', knownBondsById, { matchUnitIds: true }) + validateCampBondReferences(visitEvents, 'campVisits', knownBondsById); + const rewardBondLinks = + validateRewardBondLinks(dialogueEvents, 'campDialogues', 'rewardExp') + + validateRewardBondLinks(visitEvents, 'campVisits', 'bondExp'); validateNumericProperties('gold', { min: 1, max: 20000 }); validateNumericProperties('bondExp', { min: 0, max: 200 }); validateNumericProperties('rewardExp', { min: 1, max: 200 }); @@ -38,7 +41,7 @@ try { } console.log( - `Verified ${dialogueEvents.length} camp dialogues, ${visitEvents.length} camp visits, ${campBattleIdEntries.length} camp battle ids, ${campaignStepReferences} campaign-step references, ${campBondReferences} camp bond references, ${itemRewardArrays.length} camp item reward lists, and camp reward numeric fields.` + `Verified ${dialogueEvents.length} camp dialogues, ${visitEvents.length} camp visits, ${campBattleIdEntries.length} camp battle ids, ${campaignStepReferences} campaign-step references, ${campBondReferences} camp bond references, ${rewardBondLinks} reward-bond links, ${itemRewardArrays.length} camp item reward lists, and camp reward numeric fields.` ); } finally { await server.close(); @@ -280,6 +283,24 @@ function validateCampBondReferences(events, collectionName, knownBondsById, opti return bondReferenceCount; } +function validateRewardBondLinks(events, collectionName, rewardPropertyName) { + let rewardReferenceCount = 0; + events.forEach((event, index) => { + const context = `${collectionName}[${index}]`; + const rewardEntries = collectNumericProperties(event.body, rewardPropertyName, event.offset).filter((entry) => entry.value > 0); + if (rewardEntries.length === 0) { + return; + } + rewardReferenceCount += rewardEntries.length; + if (collectStringProperties(event.body, 'bondId').length === 0) { + errors.push( + `${sourcePath}:${lineNumber(rewardEntries[0].offset)} ${context} has ${rewardPropertyName} rewards but no bondId` + ); + } + }); + return rewardReferenceCount; +} + function collectStringProperties(text, propertyName) { const pattern = new RegExp(`\\b${propertyName}:\\s*'((?:\\\\'|[^'])*)'`, 'g'); return [...text.matchAll(pattern)].map((match) => ({ @@ -288,6 +309,14 @@ function collectStringProperties(text, propertyName) { })); } +function collectNumericProperties(text, propertyName, offset = 0) { + const pattern = new RegExp(`\\b${propertyName}:\\s*(-?\\d+)`, 'g'); + return [...text.matchAll(pattern)].map((match) => ({ + value: Number(match[1]), + offset: offset + (match.index ?? 0) + })); +} + function collectStringLiterals(text, offset = 0) { return [...text.matchAll(/'((?:\\'|[^'])*)'/g)].map((match) => ({ value: match[1].replace(/\\'/g, "'"),