- 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)
138 lines
6.4 KiB
JavaScript
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(); }
|
|
}
|
|
}
|