75 lines
2.6 KiB
JavaScript
75 lines
2.6 KiB
JavaScript
import { readFileSync } from 'node:fs';
|
|
|
|
const sourcePath = 'src/game/scenes/CampScene.ts';
|
|
const source = readFileSync(sourcePath, 'utf8');
|
|
const errors = [];
|
|
|
|
const itemRewardArrays = collectItemRewardArrays(source);
|
|
itemRewardArrays.forEach(({ body, index, offset }) => validateItemRewards(body, index, offset));
|
|
validateNumericProperties('gold', { min: 1, max: 20000 });
|
|
validateNumericProperties('bondExp', { min: 0, max: 200 });
|
|
validateNumericProperties('rewardExp', { min: 1, max: 200 });
|
|
|
|
if (errors.length > 0) {
|
|
throw new Error(`Camp reward data verification failed:\n${errors.map((error) => `- ${error}`).join('\n')}`);
|
|
}
|
|
|
|
console.log(`Verified ${itemRewardArrays.length} camp item reward lists and camp reward numeric fields.`);
|
|
|
|
function collectItemRewardArrays(text) {
|
|
return [...text.matchAll(/itemRewards:\s*\[([\s\S]*?)\]/g)].map((match, index) => ({
|
|
body: match[1],
|
|
index,
|
|
offset: match.index ?? 0
|
|
}));
|
|
}
|
|
|
|
function validateItemRewards(body, index, offset) {
|
|
const entries = [...body.matchAll(/'((?:\\'|[^'])*)'/g)].map((match) => match[1].replace(/\\'/g, "'"));
|
|
if (entries.length === 0) {
|
|
return;
|
|
}
|
|
|
|
const labels = new Set();
|
|
entries.forEach((reward, rewardIndex) => {
|
|
const parsed = parseRewardLabel(reward);
|
|
if (!parsed.label) {
|
|
errors.push(`${sourcePath}:${lineNumber(offset)} itemRewards[${index}][${rewardIndex}] has an empty parsed label`);
|
|
}
|
|
if (!Number.isInteger(parsed.amount) || parsed.amount < 1) {
|
|
errors.push(`${sourcePath}:${lineNumber(offset)} itemRewards[${index}][${rewardIndex}] has invalid amount ${parsed.amount}`);
|
|
}
|
|
if (labels.has(parsed.label)) {
|
|
errors.push(`${sourcePath}:${lineNumber(offset)} itemRewards[${index}] has duplicate label "${parsed.label}"`);
|
|
}
|
|
labels.add(parsed.label);
|
|
});
|
|
}
|
|
|
|
function validateNumericProperties(propertyName, { min, max }) {
|
|
const pattern = new RegExp(`${propertyName}:\\s*(-?\\d+)`, 'g');
|
|
for (const match of source.matchAll(pattern)) {
|
|
const value = Number(match[1]);
|
|
if (!Number.isInteger(value) || value < min || value > max) {
|
|
errors.push(`${sourcePath}:${lineNumber(match.index ?? 0)} ${propertyName} has out-of-range value ${value}`);
|
|
}
|
|
}
|
|
}
|
|
|
|
function parseRewardLabel(reward) {
|
|
const normalized = String(reward).replace(/\s+/g, ' ').trim();
|
|
const match = normalized.match(/^(.*?)(?:\s*[+xX]?\s*(\d+))$/);
|
|
if (!match) {
|
|
return { label: normalized, amount: 1 };
|
|
}
|
|
|
|
return {
|
|
label: match[1].trim() || normalized,
|
|
amount: Number(match[2] ?? 1)
|
|
};
|
|
}
|
|
|
|
function lineNumber(offset) {
|
|
return source.slice(0, offset).split(/\r?\n/).length;
|
|
}
|