diff --git a/index.html b/index.html
index e9e175f..4f176a2 100644
--- a/index.html
+++ b/index.html
@@ -193,10 +193,13 @@ const LANES=[
{label:"Blue", color:"#3182ce",key:"h", type:"hihat"},
{label:"Green", color:"#38a169",key:"j", type:"tom2"},
{label:"Kick", color:"#805ad5",key:" ", type:"kick"},
+ {label:"Crash", color:"#ed8936",key:"d", type:"crash"},
+ {label:"Ride", color:"#4fd1c5",key:"k", type:"ride"},
+ {label:"Tom 3", color:"#d53f8c",key:"l", type:"tom3"},
];
// which pads are active (show notes) — all on by default
-let activePads=[true,true,true,true,true];
+let activePads=[true,true,true,true,true,false,false,false];
// Simple mode — thins out notes, keeping only strong beats
let simpleMode=false;
@@ -4289,9 +4292,9 @@ let gameAc=null,mp3Buffer=null,mp3Src=null;
let notes=[],gameStartTime=null,gameEndTime=null,playing=false;
let gamePlayers=[],activePIdx=0;
let cScore=0,cStreak=0,cTotal=0,cGood=0,cMaxStreak=0;
-let laneFlash=[0,0,0,0,0],msgTmr=null,prevBtns={},gameSynthNodes=[],classicalHitMode='orchestra';
+let laneFlash=[0,0,0,0,0,0,0,0],msgTmr=null,prevBtns={},gameSynthNodes=[],classicalHitMode='orchestra';
let paused=false,pauseTime=0;
-var gpMap=JSON.parse(localStorage.getItem("drgameGpMap")||"null")||{0:2,1:3,2:0,3:1,4:4,8:4};
+var gpMap=JSON.parse(localStorage.getItem("drgameGpMap")||"null")||{0:2,1:3,2:0,3:1,4:4,5:5,6:6,7:7,8:4};
var remapping=false,remapStep=0,remapResult={};
var _savedSettings=JSON.parse(localStorage.getItem("drgameSettings")||"{}");
var gameSpeed=_savedSettings.speed||1.0,masterVolume=_savedSettings.volume||1.0;
@@ -4324,7 +4327,7 @@ function buildPadToggles(){
const b=document.createElement("button");
b.className="ptog"+(activePads[i]?" on":"");
b.style.borderColor=lane.color;b.style.color=lane.color;
- b.textContent=lane.label+(i===4?" (Kick)":"");
+ b.textContent=lane.label;
b.onclick=()=>{activePads[i]=!activePads[i];buildPadToggles();};
el.appendChild(b);
});
@@ -4645,34 +4648,35 @@ function draw(){
if(!W||!H)return;
cx.clearRect(0,0,W,H);
- // Active pad lanes (only those toggled on, excluding kick)
- const activeLanes=LANES.slice(0,4).map((l,i)=>i).filter(i=>activePads[i]);
+ // Pad lanes (everything except kick) in columns; kick centered at bottom
+ const padLanes=LANES.map((l,i)=>i).filter(i=>i!==4&&activePads[i]);
const hasKick=activePads[4];
const PAD_H=hasKick?Math.floor(H*0.78):H;
const KICK_H=H-PAD_H;
- const nLanes=activeLanes.length;
- const PAD_W=nLanes>0?W/nLanes:W;
+ const nLanes=padLanes.length;
+ const LANE_W=nLanes>0?W/nLanes:W;
const HIT_Y=Math.floor(PAD_H*0.76);
const KICK_HIT_Y=PAD_H+Math.floor(KICK_H*0.55);
const now=(playing&&gameStartTime!=null)?getAc().currentTime-gameStartTime:-9999;
// Lane positions map: lane index -> x center
const laneX={};
- activeLanes.forEach((li,col)=>{laneX[li]=col*PAD_W+PAD_W/2;});
+ padLanes.forEach((li,col)=>{laneX[li]=col*LANE_W+LANE_W/2;});
// Draw pad lanes
- activeLanes.forEach((li,col)=>{
- const x=col*PAD_W;
+ padLanes.forEach((li,col)=>{
+ const x=col*LANE_W;
cx.fillStyle=laneFlash[li]?LANES[li].color+"33":"#0d0d16";
- cx.fillRect(x,0,PAD_W,PAD_H);
+ cx.fillRect(x,0,LANE_W,PAD_H);
if(col>0){cx.strokeStyle="#1e1e2e";cx.lineWidth=1;cx.beginPath();cx.moveTo(x,0);cx.lineTo(x,PAD_H);cx.stroke();}
cx.fillStyle=LANES[li].color;cx.font="bold 12px sans-serif";cx.textAlign="center";
- cx.fillText(LANES[li].label,x+PAD_W/2,PAD_H-20);
+ cx.fillText(LANES[li].label,x+LANE_W/2,PAD_H-20);
cx.fillStyle="#999";cx.font="10px sans-serif";
- cx.fillText(LANES[li].key.toUpperCase(),x+PAD_W/2,PAD_H-7);
+ var keyLabel=LANES[li].key===" "?"SPACE":LANES[li].key.toUpperCase();
+ cx.fillText(keyLabel,x+LANE_W/2,PAD_H-7);
});
- // Kick zone
+ // Kick zone — centered at bottom, notes fall from top of screen
if(hasKick){
cx.fillStyle=laneFlash[4]?LANES[4].color+"33":"#0a0a12";
cx.fillRect(0,PAD_H,W,KICK_H);
@@ -4685,7 +4689,7 @@ function draw(){
if(nLanes===0&&!hasKick)return;
- // Hit line
+ // Pad hit line
if(nLanes>0){
cx.strokeStyle="rgba(255,255,255,0.5)";cx.lineWidth=2;
cx.beginPath();cx.moveTo(0,HIT_Y);cx.lineTo(W,HIT_Y);cx.stroke();
@@ -4699,9 +4703,9 @@ function draw(){
cx.beginPath();cx.moveTo(W*0.15,KICK_HIT_Y);cx.lineTo(W*0.85,KICK_HIT_Y);cx.stroke();
}
- // Target rings — pads
- activeLanes.forEach(li=>{
- const x=laneX[li],r=Math.min(PAD_W*0.33,26);
+ // Target rings — pad lanes
+ padLanes.forEach(li=>{
+ const x=laneX[li],r=Math.min(LANE_W*0.33,26);
cx.beginPath();cx.arc(x,HIT_Y,r,0,Math.PI*2);
cx.strokeStyle=laneFlash[li]?LANES[li].color:LANES[li].color+"55";
cx.lineWidth=laneFlash[li]?3:2;cx.stroke();
@@ -4721,30 +4725,16 @@ function draw(){
if(notes.length===0||notes.every(n=>n.hit||n.missed))endTurn();
}
- // Notes
+ // Notes — pad lanes fall in columns, kick falls centered from top
if(mode==="builtin"&&now>-9000){
for(const n of notes){
if(n.hit)continue;
const dt=n.time-now;
- if(n.lane<4){
- if(!laneX.hasOwnProperty(n.lane))continue;
- const ny=HIT_Y-dt*SPEED;
- if(ny<-40||ny>PAD_H+40){
- if(!n.missed&&dt<-HIT_WIN){n.missed=true;if(cStreak>0){cStreak=0;updateHud();}}
- continue;
- }
- const x=laneX[n.lane],r=Math.min(PAD_W*0.33,26);
- cx.globalAlpha=n.missed?0.2:1;
- const g=cx.createRadialGradient(x,ny,0,x,ny,r*2);
- g.addColorStop(0,LANES[n.lane].color+"aa");g.addColorStop(1,LANES[n.lane].color+"00");
- cx.fillStyle=g;cx.beginPath();cx.arc(x,ny,r*2,0,Math.PI*2);cx.fill();
- cx.fillStyle=LANES[n.lane].color;cx.beginPath();cx.arc(x,ny,r,0,Math.PI*2);cx.fill();
- cx.strokeStyle="#fff";cx.lineWidth=2;cx.beginPath();cx.arc(x,ny,r,0,Math.PI*2);cx.stroke();
- cx.globalAlpha=1;
- if(!n.missed&&dt<-HIT_WIN){n.missed=true;if(cStreak>0){cStreak=0;updateHud();}}
- } else if(hasKick){
- const ky=KICK_HIT_Y-dt*SPEED*0.5;
- if(kyH+30){
+ if(n.lane===4){
+ // Kick — falls from top of screen, centered, landing on KICK_HIT_Y
+ if(!hasKick)continue;
+ const ky=KICK_HIT_Y-dt*SPEED;
+ if(ky<-40||ky>H+40){
if(!n.missed&&dt<-HIT_WIN){n.missed=true;if(cStreak>0){cStreak=0;updateHud();}}
continue;
}
@@ -4754,6 +4744,23 @@ function draw(){
cx.strokeStyle="#fff";cx.lineWidth=2;cx.beginPath();cx.arc(W/2,ky,kr,0,Math.PI*2);cx.stroke();
cx.globalAlpha=1;
if(!n.missed&&dt<-HIT_WIN){n.missed=true;if(cStreak>0){cStreak=0;updateHud();}}
+ } else {
+ // Pad lanes — fall in columns
+ if(!laneX.hasOwnProperty(n.lane))continue;
+ const ny=HIT_Y-dt*SPEED;
+ if(ny<-40||ny>PAD_H+40){
+ if(!n.missed&&dt<-HIT_WIN){n.missed=true;if(cStreak>0){cStreak=0;updateHud();}}
+ continue;
+ }
+ const x=laneX[n.lane],r=Math.min(LANE_W*0.33,26);
+ cx.globalAlpha=n.missed?0.2:1;
+ const g=cx.createRadialGradient(x,ny,0,x,ny,r*2);
+ g.addColorStop(0,LANES[n.lane].color+"aa");g.addColorStop(1,LANES[n.lane].color+"00");
+ cx.fillStyle=g;cx.beginPath();cx.arc(x,ny,r*2,0,Math.PI*2);cx.fill();
+ cx.fillStyle=LANES[n.lane].color;cx.beginPath();cx.arc(x,ny,r,0,Math.PI*2);cx.fill();
+ cx.strokeStyle="#fff";cx.lineWidth=2;cx.beginPath();cx.arc(x,ny,r,0,Math.PI*2);cx.stroke();
+ cx.globalAlpha=1;
+ if(!n.missed&&dt<-HIT_WIN){n.missed=true;if(cStreak>0){cStreak=0;updateHud();}}
}
}
}
@@ -4789,8 +4796,29 @@ function playDrumAt(ac,lane,t,vol,arr){
f.type="highpass";f.frequency.value=7000;s.buffer=buf;s.connect(f);f.connect(g);g.connect(ac.destination);
g.gain.setValueAtTime(vol*.5,t);g.gain.exponentialRampToValueAtTime(0.001,t+0.05);
s.start(t);s.stop(t+0.06);mk(s);
- } else { // tom / tom2
- const freq=type==="tom"?160:120;
+ } else if(type==="crash"){
+ // Crash cymbal — long noise burst with resonance
+ const sz=ac.sampleRate*0.4,buf=ac.createBuffer(1,sz,ac.sampleRate),d=buf.getChannelData(0);
+ for(let i=0;i