- Full manager sim: 28 orgs / 168 players, calendar, transfers, youth scouting, loans, training, board confidence - Simulation Mode with real-time micro-engine (live.js): A* pathfinding on map geometry, raycast ballistics (spread/falloff/armor/headshots), smokes/flashes/HE that matter, plant/defuse/retake AI, clutch detection - Canvas renderer (viz.js): follow/radar cameras, HP bars, CS2-style kill feed, callouts, synthesized Web-Audio SFX, speed x1-x3, AUTO-SPECTATE hands-free series playback - Round results flow from the firefight back into the career engine (score, economy, box score, MVP) - Playwright + Node VM test suites included (test/, plus external pwtest harness)
78 lines
2.6 KiB
JavaScript
78 lines
2.6 KiB
JavaScript
'use strict';
|
|
/* ================= bootstrap ================= */
|
|
const Main={
|
|
boot(){
|
|
const info=this.saveInfo();
|
|
if(info){
|
|
$('btnContinue').style.display='';
|
|
$('btnContinue').innerHTML=`▶ Continue — ${U.esc(info.tag)} · S${info.season} · ${info.date}`;
|
|
}
|
|
},
|
|
saveInfo(){
|
|
const ls=Save.store();if(!ls)return null;
|
|
try{
|
|
const g=JSON.parse(ls.getItem(SAVE_KEY));
|
|
if(!g||g.ver!==1)return null;
|
|
const t=g.teams[g.playerTeamId];
|
|
return {tag:t?t.tag:'?',season:g.season,date:U.fmtDate(g.day)};
|
|
}catch(e){return null;}
|
|
},
|
|
continueGame(){
|
|
if(Save.load()){
|
|
UI.show();
|
|
UI.toast('Career loaded — welcome back, GM.','good');
|
|
}else{
|
|
alert('Save data was corrupted. Start a new career.');
|
|
Save.wipe();
|
|
}
|
|
},
|
|
toTitle(){
|
|
Save.save(true);
|
|
$('gameShell').style.display='none';
|
|
$('simOverlay').style.display='none';
|
|
$('titleScreen').style.display='flex';
|
|
$('btnContinue').style.display=Save.exists()?'':'none';
|
|
SimSession.s=null;
|
|
},
|
|
exportSave(){
|
|
if(!G){alert('No career running.');return;}
|
|
const blob=new Blob([Game.serialize()],{type:'application/json'});
|
|
const a=document.createElement('a');
|
|
a.href=URL.createObjectURL(blob);
|
|
a.download=`csm26_${(G.teams[G.playerTeamId]?.tag||'save')}_S${G.season}_d${G.day}.json`;
|
|
a.click();URL.revokeObjectURL(a.href);
|
|
UI.toast('Save exported.','good');
|
|
},
|
|
importSave(){
|
|
const inp=document.createElement('input');
|
|
inp.type='file';inp.accept='.json,application/json';
|
|
inp.onchange=()=>{
|
|
const f=inp.files[0];if(!f)return;
|
|
const rd=new FileReader();
|
|
rd.onload=()=>{
|
|
try{
|
|
Game.staticLoad(String(rd.result));
|
|
Save.save(true);
|
|
UI.closeModal();
|
|
UI.show();
|
|
UI.toast('Save imported ✔','good');
|
|
}catch(e){alert('Invalid save file.');}
|
|
};
|
|
rd.readAsText(f);
|
|
};
|
|
inp.click();
|
|
},
|
|
};
|
|
window.addEventListener('DOMContentLoaded',()=>Main.boot());
|
|
window.addEventListener('visibilitychange',()=>{if(document.visibilityState==='hidden'&&G)Save.save(true);});
|
|
/* keyboard: Space/Enter = advance week · Esc = close modal */
|
|
window.addEventListener('keydown',e=>{
|
|
if(e.key==='Escape'){const m=$('modalBg');if(m){m.remove();return;}}
|
|
if(!G)return;
|
|
if(e.key!==' '&&e.key!=='Enter')return;
|
|
if($('modalBg')||$('simOverlay').style.display==='flex'||$('titleScreen').style.display==='flex')return;
|
|
if(['INPUT','SELECT','TEXTAREA','BUTTON'].includes(document.activeElement?.tagName))return;
|
|
e.preventDefault();
|
|
UI.advance();
|
|
});
|