let trail = [];
let velocities = [];
let particles = [];
let flashAlpha = 0;
let score = 0;
let bgBlue = 0;


let beachImg;
let moanaFont;
let beachSound, sliceSound;

let charFrames = [];
let slotChars = new Array(10).fill(-1);
let slotOffsets = new Array(10).fill(0);
const ANI_FPS = 18;

const CHAR_SCALES = [0.9, 1.5, 1.2, 1.5, 1.5, 1.5, 1.5];

let charOrder = [];
let charOrderIdx = 0;

// ====== GAME STATE ======
let gameState = 'name'; // 'name' | 'intro' | 'playing' | 'departure'
let playerName = '';
let nameInput, nameConfirmBtn;
const COCONUT_TIME_MS = 5000;
let coconutTimerEnd = 0;   // millis() when current coconut expires
let slotPowers = [];       // 0–100, speed bonus per slot

let coconut = {
  x: 0, y: 0,
  r: 0,
  state: 0,
  slices: 0,
  shakeX: 0, shakeY: 0,
  shakeTimer: 0,
  baseAngle: 0,
  flying: false,
  flyVX: 0, flyVY: 0,
  flyAlpha: 255,
  flyRotation: 0, flyRotSpeed: 0,
  entering: false,
  enterT: 0,
  enterFromX: 0, enterFromY: 0
};

let coconutImgs = [];
let flyingKakamoraList = [];
let knifeImg;
let effectImgs = [];
let imgParticles = [];
let slashLingerAlpha = 0;
let lingerTrail = [];
let lingerVelocities = [];

// ====== PRELOAD ======
function preload() {
  for (let i = 0; i < 5; i++) {
    coconutImgs[i] = loadImage(`assets/coconut/coconut_${i}.png`);
  }

  // char1
  charFrames[0] = [];
  for (let i = 1; i <= 5; i++) charFrames[0].push(loadImage(`assets/kakamora-characters/char1/co_ani_${i}.png`));
  // char2–7: Frame N.png
  const charRanges = [[6,10],[11,15],[16,21],[22,26],[27,31],[32,36]];
  for (let c = 0; c < charRanges.length; c++) {
    let [start, end] = charRanges[c];
    charFrames[c + 1] = [];
    for (let n = start; n <= end; n++) charFrames[c + 1].push(loadImage(`assets/kakamora-characters/char${c + 2}/Frame ${n}.png`));
  }

  beachImg  = loadImage('assets/beach.png');
  moanaFont = loadFont('assets/fonts/Moanas.ttf');
  knifeImg  = loadImage('assets/knife.png');
  for (let i = 0; i < 3; i++) effectImgs.push(loadImage(`assets/effect/particles${i}.png`));

}

// ====== SETUP ======
function setup() {
  createCanvas(windowWidth, windowHeight);
  resetCoconutHome();

  world.gravity.y = 0;
  shuffleCharOrder();

  beachSound = new Howl({
    src: ['assets/sound/beach%20sound.wav'],
    loop: true,
    volume: 0.45,
    fade: true
  });
  sliceSound = new Howl({
    src: ['assets/sound/slice.wav'],
    volume: 0.75
  });

  // HTML name input
  nameInput = createInput('');
  nameInput.attribute('placeholder', 'Enter your name...');
  nameInput.attribute('maxlength', '16');
  nameInput.style('font-size', '18px');
  nameInput.style('font-family', 'Google Sans, Nunito, sans-serif');
  nameInput.style('background', 'rgba(14, 20, 36, 0.92)');
  nameInput.style('color', '#e8f4ff');
  nameInput.style('border', '2px solid rgba(90, 185, 255, 0.55)');
  nameInput.style('border-radius', '2px');
  nameInput.style('padding', '10px 16px');
  nameInput.style('width', '260px');
  nameInput.style('outline', 'none');
  nameInput.style('letter-spacing', '1px');
  nameInput.style('position', 'absolute');
  nameInput.elt.addEventListener('keydown', e => { if (e.key === 'Enter') confirmName(); });

  nameConfirmBtn = createButton('CONFIRM');
  nameConfirmBtn.style('font-size', '16px');
  nameConfirmBtn.style('font-family', 'Google Sans, Nunito, sans-serif');
  nameConfirmBtn.style('font-weight', '700');
  nameConfirmBtn.style('letter-spacing', '2px');
  nameConfirmBtn.style('background', 'rgba(18, 80, 150, 0.95)');
  nameConfirmBtn.style('color', '#cce8ff');
  nameConfirmBtn.style('border', '2px solid rgba(90, 185, 255, 0.7)');
  nameConfirmBtn.style('border-radius', '2px');
  nameConfirmBtn.style('padding', '10px 36px');
  nameConfirmBtn.style('cursor', 'pointer');
  nameConfirmBtn.style('position', 'absolute');
  nameConfirmBtn.mousePressed(confirmName);

  positionNameUI();
}

