Counter-Strike esports manager: career mode + LIVE tactical top-down simulation
- 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)
This commit is contained in:
+77
@@ -0,0 +1,77 @@
|
||||
'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();
|
||||
});
|
||||
Reference in New Issue
Block a user