<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Florr.io Offline</title>
  <style>
    * { margin: 0; padding: 0; box-sizing: border-box; }
    body { background: #1a1a1a; display: flex; justify-content: center; align-items: center; min-height: 100vh; font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; }
    #game { border: 3px solid #333; background: #2d2d2d; }
    #ui { position: absolute; top: 10px; left: 10px; color: #fff; font-size: 14px; line-height: 1.5; background: rgba(0,0,0,0.5); padding: 8px 12px; border-radius: 6px; }
  </style>
</head>
<body>
<div id="ui">
  Level: <span id="level">1</span> | XP: <span id="xp">0</span>/100<br>
  HP: <span id="hp">100</span> | Petals: <span id="petalCount">3</span>
</div>
<canvas id="game" width="1000" height="600"></canvas>

<script>
const canvas = document.getElementById('game');
const ctx = canvas.getContext('2d');
const ui = {
  level: document.getElementById('level'),
  xp: document.getElementById('xp'),
  hp: document.getElementById('hp'),
  petalCount: document.getElementById('petalCount')
};

// --------------------------
// 游戏数据
// --------------------------
const player = {
  x: canvas.width/2,
  y: canvas.height/2,
  size: 24,
  speed: 3.5,
  hp: 100,
  maxHp: 100,
  level: 1,
  xp: 0,
  xpToNext: 100,
  petals: [],
  invulnerable: 0
};

const mobs = [];
const drops = [];
const keys = {};
let mouse = { x: player.x, y: player.y };

// 花瓣类型(文字替代)
const PETAL_TYPES = [
  { char: 'P', color: '#ff69b4', dmg: 8,  hp: 20, speed: 0.12 },
  { char: 'S', color: '#ff4500', dmg: 168, hp: 1, speed: 0.18 },
  { char: 'B', color: '#1e90ff', dmg: 5,  hp: 35, speed: 0.09 },
  { char: 'Y', color: '#ffd700', dmg: 12, hp: 18, speed: 0.15 }
];

// 怪物类型
const MOB_TYPES = [
  { char: '普通', color: '#90ee90', hp: 40,  dmg: 6,  speed: 1.5, xp: 150, dropChance: 0.20 },
  { char: '罕见', color: '#ffd700', hp: 120,  dmg: 18, speed: 1.0, xp: 500, dropChance: 0.80 },
  { char: '稀有', color: '#1e90ff', hp: 360, dmg: 54, speed: 0.75, xp: 2000, dropChance: 4 }
];

// --------------------------
// 初始化
// --------------------------
function init() {
  // 初始花瓣
  for (let i=0; i<3; i++) {
    addPetal(0);
  }
  // 初始怪物
  for (let i=0; i<player.level+5; i++) spawnMob();
  loop();
}

// 添加花瓣
function addPetal(typeIdx) {
  const t = PETAL_TYPES[typeIdx];
  player.petals.push({
    type: typeIdx,
    angle: Math.random() * Math.PI*2,
    dist: 35+20,
    hp: t.hp,
    maxHp: t.hp
  });
}

// 生成怪物
function spawnMob() {
  const t = MOB_TYPES[Math.floor(Math.random()*MOB_TYPES.length)];
  const side = Math.random() < 0.5 ? 0 : canvas.width;
  mobs.push({
    x: side + (Math.random()-0.5)*100,
    y: Math.random()*canvas.height,
    size: 20,
    type: t,
    hp: t.hp,
    maxHp: t.hp
  });
}

// --------------------------
// 输入
// --------------------------
window.addEventListener('mousemove', e => {
  const r = canvas.getBoundingClientRect();
  mouse.x = e.clientX - r.left;
  mouse.y = e.clientY - r.top;
});
window.addEventListener('keydown', e => { keys[e.code] = true; });
window.addEventListener('keyup',   e => { keys[e.code] = false; });

// --------------------------
// 游戏循环
// --------------------------
function loop() {
  update();
  render();
  requestAnimationFrame(loop);
}

// --------------------------
// 更新逻辑
// --------------------------
function update() {
  // 玩家移动
  const dx = mouse.x - player.x;
  const dy = mouse.y - player.y;
  const dist = Math.hypot(dx, dy);
  if (dist > 4) {
    player.x += (dx/dist) * player.speed;
    player.y += (dy/dist) * player.speed;
  }
  // 边界
  player.x = Math.max(player.size, Math.min(canvas.width-player.size, player.x));
  player.y = Math.max(player.size, Math.min(canvas.height-player.size, player.y));

  // 无敌帧
  if (player.invulnerable > 0) player.invulnerable -= 1;

  // 花瓣旋转
  player.petals.forEach((p,i) => {
    p.angle += PETAL_TYPES[p.type].speed;
    if (p.hp <= 0) {
      player.petals.splice(i, 1);
      // 补一个低级花瓣
      setTimeout(()=>addPetal(0), 3000);
    }
  });

  // 怪物移动 & 追击
  mobs.forEach((mob,i) => {
    const dx = player.x - mob.x;
    const dy = player.y - mob.y;
    const dist = Math.hypot(dx, dy);
    if (dist > 0) {
      mob.x += (dx/dist) * mob.type.speed;
      mob.y += (dy/dist) * mob.type.speed;
    }

    // 玩家碰撞
    if (dist < mob.size + player.size && player.invulnerable === 0) {
      player.hp -= mob.type.dmg;
      player.invulnerable = 60;
      checkGameOver();
    }

    // 死亡
    if (mob.hp <= 0) {
      player.xp += mob.type.xp;
      checkLevelUp();
      // 掉落
      if (Math.random() < mob.type.dropChance) {
        drops.push({
          x: mob.x, y: mob.y,
          type: Math.floor(Math.random()*PETAL_TYPES.length)
        });
      }
      mobs.splice(i,1);
      setTimeout(spawnMob, 800);
    }
  });

  // 花瓣 vs 怪物
  player.petals.forEach(p => {
    const t = PETAL_TYPES[p.type];
    const px = player.x + Math.cos(p.angle)*p.dist;
    const py = player.y + Math.sin(p.angle)*p.dist;
    mobs.forEach(mob => {
      const d = Math.hypot(px-mob.x, py-mob.y);
      if (d < 12 + mob.size/2) {
        mob.hp -= t.dmg;
        p.hp -= mob.type.dmg * 0.5;
      }
    });
  });

  // 拾取花瓣
  drops.forEach((d,i) => {
    if (Math.hypot(d.x-player.x, d.y-player.y) < 30) {
      addPetal(d.type);
      drops.splice(i,1);
    }
  });

  // UI
  ui.level.textContent = player.level;
  ui.xp.textContent = player.xp;
  ui.hp.textContent = Math.max(0, player.hp);
  ui.petalCount.textContent = player.petals.length;
}

// 升级
function checkLevelUp() {
  while (player.xp >= player.xpToNext) {
    player.xp -= player.xpToNext;
    player.level++;
    player.xpToNext = Math.floor(player.xpToNext * 1.35);
    player.maxHp += 15;
    player.hp = player.maxHp;
    player.speed += 0.15;
    // 加花瓣
    if (player.level % 2 === 0) {
      addPetal(Math.min(1, player.level-1));
    }
  }
}

function checkGameOver() {
  if (player.hp <= 0) {
    alert(`Game Over | Level: ${player.level}`);
    location.reload();
  }
}

// --------------------------
// 渲染(文字版)
// --------------------------
function render() {
  ctx.clearRect(0,0,canvas.width,canvas.height);

  // 背景网格
  ctx.strokeStyle = '#333';
  ctx.lineWidth = 1;
  for (let x=0;x<canvas.width;x+=40) {
    ctx.beginPath(); ctx.moveTo(x,0); ctx.lineTo(x,canvas.height); ctx.stroke();
  }
  for (let y=0;y<canvas.height;y+=40) {
    ctx.beginPath(); ctx.moveTo(0,y); ctx.lineTo(canvas.width,y); ctx.stroke();
  }

  // 花瓣
  player.petals.forEach(p => {
    const t = PETAL_TYPES[p.type];
    const px = player.x + Math.cos(p.angle)*p.dist;
    const py = player.y + Math.sin(p.angle)*p.dist;
    ctx.fillStyle = t.color;
    ctx.font = '20px monospace';
    ctx.textAlign = 'center';
    ctx.fillText(t.char, px, py+6);
  });

  // 玩家
  ctx.fillStyle = player.invulnerable%10<5 ? '#fff' : '#87ceeb';
  ctx.font = 'bold 28px monospace';
  ctx.fillText('●', player.x, player.y+8);

  // 怪物
  mobs.forEach(mob => {
    ctx.fillStyle = mob.type.color;
    ctx.font = '22px monospace';
    ctx.fillText(mob.type.char, mob.x, mob.y+7);
    // 血条
    const w = 22;
    const h = 3;
    ctx.fillStyle = '#444';
    ctx.fillRect(mob.x-w/2, mob.y-15, w, h);
    ctx.fillStyle = '#ff4444';
    ctx.fillRect(mob.x-w/2, mob.y-15, w*(mob.hp/mob.maxHp), h);
  });

  // 掉落
  drops.forEach(d => {
    const t = PETAL_TYPES[d.type];
    ctx.fillStyle = t.color;
    ctx.font = '16px monospace';
    ctx.fillText(t.char, d.x, d.y+5);
  });

  // 玩家血条
  const bw = 40;
  const bh = 4;
  ctx.fillStyle = '#333';
  ctx.fillRect(player.x-bw/2, player.y-20, bw, bh);
  ctx.fillStyle = '#7ccd7c';
  ctx.fillRect(player.x-bw/2, player.y-20, bw*(player.hp/player.maxHp), bh);
}

// 启动
init();
</script>
</body>
</html></u>*</u>