function positionNameUI() {
  let pw = min(windowWidth * 0.5, 440);
  let ph = 240;
  let px = (windowWidth - pw) / 2;
  let py = (windowHeight - ph) / 2;
  let inputW = pw * 0.65;
  let inputX = px + (pw - inputW) / 2;
  nameInput.position(inputX, py + 104);
  nameInput.style('width', inputW + 'px');
  nameConfirmBtn.position(px + pw / 2 - 80, py + 164);
}

function shuffleCharOrder() {
  charOrder = [0, 1, 2, 3, 4, 5, 6];
  for (let i = charOrder.length - 1; i > 0; i--) {
    let j = floor(random(i + 1));
    [charOrder[i], charOrder[j]] = [charOrder[j], charOrder[i]];
  }
  charOrderIdx = 0;
}

function windowResized() {
  resizeCanvas(windowWidth, windowHeight);
  resetCoconutHome();
  if (gameState === 'name') positionNameUI();
}


function resetCoconutHome() {
  coconut.r = min(windowWidth, windowHeight) * 0.13;
  coconut.x = width / 2;
  coconut.y = height * 0.42;
}

// ====== DRAW ======
function draw() {
  imageMode(CORNER);
  image(beachImg, 0, 0, width, height);
  if (bgBlue > 0) {
    fill(25, 90, 200, bgBlue * 0.4);
    noStroke();
    rect(0, 0, width, height);
    bgBlue = max(0, bgBlue - 4);
  }

  if (gameState === 'name') { drawNameEntry(); return; }

  if (gameState === 'playing') {
    checkCoconutTimer();
    updateShake();
    updateEnter();
    updateFlyAway();
    drawCoconut();
    drawCoconutTimer();
    drawTrail();
    updateImgParticles();
    drawImgParticles();
  }

  drawParticles();
  drawFlash();
  if (gameState !== 'intro' && gameState !== 'name') {
    drawKakamoraSlots();
    updateFlyingKakamoraList();
    drawFlyingKakamoraList();
  }

  if (gameState === 'intro')     drawIntroQuest();
  if (gameState === 'departure') drawDepartureQuest();
}


// ====== COCONUT ======
function drawCoconut() {
  imageMode(CENTER);
  if (coconut.flying) {
    push();
    translate(coconut.x, coconut.y);
    rotate(coconut.flyRotation);
    tint(255, coconut.flyAlpha);
    image(coconutImgs[coconut.state], 0, 0, coconut.r * 2, coconut.r * 2);
    noTint();
    pop();
  } else {
    let alpha = coconut.entering ? lerp(40, 255, min(coconut.enterT * 1.8, 1)) : 255;
    tint(255, alpha);
    push();
    translate(coconut.x + coconut.shakeX, coconut.y + coconut.shakeY);
    rotate(coconut.baseAngle);
    imageMode(CENTER);
    image(coconutImgs[coconut.state], 0, 0, coconut.r * 2, coconut.r * 2);
    pop();
    noTint();
  }
}

function updateEnter() {
  if (!coconut.entering) return;
  coconut.enterT += 0.038;
  let ease = 1 - pow(1 - min(coconut.enterT, 1), 3);
  coconut.x = lerp(coconut.enterFromX, width / 2, ease);
  coconut.y = lerp(coconut.enterFromY, height * 0.42, ease);
  if (coconut.enterT >= 1) {
    coconut.entering = false;
    coconut.x = width / 2;
    coconut.y = height * 0.42;
  }
}

