improvements Cyst_Kid

This commit is contained in:
verboomp
2026-04-16 17:20:19 +02:00
parent 9cc8ac8cad
commit feed1c9c40
11 changed files with 271 additions and 155 deletions

View File

@@ -12,9 +12,7 @@ constructor(){
this.lv=1;this.lives=3;this.sc=0;this.lsc=0;
this.lt=0;this.ld=0;this.tt=0;this.td=0;
this.dots=[];this.nDots=0;this.eDots=0;
this.pl=null;this.pains=[];this.cysts=[];this.bios=[];
this.ateSt=false;this.ateBi=false;this.combD=0;this.combN=1;
this.sup=false;this.supT=0;
this.pl=null;this.pains=[];
this.fx=[];this.fr=0;this.lastT=0;this.acc=0;
// Input
this.ks={up:false,down:false,left:false,right:false,shift:false};
@@ -33,6 +31,7 @@ _rsz(){
// ---------- INPUT ----------
_inp(){
window.addEventListener('keydown',e=>{
if(e.target.tagName==='INPUT')return;
let h=true;
switch(e.code){
case'ArrowUp':case'KeyW':this.ks.up=true;break;
@@ -143,16 +142,19 @@ _dir(){
_ui(){
document.getElementById('startBtn').onclick=()=>{this.snd.init();this._start()};
document.getElementById('nextLevelBtn').onclick=()=>this._ent();
document.getElementById('restartBtn').onclick=()=>{this.sc=0;this._start()};
document.getElementById('restartBtn').onclick=()=>{this.sc=0;this._ov('start')};
document.getElementById('submitScoreBtn').onclick=()=>this._sub();
document.getElementById('playAgainBtn').onclick=()=>this._ov('start');
document.getElementById('playAgainBtn').onclick=()=>{this.sc=0;this._ov('start')};
document.getElementById('go-submitScoreBtn').onclick=()=>this._subGO();
document.getElementById('playerName').addEventListener('keydown',e=>{if(e.key==='Enter'){e.stopPropagation();this._sub()}});
document.getElementById('go-playerName').addEventListener('keydown',e=>{if(e.key==='Enter'){e.stopPropagation();this._subGO()}});
}
_esc(){if(this.state==='playing'){this.sc=0;this.lsc=0;this.state='start';this._ov('start')}}
_ent(){
if(this.state==='lvlDone'){this.lv++;this._init();this.state='playing';this._ov(null)}
else if(this.state==='over'){this.sc=0;this._start()}
else if(this.state==='over'||this.state==='win'){this.sc=0;this._ov('start')}
else if(this.state==='start'){this.snd.init();this._start()}
}
@@ -168,10 +170,13 @@ _ov(n){
// ---------- LIFECYCLE ----------
_init(){
this.dots=[];this.nDots=0;this.eDots=0;
this.meds=MED_SPAWNS.map(sp=>({r:sp.r,c:sp.c,eaten:true,pulse:0,respT:0}));
for(let r=0;r<ROWS;r++)for(let c=0;c<COLS;c++)if(MAP[r][c]===0){this.dots.push({r,c,e:false});this.nDots++}
this.lsc=0;this.lt=0;this.ld=0;this.sup=false;this.supT=0;
this.ateSt=false;this.ateBi=false;this.combD=0;this.combN=this.lv;
this.fx=[];this.lives=3;this.qDir=null;
this.lsc=0;this.lt=0;this.ld=0;
this.fx=[];this.lives=LIVES;this.qDir=null;
this.hasMed=false;this.patient=null;
this.challActive=false;this.challTimer=0;this.challGhostIdx=-1;
this.nextChallIn=(FPS*(CHALL_FIRST_MIN+Math.random()*(CHALL_FIRST_MAX-CHALL_FIRST_MIN)))|0;
this.pl={
x:PL0.c*TILE, y:PL0.r*TILE+HUD_TOP,
@@ -187,23 +192,16 @@ _init(){
x:h.c*TILE, y:h.r*TILE+HUD_TOP,
gc:h.c, gr:h.r,
dir:'up', moving:false,
spd:1.2+this.lv*0.2,
strat:st[i], scared:false, eaten:false,
spd:GHOST_SPD_BASE+this.lv*GHOST_SPD_LEVEL,
strat:st[i], scared:false, eaten:i>=2,
inHouse:true, leaving:false,
relT:i*80+50,
relT:i<2?i*GHOST_REL_INTERVAL+GHOST_REL_OFFSET:999999,
dormant:i>=2,
pulse:Math.random()*6.28
}));
this.cysts=[];
this._rp(this.lv,1,8).forEach(p=>this.cysts.push({r:p.r,c:p.c,e:false,v:true}));
this.bios=[];
}
_rp(n,mr,xr){
const cs=[];for(let r=mr;r<=xr;r++)for(let c=1;c<COLS-1;c++)if(isPath(r,c))cs.push({r,c});
for(let i=cs.length-1;i>0;i--){const j=0|Math.random()*(i+1);[cs[i],cs[j]]=[cs[j],cs[i]]}
const o=[];for(const p of cs){if(o.length>=n)break;if(o.every(q=>Math.abs(q.r-p.r)+Math.abs(q.c-p.c)>=4))o.push(p)}return o;
}
// -------- MAIN LOOP --------
_loop(ts){
@@ -219,15 +217,16 @@ _upd(){
const liveDir=this._dir();
if(liveDir) this.qDir=liveDir;
const wantDir=this.qDir;
const base=BASE_SPD+(this.lv-1)*0.2;
const base=BASE_SPD+(this.lv-1)*GHOST_SPD_LEVEL;
const gp=this._gp();
const sprint=this.ks.shift||(gp.sprint||false);
this.pl.spd=this.sup?base*2:(sprint?base*2:base);
this.pl.spd=this.sup?base*SPEED_MULT:(sprint?base*SPEED_MULT:base);
this._movePl(wantDir);
this._movePains();
this._coll();
if(this.sup){this.supT--;if(this.supT<=0)this._esup()}
this._tickMeds();
this._tickChall();
this.fx=this.fx.filter(f=>{f.t--;return f.t>0});
this._chkDone();
}
@@ -236,9 +235,8 @@ _upd(){
_coll(){
for(const p of this.pains){
if(p.eaten||p.inHouse||p.leaving)continue;
if(Math.abs(this.pl.x-p.x)+Math.abs(this.pl.y-p.y)<TILE*.8){
if(this.sup&&p.scared){p.eaten=true;this.lsc+=5;this.snd.bite();this.fx.push({x:p.x+TILE/2,y:p.y+TILE/2,co:'#00ff88',t:20,mx:20,tp:'burst'})}
else if(!this.sup){this._die();return}
if(Math.abs(this.pl.x-p.x)+Math.abs(this.pl.y-p.y)<TILE*COLL_DIST){
this._die();return;
}
}
}
@@ -246,18 +244,77 @@ _coll(){
_die(){
this.lives--;this.snd.boom();
this.fx.push({x:this.pl.x+TILE/2,y:this.pl.y+TILE/2,co:'#FF4444',t:40,mx:40,tp:'exp'});
if(this.lives<=0){this.lsc=0;this.state='over';this.snd.over();setTimeout(()=>this._ov('over'),600)}
if(this.lives<=0){this.sc+=this.lsc;this.lsc=0;this.state='over';this.snd.over();setTimeout(()=>this._ov('over'),600)}
else{
this.pl.x=PL0.c*TILE;this.pl.y=PL0.r*TILE+HUD_TOP;this.pl.gc=PL0.c;this.pl.gr=PL0.r;this.pl.dir='right';this.pl.moving=false;
this.qDir=null;this.swD=null;this.ks.up=this.ks.down=this.ks.left=this.ks.right=false;
PH.forEach((h,i)=>{const p=this.pains[i];p.x=h.c*TILE;p.y=h.r*TILE+HUD_TOP;p.gc=h.c;p.gr=h.r;p.inHouse=true;p.leaving=false;p.eaten=false;p.relT=i*90+60;p.moving=false});
PH.forEach((h,i)=>{const p=this.pains[i];
if(p.dormant){p.inHouse=true;p.leaving=false;p.eaten=true;p.relT=999999;p.moving=false;return}
p.x=h.c*TILE;p.y=h.r*TILE+HUD_TOP;p.gc=h.c;p.gr=h.r;p.inHouse=true;p.leaving=false;p.eaten=false;p.relT=i*GHOST_REL_INTERVAL+GHOST_REL_OFFSET;p.moving=false});
this._endChall();
}
}
_tickMeds(){
for(const m of this.meds){
if(m.eaten){if(m.respT>0&&--m.respT<=0){m.eaten=false;m.pulse=0}}
else{m.pulse+=0.08}
}
}
_tickChall(){
if(!this.challActive){if(--this.nextChallIn<=0)this._startChall()}
else{if(--this.challTimer<=0)this._failChall()}
}
_startChall(){
if(!MED_SPAWNS||!MED_SPAWNS.length)return;
const gi=this.pains.findIndex(p=>p.dormant);
if(gi<0)return;
// pick patient position, far from player
const cells=[];
for(let r=1;r<ROWS-1;r++)for(let c=1;c<COLS-1;c++)
if(isPath(r,c)&&Math.abs(r-this.pl.gr)+Math.abs(c-this.pl.gc)>5)cells.push({r,c});
if(!cells.length)return;
const pc=cells[0|Math.random()*cells.length];
// activate a random med spawn
const avail=this.meds.filter(m=>m.eaten);
if(!avail.length)return;
const med=avail[0|Math.random()*avail.length];
med.eaten=false;med.pulse=0;
// activate ghost
const g=this.pains[gi];
g.dormant=false;g.inHouse=true;g.leaving=false;g.eaten=false;
g.relT=FPS*CHALL_DURATION;
this.patient={r:pc.r,c:pc.c};
this.challActive=true;this.challTimer=FPS*CHALL_DURATION;this.challGhostIdx=gi;
}
_succChall(){
const g=this.pains[this.challGhostIdx];
this.fx.push({x:g.x+TILE/2,y:g.y+TILE/2,co:'#00ff88',t:40,mx:40,tp:'burst'});
g.eaten=true;g.dormant=true;g.inHouse=true;g.leaving=false;g.relT=999999;
this.lsc+=SC_CHALL;this.snd.laser();
this._endChall();
}
_failChall(){
if(this.challGhostIdx>=0)this.pains[this.challGhostIdx].relT=0;
this._endChall();
}
_endChall(){
this.meds.filter(m=>!m.eaten).forEach(m=>{m.eaten=true;});
this.patient=null;
this.challActive=false;this.challTimer=0;this.challGhostIdx=-1;
this.hasMed=false;
this.nextChallIn=(FPS*(CHALL_NEXT_MIN+Math.random()*(CHALL_NEXT_MAX-CHALL_NEXT_MIN)))|0;
}
_chkDone(){
if(this.eDots>=this.nDots&&this.cysts.every(c=>c.e)&&this.combD>=this.combN){
this.sc+=this.lsc;this.tt+=this.lt;this.td+=this.ld;this.snd.lvlUp();
if(this.lv>=3){this.state='win';setTimeout(()=>this._ov('win'),800)}
if(this.eDots>=this.nDots){
this.sc+=this.lsc;this.lsc=0;this.tt+=this.lt;this.td+=this.ld;this.snd.lvlUp();
if(this.lv>=WIN_LEVEL){this.state='win';setTimeout(()=>this._ov('win'),800)}
else{this.state='lvlDone';setTimeout(()=>this._ov('lvlDone'),800)}
}
}