public/index.html

分割 6 / 6 · 元ファイル 1019〜1094行付近

原文の連続部分です。長い圧縮行は行の途中で分割する場合があります。全分割を順に連結するとファイル全文になります。

    fn(dt); requestAnimationFrame(tick);
  }
  requestAnimationFrame(tick);
  document.addEventListener('visibilitychange',function(){
    if(document.hidden) on=false;
    else if(!on){ on=true; last=performance.now(); requestAnimationFrame(tick); }
  });
}
layout();
window.addEventListener('resize',function(){ layout(); });
loop(function(dt){ step(dt); if(RENDER) draw(); });

/* ===== 検品の口(tools/*.mjs から叩く。遊びには出てこない) ===== */
window.ZG={
  ver:VER,
  state:function(){ var p=myP(); return { mode:scr, scr:scr,
    kills:world.kills, throws:throws, stones:S.length, zombies:world.zs.length, crows:world.cs.length,
    players:world.ps.length, hp:p?Math.round(p.hp):0, base:p?p.base:0, mult:world.mult(),
    t:+world.t.toFixed(1), net:NET.mode, on:NET.on?1:0, room:NET.room, me:meId,
    rock:+rockLeft().toFixed(1), canSwap:world.canSwap()?1:0,
    W:W, H:H, ppm:L.ppm, floorY:L.floorY, hx:handX(), ry:handY(), px:MX(myX()),
    maxPull:L.maxPull, hr:L.hr, stoneR:L.stoneR, over:world.over?1:0,
    scrap:SAVE.scrap, result:result, wardrobe:[WR.COSTUMES.length,WR.HATS.length,WR.STONES.length] }; },
  start:function(net){ startGame(); if(net===false){ netStop(); NET.mode='off'; } },
  title:toTitle,
  offline:function(){ netStop(); NET.mode='off'; world.sim='full'; },
  freeze:function(b){ FREEZE=!!b; },
  render:function(b){ RENDER=b!==false; },
  clearZ:function(){ world.zs.length=0; world.cs.length=0; },
  spawn:function(m,spd){ world.spawnZ(m,spd==null?0:spd); return true; },
  spawnCrow:function(m,y){ var c=world.spawnC(); c.x=m; if(y!=null){ c.y=y; c.y0=y; } return true; },
  throwAt:function(a,pf){ ang=Math.max(14,Math.min(84,a)); pull=Math.max(0,Math.min(1,pf))*L.maxPull;
    cool=0; shoot(); },
  armRock:function(b){ var p=myP(); if(p) p.bT=0; rockArm=(b!==false); },
  swap:function(){ return world.canSwap()? (NET.on?(netSend({y:'swap'}),true):world.swap()) : false; },
  step:function(dt){ step(dt==null?1/60:dt); },
  last:function(){ return LASTEV; },
  can:function(){ return canThrow(); },
  zs:function(){
    var a=[];
    for(var i=0;i<world.zs.length;i++){ var z=world.zs[i]; if(z.dead) continue; var G=zGeo(z);
      a.push({ id:z.id, x:G.x, m:z.x, hy:G.hy, hr:G.hr, spd:z.spd, gr:z.gr?1:0 }); }
    a.sort(function(p,q){ return p.x-q.x; });
    return a;
  },
  /* 一番手前の1体へ、当たったことにして知らせる。石は飛ばさない。
     **本物と同じ道(claim)を通す**ので、2人で繋がっている時はサーバーへ出て返ってくる */
  hitNearest:function(kind){
    var b=null;
    for(var i=0;i<world.zs.length;i++){ var z=world.zs[i];
      if(!z.dead && (!b||z.x<b.x)) b=z; }
    if(!b) return false;
    claim(kind||'kill',b.id,zGeo(b));
    return true;
  },
  hurt:function(n){ var p=myP(); if(p){ p.hp-=n; if(p.hp<=0){ p.hp=0; p.alive=false; } } },
  /* 1回だけ撃って何が起きたかを返す(大根おろし検査) */
  trial:function(distM,a,pf,rock){
    scr='play'; FREEZE=true; netStop(); NET.on=false; NET.mode='off';
    world=new ZWORLD.World({sim:'full'}); meId='solo';
    world.addPlayer(meId,SAVE.av,SAVE.eq); world.ev.length=0;
    S.length=0; P.length=0; FL.length=0; LASTEV=''; LASTB=0; cool=0; acc=0;
    world.spawnZ(world.xOf(meId)+distM,0);
    rockArm=!!rock; if(rock) world.find(meId).bT=0;
    this.throwAt(a,pf);
    for(var i=0;i<700;i++){ step(1/60); if(LASTEV) break; if(!S.length) break; }
    FREEZE=false; rockArm=false;
    return { r:LASTEV||'miss', b:LASTB };
  }
};
</script>
<!-- 🐛報告の箱だけ相続する。fps/メモリの計器板は盤面に被るので既定で消す -->
<script>window.SETTINGS={memMeter:false};</script>
<script src="dev_tools.js?v=20260906a"></script>
</body>
</html>