function startCoconutEntrance() {
  coconut.entering = true;
  coconut.enterT = 0;
  coconut.enterFromX = width - 100;
  coconut.enterFromY = 100;
  coconut.x = width - 100;
  coconut.y = 100;
  coconut.baseAngle = random(TWO_PI);
}

function updateShake() {
  if (coconut.shakeTimer > 0) {
    coconut.shakeX = sin(coconut.shakeTimer * 2.4) * coconut.shakeTimer * 0.7;
    coconut.shakeY = cos(coconut.shakeTimer * 3.1) * coconut.shakeTimer * 0.4;
    coconut.shakeTimer--;
  } else {
    coconut.shakeX = 0;
    coconut.shakeY = 0;
  }
}

function updateFlyAway() {
  if (!coconut.flying) return;

  coconut.x += coconut.flyVX;
  coconut.y += coconut.flyVY;
  coconut.flyVY += 0.55;
  coconut.flyRotation += coconut.flyRotSpeed;
  coconut.flyAlpha -= 7;

  if (coconut.flyAlpha <= 0 || coconut.y > height + 100) {
    if (score < 10) launchKakamoraToSlot(score);
    score++;
    coconut.state = 0;
    coconut.slices = 0;
    coconut.flying = false;
    coconut.flyAlpha = 255;
    coconut.flyRotation = 0;
    coconut.shakeX = 0;
    coconut.shakeY = 0;
    coconut.shakeTimer = 0;
    coconutTimerEnd = millis() + COCONUT_TIME_MS;

    if (score >= 7 && gameState === 'playing') {
      gameState = 'departure';
    } else {
      startCoconutEntrance();
    }
  }
}

// ====== TRAIL INPUT ======
function mouseDragged() {
  if (gameState !== 'playing') return;
  let pos = createVector(mouseX, mouseY);
  trail.push(pos);

  let dx = 0, dy = 0;
  if (trail.length > 1) {
    let prev = trail[trail.length - 2];
    dx = pos.x - prev.x;
    dy = pos.y - prev.y;
    velocities.push(sqrt(dx * dx + dy * dy));
  } else {
    velocities.push(0);
  }

  if (dist(mouseX, mouseY, coconut.x, coconut.y) < coconut.r && !coconut.flying) {
    spawnParticles(mouseX, mouseY);
    spawnImgParticles(mouseX, mouseY, dx, dy);
    coconut.shakeTimer = max(coconut.shakeTimer, 18);
  }

  if (trail.length > 22) trail.shift();
  if (velocities.length > 22) velocities.shift();
}

function mouseReleased() {
  if (gameState !== 'playing') { trail = []; velocities = []; return; }

  let hits = trail.filter(p => dist(p.x, p.y, coconut.x, coconut.y) < coconut.r).length;

  if (hits >= 2 && !coconut.flying) {
    sliceSound.play();
    coconut.slices++;
    coconut.state = floor(coconut.slices / 2);
    flashAlpha = 25;
    if (coconut.slices >= 8) {
      let power = floor(max(0, (coconutTimerEnd - millis()) / COCONUT_TIME_MS) * 100);
      slotPowers[score] = power;
      coconut.flying = true;
      coconut.flyVX = random([-1, 1]) * random(3, 6);
      coconut.flyVY = random(-6, -2);
      coconut.flyRotSpeed = random() > 0.5 ? random(0.07, 0.13) : random(-0.13, -0.07);
      bgBlue = 255;
    }
  }

  // linger the slash line briefly
  lingerTrail = trail.slice();
  lingerVelocities = velocities.slice();
  slashLingerAlpha = 255;
  trail = [];
  velocities = [];
}

