diff --git a/index.html b/index.html index deaa194..01cc58b 100644 --- a/index.html +++ b/index.html @@ -139,6 +139,8 @@ canvas{display:block;}
Streak0
Acc-
Player-
+ + No gamepad
@@ -1915,18 +1917,73 @@ const SINGALONG_PIECES=(function(){ [3,1,2,1,3,0,3,1,2,0,1,2,1,3,1,2,1,3,0,3,1,2,1,0,2,3,2,0], [1,1,1,1,1,2,1,1,1,2,1,1,2,1,1,1,1,1,2,1,1,1,1,2,1,2,1,4], 5,C4); - // ── Wellerman ── - var wellerman=pub("Wellerman","NZ Sea Shanty (1860s)",125, - [A3,A3,A3,A3,C4,C4,B3,A3,A3,A3,A3,C4,C4,B3,A3,G3, - E4,E4,E4,E4,E4,D4,C4,D4,E4,C4,A3,C4,B3,A3, - C4,C4,C4,C4,D4,E4,E4,D4,C4,D4,E4,C4,A3,C4,B3,A3,G3,A3], - [0,0,0,0,1,1,3,0,0,0,0,1,1,3,0,3, - 2,2,2,2,2,1,0,1,2,0,0,1,3,0, - 1,1,1,1,1,2,2,1,0,1,2,0,0,1,3,0,3,0], - [1,1,1,1,1,1,1,2,1,1,1,1,1,1,2,2, - 1,1,1,1,1,1,1,1,2,1,1,1,1,2, - 1,1,1,1,1,2,1,1,1,1,2,1,1,1,1,2,1,3], - 4,A3); + // ── Wellerman (accurate melody with driving stomp beat) ── + var wellerman=(function(){ + var bg=[],mel=[],t=0,q=0.32; + function vox(t,f,d,v,inst){bg.push({t:t,f:f,d:d,i:inst||'strings',v:v||0.35});} + function stomp(t,v){bg.push({t:t,f:110,d:0.2,i:'timpani',v:v||0.4});} + // Verse melody (Am): "There once was a ship that put to sea..." + var verse1=[E4,E4,E4,E4,A4,A4,G4,E4]; + var verse2=[E4,E4,E4,E4,A4,A4,G4,E4]; + var verse3=[A4,A4,A4,A4,C5,C5,B4,A4]; + var verse4=[E4,E4,G4,G4,E4,D4]; + var vL1=[2,2,2,2,0,0,3,2],vL2=[2,2,2,2,0,0,3,2],vL3=[0,0,0,0,1,1,3,0],vL4=[2,2,3,3,2,1]; + var vD1=[1,1,1,1,1,1,1,2],vD2=[1,1,1,1,1,1,1,2],vD3=[1,1,1,1,1,1,1,2],vD4=[1,1,1,1,1,3]; + // Chorus melody: "Soon may the Wellerman come..." + var ch1=[A4,C5,C5,C5,D5,E5]; + var ch2=[E5,D5,C5,D5,E5,C5]; + var ch3=[A4,C5,C5,C5,D5,E5]; + var ch4=[E5,D5,C5,B4,A4]; + var cL1=[0,1,1,1,1,2],cL2=[2,1,0,1,2,0],cL3=[0,1,1,1,1,2],cL4=[2,1,0,3,0]; + var cD1=[1,1,1,1,1,2],cD2=[1,1,1,1,1,2],cD3=[1,1,1,1,1,2],cD4=[1,1,1,1,4]; + function playLine(notes,lanes,durs,v,inst){ + notes.forEach(function(f,i){ + var d=durs[i]*q; + vox(t,f,d*0.85,v,inst); + if(v>0.3)bg.push({t:t,f:f/2,d:d*0.85,i:'bass',v:v*0.4}); + mel.push({t:t,l:lanes[i]}); + // Driving stomp on every beat + if(durs[i]>=1)stomp(t,v*0.8); + t+=d; + }); + } + // 3 full rounds: verse+chorus, each building + var rounds=[ + {v:0.3,i:'woodwind'},{v:0.4,i:'strings'},{v:0.55,i:'brass'} + ]; + rounds.forEach(function(r,ri){ + // Add chord backing from round 2 + if(ri>0){ + var chordT=t; + [A3,A3,A3,A3,A3,A3,E3,E3].forEach(function(f,ci){ + bg.push({t:chordT+ci*q*4,f:f,d:q*3.5,i:'strings',v:r.v*0.3}); + }); + } + // Add choir from round 3 + if(ri>1){ + var choirNotes=verse1.concat(verse2,verse3,verse4,ch1,ch2,ch3,ch4); + var choirT=t; + var allDurs=vD1.concat(vD2,vD3,vD4,cD1,cD2,cD3,cD4); + choirNotes.forEach(function(f,i){bg.push({t:choirT,f:f,d:allDurs[i]*q*0.8,i:'choir',v:r.v*0.3});choirT+=allDurs[i]*q;}); + } + // Verse + playLine(verse1,vL1,vD1,r.v,r.i); + playLine(verse2,vL2,vD2,r.v,r.i); + playLine(verse3,vL3,vD3,r.v,r.i); + playLine(verse4,vL4,vD4,r.v,r.i); + t+=q*0.5; + // Chorus (bigger) + playLine(ch1,cL1,cD1,r.v*1.2,r.i); + playLine(ch2,cL2,cD2,r.v*1.2,r.i); + playLine(ch3,cL3,cD3,r.v*1.2,r.i); + playLine(ch4,cL4,cD4,r.v*1.2,r.i); + t+=q; + }); + // Finale: big Am chord + [A3,C4,E4,A4].forEach(function(f){bg.push({t:t,f:f,d:2.5,i:'brass',v:0.55});bg.push({t:t,f:f,d:2.5,i:'choir',v:0.4});}); + bg.push({t:t,f:A3/2,d:2.0,i:'timpani',v:0.6});mel.push({t:t,l:4}); + return {n:"Wellerman",composer:"NZ Sea Shanty (1860s)",bpm:125,duration:Math.ceil(t+3),isClassical:true,bg:bg,melody:mel}; + })(); // ── Leave Her Johnny ── var leavejohnny=pub("Leave Her Johnny","Sea Shanty (Trad.)",105, [A3,A3,C4,D4,E4,E4,D4,C4,A3,G3,A3,C4,D4,E4,G4,E4,D4,C4,A3,G3,A3,C4,E4,D4,C4,A3], @@ -2197,15 +2254,17 @@ function buildPadToggles(){ } buildPadToggles(); function saveSettings(){localStorage.setItem("drgameSettings",JSON.stringify({speed:gameSpeed,volume:masterVolume}));} -function setSpeed(v){gameSpeed=v/100;document.getElementById("speed-val").textContent=v+"%";saveSettings();} -function setVolume(v){masterVolume=v/100;document.getElementById("vol-val").textContent=v+"%";saveSettings();} -function resetSettings(){gameSpeed=1.0;masterVolume=1.0;document.getElementById("speed-slider").value=100;document.getElementById("vol-slider").value=100;document.getElementById("speed-val").textContent="100%";document.getElementById("vol-val").textContent="100%";saveSettings();} -function loadSettings(){ - document.getElementById("speed-slider").value=Math.round(gameSpeed*100); - document.getElementById("speed-val").textContent=Math.round(gameSpeed*100)+"%"; - document.getElementById("vol-slider").value=Math.round(masterVolume*100); - document.getElementById("vol-val").textContent=Math.round(masterVolume*100)+"%"; +function syncSliders(){ + var sv=Math.round(gameSpeed*100),vv=Math.round(masterVolume*100); + ['speed-slider','hud-speed'].forEach(function(id){var e=document.getElementById(id);if(e)e.value=sv;}); + ['vol-slider','hud-vol'].forEach(function(id){var e=document.getElementById(id);if(e)e.value=vv;}); + var se=document.getElementById("speed-val");if(se)se.textContent=sv+"%"; + var ve=document.getElementById("vol-val");if(ve)ve.textContent=vv+"%"; } +function setSpeed(v){gameSpeed=v/100;syncSliders();saveSettings();} +function setVolume(v){masterVolume=v/100;syncSliders();saveSettings();} +function resetSettings(){gameSpeed=1.0;masterVolume=1.0;syncSliders();saveSettings();} +function loadSettings(){syncSliders();} function confirmReset(){ var a=Math.floor(Math.random()*20)+5,b=Math.floor(Math.random()*20)+5; var ans=prompt("To reset ALL saved data (scores, settings, gamepad mapping, hidden genres), solve this:\n\nWhat is "+a+" + "+b+"?"); @@ -2688,10 +2747,13 @@ function showRemapStep(){ document.getElementById("remap-prompt").innerHTML="Hit your "+rl.name+" pad"; document.getElementById("remap-status").textContent="Step "+(remapStep+1)+" of "+remapLanes.length+(remapStep===4?" (or press foot pedal)":""); } +var remapCooldown=false; function handleRemapButton(bi){ - if(!remapping)return false; + if(!remapping||remapCooldown)return false; remapResult[bi]=remapLanes[remapStep].l; remapStep++; + remapCooldown=true; + setTimeout(function(){remapCooldown=false;},300); showRemapStep(); return true; } @@ -2709,9 +2771,12 @@ function pollGP(){ for(const gp of gps){ if(!gp)continue;found=true; document.getElementById("gpd").textContent="🎮 "+gp.id.slice(0,20); + var remapHandled=false; gp.buttons.forEach((btn,bi)=>{ if(btn.pressed&&!prevBtns[bi]){ - if(remapping){handleRemapButton(bi);} + if(remapping){ + if(!remapHandled){remapHandled=true;handleRemapButton(bi);} + } else if(!paused&&gpMap[bi]!==undefined)triggerPad(gpMap[bi]); } prevBtns[bi]=btn.pressed;