①图鉴隐藏测试模式:连点标题'军'字10次开关,纯内存标志位全部军械可见可演示,不动SAVE.codex(persist/submitRun读它,动了会污染后端),刷新失效 ②24件主武器说明文案全部替换(用户提供梗文案);演示页介绍单行显示、去掉类别前缀、删'实战模拟·自动驾驶'提示行 ③新主武器'巡飞弹'(loiter):慢攻速追踪导弹(制导引擎新增maxSpd上限5保持中速),命中留火场(zones新kind:fire纯粒子火舌,无圆形区域)+分裂4枚小炸弹快爆;新精灵loms;CODEX_KEYS同步63 ④存档云同步:星币/机体/选中机体/永久强化/本地纪录上服务端(player_state表+POST /api/state+vState白名单清洗);login/me/register响应带state;客户端persist()钩子防抖600ms自动上传;服务端整体替换本地防串号,登出全清;老账号首登自动上传本地存档迁移 ⑤机体选择/购买从出击准备并入机库强化(buildShips);出击默认无尽模式 服务端已重启生效;/api/state全链路在独立测试库curl验证通过(合法推送/回读/非法拦截清洗/401)
53 lines
2.6 KiB
JavaScript
53 lines
2.6 KiB
JavaScript
"use strict";
|
||
/* ================================================================
|
||
星尘突击队 STAR RAID —— 像素肉鸽竖版射击
|
||
单文件实现:像素引擎 / 程序化音频 / 双模式 / 局内外成长
|
||
================================================================ */
|
||
|
||
/* ---------------- 工具 ---------------- */
|
||
const $=id=>document.getElementById(id);
|
||
const clamp=(v,a,b)=>v<a?a:v>b?b:v;
|
||
const lerp=(a,b,t)=>a+(b-a)*t;
|
||
const rnd=(a=1,b)=>b===undefined?Math.random()*a:a+Math.random()*(b-a);
|
||
const rndi=(a,b)=>Math.floor(rnd(a,b+1));
|
||
const pick=arr=>arr[Math.floor(Math.random()*arr.length)];
|
||
const TAU=Math.PI*2;
|
||
function shuffle(a){for(let i=a.length-1;i>0;i--){const j=Math.floor(Math.random()*(i+1));[a[i],a[j]]=[a[j],a[i]];}return a;}
|
||
const dist2=(ax,ay,bx,by)=>{const dx=ax-bx,dy=ay-by;return dx*dx+dy*dy;};
|
||
|
||
/* ---------------- 存档 ---------------- */
|
||
const SAVE_KEY="starraid_v1";
|
||
let SAVE;
|
||
function loadSave(){
|
||
try{SAVE=JSON.parse(localStorage.getItem(SAVE_KEY))||null;}catch(e){SAVE=null;}
|
||
if(!SAVE) SAVE={coins:0, m:{}, ships:["falcon"], best:{s0:0,s1:0,e0:0,e1:0,stage:0}, mute:false, music:true};
|
||
SAVE.m=SAVE.m||{}; SAVE.ships=SAVE.ships||["falcon"]; SAVE.best=SAVE.best||{s0:0,s1:0,e0:0,e1:0,stage:0};
|
||
SAVE.codex=SAVE.codex||{};
|
||
}
|
||
function persist(){try{localStorage.setItem(SAVE_KEY,JSON.stringify(SAVE));}catch(e){}
|
||
if(typeof NET!=="undefined")NET.pushState();} // 登录态下云端同步(NET 内防抖;未登录自动跳过)
|
||
loadSave();
|
||
|
||
/* ---------------- 平衡数值总表 ----------------
|
||
所有概率与成长曲线集中于此,方便调平衡 */
|
||
const BAL={
|
||
player:{ speed:2.35, lives:3, hp:100, bombs:2, hitR:3, grazeR:14, focusMul:0.5,
|
||
fireInt:8, dmg:6, bulletSpd:5.4, critC:0.05, critM:2.5, magnetR:36 },
|
||
// 稀有度权重 [普通,稀有,史诗],每点幸运: 稀有+2 史诗+1.5
|
||
rarity:[62,28,10],
|
||
xpNeed:l=>Math.round(4+l*2.5+Math.pow(l,1.5)), // 升级所需经验(下调,保证每波≈1级)
|
||
// 波次缩放(n 从 0 起):平缓曲线,匹配玩家成长
|
||
hpMul: n=>1+0.10*n+0.012*Math.pow(n,1.5),
|
||
spdMul:n=>Math.max(0.6,1-0.015*n), // 血量越高波次,移动越慢
|
||
fireMul:n=>Math.min(1.3,1+0.012*n),
|
||
eliteC:n=>Math.min(0.16,0.03+n*0.006), // 精英出现率
|
||
coinDrop:0.5, // 普通敌掉币率
|
||
scoreCombo:k=>Math.min(3,1+k*0.02), // 连击倍率上限 x3
|
||
odGain:{kill:2.6,graze:2.2},
|
||
coinGlobal:4, // 全局金币倍率
|
||
bombDmg:80,
|
||
reviveInv:160,
|
||
hard:{hp:1.35,fire:1.3,coin:1.5}, // 困难修正
|
||
};
|
||
|