// ====== TRAIL DRAW ======
function drawSlashSegments(pts, vels, masterAlpha) {
  if (pts.length < 2) return;
  noFill();
  for (let i = 1; i < pts.length; i++) {
    let t = i / pts.length; // 0=tail, 1=head
    let speed = vels[i] || 0;
    let a = t * masterAlpha;

    // Outer glow
    strokeWeight(map(speed, 0, 40, 6, 22));
    stroke(255, 240, 180, a * 0.18);
    line(pts[i-1].x, pts[i-1].y, pts[i].x, pts[i].y);

    // Mid glow
    strokeWeight(map(speed, 0, 40, 3, 12));
    stroke(255, 255, 220, a * 0.45);
    line(pts[i-1].x, pts[i-1].y, pts[i].x, pts[i].y);

    // Sharp core
    strokeWeight(map(speed, 0, 40, 1, 4));
    stroke(255, 255, 255, a);
    line(pts[i-1].x, pts[i-1].y, pts[i].x, pts[i].y);
  }
  noStroke();
}

function drawTrail() {
  drawSlashSegments(trail, velocities, 255);

  // Linger fade after release
  if (slashLingerAlpha > 0) {
    drawSlashSegments(lingerTrail, lingerVelocities, slashLingerAlpha);
    slashLingerAlpha -= 28;
    if (slashLingerAlpha <= 0) { lingerTrail = []; lingerVelocities = []; }
  }
}



// ====== SLOT LAYOUT (horizontal top-left) ======
const S_MARGIN = 14;
const S_HDRH   = 30;
const S_PAD    = 12;
const S_GAP    = 10;

function getSlotSize() {
  // fit 7 slots between left margin and timer area (right ~220px)
  let available = width - S_MARGIN * 2 - S_PAD * 2 - 6 * S_GAP - 220;
  return constrain(floor(available / 7), 60, 92);
}

function getSlotPos(i) {
  let sz = getSlotSize();
  return {
    x: S_MARGIN + S_PAD + sz / 2 + i * (sz + S_GAP),
    y: S_MARGIN + S_HDRH + S_PAD + sz / 2,
    size: sz
  };
}

// ====== KAKAMORA SLOTS ======
function drawKakamoraSlots() {
  let sz     = getSlotSize();
  let panelW = S_PAD * 2 + 7 * sz + 6 * S_GAP;
  let pwrH   = 20;
  let panelH = S_HDRH + S_PAD + sz + pwrH + S_PAD;
  let px     = S_MARGIN;
  let py     = S_MARGIN;

  // Panel background
  fill(12, 16, 26, 210);
  noStroke();
  rect(px, py, panelW, panelH, 2);

  // Header bar
  fill(35, 42, 60, 255);
  noStroke();
  rect(px, py, panelW, S_HDRH, 2, 2, 0, 0);
  fill(255, 195, 55);
  textAlign(LEFT, CENTER);
  textFont(moanaFont);
  textSize(13);
  text('WARRIOR CREW', px + S_PAD, py + S_HDRH / 2);
  // score counter right side
  textAlign(RIGHT, CENTER);
  fill(200, 210, 230);
  textSize(12);
  text(`${score} / 7`, px + panelW - S_PAD, py + S_HDRH / 2);
  textFont('sans-serif');

  for (let i = 0; i < 7; i++) {
    let { x, y, size } = getSlotPos(i);
    let filled = i < score;

    if (filled && slotChars[i] >= 0) {
      let frames = charFrames[slotChars[i]];
      let frameIdx = floor((frameCount + slotOffsets[i]) / ANI_FPS) % frames.length;
      let img = frames[frameIdx];
      let sc = min(size / img.width, size / img.height) * CHAR_SCALES[slotChars[i]];
      drawingContext.save();
      drawingContext.beginPath();
      drawingContext.arc(x, y, size / 2, 0, Math.PI * 2);
      drawingContext.clip();
      imageMode(CENTER);
      image(img, x, y, img.width * sc, img.height * sc);
      drawingContext.restore();

      // Power display — threshold at 55: pwr >= 55 = full green
      let pwr = slotPowers[i] !== undefined ? slotPowers[i] : 0;
      let pwrT = min(pwr / 55, 1);
      let pwrCol = lerpColor(color(220, 50, 50), color(50, 215, 85), pwrT);

      // Glow ring (outer) — pulses slightly based on power
      noFill();
      strokeWeight(7);
      stroke(red(pwrCol), green(pwrCol), blue(pwrCol), 55 + pwrT * 50);
      ellipse(x, y, size + 11, size + 11);
      // Sharp ring (inner)
      strokeWeight(2.5);
      stroke(pwrCol);
      ellipse(x, y, size + 2, size + 2);
      noStroke();

      // Power badge below circle
      let pillW = floor(size * 0.86);
      let pillH = 23;
      let pillX = x - pillW / 2;
      let pillY = y + size / 2 + 6;
      // shadow
      fill(0, 0, 0, 150);
      rect(pillX + 1, pillY + 1, pillW, pillH, 12);
      // dark background
      fill(8, 10, 20, 240);
      rect(pillX, pillY, pillW, pillH, 12);
      // progress fill — bar shows true pwr/100, color uses lowered threshold
      fill(red(pwrCol), green(pwrCol), blue(pwrCol), 210);
      let barW = max(0, (pillW - 4) * (pwr / 100));
      if (barW > 0) rect(pillX + 2, pillY + 2, barW, pillH - 4, 10);
      // label: "PWR XX"
      fill(255, 255, 255, 245);
      textAlign(CENTER, CENTER);
      textFont('Google Sans, Nunito, sans-serif');
      textStyle(BOLD);
      textSize(12);
      text(`PWR ${pwr}`, x, pillY + pillH / 2);
      textStyle(NORMAL);
      textFont('sans-serif');
    } else {
      fill(22, 28, 42);
      noStroke();
      ellipse(x, y, size, size);
      stroke(50, 58, 78);
      strokeWeight(1.5);
      noFill();
      ellipse(x, y, size, size);
      fill(55, 65, 88);
      noStroke();
      textAlign(CENTER, CENTER);
      textSize(13);
      text(i + 1, x, y);
    }
  }
}

