<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
    <title>🌸 花瓣防卫 · 九宫格区域</title>
    <style>
        *{box-sizing:border-box;user-select:none}
        body{margin:0;min-height:100vh;background:linear-gradient(135deg,#0a1a0a,#1a2e1a);display:flex;justify-content:center;align-items:center;font-family:'Segoe UI',Arial,sans-serif;padding:16px}
        #game-wrapper{background:#1a2e1a;border-radius:48px;padding:20px;box-shadow:0 30px 60px rgba(0,0,0,.9),inset 0 0 0 2px #3a5a3a;border:3px solid #b8a87c;position:relative}
        canvas{display:block;width:1200px;height:780px;max-width:100%;max-height:85vh;background:radial-gradient(circle at 30% 30%,#2a4525,#0f1f0a);border-radius:32px;border:4px solid #6e9a5e;cursor:crosshair;touch-action:none;box-shadow:inset 0 0 40px rgba(0,0,0,.5)}
        .game-title{text-align:center;margin-bottom:8px}
        .game-title h1{margin:0;color:#f3e9c0;font-size:28px;text-shadow:3px 3px 0 #2a4a2a;letter-spacing:4px}
        .control-hint{color:#8a9a7a;text-align:center;margin-top:8px;font-size:14px}
        .lobby{position:absolute;top:10px;right:10px;display:flex;gap:5px;background:#000a;padding:5px;border-radius:8px}
        button{padding:8px 12px;font-size:14px;cursor:pointer}
    </style>
</head>
<body>
<div style="display:flex;flex-direction:column">
    <div class="game-title"><h1>🌸 花瓣防卫 · 九宫格区域 🌸</h1></div>
    <div id="game-wrapper">
        <canvas id="gameCanvas"></canvas>
        <div class="lobby">
            <button id="createBtn">创建房间</button>
            <button id="joinBtn">加入房间</button>
            <button id="setRemoteBtn" disabled>设置远程Answer</button>
            <span id="statusText" style="color:#ff0"></span>
        </div>
    </div>
    <div class="control-hint">🖱️ 鼠标控制角色 | ESC暂停 | 联机:主机创建→复制Offer→客机粘贴并回传Answer→主机粘贴Answer</div>
</div>
<script>
(function() {
    "use strict";
    const canvas=document.getElementById('gameCanvas');
    const ctx=canvas.getContext('2d');
    const CW=1200,CH=780; canvas.width=CW;canvas.height=CH;
    const ROOM_W=2000,ROOM_H=1600;
    const WORLD_W=ROOM_W*3,WORLD_H=ROOM_H*3;
    const WALL_THICK=40,GAP_HALF=50;

    const ZONE_GRADE = [[0,1,2],[5,4,3],[6,7,8]];

    function buildWalls(){
        let r=[];
        const VWALL_X=[ROOM_W,ROOM_W*2],HWALL_Y=[ROOM_H,ROOM_H*2];
        const noGap=[[0,0],[0,1],[1,1],[1,2]];
        for(let xi=0;xi<VWALL_X.length;xi++){
            let x=VWALL_X[xi];
            for(let seg=0;seg<3;seg++){
                let ys=seg*ROOM_H,ye=ys+ROOM_H,gy=ys+ROOM_H/2;
                let n=noGap.some(n=>n[0]===xi&&n[1]===seg);
                if(n) r.push({x:x-WALL_THICK/2,y:ys,w:WALL_THICK,h:ROOM_H});
                else{
                    r.push({x:x-WALL_THICK/2,y:ys,w:WALL_THICK,h:gy-GAP_HALF-ys});
                    r.push({x:x-WALL_THICK/2,y:gy+GAP_HALF,w:WALL_THICK,h:ye-(gy+GAP_HALF)});
                }
            }
        }
        for(let yi=0;yi<HWALL_Y.length;yi++){
            let y=HWALL_Y[yi];
            for(let seg=0;seg<3;seg++){
                let xs=seg*ROOM_W,xe=xs+ROOM_W,gx=xs+ROOM_W/2;
                r.push({x:xs,y:y-WALL_THICK/2,w:gx-GAP_HALF-xs,h:WALL_THICK});
                r.push({x:gx+GAP_HALF,y:y-WALL_THICK/2,w:xe-(gx+GAP_HALF),h:WALL_THICK});
            }
        }
        r.push({x:0,y:0,w:WORLD_W,h:WALL_THICK},{x:0,y:WORLD_H-WALL_THICK,w:WORLD_W,h:WALL_THICK},{x:0,y:0,w:WALL_THICK,h:WORLD_H},{x:WORLD_W-WALL_THICK,y:0,w:WALL_THICK,h:WORLD_H});
        return r;
    }
    const walls=buildWalls();

    const State={MAIN:0,WORLD_SELECT:1,AREA_SELECT:2,EXPLORING:3,BACKPACK:4,TALENT:5,DEAD:6,PAUSED:7};
    let currentState=State.MAIN,previousState=State.MAIN;
    let playerLevel=1,playerExp=0,talentPoints=0;
    let talents=[0,0,0,0,0];
    const TALENT_MAX=[8,6,8,5,6];
    const TALENT_NAMES=['❤️ 生命','⚡ 移速','🗡️ 伤害','🌀 转速','📏 范围'];
    const TALENT_BASE=[100,3.2,1.0,0.024,90];
    const TALENT_SCALE=[28,0.45,0.18,0.0045,14];
    let inventory=[],slots=new Array(7).fill(null);
    const GRADE_NAMES=['Common','Unusual','Rare','Epic','Legendary','Mythic','Ultra','Super','Unique'];
    const GRADE_SHORT=['Com','Uns','Rar','Epi','Lgd','Mth','Ult','Sup','Unq'];
    const GRADE_COLORS=['#2e8b57','#ffff00','#4169e1','#9932cc','#ff0000','#00ffff','#ff69b4','#39ff14','#000000'];
    const MAX_GRADE=8;
    const COMBINE_CHANCES=[0.64,0.32,0.16,0.08,0.04,0.02,0.01,0.005,0.0025];
    const gradeMult=g=>Math.pow(3,g);
    const WORLD_NAMES={garden:'🌿 花园',desert:'🏜️ 沙漠',ocean:'🌊 海洋',tw:'🖼️ 图文'};
    const PETAL_STATS={
        basic:{dmg:8,hp:20,cd:40,icon:'⚪',name:'基础',effect:'基础花瓣'},
        stinger:{dmg:24,hp:12,cd:75,icon:'🦂',name:'毒刺',effect:'高伤害,冷却长'},
        missle:{dmg:14,hp:16,cd:35,icon:'🚀',name:'导弹',effect:'较快攻速'},
        web:{dmg:3,hp:30,cd:55,icon:'🕸️',name:'蛛网',effect:'生成减速区域'},
        beetle_egg:{dmg:16,hp:22,cd:65,icon:'🥚',name:'甲虫卵',effect:'25%几率召唤甲虫'},
        totem:{dmg:0,hp:50,cd:0,icon:'🗿',name:'图腾',effect:'击杀怪物时回血'},
        lightning:{dmg:12,hp:18,cd:45,icon:'⚡',name:'闪电',effect:'连锁2个额外目标'},
        turtle:{dmg:7,hp:60,cd:55,icon:'🐢',name:'龟壳',effect:'高生命值'},
        starfish:{dmg:5,hp:25,cd:35,icon:'⭐',name:'海星',effect:'血量≤80%时回复'},
        mystic_powder:{dmg:8,hp:20,cd:40,icon:'✨',name:'神秘粉末',effect:'提升移速(乘算叠加)'},
        vector:{dmg:24,hp:20,cd:40,icon:'➡️',name:'矢量',effect:'击中后3秒内敌人反向移动'},
        paper:{dmg:40,hp:1,cd:40,icon:'📄',name:'打印纸',effect:'增加同等级怪物掉落判定'}
    };
    const POWDER_SPEED_MULT=[1.1,1.2,1.3,1.4,1.5,1.6,1.7,1.8,2.0];
    const MONSTER_STATS={
        bee:{hp:50,dmg:12,spd:2.2,exp:12,color:'#e0b040',icon:'🐝',name:'蜜蜂'},
        hornet:{hp:40,dmg:10,spd:1.7,exp:10,color:'#c08030',icon:'🐝',name:'黄蜂'},
        spider:{hp:29,dmg:28,spd:3.4,exp:14,color:'#604080',icon:'🕷️',name:'毒蛛'},
        beetle:{hp:58,dmg:14,spd:1.7,exp:13,color:'#8b5e3c',icon:'🪲',name:'甲虫'},
        bandage_beetle:{hp:50,dmg:11,spd:1.6,exp:15,color:'#a0522d',icon:'🩹',name:'绷带甲虫'},
        tomb:{hp:150,dmg:0,spd:0,exp:25,color:'#6a5a4a',icon:'🪦',name:'古墓'},
        desert_centipede:{hp:19,dmg:8,spd:8.5,exp:20,color:'#d2b48c',icon:'🪱',name:'沙漠蜈蚣'},
        jellyfish:{hp:44,dmg:7,spd:1.1,exp:11,color:'#ff69b4',icon:'🎐',name:'水母'},
        starfish:{hp:40,dmg:10,spd:1.6,exp:10,color:'#ffa500',icon:'⭐',name:'海星'},
        turtle:{hp:120,dmg:6,spd:0.9,exp:18,color:'#228b22',icon:'🐢',name:'海龟'},
        tai_yang:{hp:174,dmg:42,spd:0.34,exp:30,color:'#c0c0c0',icon:'台',name:'台阳'},
        yi_you:{hp:580,dmg:42,spd:0,exp:50,color:'#c0a000',icon:'益',name:'益友'}
    };
    const DROP_TABLE={
        bee:'stinger',hornet:'missle',spider:'web',beetle:'beetle_egg',
        bandage_beetle:'beetle_egg',tomb:'totem',desert_centipede:'mystic_powder',
        jellyfish:'lightning',starfish:'starfish',turtle:'turtle',
        tai_yang:'vector',yi_you:'paper'
    };
    const DROP_GRADE_TABLE=[
        [[0,1.0]],[[0,0.2],[1,1.0]],[[0,0.25],[1,0.75],[2,1.0]],
        [[1,0.2],[2,0.84],[3,1.0]],[[2,0.4],[3,0.92],[4,1.0]],
        [[3,0.5],[4,0.96],[5,1.0]],[[4,0.6],[5,0.98],[6,1.0]],
        [[5,0.7],[6,0.99],[7,1.0]],[[5,0.7],[6,0.99],[7,1.0]]
    ];

    let worldId='garden',monsters=[],drops=[],projectiles=[],webs=[],summons=[];
    const MAX_SUMMONS=8,MAX_PROJECTILES=30,MAX_WEBS=15;
    let player={
        x:WORLD_W/2,y:WORLD_H/2,hp:100,maxHp:100,speed:3.2,dmgMul:1.0,
        orbitSpeed:0.024,range:90,invincible:0,healStacks:[],radius:24,
        pendingPoison:0,poisonTickRate:0
    };
    let petals=[],frame=0,mouse={x:CW/2,y:CH/2},targetPos={x:WORLD_W/2,y:WORLD_H/2};
    let backpackOpen=false,backpackScrollY=0;
    let selectedInvIndex=-1,hoverInvIndex=-1,hoverSlot=-1,hoverMonsterIdx=-1,hoverDropIdx=-1;
    let messages=[],killCount=0;
    let selectedWorld=null;

    function clamp(v,mn,mx){return Math.max(mn,Math.min(mx,v));}
    function random(a,b){return a+Math.random()*(b-a);}
    function dist(x1,y1,x2,y2){return Math.hypot(x2-x1,y2-y1);}
    function addMessage(t,c='#fff'){messages.push({text:t,color:c,timer:120});if(messages.length>5)messages.shift();}
    function resolveWallCollision(o,r=20){
        for(const w of walls){
            let cx=clamp(o.x,w.x,w.x+w.w),cy=clamp(o.y,w.y,w.y+w.h);
            let d=dist(o.x,o.y,cx,cy);
            if(d<r){
                let ov=r-d,dx=o.x-cx,dy=o.y-cy,l=Math.hypot(dx,dy);
                if(l<0.001){o.x+=r;continue;}
                o.x+=(dx/l)*ov;o.y+=(dy/l)*ov;
            }
        }
    }

    function applyPoison(target,amount,tickRatePerSec){
        target.pendingPoison+=amount;
        if(tickRatePerSec>target.poisonTickRate)target.poisonTickRate=tickRatePerSec;
    }
    function processPoison(target){
        if(target.pendingPoison<=0){target.poisonTickRate=0;return;}
        let dmgThisFrame=target.poisonTickRate/60;
        let actual=Math.min(dmgThisFrame,target.pendingPoison);
        target.hp-=actual;
        target.pendingPoison-=actual;
        if(target.pendingPoison<=0)target.poisonTickRate=0;
    }

    function initGame(){
        inventory=[]; addToInventory('basic',0,7);
        for(let i=0;i<7;i++) if(inventory[i]) slots[i]=i;
        updatePlayerStats();
        addMessage('🌸 欢迎!选择世界与区域开始冒险','#ffd700');
    }

    function addToInventory(type,grade,count=1){
        let e=inventory.find(i=>i.type===type&&i.grade===grade);
        if(e) e.count+=count; else inventory.push({type,grade,count});
    }
    function getPetalStats(type,grade){
        let b=PETAL_STATS[type]||PETAL_STATS.basic;
        let gm=gradeMult(grade);
        return {dmg:b.dmg*gm,hp:type==='paper'?1:b.hp*gm,cd:b.cd,icon:b.icon,name:b.name};
    }
    function applySpeed(){
        let m=1;
        for(let s=0;s<7;s++){
            let idx=slots[s];
            if(idx!==null&&inventory[idx]?.type==='mystic_powder')m*=POWDER_SPEED_MULT[inventory[idx].grade]||1;
        }
        player.speed=(TALENT_BASE[1]+talents[1]*TALENT_SCALE[1])*m;
    }
    function rebuildPetals(){
        petals=[];
        let valid=slots.filter(i=>i!==null&&inventory[i]?.count>0);
        if(!valid.length){applySpeed();return;}
        let step=(Math.PI*2)/valid.length;
        valid.forEach((invIdx,i)=>{
            let item=inventory[invIdx],stats=getPetalStats(item.type,item.grade);
            let hm=1+talents[0]*0.1;
            petals.push({
                type:item.type,grade:item.grade,
                hp:item.type==='paper'?1:stats.hp*hm,maxHp:item.type==='paper'?1:stats.hp*hm,
                dmg:stats.dmg*player.dmgMul,cd:0,maxCd:stats.cd,
                angle:i*step,range:player.range,
                icon:stats.icon,name:stats.name,
                speedOffset:0.8+item.grade*0.1+talents[3]*0.02
            });
        });
        applySpeed();
    }
    function updatePlayerStats(){
        player.maxHp=Math.floor(TALENT_BASE[0]+talents[0]*TALENT_SCALE[0]);
        player.dmgMul=TALENT_BASE[2]+talents[2]*TALENT_SCALE[2];
        player.orbitSpeed=TALENT_BASE[3]+talents[3]*TALENT_SCALE[3];
        player.range=TALENT_BASE[4]+talents[4]*TALENT_SCALE[4];
        if(player.hp>player.maxHp)player.hp=player.maxHp;
        rebuildPetals();
    }
    function addExperience(amt){
        playerExp+=amt;
        let need=playerLevel*25;
        let loops=0;
        while(playerExp>=need&&playerLevel<40&&loops<100){
            playerLevel++;talentPoints++;playerExp-=need;
            need=playerLevel*25;loops++;
            addMessage(`✨ 升级! 等级 ${playerLevel}  天赋点 +1`,'#ffd700');
        }
        updatePlayerStats();
    }

    function getMonsterGradeForZone(zoneGrade){
        let r=Math.random();
        switch(zoneGrade){
            case 0:return r<0.8?0:1;
            case 1:return r<0.7?1:(r<0.9?0:2);
            case 2:return r<0.6?2:(r<0.85?1:(r<0.95?3:0));
            case 3:return r<0.6?3:(r<0.85?2:(r<0.95?4:1));
            case 4:return r<0.6?4:(r<0.85?3:(r<0.95?5:2));
            case 5:return r<0.6?5:(r<0.85?4:(r<0.95?6:3));
            case 6:return r<0.6?6:(r<0.85?5:(r<0.95?7:4));
            case 7:return r<0.7?7:(r<0.95?6:8);
            case 8:return r<0.8?8:7;
        }
        return 0;
    }

    function spawnMonster(){
        if(monsters.length>=15+playerLevel*2)return;
        let types={
            garden:['bee','hornet','spider'],
            desert:['beetle','bandage_beetle','tomb','desert_centipede'],
            ocean:['jellyfish','starfish','turtle'],
            tw:['tai_yang','yi_you']
        }[worldId];
        let type=types[Math.floor(Math.random()*types.length)];
        let base=MONSTER_STATS[type];
        let {col,row}=getZoneIndex(player.x,player.y);
        let zoneGrade=ZONE_GRADE[row][col];
        let grade=getMonsterGradeForZone(zoneGrade);
        let gm=gradeMult(grade);
        let minDist=player.range*3;
        let x,y,attempts=0;
        do{
            x=random(60,WORLD_W-60);y=random(60,WORLD_H-60);
            attempts++;
        }while(dist(x,y,player.x,player.y)<minDist&&attempts<200);
        let radius=(type==='tai_yang'?3:type==='yi_you'?2:1)*22*Math.pow(1.1,grade);
        if(type==='desert_centipede'){
            const SEGMENTS=5;let prev=null;
            for(let i=0;i<SEGMENTS;i++){
                let seg={
                    type,grade,x:x-i*25,y,
                    hp:base.hp*gm*4,maxHp:base.hp*gm*4,
                    damage:base.dmg*gm,speed:base.spd,expValue:base.exp*gm,
                    color:base.color,icon:base.icon,name:base.name,
                    radius,invincible:0,knockback:{x:0,y:0},reverseTimer:0,
                    chain:{prev,next:null,isHead:i===0}
                };
                if(prev)prev.chain.next=seg;
                monsters.push(seg);
                prev=seg;
            }
        }else{
            monsters.push({
                type,grade,x,y,
                hp:base.hp*gm*4,maxHp:base.hp*gm*4,
                damage:base.dmg*gm,speed:base.spd,expValue:base.exp*gm,
                color:base.color,icon:base.icon,name:base.name,
                radius,invincible:0,knockback:{x:0,y:0},reverseTimer:0,chain:null
            });
        }
    }

    function getZoneIndex(x,y){
        let col=Math.floor(x/ROOM_W),row=Math.floor(y/ROOM_H);
        return {col:clamp(col,0,2),row:clamp(row,0,2)};
    }

    function updateCentipedeChains(){
        for(const m of monsters){
            if(!m.chain||m.chain.isHead)continue;
            const prev=m.chain.prev;
            if(!prev)continue;
            const targetDist=(prev.radius+m.radius)*0.9;
            let dx=m.x-prev.x,dy=m.y-prev.y,d=Math.hypot(dx,dy);
            if(d>targetDist){
                let moveX=(prev.x-m.x)/d*Math.min(m.speed,d-targetDist);
                let moveY=(prev.y-m.y)/d*Math.min(m.speed,d-targetDist);
                m.x+=moveX;m.y+=moveY;
            }
            m.x=clamp(m.x,20,WORLD_W-20);m.y=clamp(m.y,20,WORLD_H-20);
            resolveWallCollision(m,m.radius);
        }
    }

    function resolveEntityCollisions(){
        let entities=[];
        for(let m of monsters)entities.push({obj:m,radius:m.radius||22,isMonster:true});
        for(let s of summons)entities.push({obj:s,radius:s.radius||14,isMonster:false});
        for(let i=0;i<entities.length;i++){
            for(let j=i+1;j<entities.length;j++){
                let a=entities[i].obj,b=entities[j].obj;
                if(a.chain&&b.chain&&(a.chain.prev===b||a.chain.next===b||b.chain.prev===a||b.chain.next===a))continue;
                let r1=entities[i].radius,r2=entities[j].radius;
                let d=dist(a.x,a.y,b.x,b.y),minDist=r1+r2;
                if(d<minDist){
                    let ov=minDist-d,dx=b.x-a.x,dy=b.y-a.y;
                    if(d<0.001){dx=1;dy=0;}else{dx/=d;dy/=d;}
                    let aMov=!(a.type==='tomb'||a.type==='yi_you'),bMov=!(b.type==='tomb'||b.type==='yi_you');
                    if(!aMov&&!bMov)continue;
                    if(!aMov){b.x+=dx*ov;b.y+=dy*ov;}
                    else if(!bMov){a.x-=dx*ov;a.y-=dy*ov;}
                    else{
                        if(r1>r2){b.x+=dx*ov;b.y+=dy*ov;}
                        else if(r2>r1){a.x-=dx*ov;a.y-=dy*ov;}
                        else{let h=ov/2;a.x-=dx*h;a.y-=dy*h;b.x+=dx*h;b.y+=dy*h;}
                    }
                }
            }
        }
        for(let e of entities){
            e.obj.x=clamp(e.obj.x,20,WORLD_W-20);e.obj.y=clamp(e.obj.y,20,WORLD_H-20);
            resolveWallCollision(e.obj,e.radius);
        }
    }

    function updateMonsters(){
        for(const m of monsters){
            if(m.type==='tomb'||(m.chain&&!m.chain.isHead))continue;
            let slow=1;
            for(const w of webs)if(dist(m.x,m.y,w.x,w.y)<w.radius){slow=w.slow;break;}
            if(m.knockback){m.x+=m.knockback.x;m.y+=m.knockback.y;m.knockback.x*=0.8;m.knockback.y*=0.8;}
            let dx=player.x-m.x,dy=player.y-m.y,d=Math.hypot(dx,dy);
            if(m.reverseTimer>0){dx=m.x-player.x;dy=m.y-player.y;d=Math.hypot(dx,dy);}
            if(d>1){m.x+=(dx/d)*m.speed*slow;m.y+=(dy/d)*m.speed*slow;}
            if(m.reverseTimer>0)m.reverseTimer--;
            m.x=clamp(m.x,20,WORLD_W-20);m.y=clamp(m.y,20,WORLD_H-20);
            resolveWallCollision(m,m.radius);
            if(dist(m.x,m.y,player.x,player.y)<24+m.radius&&player.invincible<=0){
                if(m.type==='spider'){
                    let normalDmg=m.damage/4;
                    player.hp-=normalDmg;
                    applyPoison(player,m.damage*0.75,normalDmg);
                    addMessage(`🕷️ 中毒!每秒损失 ${normalDmg.toFixed(1)} 生命`,'#a020f0');
                }else{player.hp-=m.damage;}
                player.invincible=18;
                let ang=Math.atan2(player.y-m.y,player.x-m.x);
                player.x+=Math.cos(ang)*30;player.y+=Math.sin(ang)*30;
                player.x=clamp(player.x,28,WORLD_W-28);player.y=clamp(player.y,28,WORLD_H-28);
                resolveWallCollision(player,24);
                targetPos.x=player.x;targetPos.y=player.y;
            }
            if(m.hp<=0)killMonster(m);
        }
        updateCentipedeChains();
        monsters=monsters.filter(m=>m.hp>0);
    }

    function handleCentipedeDeath(m){
        if(!m.chain)return;
        let prev=m.chain.prev,next=m.chain.next;
        if(prev)prev.chain.next=next;
        if(next)next.chain.prev=prev;
        if(m.chain.isHead&&next){next.chain.isHead=true;next.chain.prev=null;}
        else if(next){next.chain.prev=null;next.chain.isHead=true;}
    }

    function updateSummons(){
        for(const s of summons){
            let closest=null,cd=Infinity;
            for(const m of monsters){let d=dist(s.x,s.y,m.x,m.y);if(d<cd){cd=d;closest=m;}}
            if(closest){let dx=closest.x-s.x,dy=closest.y-s.y,d=Math.hypot(dx,dy);if(d>1){s.x+=(dx/d)*s.speed;s.y+=(dy/d)*s.speed;}}
            if(s.attackCd>0)s.attackCd--;
            if(s.attackCd<=0&&monsters.length){
                let best=null,bestDist=Infinity;
                for(const m of monsters){
                    let ar=(s.radius||14)+(m.radius||22)+15;
                    let d=dist(s.x,s.y,m.x,m.y);
                    if(d<ar&&m.invincible<=0&&d<bestDist){best=m;bestDist=d;}
                }
                if(best){
                    best.hp-=s.dmg;s.hp-=best.damage;s.attackCd=20;
                    let ang=Math.atan2(best.y-s.y,best.x-s.x);
                    best.knockback=best.knockback||{x:0,y:0};
                    best.knockback.x+=Math.cos(ang)*15;best.knockback.y+=Math.sin(ang)*15;
                }
            }
            s.x=clamp(s.x,20,WORLD_W-20);s.y=clamp(s.y,20,WORLD_H-20);
            resolveWallCollision(s,s.radius||14);
        }
        summons=summons.filter(s=>s.hp>0);
    }

    function rollDropGrade(grade){
        let table=DROP_GRADE_TABLE[grade];
        let r=Math.random();
        for(let[g,prob]of table)if(r<prob)return g;
        return table[table.length-1][0];
    }

    function killMonster(m){
        if(m.chain)handleCentipedeDeath(m);
        addExperience(m.expValue);killCount++;
        let totems=petals.filter(p=>p.type==='totem');
        if(totems.length){
            let heal=totems.reduce((s,p)=>s+3*gradeMult(p.grade),0);
            player.healStacks.push({power:heal,duration:150});
            addMessage(`🗿 图腾回血 +${heal.toFixed(0)}`,'#90ff90');
        }
        if(!m.chain||m.chain.isHead){
            let dropType=DROP_TABLE[m.type];
            if(dropType){
                let rolls=(m.grade===8)?50:5;
                let paperCount=0;
                for(let s=0;s<7;s++){let idx=slots[s];if(idx!==null&&inventory[idx]?.type==='paper'&&inventory[idx].grade===m.grade)paperCount++;}
                rolls+=paperCount;
                for(let i=0;i<rolls;i++)drops.push({type:dropType,grade:rollDropGrade(m.grade),x:m.x,y:m.y});
            }
        }
    }

    function updatePetals(){
        let px=player.x,py=player.y;
        for(const p of petals){
            p.angle+=player.orbitSpeed*p.speedOffset;
            if(p.cd>0){p.cd--;continue;}
            if(p.dmg<=0)continue;
            for(const m of monsters){
                if(dist(px,py,m.x,m.y)<p.range+(m.radius||22)+10){
                    if(m.invincible<=0){
                        m.hp-=p.dmg;m.knockback=m.knockback||{x:0,y:0};
                        let a=Math.atan2(m.y-py,m.x-px);
                        m.knockback.x=Math.cos(a)*20;m.knockback.y=Math.sin(a)*20;
                        if(p.type==='vector')m.reverseTimer=180;
                    }
                    p.cd=p.maxCd;
                    if(p.type==='lightning')monsters.filter(m2=>m2!==m&&dist(m.x,m.y,m2.x,m2.y)<90).slice(0,2).forEach(m2=>{if(m2.invincible<=0)m2.hp-=p.dmg*0.6;});
                    if(p.type==='starfish'&&player.hp/player.maxHp<=0.8)player.hp=Math.min(player.maxHp,player.hp+7*gradeMult(p.grade));
                    if(p.type==='beetle_egg'&&Math.random()<0.25&&summons.length<MAX_SUMMONS){
                        let gm=gradeMult(p.grade),hm=1+talents[0]*0.1;
                        summons.push({x:px+random(-30,30),y:py+random(-30,30),hp:40*gm*2*hm,maxHp:40*gm*2*hm,dmg:16*gm*player.dmgMul,speed:3.0+p.grade*0.15,attackCd:0,radius:14*Math.pow(1.05,p.grade)});
                    }
                    break;
                }
            }
        }
    }

    function selectWorld(w){
        selectedWorld=w;
        currentState=State.AREA_SELECT;
    }

    function enterArea(col,row){
        worldId=selectedWorld;
        monsters=[];drops=[];projectiles=[];webs=[];summons=[];
        let spawnX,spawnY,attempts=0;
        do{
            spawnX=col*ROOM_W+random(60,ROOM_W-60);
            spawnY=row*ROOM_H+random(60,ROOM_H-60);
            attempts++;
        }while(attempts<100);
        player.x=spawnX;player.y=spawnY;
        targetPos.x=player.x;targetPos.y=player.y;
        resolveWallCollision(player,24);
        player.hp=player.maxHp;player.invincible=0;player.healStacks=[];
        player.pendingPoison=0;player.poisonTickRate=0;
        rebuildPetals();
        for(let i=0;i<8;i++)spawnMonster();
        currentState=State.EXPLORING;backpackOpen=false;backpackScrollY=0;
        addMessage(`进入 ${WORLD_NAMES[worldId]} ${GRADE_NAMES[ZONE_GRADE[row][col]]}区`,'#a0d080');
    }

    function update(){
        if(currentState!==State.EXPLORING||backpackOpen)return;
        let dx=targetPos.x-player.x,dy=targetPos.y-player.y,d=Math.hypot(dx,dy);
        if(d>5){let spd=Math.min(player.speed,d);player.x+=(dx/d)*spd;player.y+=(dy/d)*spd;}
        player.x=clamp(player.x,28,WORLD_W-28);player.y=clamp(player.y,28,WORLD_H-28);
        resolveWallCollision(player,24);
        if(player.invincible>0)player.invincible--;
        processPoison(player);
        for(let i=player.healStacks.length-1;i>=0;i--){
            if(frame%8===0)player.hp=Math.min(player.maxHp,player.hp+player.healStacks[i].power);
            if(--player.healStacks[i].duration<=0)player.healStacks.splice(i,1);
        }
        updatePetals();updateMonsters();updateSummons();resolveEntityCollisions();
        for(let i=drops.length-1;i>=0;i--)if(dist(player.x,player.y,drops[i].x,drops[i].y)<45){addToInventory(drops[i].type,drops[i].grade,1);drops.splice(i,1);}
        if(frame%70===0)spawnMonster();
        if(player.hp<=0){currentState=State.DEAD;addMessage('💀 你倒下了...','#ffaaaa');}
        frame++;
        for(const msg of messages)msg.timer--;
        messages=messages.filter(m=>m.timer>0);
    }

    function draw(){
        ctx.clearRect(0,0,CW,CH);
        if(currentState===State.MAIN)drawMainMenu();
        else if(currentState===State.WORLD_SELECT)drawWorldSelect();
        else if(currentState===State.AREA_SELECT)drawAreaSelect();
        else if(currentState===State.TALENT)drawTalent();
        else if(currentState===State.DEAD)drawDead();
        else if(currentState===State.PAUSED)drawPaused();
        else{
            let vx=player.x-CW/2,vy=player.y-CH/2;
            for(let row=0;row<3;row++)for(let col=0;col<3;col++){
                let x=col*ROOM_W-vx,y=row*ROOM_H-vy;
                ctx.fillStyle=GRADE_COLORS[ZONE_GRADE[row][col]]+'22';
                ctx.fillRect(x,y,ROOM_W,ROOM_H);
            }
            ctx.strokeStyle='#3a5a3a44';ctx.lineWidth=1;
            for(let x=-100;x<CW+100;x+=100)ctx.strokeRect(x-(vx%100),0,0,CH);
            for(let y=-100;y<CH+100;y+=100)ctx.strokeRect(0,y-(vy%100),CW,0);
            ctx.fillStyle='#4a4a4a';
            for(const w of walls){let sx=w.x-vx,sy=w.y-vy;ctx.fillRect(sx,sy,w.w,w.h);}
            ctx.fillStyle='#5db0e0';ctx.beginPath();ctx.arc(CW/2,CH/2,24,0,Math.PI*2);ctx.fill();
            ctx.fillStyle='#fff';ctx.font='16px Arial';ctx.fillText('⚪',CW/2-10,CH/2+6);
            for(const p of petals){
                let px=player.x+Math.cos(p.angle)*player.range-vx,py=player.y+Math.sin(p.angle)*player.range-vy;
                ctx.fillStyle=GRADE_COLORS[p.grade];ctx.beginPath();ctx.arc(px,py,14,0,Math.PI*2);ctx.fill();
                if(p.cd>0){ctx.fillStyle='#0008';ctx.beginPath();ctx.arc(px,py,14,0,Math.PI*2);ctx.fill();}
                ctx.fillStyle='#fff';ctx.font='14px Arial';ctx.fillText(p.icon,px-10,py+6);
            }
            for(const m of monsters){
                let sx=m.x-vx,sy=m.y-vy,r=m.radius||22;
                ctx.fillStyle=GRADE_COLORS[m.grade]+'88';ctx.beginPath();ctx.arc(sx,sy,r+6,0,Math.PI*2);ctx.fill();
                ctx.fillStyle=m.color;ctx.beginPath();ctx.arc(sx,sy,r,0,Math.PI*2);ctx.fill();
                let bw=r*2+8,bh=6,bx=sx-bw/2,by=sy-r-12;
                ctx.fillStyle='#300';ctx.fillRect(bx,by,bw,bh);
                ctx.fillStyle='#6f6';ctx.fillRect(bx,by,bw*(m.hp/m.maxHp),bh);
                ctx.fillStyle='#fff';ctx.font=`${Math.min(16+m.grade*2,24)}px Arial`;ctx.fillText(m.icon,sx-10,sy+6);
            }
            for(const s of summons){
                let sx=s.x-vx,sy=s.y-vy,r=s.radius||14;
                ctx.fillStyle='#8a6';ctx.beginPath();ctx.arc(sx,sy,r,0,Math.PI*2);ctx.fill();
                ctx.fillStyle='#fff';ctx.font='12px Arial';ctx.fillText('🪲',sx-8,sy+5);
            }
            for(const d of drops){
                ctx.fillStyle=GRADE_COLORS[d.grade];ctx.beginPath();ctx.arc(d.x-vx,d.y-vy,12,0,Math.PI*2);ctx.fill();
                ctx.fillStyle='#fff';ctx.font='12px Arial';ctx.fillText(PETAL_STATS[d.type]?.icon,d.x-vx-8,d.y-vy+5);
            }
            ctx.fillStyle='#1a2a1aaa';ctx.fillRect(18,18,264,50);
            ctx.fillStyle='#c44';ctx.fillRect(20,20,260*(player.hp/player.maxHp),26);
            let needExp=playerLevel*25;
            ctx.fillStyle='#4da6ff';ctx.fillRect(20,48,260*(playerExp/needExp),14);
            if(player.pendingPoison>0){
                ctx.fillStyle='#a020f0';ctx.fillRect(20,64,50,8);
                ctx.fillStyle='#fff';ctx.font='10px Arial';ctx.fillText(`毒 ${player.pendingPoison.toFixed(0)}`,75,72);
            }
            ctx.fillStyle='#fff';ctx.font='bold 18px Arial';
            ctx.fillText(`❤️ ${Math.floor(player.hp)}/${player.maxHp}`,30,40);
            ctx.fillText(`Lv.${playerLevel}`,CW-200,65);ctx.fillText(`击杀:${killCount}`,CW-200,100);
            ctx.font='12px Arial';ctx.fillText(`EXP ${playerExp}/${needExp}`,30,60);
            drawButton('⏸️',CW-180,30,80,50);drawButton('🎒',CW-90,30,80,50);
            if(backpackOpen)drawBackpack();
        }
        drawTooltip();
    }

    function drawMainMenu(){
        ctx.fillStyle='#f3e9c0';ctx.font='bold 54px Arial';ctx.textAlign='center';ctx.fillText('🌸 花瓣防卫',CW/2,130);
        drawButton('🌍 世界',350,220,200,70);drawButton('✨ 天赋',600,220,200,70);drawButton('🎒 背包',850,220,200,70);
        ctx.font='28px Arial';ctx.fillStyle='#ddd';ctx.fillText(`等级 ${playerLevel}  天赋点 ${talentPoints}`,CW/2,400);
    }
    function drawWorldSelect(){
        ctx.fillStyle='#efe6c3';ctx.font='44px Arial';ctx.textAlign='center';ctx.fillText('选择世界',CW/2,150);
        drawButton('🌿 花园',200,300,180,80);drawButton('🏜️ 沙漠',500,300,180,80);
        drawButton('🌊 海洋',800,300,180,80);drawButton('🖼️ 图文',350,450,180,80);
        drawButton('← 返回',80,650,140,60);
    }
    function drawAreaSelect(){
        ctx.fillStyle='#efe6c3';ctx.font='38px Arial';ctx.textAlign='center';ctx.fillText('选择出生区域',CW/2,70);
        for(let row=0;row<3;row++)for(let col=0;col<3;col++){
            let g=ZONE_GRADE[row][col];
            drawButton(`${GRADE_NAMES[g]}`,300+col*300,200+row*180,200,60,GRADE_COLORS[g]);
        }
        drawButton('← 返回',80,650,140,60);
    }
    function drawTalent(){
        ctx.fillStyle='#efe6c3';ctx.font='44px Arial';ctx.textAlign='center';ctx.fillText('✨ 天赋树',CW/2,100);
        for(let i=0;i<5;i++)drawButton(`${TALENT_NAMES[i]} ${talents[i]}/${TALENT_MAX[i]}`,250,250+i*70,320,50,hoverSlot===i?'#b89e5a':'#8a6e4a');
        drawButton('返回',900,600,140,60);
        ctx.fillStyle='#ffd700';ctx.font='28px Arial';ctx.fillText(`剩余天赋点: ${talentPoints}`,CW/2,650);
    }
    function drawDead(){
        ctx.fillStyle='#200a';ctx.fillRect(250,150,700,450);
        ctx.fillStyle='#faa';ctx.font='48px Arial';ctx.textAlign='center';ctx.fillText('💀 你倒下了',CW/2,320);
        drawButton('返回主界面',CW/2-100,480,200,70);
    }
    function drawPaused(){
        ctx.fillStyle='#1a2a1aee';ctx.fillRect(300,200,600,400);
        ctx.fillStyle='#f0e6c0';ctx.font='44px Arial';ctx.textAlign='center';ctx.fillText('⏸️ 暂停',CW/2,300);
        drawButton('继续',CW/2-100,380,200,60);drawButton('返回主界面',CW/2-100,460,200,60);
    }
    function drawBackpack(){
        ctx.fillStyle='#1e2e1eec';ctx.fillRect(200,80,800,600);
        ctx.save();ctx.beginPath();ctx.rect(200,80,800,600);ctx.clip();
        ctx.fillStyle='#f0e6c0';ctx.font='28px Arial';ctx.textAlign='center';ctx.fillText('🎒 背包',CW/2,130);
        let startY=170,ih=55,totalH=startY+inventory.length*ih+20,maxScroll=Math.max(0,totalH-600);
        backpackScrollY=clamp(backpackScrollY,0,maxScroll);
        for(let i=0;i<inventory.length;i++){
            let item=inventory[i],y=startY+i*ih-backpackScrollY;
            ctx.fillStyle=selectedInvIndex===i?'#ffd700':GRADE_COLORS[item.grade];
            ctx.fillRect(330,y,330,40);
            ctx.fillStyle='#fff';ctx.font='16px Arial';
            ctx.fillText(`${PETAL_STATS[item.type].icon} ${PETAL_STATS[item.type].name} [${GRADE_SHORT[item.grade]}] x${item.count}`,350,y+26);
            if(item.count>=5&&item.grade<MAX_GRADE)drawButton('合成',730,y+20,70,35);
        }
        ctx.restore();
        for(let s=0;s<7;s++){
            ctx.fillStyle='#4a6a3a';ctx.fillRect(840,190+s*65,100,42);
            if(slots[s]!==null)ctx.fillText(PETAL_STATS[inventory[slots[s]].type].icon,890,218+s*65);
        }
        drawButton('关闭',600,640,100,40);
    }
    function drawButton(text,x,y,w,h,col='#8a6e4a'){
        ctx.fillStyle=col;ctx.beginPath();ctx.roundRect(x-w/2,y-h/2,w,h,12);ctx.fill();
        ctx.fillStyle='#fff';ctx.font='bold 22px Arial';ctx.textAlign='center';ctx.fillText(text,x,y+8);
    }
    CanvasRenderingContext2D.prototype.roundRect=function(x,y,w,h,r){
        if(w<2*r)r=w/2;if(h<2*r)r=h/2;
        this.moveTo(x+r,y);this.lineTo(x+w-r,y);this.quadraticCurveTo(x+w,y,x+w,y+r);
        this.lineTo(x+w,y+h-r);this.quadraticCurveTo(x+w,y+h,x+w-r,y+h);
        this.lineTo(x+r,y+h);this.quadraticCurveTo(x,y+h,x,y+h-r);this.lineTo(x,y+r);
        this.quadraticCurveTo(x,y,x+r,y);return this;
    };

    function updateHoverInfo(mx,my){
        hoverInvIndex=-1;hoverSlot=-1;hoverMonsterIdx=-1;hoverDropIdx=-1;
        if(currentState===State.BACKPACK||(currentState===State.EXPLORING&&backpackOpen)){
            const adj=my+backpackScrollY;
            for(let i=0;i<inventory.length;i++)if(btn(370,170+i*55,340,45,mx,adj)){hoverInvIndex=i;break;}
            for(let s=0;s<7;s++)if(btn(850,190+s*65,110,45,mx,my)){hoverSlot=s;break;}
        }
        if(currentState===State.EXPLORING&&!backpackOpen){
            const vx=player.x-CW/2,vy=player.y-CH/2;
            for(let i=monsters.length-1;i>=0;i--){
                let m=monsters[i],sx=m.x-vx,sy=m.y-vy;
                if(dist(mx,my,sx,sy)<(m.radius||22)+6){hoverMonsterIdx=i;break;}
            }
            for(let i=drops.length-1;i>=0;i--){
                let d=drops[i],sx=d.x-vx,sy=d.y-vy;
                if(dist(mx,my,sx,sy)<16){hoverDropIdx=i;break;}
            }
        }
    }

    function drawTooltip(){
        let tipText='',tipSubText='',tipColor='#fff';
        if(hoverInvIndex>=0&&inventory[hoverInvIndex]){
            let item=inventory[hoverInvIndex],stats=getPetalStats(item.type,item.grade);
            let hm=1+talents[0]*0.1;
            tipText=`${stats.icon} ${stats.name} [${GRADE_NAMES[item.grade]}]`;
            tipSubText=`数量:${item.count} 伤害:${(stats.dmg*player.dmgMul).toFixed(1)} HP:${(stats.hp*hm).toFixed(0)} CD:${stats.cd}\n${PETAL_STATS[item.type].effect}`;
            if(item.type==='mystic_powder')tipSubText+=`\n移速倍率:×${POWDER_SPEED_MULT[item.grade].toFixed(1)}`;
            if(item.grade<MAX_GRADE)tipSubText+=`\n合成率:${Math.round(COMBINE_CHANCES[item.grade]*100)}%`;
            tipColor=GRADE_COLORS[item.grade];
        }else if(hoverSlot>=0){
            let idx=slots[hoverSlot];
            if(idx!==null&&inventory[idx]){
                let item=inventory[idx],stats=getPetalStats(item.type,item.grade);
                let hm=1+talents[0]*0.1;
                tipText=`槽${hoverSlot+1}: ${stats.icon} ${stats.name} [${GRADE_NAMES[item.grade]}]`;
                tipSubText=`伤害:${(stats.dmg*player.dmgMul).toFixed(1)} HP:${(stats.hp*hm).toFixed(0)} CD:${stats.cd}\n${PETAL_STATS[item.type].effect}`;
                tipColor=GRADE_COLORS[item.grade];
            }else{tipText=`槽${hoverSlot+1}: 空`;tipColor='#aaa';}
        }else if(hoverMonsterIdx>=0){
            let m=monsters[hoverMonsterIdx];
            tipText=`${m.icon} ${m.name} [${GRADE_NAMES[m.grade]}]`;
            tipSubText=`HP:${Math.ceil(m.hp)}/${Math.ceil(m.maxHp)} 伤:${Math.ceil(m.damage)} EXP:${m.expValue}`;
            tipColor=GRADE_COLORS[m.grade];
        }else if(hoverDropIdx>=0){
            let d=drops[hoverDropIdx];
            tipText=`${PETAL_STATS[d.type]?.icon} ${GRADE_NAMES[d.grade]}`;
            tipColor=GRADE_COLORS[d.grade];
        }
        if(tipText){
            let tx=mouse.x+20,ty=mouse.y-20;
            ctx.font='bold 18px Arial';
            let lines=tipSubText?tipSubText.split('\n'):[];
            let maxW=ctx.measureText(tipText).width;
            for(let l of lines){ctx.font='15px Arial';maxW=Math.max(maxW,ctx.measureText(l).width);}
            let tw=maxW+28,th=32+(lines.length*22);
            let x=clamp(tx,10,CW-tw-10),y=clamp(ty-th,10,CH-th-10);
            ctx.fillStyle='#000e';ctx.fillRect(x,y,tw,th);
            ctx.fillStyle=tipColor;ctx.font='bold 18px Arial';ctx.fillText(tipText,x+14,y+26);
            if(lines.length){ctx.fillStyle='#ddd';ctx.font='15px Arial';for(let i=0;i<lines.length;i++)ctx.fillText(lines[i],x+14,y+52+i*22);}
        }
    }

    function combinePetals(idx){
        let item=inventory[idx];
        if(!item||item.count<5||item.grade>=MAX_GRADE)return false;
        let chance=COMBINE_CHANCES[item.grade];
        if(Math.random()<chance){
            item.count-=5;if(item.count<=0)inventory.splice(idx,1);
            addToInventory(item.type,item.grade+1,1);
            rebuildPetals();addMessage('✨ 合成成功!','#90ff90');
        }else{
            item.count-=4;if(item.count<=0)inventory.splice(idx,1);
            rebuildPetals();addMessage('💔 合成失败','#ff9090');
        }
        return true;
    }

    function btn(x,y,w,h,mx,my){return mx>x-w/2&&mx<x+w/2&&my>y-h/2&&my<y+h/2;}

    canvas.addEventListener('mousemove',e=>{
        let rect=canvas.getBoundingClientRect();
        mouse.x=(e.clientX-rect.left)*(CW/rect.width);
        mouse.y=(e.clientY-rect.top)*(CH/rect.height);
        if(currentState===State.EXPLORING&&!backpackOpen){
            targetPos.x=player.x+(mouse.x-CW/2);targetPos.y=player.y+(mouse.y-CH/2);
        }
        updateHoverInfo(mouse.x,mouse.y);
    });
    canvas.addEventListener('mousedown',e=>{
        let mx=mouse.x,my=mouse.y;
        if(currentState===State.MAIN){
            if(btn(350,220,200,70,mx,my))currentState=State.WORLD_SELECT;
            else if(btn(600,220,200,70,mx,my))currentState=State.TALENT;
            else if(btn(850,220,200,70,mx,my)){backpackOpen=true;currentState=State.BACKPACK;}
        }else if(currentState===State.WORLD_SELECT){
            if(btn(200,300,180,80,mx,my))selectWorld('garden');
            else if(btn(500,300,180,80,mx,my))selectWorld('desert');
            else if(btn(800,300,180,80,mx,my))selectWorld('ocean');
            else if(btn(350,450,180,80,mx,my))selectWorld('tw');
            else if(btn(80,650,140,60,mx,my))currentState=State.MAIN;
        }else if(currentState===State.AREA_SELECT){
            for(let row=0;row<3;row++)for(let col=0;col<3;col++){
                if(btn(300+col*300,200+row*180,200,60,mx,my)){enterArea(col,row);return;}
            }
            if(btn(80,650,140,60,mx,my))currentState=State.WORLD_SELECT;
        }else if(currentState===State.EXPLORING||currentState===State.BACKPACK){
            if(btn(CW-90,30,80,50,mx,my)){backpackOpen=!backpackOpen;currentState=backpackOpen?State.BACKPACK:State.EXPLORING;}
            else if(btn(CW-180,30,80,50,mx,my)){previousState=currentState;currentState=State.PAUSED;}
            if(backpackOpen)handleBackpackClick(mx,my);
        }else if(currentState===State.TALENT){
            for(let i=0;i<5;i++)if(btn(250,250+i*70,320,50,mx,my)){
                if(talentPoints>0&&talents[i]<TALENT_MAX[i]){talents[i]++;talentPoints--;updatePlayerStats();addMessage(`${TALENT_NAMES[i]} +1`,'#aad4ff');}
                else addMessage('无法升级','#ffaa00');
            }
            if(btn(900,600,140,60,mx,my))currentState=State.MAIN;
        }else if(currentState===State.DEAD){if(btn(CW/2-100,480,200,70,mx,my)){player.hp=player.maxHp;currentState=State.MAIN;}}
        else if(currentState===State.PAUSED){
            if(btn(CW/2-100,350,200,60,mx,my))currentState=previousState;
            if(btn(CW/2-100,430,200,60,mx,my))currentState=State.MAIN;
        }
    });
    canvas.addEventListener('wheel',e=>{if(backpackOpen)backpackScrollY+=e.deltaY*0.8;});
    function handleBackpackClick(mx,my){
        let adj=my+backpackScrollY;
        for(let i=0;i<inventory.length;i++){
            if(btn(370,170+i*55,340,45,mx,adj)){selectedInvIndex=i;return;}
            if(inventory[i]?.count>=5&&inventory[i].grade<MAX_GRADE&&btn(730,170+i*55,70,35,mx,adj)){combinePetals(i);return;}
        }
        for(let s=0;s<7;s++){
            if(btn(850,190+s*65,110,45,mx,my)){
                if(selectedInvIndex!==-1){if(inventory[selectedInvIndex]?.count>0)slots[s]=selectedInvIndex;}
                else slots[s]=null;
                rebuildPetals();selectedInvIndex=-1;return;
            }
        }
        if(btn(600,640,100,40,mx,my)){backpackOpen=false;currentState=State.EXPLORING;}
    }

    window.addEventListener('keydown',e=>{
        if(e.key==='Escape'){
            if(currentState===State.BACKPACK){backpackOpen=false;currentState=State.EXPLORING;}
            else if(currentState===State.EXPLORING){previousState=currentState;currentState=State.PAUSED;}
            else if(currentState===State.PAUSED)currentState=previousState;
        }
    });

    initGame();
    function gameLoop(){update();draw();requestAnimationFrame(gameLoop);}
    gameLoop();
})();
</script>
</body>
</html>