feat: add production campaigns, gameplay labs, and review documentation
This commit is contained in:
@@ -0,0 +1,54 @@
|
||||
export const tutorialProgressKey = campaignId => `hex-trails-tutorial-v1-${campaignId}`;
|
||||
|
||||
function tutorialCount(count) {
|
||||
return Number.isInteger(count) && count > 0 ? count : 0;
|
||||
}
|
||||
|
||||
function normalizeProgress(value, count) {
|
||||
const valid = index => Number.isInteger(index) && index >= 0 && index < count;
|
||||
return {
|
||||
current: valid(value?.current) ? value.current : 0,
|
||||
completed: [...new Set(Array.isArray(value?.completed) ? value.completed.filter(valid) : [])],
|
||||
};
|
||||
}
|
||||
|
||||
export function readTutorialProgress(storage, campaignId, count) {
|
||||
count = tutorialCount(count);
|
||||
let value;
|
||||
if (count) {
|
||||
try { value = JSON.parse(storage?.getItem(tutorialProgressKey(campaignId)) ?? '{}'); } catch {}
|
||||
}
|
||||
return normalizeProgress(value, count);
|
||||
}
|
||||
|
||||
export function writeTutorialProgress(storage, campaignId, count, progress) {
|
||||
count = tutorialCount(count);
|
||||
if (!count || !storage) return false;
|
||||
try {
|
||||
storage.setItem(tutorialProgressKey(campaignId), JSON.stringify(normalizeProgress(progress, count)));
|
||||
return true;
|
||||
} catch { return false; }
|
||||
}
|
||||
|
||||
export function tutorialLaunch(search, count, progress, campaignProgress) {
|
||||
count = tutorialCount(count);
|
||||
if (!count) return null;
|
||||
const params = new URLSearchParams(search);
|
||||
const requested = params.get('tutorial');
|
||||
if (/^\d+$/.test(requested ?? '')) {
|
||||
const index = Number(requested) - 1;
|
||||
if (Number.isInteger(index) && index >= 0 && index < count) return index;
|
||||
}
|
||||
// Existing level links keep their destination, including links to level 1.
|
||||
if (params.has('level')) return null;
|
||||
if ((Number.isInteger(campaignProgress?.current) && campaignProgress.current > 0)
|
||||
|| (Array.isArray(campaignProgress?.completed) && campaignProgress.completed.length > 0)) return null;
|
||||
|
||||
const normalized = normalizeProgress(progress, count);
|
||||
const completed = new Set(normalized.completed);
|
||||
for (let offset = 0; offset < count; offset += 1) {
|
||||
const index = (normalized.current + offset) % count;
|
||||
if (!completed.has(index)) return index;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
Reference in New Issue
Block a user