// ====== FLYING KAKAMORA ======
function launchKakamoraToSlot(slotIdx) {
  let { x: tx, y: ty, size } = getSlotPos(slotIdx);
  let charIdx = charOrder[charOrderIdx % 7];
  charOrderIdx++;
  slotChars[slotIdx] = charIdx;
  slotOffsets[slotIdx] = floor(random(1000));
  flyingKakamoraList.push({
    startX: width / 2,
    startY: height * 0.42,
    targetX: tx,
    targetY: ty,
    t: 0,
    charIdx,
    questShown: false,
    size
  });
}

function updateFlyingKakamoraList() {
  for (let k of flyingKakamoraList) k.t += 0.032;
  flyingKakamoraList = flyingKakamoraList.filter(k => k.t <= 1);
}

function drawFlyingKakamoraList() {
  for (let k of flyingKakamoraList) {
    let ease = 1 - pow(1 - min(k.t, 1), 2);
    let x = lerp(k.startX, k.targetX, ease);
    let y = lerp(k.startY, k.targetY, ease) - sin(k.t * PI) * height * 0.3;
    let sz = lerp(k.size * 1.8, k.size, ease);

    let frames = charFrames[k.charIdx];
    let frameIdx = floor(frameCount / ANI_FPS) % frames.length;
    let img = frames[frameIdx];
    let sc = min(sz / img.width, sz / img.height) * CHAR_SCALES[k.charIdx];
    drawingContext.save();
    drawingContext.beginPath();
    drawingContext.arc(x, y, sz / 2, 0, Math.PI * 2);
    drawingContext.clip();
    imageMode(CENTER);
    image(img, x, y, img.width * sc, img.height * sc);
    drawingContext.restore();
  }
}

// ====== PARTICLES ======
class Particle {
  constructor(x, y) {
    this.pos = createVector(x, y);
    // 전방향 랜덤 퍼짐 (드래그 방향 편향 없이 360도)
    let baseAngle = random(TWO_PI);
    let spd = random(2, 6);
    this.vel = createVector(cos(baseAngle) * spd, sin(baseAngle) * spd);
    this.life = 255;
    this.r = random(1.5, 3.5);
    this.isHusk = random() > 0.4;
  }

  update() {
    this.pos.add(this.vel);
    this.vel.y += 0.22;
    this.vel.mult(0.91);
    this.life -= 9;
  }

