"use strict"; /* ================= 界面流转 ================= */ const OVLS=["o-auth","o-home","o-title","o-setup","o-hangar","o-cards","o-pause","o-over","o-codex","o-demo","o-rush","o-slot","o-unsaved"]; function show(id){for(const o of OVLS)$(o).classList.toggle("hide",o!==id);} const SETUP={mode:"endless",ship:"falcon",diff:0}; // 出击默认无尽模式 function bestLine(){ const b=SAVE.best; $("best-line").textContent=`无尽纪录 ${Math.max(b.e0,b.e1)} · 闯关进度 ${b.stage}/6`; } $("b-go").onclick=()=>{AU.init();show("o-setup");refreshRunSave();}; $("b-back1").onclick=()=>show("o-title"); $("b-back2").onclick=()=>show("o-title"); $("b-hangar").onclick=()=>{AU.init();buildShop();show("o-hangar");}; $("b-codex").onclick=()=>{AU.init();buildCodex();show("o-codex");}; $("b-rush").onclick=()=>{AU.init();buildRush();show("o-rush");}; $("b-back6").onclick=()=>{UI="title";show("o-title");}; $("b-back4").onclick=()=>{UI="title";bestLine();show("o-title");}; $("b-back5").onclick=exitDemoSim; /* 图鉴测试模式(隐藏入口):连点图鉴标题“军”字10次开关。 纯内存开关——不动 SAVE.codex(persist/结算上报都读它,动了会污染后端),刷新页面即失效 */ let codexTestAll=false,cxClicks=0,cxLastClick=0; $("cx-secret").onclick=()=>{ const now=Date.now(); if(now-cxLastClick>2000)cxClicks=0; // 间隔超2秒重新计数 cxLastClick=now; if(++cxClicks<10)return; cxClicks=0;codexTestAll=!codexTestAll; SFX.pick();buildCodex(); }; /* 开始出击:新开无尽对局(不分难度)前,若云端有未完成对局,先弹结算确认 */ $("b-start").onclick=async()=>{ if(SETUP.mode==="endless"&&typeof NET!=="undefined"&&NET.user){ if(NET.runSave===undefined)await NET.fetchRunSave(); if(NET.runSave){showUnsaved(NET.runSave);return;} } startGame(); }; /* ================= 无尽模式:断点续玩(波次检查点) ================= 每波开始拍快照上传(startWave 调用);中途退出=从当前波开头重打, 该波内的得分/击杀不保留,build与层数完整保留 */ function takeRunSnapshot(){ return {v:1,mode:"endless",diff:G.diff,ship:G.ship, wave:G.wave,score:Math.round(G.score),coins:Math.round(G.coins),kills:G.kills, level:G.level,xp:Math.round(G.xp),xpNeed:G.xpNeed,luck:G.luck, weapons:Object.assign({},G.weapons),loadout:G.loadout.slice(), subs:Object.assign({},G.subs),subLoadout:G.subLoadout.slice(), drones:Object.assign({},G.drones),droneLoadout:G.droneLoadout.slice(), u:Object.assign({},G.u), lives:G.lives,maxHp:G.maxHp,hp:Math.round(G.hp), shield:G.shield,od:Math.round(G.od), bossN:G.bossN,bossKills:G.bossKills||0,time:G.time}; } /* startWave 开头调用:仅无尽模式实战(演示/主页模拟/未登录跳过) */ function maybeSaveRun(){ if(!G||G.mode!=="endless"||G.demoSim)return; if(typeof NET==="undefined"||!NET.user)return; NET.saveRunSnapshot(takeRunSnapshot()); } /* 出击页:拉取云端存档并渲染“继续对局”卡片 */ async function refreshRunSave(){ if(typeof NET==="undefined"||!NET.user){buildResumeSlot();return;} await NET.fetchRunSave(); buildResumeSlot(); } function buildResumeSlot(){ const box=$("resume-slot");if(!box)return;box.innerHTML=""; const s=typeof NET!=="undefined"?NET.runSave:null; if(!s||!NET.user)return; const d=document.createElement("div");d.className="panel"; d.style.cssText="border-color:var(--gold);margin-bottom:8px;padding:8px 10px"; d.innerHTML=`
⏸ 未完成的无尽对局
WAVE ${s.wave} · ${s.diff?"困难":"普通"} · 得分 ${s.score} · ${SHIPS[s.ship]?SHIPS[s.ship].name:"猎鹰"}
`; const b=document.createElement("button"); b.className="btn primary";b.style.minWidth="min(56vw,200px)"; b.textContent="▶ 继续对局"; b.onclick=()=>{SFX.pick();resumeSavedRun(s);}; d.appendChild(b);box.appendChild(d); } /* 从波次检查点重建对局:该波从头重打 */ function resumeSavedRun(s){ AU.init();if(AU.ctx&&AU.ctx.state==="suspended")AU.ctx.resume(); newRun("endless",s.ship,s.diff); G.score=s.score;G.coins=s.coins;G.kills=s.kills; G.level=s.level;G.xp=s.xp;G.xpNeed=s.xpNeed;G.luck=s.luck; G.weapons=Object.assign({},s.weapons);G.loadout=s.loadout.slice(); G.subs=Object.assign({},s.subs);G.subLoadout=s.subLoadout.slice(); G.drones=Object.assign({},s.drones);G.droneLoadout=s.droneLoadout.slice(); G.u=Object.assign({fire:0,crit:0,shield:0,nano:0,mag:0,bounty:0,odcore:0,ghost:0},s.u); G.lives=s.lives;G.maxHp=s.maxHp;G.hp=Math.min(s.hp,s.maxHp); G.shield=Math.min(s.shield,shieldCap());G.od=s.od; G.bossN=s.bossN;G.bossKills=s.bossKills;G.time=s.time; G.wave=s.wave-1; // startWave 会 ++ 回这一波:整波重打,Boss波则重抽Boss(bossN未预增,不偏移) UI="play";show("");acc=0; MUS.start(false); banner("继续对局 — WAVE "+s.wave,"#41e6ff",130); startWave(); } /* 结算未完成对局:星币入账+本地纪录+排行榜上报,返回删除云档的 Promise */ function settleSavedRun(s){ SAVE.coins+=s.coins; SAVE.best["e"+s.diff]=Math.max(SAVE.best["e"+s.diff]||0,s.score); persist(); if(typeof NET!=="undefined"&&NET.user){ NET.submitRun({mode:"endless",diff:s.diff,score:s.score,wave:s.wave,stage:1, timeSec:Math.round((s.time||0)/60),bossKills:s.bossKills||0,win:false, codex:Object.keys(SAVE.codex)}); return NET.deleteRunSave(); } return Promise.resolve(); } /* “将直接结算未完成的对局”确认弹窗 */ function showUnsaved(s){ $("unsaved-info").innerHTML= `抵达波次WAVE ${s.wave} 难度${s.diff?"困难":"普通"} 当前得分${s.score} 持有星币✦ ${s.coins}`; show("o-unsaved"); } $("b-settle-go").onclick=async()=>{ // 结算旧档(等删除完成再开新局,防队列外竞态已由 NET 队列兜底) const s=typeof NET!=="undefined"?NET.runSave:null; if(s)await settleSavedRun(s); startGame(); }; $("b-unsaved-resume").onclick=()=>{ const s=typeof NET!=="undefined"?NET.runSave:null; if(s)resumeSavedRun(s);else show("o-setup"); }; $("b-unsaved-cancel").onclick=()=>show("o-setup"); if("ontouchstart" in window){const pb=$("tb-pause");pb.style.display="block";pb.onclick=()=>togglePause();} $("b-resume").onclick=()=>togglePause(); $("b-restart").onclick=()=>{show("");restartSameRun();}; /* 暂时退出:无尽模式且已有云端断点存档时【不结算】——星币/分数留在波次快照里,回基地可续玩;其余情况照旧结算 */ $("b-quit").onclick=()=>{ const keep=G&&G.mode==="endless"&&!G.demoSim&&typeof NET!=="undefined"&&NET.user&&NET.runSave; if(!keep)bank(); G=null;MUS.stop();UI="title";bestLine();show("o-title"); }; /* 再来一局:按刚结束那一局自己的 mode/ship/diff 重开(修复 SETUP 漂移导致进错模式,如 rush/闯关死后进了无尽) */ function restartSameRun(){ if(!G){startGame();return;} if(G.mode==="rush"){startRush(G.rushIdx);return;} SETUP.mode=G.mode;SETUP.ship=G.ship;SETUP.diff=G.diff; startGame(); } $("b-again").onclick=()=>restartSameRun(); $("b-home").onclick=()=>{G=null;UI="title";bestLine();show("o-title");}; $("mode-pick").addEventListener("click",e=>{ const c=e.target.closest(".pcard");if(!c)return; SETUP.mode=c.dataset.m; for(const el of $("mode-pick").children)el.classList.toggle("sel",el===c); }); $("diff-pick").addEventListener("click",e=>{ const b=e.target.closest("button");if(!b)return; SETUP.diff=+b.dataset.d; for(const el of $("diff-pick").children)el.classList.toggle("primary",el===b); }); /* 机体选择/购买(机库内):购买后整店刷新(星币/按钮态变化),选择只刷新机体卡 */ function buildShips(){ const box=$("ship-pick");box.innerHTML=""; for(const k in SHIPS){ const s=SHIPS[k],owned=SAVE.ships.includes(k); const d=document.createElement("div"); d.className="pcard"+(owned?"":" lock")+(SETUP.ship===k?" sel":""); const c=document.createElement("canvas");c.width=52;c.height=64; const g=c.getContext("2d");g.imageSmoothingEnabled=false; const spr=SPR[s.spr];g.drawImage(spr,(52-spr.width*3)/2,(64-spr.height*3)/2,spr.width*3,spr.height*3); d.appendChild(c); d.insertAdjacentHTML("beforeend",`
${s.name}
${s.trait}
`+(owned?"":`
✦ ${s.cost} 解锁
`)); d.onclick=()=>{ if(!SAVE.ships.includes(k)){ if(SAVE.coins>=s.cost){SAVE.coins-=s.cost;SAVE.ships.push(k);persist();SFX.level();buildShop();} else SFX.hurt(); return; } SETUP.ship=k;persist();buildShips(); // persist 触发云端同步选中机体 }; box.appendChild(d); } } /* ================= 机库商店 ================= */ const META=[ {key:"weapon",name:"主武器校准",ds:"出击时主武器等级 +1",max:2,costs:[300,800]}, {key:"armor",name:"强化装甲",ds:"出击时生命上限 +1",max:2,costs:[400,1000]}, {key:"hpup",name:"结构强化",ds:"出击时结构值 +15",max:2,costs:[250,700]}, {key:"luck",name:"幸运币",ds:"高品质强化概率提升",max:2,costs:[350,900]}, {key:"wallet",name:"收藏家协议",ds:"星币获取 +15%",max:3,costs:[300,800,2000]}, {key:"mag2",name:"引力透镜",ds:"拾取范围 +15%",max:2,costs:[200,600]}, {key:"odstart",name:"超频预载",ds:"出击时超频已充能 50%",max:1,costs:[500]} ]; function buildShop(){ $("wallet").textContent=SAVE.coins; buildShips(); const box=$("shop");box.innerHTML=""; for(const m of META){ const lv=SAVE.m[m.key]||0,maxed=lv>=m.max,cost=maxed?0:m.costs[lv]; const d=document.createElement("div");d.className="sitem"; d.innerHTML=`
${m.name}
${m.ds}
${"■".repeat(lv)}${"□".repeat(m.max-lv)}
`; if(!maxed)d.querySelector("button").onclick=()=>{ if(SAVE.coins{ const sec=document.createElement("div"); sec.innerHTML=`
${title}(${active.length}/${max})· 点击切换装备
`; const row=document.createElement("div"); for(const k in owned){ const d=document.createElement("span"); const on=active.includes(k); d.className="litem"+(on?" on":""); d.textContent=`${dict[k].name} Lv${owned[k]}`; d.onclick=()=>{ const i=active.indexOf(k); if(i>=0){if(active===G.loadout&&active.length===1){SFX.hurt();return;}active.splice(i,1);} else{if(active.length>=max){SFX.hurt();return;}active.push(k);} SFX.pick();buildLoadoutUI(); }; row.appendChild(d); } if(Object.keys(owned).length===0)row.innerHTML='尚未获得'; sec.appendChild(row);box.appendChild(sec); }; mk("主武器",WEAPONS,G.weapons,G.loadout,5); mk("副武器",SUBS,G.subs,G.subLoadout,5); mk("僚机",DRONES,G.drones,G.droneLoadout,3); } /* ================= 图鉴 ================= */ function iconCanvas(img,size,sil){ const c=document.createElement("canvas");c.width=c.height=size; const g=c.getContext("2d");g.imageSmoothingEnabled=false; const sc=Math.min(size/img.width,size/img.height); g.drawImage(img,(size-img.width*sc)/2,(size-img.height*sc)/2,img.width*sc,img.height*sc); if(sil){g.globalCompositeOperation="source-atop";g.fillStyle="#232f52";g.fillRect(0,0,size,size);g.globalCompositeOperation="source-over";} return c; } function buildCodex(){ const box=$("codex");box.innerHTML=""; const total=MAINS.length+SUB_KEYS.length+DRONE_KEYS.length+PAS_KEYS.length; $("codex-t").textContent=total; $("codex-n").textContent=codexCount(); // 计数永远显示真实收集数,测试模式不影响 $("codex-test").style.display=codexTestAll?"":"none"; $("cx-secret").style.color=codexTestAll?"var(--gold)":""; // 开启后“军”字变金 const mk=(title,keys,dict,kind)=>{ const h=document.createElement("div");h.className="cx-sec";h.textContent=title;box.appendChild(h); const grid=document.createElement("div");grid.className="cx-grid"; for(const k of keys){ const def=dict[k],owned=!!SAVE.codex[k]||codexTestAll; // 测试模式:全部可见可演示 const d=document.createElement("div"); d.className="cx-item"+(owned?"":" lock"); // 未收集:剪影+???,不可演示 const img=def.icon?ICONS[def.icon]:SPR[def.spr]; d.appendChild(iconCanvas(img,28,!owned)); d.insertAdjacentHTML("beforeend",`
${owned?def.name:"???"}
`); if(owned)d.onclick=()=>{SFX.pick();startDemoSim(kind,k);}; grid.appendChild(d); } box.appendChild(grid); }; mk("主武器",MAINS,WEAPONS,"m"); mk("副武器",SUB_KEYS,SUBS,"s"); mk("僚机",DRONE_KEYS,DRONES,"d"); mk("被动强化",PAS_KEYS,PASSIVES,"p"); } document.addEventListener("visibilitychange",()=>{if(document.hidden&&UI==="play")togglePause();}); function bank(){ if(!G||G.banked)return;G.banked=true; SAVE.coins+=G.coins; if(G.mode!=="rush"){const bk=(G.mode==="endless"?"e":"s")+G.diff; SAVE.best[bk]=Math.max(SAVE.best[bk]||0,G.score);} persist(); } /* ---- Boss 挑战模式 ---- */ function buildRush(){ G=null; // 清掉上一局残留(rush胜利后G仍在),防背景卡残影 SAVE.rush=SAVE.rush||{}; const ra=$("rush-anim"); // 老虎机开关(持久化) if(ra){ra.checked=!!SAVE.rushAnim;ra.onchange=()=>{SAVE.rushAnim=ra.checked?1:0;persist();};} const el=$("rush-pick");el.innerHTML=""; BOSSES.forEach((b,i)=>{ const best=SAVE.rush[i]; const d=document.createElement("div");d.className="pcard"; d.innerHTML=`
${b.name}${best?" ✓":""}
${b.sub}
${best?("最快 "+Math.floor(best/60)+":"+("0"+best%60).slice(-2)):"未击破"}
`; d.onclick=()=>startRush(i); el.appendChild(d); }); } function rollRushBuild(){ // 随机武装:3主武Lv3 + 3副武Lv3 + 2僚机Lv2 const sh=a=>{const x=a.slice();for(let i=x.length-1;i>0;i--){const j=rndi(0,i),t2=x[i];x[i]=x[j];x[j]=t2;}return x;}; return {m:sh(Object.keys(WEAPONS)).slice(0,3),s:sh(Object.keys(SUBS)).slice(0,3),d:sh(Object.keys(DRONES)).slice(0,2)}; } function startRush(i){ AU.init();if(AU.ctx&&AU.ctx.state==="suspended")AU.ctx.resume(); const build=rollRushBuild(); if(SAVE.rushAnim)playSlot(build,()=>startRushGo(i,build)); // 老虎机动画抽取 else startRushGo(i,build); // 直接随机 } function startRushGo(i,build){ newRun("rush","falcon",0); G.weapons={};build.m.forEach(k=>G.weapons[k]=3);G.loadout=build.m.slice(); G.subs={};build.s.forEach(k=>G.subs[k]=3);G.subLoadout=build.s.slice(); G.drones={};build.d.forEach(k=>G.drones[k]=2);G.droneLoadout=build.d.slice(); G.xpNeed=1e9; // 挑战模式无升级打断 G.rushIdx=i;G.rushT0=0; UI="play";show("");acc=0; MUS.start(true); banner("BOSS 挑战 — "+BOSSES[i].name,"#ff5566",130); G.rushT0=G.time; startBoss(); } /* ---- 老虎机抽奖动画 ---- */ let slotTimers=[]; function playSlot(build,cb){ UI="slot";show("o-slot"); const row=$("slot-row");row.innerHTML=""; $("slot-hint").textContent=" "; const items=[ ...build.m.map(k=>({cat:"主武器",pool:WEAPONS,key:k})), ...build.s.map(k=>({cat:"副武器",pool:SUBS,key:k})), ...build.d.map(k=>({cat:"僚机",pool:DRONES,key:k}))]; let done=0; items.forEach((it,idx)=>{ const d=document.createElement("div");d.className="slotbox"; d.innerHTML=`
${it.cat}
???
`; row.appendChild(d); const sn=d.querySelector(".sn"),names=Object.values(it.pool).map(x=>x.name); const iv=setInterval(()=>{sn.textContent=names[rndi(0,names.length-1)];},60); slotTimers.push(iv); setTimeout(()=>{clearInterval(iv); sn.textContent=it.pool[it.key].name;sn.classList.add("hit"); SFX.graze();done++; if(done>=items.length){$("slot-hint").textContent="— 出击 —";setTimeout(cb,700);} },700+idx*280); }); } /* 结算上报服务端(每局一次,含rush胜利;图鉴演示除外) */ function submitRun(win){ if(!G||G.submitted||G.demoSim)return; G.submitted=true; if(typeof NET==="undefined"||!NET.user)return; NET.submitRun({mode:G.mode,diff:G.diff,score:G.score,wave:G.wave,stage:G.stage, timeSec:Math.round(G.time/60),bossKills:G.bossKills||0,win:!!win, codex:Object.keys(SAVE.codex)}); // 注意:不上报 localStorage 历史最高分(SAVE.best 是浏览器级共享,会串号) } function endRun(win){ if(UI==="over")return; bank();MUS.stop(); submitRun(win); if(G.mode==="endless"&&typeof NET!=="undefined"&&NET.user)NET.deleteRunSave(); // 对局真正结束:清除云端断点存档 UI="over"; $("over-title").textContent=win?"★ 任务完成 ★":"任务失败"; $("over-title").style.color=win?"#ffcf5c":"#ff5566"; const mins=Math.floor(G.time/3600),secs=Math.floor(G.time/60)%60; $("over-stats").innerHTML= `最终得分${G.score} ${G.mode==="endless"?"抵达波次":G.mode==="rush"?"挑战目标":"抵达关卡"}${G.mode==="endless"?G.wave:G.mode==="rush"?BOSSES[G.rushIdx].name:G.stage+"-"+G.wave} 击坠数${G.kills} 强化等级Lv.${G.level} 存活时间${mins}分${secs}秒 持有军械${Object.keys(G.weapons).length}主/${Object.keys(G.subs).length}副/${Object.keys(G.drones).length}机`; $("over-coins").textContent=G.coins; setTimeout(()=>show("o-over"),win?400:900); } /* ================= 三选一卡片 ================= */ function offerCards(bossRare){ if(!G||G.p.dead>0&&!bossRare)return; G.bossCard=!!bossRare; const opts=rollCards(bossRare); G.cardOpts=opts; const box=$("cards");box.innerHTML=""; opts.forEach((c,i)=>{ let nm,ds,rare,img; if(c.kind==="wlvl"){const w=WEAPONS[c.key],lv=G.weapons[c.key];nm=w.name;rare=w.rare;ds=`主武器强化 Lv.${lv} → Lv.${lv+1}`;img=w.icon?ICONS[w.icon]:SPR[w.spr];} else if(c.kind==="weapon"){const w=WEAPONS[c.key];nm="主武器·"+w.name;rare=w.rare;ds=w.ds;img=w.icon?ICONS[w.icon]:SPR[w.spr];} else if(c.kind==="slvl"){const u=SUBS[c.key],lv=G.subs[c.key];nm=u.name;rare=u.rare;ds=`副武器强化 Lv.${lv} → Lv.${lv+1}`;img=u.icon?ICONS[u.icon]:SPR[u.spr];} else if(c.kind==="sub"){const u=SUBS[c.key];nm="副武器·"+u.name;rare=u.rare;ds=typeof u.ds==="function"?u.ds(0):u.ds;img=u.icon?ICONS[u.icon]:SPR[u.spr];} else if(c.kind==="dlvl"){const u=DRONES[c.key],lv=G.drones[c.key];nm=u.name;rare=u.rare;ds=`僚机强化 Lv.${lv} → Lv.${lv+1}`;img=SPR[u.spr];} else if(c.kind==="drone"){const u=DRONES[c.key];nm="僚机·"+u.name;rare=u.rare;ds=typeof u.ds==="function"?u.ds(0):u.ds;img=SPR[u.spr];} else if(c.kind==="upg"){const u=PASSIVES[c.key];nm=u.name;rare=u.rare;ds=u.ds(G.u[c.key]);img=u.icon?ICONS[u.icon]:SPR[u.spr];} else{rare=0; if(c.key==="heal"){nm="紧急修复";ds="生命 +1";img=SPR.heart;} else if(c.key==="coins"){nm="星币补给";ds="星币 +50";img=SPR.coin;} else{nm="超频充能";ds="超频立即充满";img=SPR.odc;}} const d=document.createElement("div"); d.className="ucard r"+rare; const cv2=document.createElement("canvas");cv2.width=40;cv2.height=40; const g=cv2.getContext("2d");g.imageSmoothingEnabled=false; const sc=Math.min(40/img.width,40/img.height); g.drawImage(img,(40-img.width*sc)/2,(40-img.height*sc)/2,img.width*sc,img.height*sc); d.appendChild(cv2); d.insertAdjacentHTML("beforeend", `
${i+1}
${nm}
${["普通","稀有","史诗"][rare]}
${ds}
`); d.onclick=()=>pickCard(i); box.appendChild(d); }); UI="cards";show("o-cards");SFX.level(); } function pickCard(i){ if(UI!=="cards"||!G.cardOpts||!G.cardOpts[i])return; const c=G.cardOpts[i];G.cardOpts=null; if(c.kind==="wlvl")G.weapons[c.key]++; else if(c.kind==="weapon"){G.weapons[c.key]=1;if(G.loadout.length<5)G.loadout.push(c.key);banner("获得 "+WEAPONS[c.key].name,"#b98cff",80);} else if(c.kind==="slvl")G.subs[c.key]++; else if(c.kind==="sub"){G.subs[c.key]=1;if(G.subLoadout.length<5)G.subLoadout.push(c.key);banner("获得 "+SUBS[c.key].name,"#b98cff",80);} else if(c.kind==="dlvl")G.drones[c.key]++; else if(c.kind==="drone"){G.drones[c.key]=1;if(G.droneLoadout.length<3)G.droneLoadout.push(c.key);banner("获得 "+DRONES[c.key].name,"#b98cff",80);} else if(c.kind==="upg"){ G.u[c.key]++; if(c.key==="nano"){G.maxHp+=25;G.hp=Math.min(G.maxHp,G.hp+40);} if(c.key==="shield")G.shield=Math.min(shieldCap(),G.shield+1); }else{ if(c.key==="heal")G.lives=Math.min(G.stat.maxLives,G.lives+1); if(c.key==="coins")addCoins(50); if(c.key==="od")G.od=100; } if(c.key&&c.kind!=="fill"){SAVE.codex[c.key]=true;persist();} // 图鉴收录 SFX.pick(); if(G.bossCard){G.bossCard=false;UI="play";show("");} else{G.cardQ=(G.cardQ||1)-1; if(G.cardQ>0)offerCards(false); else{UI="play";show("");}} } /* ================= 图鉴:全屏实战模拟 ================= 复用真实战斗引擎:只装备选定军械,杂兵+射手+精英持续来袭 */ function startDemoSim(kind,key){ const def=kind==="m"?WEAPONS[key]:kind==="s"?SUBS[key]:kind==="p"?PASSIVES[key]:DRONES[key]; newRun("stage","falcon",0); G.p.inv=0; // 图鉴演示:取消出生保护闪烁 const lv=3; G.demoSim={kind,key}; if(kind==="m"){G.weapons={};G.weapons[key]=lv;G.loadout=[key];} else if(kind==="s"){G.weapons={vulcan:1};G.loadout=["vulcan"];G.subs={};G.subs[key]=lv;G.subLoadout=[key];} else if(kind==="d"){G.weapons={};G.loadout=[];G.drones={};G.drones[key]=lv;G.droneLoadout=[key];} else{G.weapons={vulcan:2};G.loadout=["vulcan"];G.u[key]=3; if(key==="nano"){G.maxHp+=75;G.hp=G.maxHp;} if(key==="shield")G.shield=shieldCap();} $("demo-name").textContent=def.name; const ds=typeof def.ds==="function"?def.ds(lv):def.ds; $("demo-ds").textContent=ds; // 只显示介绍本身,单行不折行(nowrap 在 index.html 上) UI="demoSim";show("o-demo");acc=0; banner(def.name,"#41e6ff",90); } function exitDemoSim(){G=null;UI="codex";buildCodex();show("o-codex");} function demoSpawn(){ const D=G.demoSim; D.t=(D.t||0)-1; if(D.t>0||G.enemies.length>=10)return; D.t=Math.max(30,52-Math.floor(G.time/900)); // 渐进增密 const r=Math.random(); if(r<0.5)spawnEnemy(pick(["scout","scout","weaver","kami"]),rnd(20,W-20),-12,false); // 杂兵为主 else if(r<0.84)spawnEnemy(pick(["gunship","splitter","sniper","mine"]),rnd(20,W-20),-12,false); // 射手少数 else spawnEnemy(pick(["gunship","weaver","splitter"]),rnd(20,W-20),-12,true); // 精英 } bestLine();