hv-unified/src/progress-tracker.js
GaboGG 402db6bb2f Initial commit: HV Unified v0.11.0 structure
- 23 source files in src/ (build via scripts/build.sh)
- Forum-sourced player knowledge in references/
- DESIGN.md with architecture and corrections
- References to existing scripts (Monsterbation, jpx, HV Utils)
2026-07-20 19:30:26 -04:00

138 lines
6.4 KiB
JavaScript

// ═══════════════════════════════════════════════════════════════════════
// PROGRESS TRACKER — daily task checklist on all pages
// ═══════════════════════════════════════════════════════════════════════
function buildTaskList() {
const today = new Date().toDateString();
const saved = JSON.parse(localStorage[SP + 'tasks'] || '{"_date":"","done":[],"stats":{}}');
if (saved._date !== today) { saved._date = today; saved.done = []; saved.stats = {}; }
const tasks = [];
const tier = STATE.tier;
const lv = STATE.level;
// Core tasks (all tiers)
tasks.push({ id: 'arenas', icon: '⚔', text: 'Clear all available Arenas', tier: 'all', urgent: true });
tasks.push({ id: 'battle', icon: '👊', text: 'Complete at least one battle', tier: 'all', urgent: false });
tasks.push({ id: 'feed', icon: '🍖', text: 'Feed monsters in Monster Lab', tier: 'all', urgent: false });
tasks.push({ id: 'training', icon: '🎓', text: 'Start a new Training session', tier: 'all', urgent: true });
// Novice-specific
if (tier === 'novice') {
tasks.push({ id: 'items', icon: '🧪', text: 'Keep Health/Mana Draughts stocked', detail: 'Items > spells', tier: 'novice', urgent: true });
tasks.push({ id: 'first-blood', icon: '⚔', text: 'Clear "First Blood" arena daily', detail: '100 credits, 2 rounds', tier: 'novice', urgent: true });
tasks.push({ id: 'normal-diff', icon: '⚠', text: 'Stay on Normal difficulty', tier: 'novice', urgent: false });
}
// Adept
if (tier === 'adept') {
tasks.push({ id: 'hard-mode', icon: '⬆', text: 'Switch to Hard difficulty', tier: 'adept', urgent: false });
tasks.push({ id: 'scavenger', icon: '🎓', text: 'Train Scavenger to Lv25', tier: 'adept', urgent: false });
}
// Veteran
if (tier === 'veteran') {
tasks.push({ id: 'pfudor', icon: '💀', text: 'Run Grindfest on PFUDOR', tier: 'veteran', urgent: false });
tasks.push({ id: 'spirit-stance', icon: '✨', text: 'Use Spirit Stance when OC > 70%', tier: 'veteran', urgent: false });
}
// Master
if (tier === 'master') {
tasks.push({ id: 'all-arenas', icon: '🏆', text: 'Clear all 17 arenas daily', tier: 'master', urgent: true });
tasks.push({ id: 'tower', icon: '🗼', text: 'Progress in the Tower', tier: 'master', urgent: false });
}
// Tips
tasks.push({ id: 'dawn', icon: '🌅', text: 'Battles reset at Dawn (~midnight UTC)', tier: 'all', urgent: false, tip: true });
tasks.push({ id: 'hath', icon: '💰', text: 'H@H generates Hath passively', tier: 'all', urgent: false, tip: true });
return { tasks, saved };
}
function renderProgressPanel() {
if (document.getElementById('hv-progress')) return;
const { tasks, saved } = buildTaskList();
const done = saved.done || [];
const doneCount = done.length;
const totalCount = tasks.filter(t => !t.tip).length;
const collapsed = localStorage[SP + 'progressCollapsed'] === '1';
const panel = document.createElement('div');
panel.id = 'hv-progress';
panel.style.cssText = css({
position: 'fixed',
top: '60px',
right: '4px',
zIndex: '9997',
background: '#111827',
color: '#d1d5db',
padding: '8px 10px',
borderRadius: '6px',
fontSize: '10px',
fontFamily: 'monospace',
maxWidth: '320px',
boxShadow: '0 0 15px rgba(0,0,0,0.6)',
border: '1px solid #374151',
maxHeight: '70vh',
overflowY: 'auto',
});
panel.innerHTML = `<div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:6px;cursor:pointer" id="hv-progress-header">
<b style="color:#fdcb00;font-size:11px">📋 Today: ${doneCount}/${totalCount}</b>
<span id="hv-progress-toggle" style="color:#888;font-size:14px">${collapsed ? '▶' : '▼'}</span>
</div>
<div id="hv-progress-body" style="display:${collapsed ? 'none' : 'block'}">${
tasks.map(t => {
const isDone = done.includes(t.id);
const style = isDone ? 'text-decoration:line-through;color:#666'
: t.urgent ? 'color:#fdcb00'
: t.tip ? 'color:#888;font-style:italic'
: 'color:#9ca3af';
const cb = isDone ? '☑' : '☐';
return `<div style="padding:2px 0;${style};cursor:${t.tip ? 'default' : 'pointer'}"
data-task="${t.id}" class="hv-task-item">
${cb} ${t.icon} ${t.text}
${t.detail ? `<br><span style="margin-left:18px;font-size:9px;color:#666">↳ ${t.detail}</span>` : ''}
</div>`;
}).join('')
}</div>`;
document.body.appendChild(panel);
document.getElementById('hv-progress-header').onclick = () => {
const body = document.getElementById('hv-progress-body');
const toggle = document.getElementById('hv-progress-toggle');
const hidden = body.style.display === 'none';
body.style.display = hidden ? 'block' : 'none';
toggle.textContent = hidden ? '▼' : '▶';
localStorage[SP + 'progressCollapsed'] = hidden ? '0' : '1';
};
panel.querySelectorAll('.hv-task-item').forEach(el => {
if (el.dataset.task === 'dawn' || el.dataset.task === 'hath') return;
el.addEventListener('click', () => {
const id = el.dataset.task;
const s = JSON.parse(localStorage[SP + 'tasks'] || '{}');
if (!s.done) s.done = [];
const idx = s.done.indexOf(id);
if (idx >= 0) s.done.splice(idx, 1);
else s.done.push(id);
localStorage[SP + 'tasks'] = JSON.stringify(s);
el.remove();
panel.remove();
renderProgressPanel();
});
});
}
function autoCheckTask(taskId) {
const saved = JSON.parse(localStorage[SP + 'tasks'] || '{}');
if (!saved.done) saved.done = [];
if (!saved.done.includes(taskId)) {
saved.done.push(taskId);
localStorage[SP + 'tasks'] = JSON.stringify(saved);
const panel = document.getElementById('hv-progress');
if (panel) { panel.remove(); renderProgressPanel(); }
}
}