  draw() {
    noStroke();
    if (this.isHusk) fill(158, 108, 52, this.life);
    else fill(242, 224, 188, this.life);
    ellipse(this.pos.x, this.pos.y, this.r, this.r * 0.55);
  }
}

function spawnParticles(x, y) {
  for (let i = 0; i < 12; i++) particles.push(new Particle(x, y));
}

function drawParticles() {
  for (let i = particles.length - 1; i >= 0; i--) {
    particles[i].update();
    particles[i].draw();
    if (particles[i].life <= 0) particles.splice(i, 1);
  }
}

// ====== FLASH ======
function drawFlash() {
  if (flashAlpha > 0) {
    fill(255, flashAlpha);
    rect(0, 0, width, height);
    flashAlpha -= 20;
  }
}

// ====== COCONUT TIMER ======
function checkCoconutTimer() {
  if (coconut.flying || coconutTimerEnd === 0) return;
  if (millis() > coconutTimerEnd) {
    coconut.state = 0;
    coconut.slices = 0;
    coconutTimerEnd = millis() + COCONUT_TIME_MS;
  }
}

function drawCoconutTimer() {
  if (coconut.flying || coconutTimerEnd === 0) return;
  let fraction = max(0, (coconutTimerEnd - millis()) / COCONUT_TIME_MS);
  let secs = (fraction * (COCONUT_TIME_MS / 1000)).toFixed(1);
  let c = lerpColor(color(255, 60, 60), color(80, 220, 100), fraction);

  // Top-right pill
  let tx = width - 18;
  let ty = 18;
  let label = `TIME  ${secs}s`;
  textFont('Google Sans, Nunito, sans-serif');
  textSize(26);
  let tw = textWidth(label) + 36;
  let th = 54;

  fill(12, 16, 26, 220);
  noStroke();
  rect(tx - tw, ty, tw, th, 2);

  // Progress bar
  fill(30, 37, 54);
  rect(tx - tw + 8, ty + th - 12, tw - 16, 6, 2);
  fill(c);
  rect(tx - tw + 8, ty + th - 12, (tw - 16) * fraction, 6, 2);

  fill(c);
  textAlign(RIGHT, TOP);
  text(label, tx - 10, ty + 10);
  textFont('sans-serif');

}

// ====== SHARED DIALOG HELPER ======
function drawDialogBox(dx, dy, dw, dh, speakerName, lines, btnLabel) {
  fill(0, 0, 0, 90);
  noStroke();
  rect(0, 0, width, height);

  fill(28, 32, 45, 185);
  noStroke();
  rect(dx, dy, dw, dh, 2);

  // Name banner — sharp corners
  textFont(moanaFont);
  textSize(20);
  let bw = textWidth(speakerName) + 44;
  let bh = 36;
  fill(210, 105, 20);
  stroke(255, 175, 70);
  strokeWeight(2);
  rect(dx + 22, dy - bh / 2, bw, bh, 2);
  noStroke();
  fill(255);
  textAlign(LEFT, CENTER);
  text(speakerName, dx + 34, dy + 2);

  // Quest lines — system font for readability
  textFont('sans-serif');
  textSize(14);
  fill(210, 210, 215);
  textAlign(LEFT, TOP);
  for (let i = 0; i < lines.length; i++) {
    text(`• ${lines[i]}`, dx + 28, dy + 46 + i * 34);
  }

  // Button row — Moana font
  let btnW = 180;
  let btnH = 36;
  let btnX = dx + dw / 2 - btnW / 2;
  let btnY = dy + dh - btnH - 16;
  fill(18, 80, 150);
  noStroke();
  rect(btnX, btnY, btnW, btnH, 2);
  stroke(90, 185, 255);
  strokeWeight(1.5);
  noFill();
  rect(btnX, btnY, btnW, btnH, 2);
  noStroke();
  fill(210, 240, 255);
  textFont(moanaFont);
  textAlign(CENTER, CENTER);
  textSize(18);
  text(btnLabel, dx + dw / 2, btnY + btnH / 2);
  textFont('sans-serif');
}

