added thing
This commit is contained in:
@@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
const page = document.body.dataset.page;
|
const page = document.body.dataset.page;
|
||||||
let cachedItems = null;
|
let cachedItems = null;
|
||||||
|
let cachedLevelMeta = null;
|
||||||
|
|
||||||
// Storage helpers
|
// Storage helpers
|
||||||
function read(key, fallback){
|
function read(key, fallback){
|
||||||
@@ -19,6 +20,21 @@
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function parseLevelMeta(txt){
|
||||||
|
const map = {};
|
||||||
|
txt.split(/\r?\n/).map(l=>l.trim()).filter(Boolean).forEach(l=>{
|
||||||
|
if(l.startsWith('//')) return;
|
||||||
|
const parts = l.split('|').map(p=>p.trim());
|
||||||
|
const title = parts[0] || '';
|
||||||
|
if(!title) return;
|
||||||
|
map[title] = {
|
||||||
|
levelId: parts[1] || 'unknown',
|
||||||
|
percent: parts[2] || '100'
|
||||||
|
};
|
||||||
|
});
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
function loadItems(){
|
function loadItems(){
|
||||||
if(cachedItems) return Promise.resolve(cachedItems);
|
if(cachedItems) return Promise.resolve(cachedItems);
|
||||||
return fetch('data.txt').then(r=>r.text()).then(txt=>{
|
return fetch('data.txt').then(r=>r.text()).then(txt=>{
|
||||||
@@ -27,17 +43,45 @@
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function loadLevelMeta(){
|
||||||
|
if(cachedLevelMeta) return Promise.resolve(cachedLevelMeta);
|
||||||
|
return fetch('level-ids.txt').then(r=>r.text()).then(txt=>{
|
||||||
|
cachedLevelMeta = parseLevelMeta(txt);
|
||||||
|
return cachedLevelMeta;
|
||||||
|
}).catch(()=>{
|
||||||
|
cachedLevelMeta = {};
|
||||||
|
return cachedLevelMeta;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function fetchLevelIdFromApi(title){
|
||||||
|
const url = `https://gdbrowser.com/api/search/${encodeURIComponent(title)}?diff=-2&demonFilter=5&count=10`;
|
||||||
|
return fetch(url).then(r=>r.json()).then(results=>{
|
||||||
|
if(!Array.isArray(results) || !results.length) return null;
|
||||||
|
const exact = results.find(item=>String(item.name||'').toLowerCase() === String(title||'').toLowerCase());
|
||||||
|
const match = exact || results[0];
|
||||||
|
if(!match || !match.id) return null;
|
||||||
|
return String(match.id);
|
||||||
|
}).catch(()=>null);
|
||||||
|
}
|
||||||
|
|
||||||
if(page==='roulette'){
|
if(page==='roulette'){
|
||||||
const spinBtn = qs('roulette-spin');
|
const spinBtn = qs('roulette-spin');
|
||||||
const statusEl = qs('roulette-status');
|
const statusEl = qs('roulette-status');
|
||||||
const titleEl = qs('roulette-title');
|
const titleEl = qs('roulette-title');
|
||||||
const rankEl = qs('roulette-rank');
|
const rankEl = qs('roulette-rank');
|
||||||
|
const idEl = qs('roulette-level-id');
|
||||||
|
const noteEl = qs('roulette-note');
|
||||||
const openEl = qs('roulette-open');
|
const openEl = qs('roulette-open');
|
||||||
|
|
||||||
function showPick(item){
|
function showPick(item, meta){
|
||||||
statusEl.textContent = 'Your demon is:';
|
statusEl.textContent = 'Your demon is:';
|
||||||
titleEl.textContent = item.title;
|
titleEl.textContent = item.title;
|
||||||
rankEl.textContent = `Rank: #${item.position}`;
|
rankEl.textContent = `Rank: #${item.position}`;
|
||||||
|
idEl.textContent = `Level ID: ${meta.levelId || 'unknown'}`;
|
||||||
|
noteEl.textContent = meta.source === 'api'
|
||||||
|
? 'Level ID was looked up from the Geometry Dash community API.'
|
||||||
|
: 'Level ID came from your local level-ids.txt file.';
|
||||||
if(item.url){
|
if(item.url){
|
||||||
openEl.hidden = false;
|
openEl.hidden = false;
|
||||||
openEl.href = item.url;
|
openEl.href = item.url;
|
||||||
@@ -50,19 +94,37 @@
|
|||||||
statusEl.textContent = 'Spinning...';
|
statusEl.textContent = 'Spinning...';
|
||||||
titleEl.textContent = 'Choosing a demon';
|
titleEl.textContent = 'Choosing a demon';
|
||||||
rankEl.textContent = 'Rank: -';
|
rankEl.textContent = 'Rank: -';
|
||||||
|
idEl.textContent = 'Level ID: -';
|
||||||
|
noteEl.textContent = 'Checking your local file and API if needed.';
|
||||||
openEl.hidden = true;
|
openEl.hidden = true;
|
||||||
loadItems().then(items=>{
|
Promise.all([loadItems(), loadLevelMeta()]).then(([items, metaMap])=>{
|
||||||
if(!items.length){
|
if(!items.length){
|
||||||
statusEl.textContent = 'No demons found.';
|
statusEl.textContent = 'No demons found.';
|
||||||
titleEl.textContent = 'Add demons to data.txt';
|
titleEl.textContent = 'Add demons to data.txt';
|
||||||
|
idEl.textContent = 'Level ID: -';
|
||||||
|
noteEl.textContent = 'No list data was found.';
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const item = items[Math.floor(Math.random()*items.length)];
|
const item = items[Math.floor(Math.random()*items.length)];
|
||||||
window.setTimeout(()=>showPick(item), 350);
|
const localMeta = metaMap[item.title] || {levelId:'unknown', percent:'100'};
|
||||||
|
if(localMeta.levelId && localMeta.levelId !== 'unknown'){
|
||||||
|
window.setTimeout(()=>showPick(item, {levelId: localMeta.levelId, percent: localMeta.percent, source: 'file'}), 350);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
fetchLevelIdFromApi(item.title).then(levelId=>{
|
||||||
|
const meta = {
|
||||||
|
levelId: levelId || 'unknown',
|
||||||
|
percent: localMeta.percent || '100',
|
||||||
|
source: levelId ? 'api' : 'file'
|
||||||
|
};
|
||||||
|
window.setTimeout(()=>showPick(item, meta), 350);
|
||||||
|
});
|
||||||
}).catch(err=>{
|
}).catch(err=>{
|
||||||
statusEl.textContent = 'Could not load the list.';
|
statusEl.textContent = 'Could not load the list.';
|
||||||
titleEl.textContent = 'Run the site on a local server';
|
titleEl.textContent = 'Run the site on a local server';
|
||||||
rankEl.textContent = 'Rank: -';
|
rankEl.textContent = 'Rank: -';
|
||||||
|
idEl.textContent = 'Level ID: -';
|
||||||
|
noteEl.textContent = 'The local file or API lookup failed.';
|
||||||
console.error(err);
|
console.error(err);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -47,4 +47,4 @@ new|46|The Halucination|https://youtu.be/tYbXsNkO9HE?si=b8hmXS98BAjDlPzF
|
|||||||
new|47|CONVULSION|https://youtu.be/qeRKuyU3eGI?si=qJN026t6RcGjU3iW
|
new|47|CONVULSION|https://youtu.be/qeRKuyU3eGI?si=qJN026t6RcGjU3iW
|
||||||
new|48|Solar Flare|https://youtu.be/eHQNgty8ypY?si=ZdUIODdeDYLAXeHI
|
new|48|Solar Flare|https://youtu.be/eHQNgty8ypY?si=ZdUIODdeDYLAXeHI
|
||||||
new|49|LIMBO|https://youtu.be/kXYMbaMVOZg?si=fWm4ngeSxBhFZadA
|
new|49|LIMBO|https://youtu.be/kXYMbaMVOZg?si=fWm4ngeSxBhFZadA
|
||||||
new|50|The Catacombs|https://youtu.be/T9-75lfKVQg?si=zEH6vP1617n5666I
|
new|50|The Catacombs|https://youtu.be/T9-75lfKVQg?si=zEH6vP1617n5666I
|
||||||
|
|||||||
@@ -0,0 +1,52 @@
|
|||||||
|
// format: title|levelId|percent
|
||||||
|
// replace "unknown" with the real Geometry Dash level ID when you have it
|
||||||
|
Flamewall|unknown|100
|
||||||
|
Thinking Space II|unknown|100
|
||||||
|
Amethyst|unknown|100
|
||||||
|
Tidal Wave|unknown|100
|
||||||
|
Orbit|unknown|100
|
||||||
|
BOOBAWAMBA|unknown|100
|
||||||
|
Nullscapes|unknown|100
|
||||||
|
Quantuese Processing|unknown|100
|
||||||
|
Subsuming Vortex|unknown|100
|
||||||
|
Andromeda|unknown|100
|
||||||
|
Every End|unknown|100
|
||||||
|
Silent Clubstep|unknown|100
|
||||||
|
Anathema|unknown|100
|
||||||
|
Acheron|unknown|100
|
||||||
|
Ashley Wave Trials|unknown|100
|
||||||
|
Avernus|unknown|100
|
||||||
|
Menace|unknown|100
|
||||||
|
Spectre|unknown|100
|
||||||
|
Abyss Of Darkness|unknown|100
|
||||||
|
Defeated Circles|unknown|100
|
||||||
|
Tunnel Of Despair|unknown|100
|
||||||
|
Subterminal Point|unknown|100
|
||||||
|
KOCMOC|unknown|100
|
||||||
|
Slaughterhouse|unknown|100
|
||||||
|
Kyouki|unknown|100
|
||||||
|
The Lightning Rod|unknown|100
|
||||||
|
Based After Based|unknown|100
|
||||||
|
CHIL|unknown|100
|
||||||
|
Sakupen Circles|unknown|100
|
||||||
|
Deimos (ItsHybrid)|unknown|100
|
||||||
|
Eyes In The Water|unknown|100
|
||||||
|
Voltage|unknown|100
|
||||||
|
Firework|unknown|100
|
||||||
|
Silentlocked|unknown|100
|
||||||
|
poocubed|unknown|100
|
||||||
|
KOSETSU|unknown|100
|
||||||
|
Through The Gates|unknown|100
|
||||||
|
Saul Goodman|unknown|100
|
||||||
|
The Salt Factory|unknown|100
|
||||||
|
Snowbound|unknown|100
|
||||||
|
CONVOLSION|unknown|100
|
||||||
|
The Apocalyptic Trilogy|unknown|100
|
||||||
|
MINUSdry|unknown|100
|
||||||
|
Sevvend Clubstep|unknown|100
|
||||||
|
Edge Of Destiny|unknown|100
|
||||||
|
The Halucination|unknown|100
|
||||||
|
CONVULSION|unknown|100
|
||||||
|
Solar Flare|unknown|100
|
||||||
|
LIMBO|unknown|100
|
||||||
|
The Catacombs|unknown|100
|
||||||
+17
-1
@@ -17,12 +17,26 @@
|
|||||||
</nav>
|
</nav>
|
||||||
</header>
|
</header>
|
||||||
<main>
|
<main>
|
||||||
|
<section class="panel roulette-rules">
|
||||||
|
<p class="roulette-kicker">Rules</p>
|
||||||
|
<h2>How Roulette Works</h2>
|
||||||
|
<ul class="rules-list">
|
||||||
|
<li>Extreme Demon Roulette is a community challenge built around a roulette of hard demons from a chosen list.</li>
|
||||||
|
<li>You can use a main list, extended list, legacy list, or a custom list like this FEDL list.</li>
|
||||||
|
<li>A common format is to start at <strong>1%</strong> and raise the goal by <strong>1%</strong> for each new level until you fail or finish the challenge.</li>
|
||||||
|
<li>Some versions allow skips, rerolls, or custom limits, depending on the rules you want to use.</li>
|
||||||
|
<li>This page shows the demon name, rank, and level ID for the selected result.</li>
|
||||||
|
<li>Percent targets are stored in <code>level-ids.txt</code> using the format <code>title|levelId|percent</code>.</li>
|
||||||
|
<li>If a level ID is missing in that file, this page will try to look it up through the Geometry Dash community API automatically.</li>
|
||||||
|
</ul>
|
||||||
|
</section>
|
||||||
|
|
||||||
<section class="panel roulette-panel">
|
<section class="panel roulette-panel">
|
||||||
<div class="roulette-head">
|
<div class="roulette-head">
|
||||||
<div>
|
<div>
|
||||||
<p class="roulette-kicker">Random Challenge</p>
|
<p class="roulette-kicker">Random Challenge</p>
|
||||||
<h2>Demon Roulette</h2>
|
<h2>Demon Roulette</h2>
|
||||||
<p class="muted">Spin the list and get a random demon from your current FEDL rankings.</p>
|
<p class="muted">Spin the FEDL list to get a random demon for your roulette run.</p>
|
||||||
</div>
|
</div>
|
||||||
<button class="btn roulette-btn" id="roulette-spin" type="button">Spin</button>
|
<button class="btn roulette-btn" id="roulette-spin" type="button">Spin</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -31,6 +45,8 @@
|
|||||||
<p class="roulette-status muted" id="roulette-status">Press spin to choose a demon.</p>
|
<p class="roulette-status muted" id="roulette-status">Press spin to choose a demon.</p>
|
||||||
<h3 id="roulette-title">No demon selected</h3>
|
<h3 id="roulette-title">No demon selected</h3>
|
||||||
<p class="roulette-rank" id="roulette-rank">Rank: -</p>
|
<p class="roulette-rank" id="roulette-rank">Rank: -</p>
|
||||||
|
<p class="roulette-meta" id="roulette-level-id">Level ID: -</p>
|
||||||
|
<p class="roulette-note muted" id="roulette-note">Level IDs come from your local file first, then API lookup if needed.</p>
|
||||||
<a class="btn roulette-open" id="roulette-open" href="#" target="_blank" rel="noopener noreferrer" hidden>Open Video</a>
|
<a class="btn roulette-open" id="roulette-open" href="#" target="_blank" rel="noopener noreferrer" hidden>Open Video</a>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ table.levels-table tr:hover td{background:rgba(255,255,255,0.01)}
|
|||||||
|
|
||||||
/* small helpers reused */
|
/* small helpers reused */
|
||||||
.small{font-size:0.9rem}
|
.small{font-size:0.9rem}
|
||||||
|
.roulette-rules{margin-bottom:18px}
|
||||||
.roulette-panel{margin-top:18px;padding:24px 26px;background:linear-gradient(135deg,rgba(92,197,255,0.12),rgba(7,19,38,0.96));border:1px solid rgba(92,197,255,0.16)}
|
.roulette-panel{margin-top:18px;padding:24px 26px;background:linear-gradient(135deg,rgba(92,197,255,0.12),rgba(7,19,38,0.96));border:1px solid rgba(92,197,255,0.16)}
|
||||||
.roulette-head{display:flex;align-items:flex-end;justify-content:space-between;gap:18px;margin-bottom:18px}
|
.roulette-head{display:flex;align-items:flex-end;justify-content:space-between;gap:18px;margin-bottom:18px}
|
||||||
.roulette-kicker{margin:0 0 8px 0;text-transform:uppercase;letter-spacing:0.14em;font-size:0.72rem;font-weight:700;color:var(--accent)}
|
.roulette-kicker{margin:0 0 8px 0;text-transform:uppercase;letter-spacing:0.14em;font-size:0.72rem;font-weight:700;color:var(--accent)}
|
||||||
@@ -42,6 +43,8 @@ table.levels-table tr:hover td{background:rgba(255,255,255,0.01)}
|
|||||||
.roulette-status{margin:0 0 8px 0}
|
.roulette-status{margin:0 0 8px 0}
|
||||||
.roulette-card h3{margin:0 0 8px 0;font-size:1.5rem}
|
.roulette-card h3{margin:0 0 8px 0;font-size:1.5rem}
|
||||||
.roulette-rank{margin:0 0 16px 0;font-size:1rem;color:#dce8f5}
|
.roulette-rank{margin:0 0 16px 0;font-size:1rem;color:#dce8f5}
|
||||||
|
.roulette-meta{margin:0 0 10px 0;font-size:1rem;color:#dce8f5}
|
||||||
|
.roulette-note{margin:10px 0 16px 0}
|
||||||
.roulette-open{color:#042}
|
.roulette-open{color:#042}
|
||||||
.discord-panel{display:flex;align-items:center;justify-content:space-between;gap:24px;margin-top:18px;padding:26px 28px;background:linear-gradient(135deg,rgba(88,101,242,0.18),rgba(7,19,38,0.95));border:1px solid rgba(88,101,242,0.22)}
|
.discord-panel{display:flex;align-items:center;justify-content:space-between;gap:24px;margin-top:18px;padding:26px 28px;background:linear-gradient(135deg,rgba(88,101,242,0.18),rgba(7,19,38,0.95));border:1px solid rgba(88,101,242,0.22)}
|
||||||
.discord-copy{flex:1}
|
.discord-copy{flex:1}
|
||||||
|
|||||||
Reference in New Issue
Block a user