// ====== INTRO QUEST ======
function drawIntroQuest() {
  let dw = min(width * 0.54, 580);
  let dh = 230;
  let dx = (width - dw) / 2;
  let dy = (height - dh) / 2;
  drawDialogBox(dx, dy, dw, dh, 'Chief Tamatoa', [
    'You have 5 seconds to crack each coconut and claim a warrior.',
    'Strike fast. The quicker the slash, the stronger they become.',
    'Recruit all 7 warriors before we head into battle.'
  ], 'BEGIN');
}

// ====== DEPARTURE QUEST ======
function drawDepartureQuest() {
  let dw = min(width * 0.54, 580);
  let dh = 190;
  let dx = (width - dw) / 2;
  let dy = height - dh - 28;
  drawDialogBox(dx, dy, dw, dh, 'Chief Tamatoa', [
    'Seven warriors stand ready. The crew is assembled.',
    'The enemy will not hold back. Neither will we.',
    'The tide is turning. Now we sail and fight.'
  ], 'SET SAIL');
}

// ====== NAME ENTRY ======
function drawNameEntry() {
  fill(0, 0, 0, 130);
  noStroke();
  rect(0, 0, width, height);

  let pw = min(width * 0.5, 440);
  let ph = 240;
  let px = (width - pw) / 2;
  let py = (height - ph) / 2;

  fill(14, 20, 36, 225);
  noStroke();
  rect(px, py, pw, ph, 2);

  // Header bar
  fill(24, 35, 58);
  rect(px, py, pw, 42, 2, 2, 0, 0);
  textFont(moanaFont);
  textAlign(CENTER, CENTER);
  textSize(18);
  fill(255, 215, 80);
  text('KAKAMORA WARRIOR', width / 2, py + 21);
  textFont('sans-serif');

  // Prompt
  fill(160, 185, 220);
  textAlign(CENTER, CENTER);
  textSize(13);
  text('Enter your name to join the crew.', width / 2, py + 72);
  text('Your score will be saved to the leaderboard.', width / 2, py + 90);
}

function confirmName() {
  let val = nameInput.value().trim();
  if (val.length === 0) return;
  playerName = val;
  nameInput.hide();
  nameConfirmBtn.hide();
  gameState = 'intro';
}


// ====== IMAGE PARTICLES ======
class ImgParticle {
  constructor(x, y, dx, dy) {
    this.pos = createVector(x, y);
    let baseAngle = (dx !== 0 || dy !== 0)
      ? atan2(dy, dx) + PI + random(-0.6, 0.6)
      : random(TWO_PI);
    let spd = random(1.5, 4.5);
    this.vel = createVector(cos(baseAngle) * spd, sin(baseAngle) * spd);
    this.life = 255;
    this.size = random(20, 40);
    this.img = random(effectImgs);
    this.rot = random(TWO_PI);
    this.rotSpeed = random(-0.18, 0.18);
  }

  update() {
    this.pos.add(this.vel);
    this.vel.y += 0.14;
    this.vel.mult(0.91);
    this.life -= 14;
    this.rot += this.rotSpeed;
  }

  draw() {
    push();
    translate(this.pos.x, this.pos.y);
    rotate(this.rot);
    tint(255, this.life);
    imageMode(CENTER);
    image(this.img, 0, 0, this.size, this.size);
    noTint();
    pop();
  }
}

function spawnImgParticles(x, y, dx, dy) {
  for (let i = 0; i < 4; i++) imgParticles.push(new ImgParticle(x, y, dx, dy));
}

function updateImgParticles() {
  for (let i = imgParticles.length - 1; i >= 0; i--) {
    imgParticles[i].update();
    if (imgParticles[i].life <= 0) imgParticles.splice(i, 1);
  }
}

function drawImgParticles() {
  for (let p of imgParticles) p.draw();
}

// ====== MOUSE HANDLER ======
function mousePressed() {
  if (gameState === 'name') return;
  if (gameState === 'intro') {
    gameState = 'playing';
    coconutTimerEnd = millis() + COCONUT_TIME_MS;
    startCoconutEntrance();
    beachSound.play();
    return;
  }
  if (gameState === 'departure') {
    // 출항 처리 (추후 배틀 씬으로 전환)
    return;
  }
}
