Files
kaltaquise-gamification/sde/js/render.js
2026-04-16 08:14:20 +02:00

251 lines
11 KiB
JavaScript

"use strict";
function render(){
var canvas=$("gc"),ctx=canvas.getContext("2d");
var cam=S.camera,P=S.player,net=S.net,cfg=S.cfg;
ctx.save();ctx.clearRect(0,0,CW,CH);
// Sky
var sg=ctx.createLinearGradient(0,0,0,CH);
if(S.phase===1){sg.addColorStop(0,cfg.skyA);sg.addColorStop(1,cfg.skyB);}
else{var u=Math.min(1,S.kidneyDmg/80);sg.addColorStop(0,lerpCol(cfg.skyA,"#5a2020",u));sg.addColorStop(1,lerpCol(cfg.skyB,"#3a1515",u));}
ctx.fillStyle=sg;ctx.fillRect(0,0,CW,CH);
ctx.translate(-cam.x,-cam.y);
// Ground
ctx.fillStyle=cfg.ground;ctx.fillRect(0,0,net.mapW,net.mapH);
ctx.fillStyle="#00000014";
for(var gi=0;gi<250;gi++)ctx.fillRect((gi*137.5)%net.mapW,(gi*97.3)%net.mapH,2,2);
// ── Paths ──
ctx.lineCap="round";ctx.lineJoin="round";
ctx.strokeStyle="#1a150f";ctx.lineWidth=PATH_W+8;
net.edges.forEach(function(e){var a=net.nodes[e[0]],b=net.nodes[e[1]];ctx.beginPath();ctx.moveTo(a.x,a.y);ctx.lineTo(b.x,b.y);ctx.stroke()});
ctx.strokeStyle="#8a7a5e";ctx.lineWidth=PATH_W;
net.edges.forEach(function(e){var a=net.nodes[e[0]],b=net.nodes[e[1]];ctx.beginPath();ctx.moveTo(a.x,a.y);ctx.lineTo(b.x,b.y);ctx.stroke()});
ctx.strokeStyle="#a0906840";ctx.lineWidth=PATH_W*0.5;
net.edges.forEach(function(e){var a=net.nodes[e[0]],b=net.nodes[e[1]];ctx.beginPath();ctx.moveTo(a.x,a.y);ctx.lineTo(b.x,b.y);ctx.stroke()});
// ── Bushes ──
var bCols=["#2d6b1e","#3a7a2a","#1e5a14"];
S.veg.bushes.forEach(function(b){
ctx.fillStyle=bCols[b.shade%3];
ctx.beginPath();ctx.arc(b.x,b.y,b.sz,0,Math.PI*2);ctx.fill();
ctx.fillStyle="#22551540";
ctx.beginPath();ctx.arc(b.x-b.sz*0.3,b.y-b.sz*0.3,b.sz*0.5,0,Math.PI*2);ctx.fill();
});
// ── Trees ──
var tCols=["#1e6b1e","#2a7a25","#22651a","#2b7030"];
S.veg.trees.forEach(function(t){
ctx.fillStyle="#5a3a1a";ctx.fillRect(t.x-3,t.y,6,t.trunk);
ctx.fillStyle="#00000020";ctx.beginPath();ctx.ellipse(t.x,t.y+t.trunk+2,t.sz*0.6,t.sz*0.25,0,0,Math.PI*2);ctx.fill();
ctx.fillStyle=tCols[t.shade%4];
ctx.beginPath();ctx.arc(t.x,t.y-t.sz*0.2,t.sz,0,Math.PI*2);ctx.fill();
ctx.fillStyle="#3a9a3018";ctx.beginPath();ctx.arc(t.x-t.sz*0.25,t.y-t.sz*0.5,t.sz*0.45,0,Math.PI*2);ctx.fill();
});
// ── Keims ──
for(var ki=0;ki<S.keims.length;ki++){
var k=S.keims[ki];
var sz=k.size*30;
var pulse=Math.sin(k.pulse)*0.12+1;
var r2=sz*pulse;
var auraA=0.08+k.size*0.25;
ctx.fillStyle="rgba(220,40,40,"+auraA+")";
ctx.beginPath();ctx.arc(k.x,k.y,r2*2.5,0,Math.PI*2);ctx.fill();
ctx.fillStyle="rgba(220,200,50,"+(0.5+k.size*0.4)+")";
drawCrystal(ctx,k.x,k.y,r2);
ctx.fillStyle="rgba(255,240,100,"+(0.3+k.size*0.3)+")";
drawCrystal(ctx,k.x,k.y,r2*0.4);
if(k.size>0.35){
ctx.strokeStyle="rgba(255,50,50,"+(k.size*0.6)+")";
ctx.lineWidth=1.5;ctx.beginPath();ctx.arc(k.x,k.y,r2*2,0,Math.PI*2);ctx.stroke();
}
}
// ── Spray particles ──
sprayParticles.forEach(function(p){
var alpha=p.life*1.5;
ctx.fillStyle=p.color.replace(")",","+alpha+")").replace("rgb","rgba");
ctx.beginPath();ctx.arc(p.x,p.y,2+p.life*3,0,Math.PI*2);ctx.fill();
});
// ── Buildings ──
drawBldg(ctx,net.lab.x,net.lab.y,"\uD83D\uDD2C","Labor","#304050");
drawBldg(ctx,net.apo.x,net.apo.y,"\uD83D\uDC8A","Apotheke","#2a4a2a");
// Peak
ctx.fillStyle="#9a9a8a";
ctx.beginPath();ctx.moveTo(net.peak.x-50,net.peak.y+30);ctx.lineTo(net.peak.x-12,net.peak.y-40);ctx.lineTo(net.peak.x+8,net.peak.y-35);ctx.lineTo(net.peak.x+50,net.peak.y+30);ctx.closePath();ctx.fill();
ctx.fillStyle="#e0e0e0";ctx.beginPath();ctx.moveTo(net.peak.x-18,net.peak.y-22);ctx.lineTo(net.peak.x-12,net.peak.y-40);ctx.lineTo(net.peak.x+8,net.peak.y-35);ctx.lineTo(net.peak.x+14,net.peak.y-20);ctx.closePath();ctx.fill();
ctx.fillStyle="#fff8";ctx.font="11px sans-serif";ctx.textAlign="center";ctx.fillText("\u26F0\uFE0F Gipfel",net.peak.x,net.peak.y+48);
// ── Hints (phase 1) ──
if(S.phase===1){
var hAlpha=S.cfg.hintAlpha;
S.hints.forEach(function(h){
var sp=Math.sin(frame*0.06+h.phase)*0.5+0.5;
ctx.fillStyle="rgba(255,240,180,"+(sp*hAlpha)+")";
ctx.beginPath();ctx.arc(h.x,h.y,3+sp*3,0,Math.PI*2);ctx.fill();
});
}
// ── Stones ──
S.stones.forEach(function(st){
if(st.rolling)return;
if(st.scanned&&!st.isCystine){
ctx.globalAlpha=0.25;ctx.fillStyle="#555";drawStone(ctx,st.x,st.y,st.shape,st.rollAngle);ctx.globalAlpha=1;return;
}
ctx.fillStyle=st.color;
drawStone(ctx,st.x,st.y,st.shape,st.rollAngle);
if(!st.scanned&&S.phase===1){
ctx.fillStyle="#fff7";ctx.font="11px sans-serif";ctx.textAlign="center";ctx.fillText("?",st.x,st.y-18);
}
});
// Rolling stone
if(S.rollingStone){
var rs=S.rollingStone;
ctx.fillStyle=rs.color;
drawStone(ctx,rs.x,rs.y,rs.shape,rs.rollAngle);
if(frame%3===0){
ctx.fillStyle="#a0906840";
ctx.beginPath();ctx.arc(rs.x+rng(-8,8),rs.y+rng(8,14),rng(2,4),0,Math.PI*2);ctx.fill();
}
}
// Parked stone glow
if(S.parkedStone){
var gl=Math.sin(frame*0.08)*0.3+0.5;
ctx.strokeStyle="rgba(255,200,50,"+gl+")";ctx.lineWidth=2;
ctx.beginPath();ctx.arc(S.parkedStone.x,S.parkedStone.y,STONE_R+8,0,Math.PI*2);ctx.stroke();
ctx.fillStyle=S.parkedStone.color;
drawStone(ctx,S.parkedStone.x,S.parkedStone.y,S.parkedStone.shape,S.parkedStone.rollAngle);
}
// ── Player (Sisyphus) ──
var bob=Math.sin(P.frame*2)*1.5;
var sprinting=P.sprinting;
ctx.fillStyle="#00000028";ctx.beginPath();ctx.ellipse(P.x,P.y+20+bob,10,4,0,0,Math.PI*2);ctx.fill();
ctx.fillStyle="#d4a060";ctx.beginPath();ctx.arc(P.x,P.y-14+bob,9,0,Math.PI*2);ctx.fill();
ctx.fillStyle="#5a3a1a";ctx.beginPath();ctx.arc(P.x,P.y-18+bob,6,Math.PI,Math.PI*2);ctx.fill();
ctx.fillStyle=sprinting?"#7a5535":"#8b6040";
ctx.fillRect(P.x-6,P.y-5+bob,12,15);
if(S.rollingStone){
var armDx=Math.cos(P.dir)*10,armDy=Math.sin(P.dir)*10;
ctx.strokeStyle="#d4a060";ctx.lineWidth=3;
ctx.beginPath();ctx.moveTo(P.x,P.y+2+bob);ctx.lineTo(P.x+armDx,P.y+2+bob+armDy);ctx.stroke();
}
ctx.fillStyle="#4a3020";ctx.fillRect(P.x-7,P.y+3+bob,14,3);
ctx.fillStyle="#6a4830";
var lOff=Math.sin(P.frame*3)*(sprinting?3:1.5);
ctx.fillRect(P.x-5,P.y+10+bob+lOff,4,8);
ctx.fillRect(P.x+1,P.y+10+bob-lOff,4,8);
if(sprinting&&frame%2===0){
ctx.fillStyle="#a0906830";
ctx.beginPath();ctx.arc(P.x-Math.cos(P.dir)*12,P.y-Math.sin(P.dir)*12+20,rng(2,4),0,Math.PI*2);ctx.fill();
}
// ── Prompts ──
ctx.font="bold 11px sans-serif";ctx.textAlign="center";
if(S.phase===1){
S.stones.forEach(function(st){
if(!st.scanned&&!st.rolling&&dist(P,st)<55){
ctx.fillStyle="#ffffffcc";ctx.fillText("[Leertaste] Aufheben",st.x,st.y-22);
}
});
if(S.rollingStone&&dist(P,net.lab)<65){
ctx.fillStyle="#00ff88cc";ctx.font="bold 12px sans-serif";
ctx.fillText("[Leertaste] Scannen!",net.lab.x,net.lab.y-48);
}
}
if(S.phase===2){
if(S.parkedStone&&!S.rollingStone&&dist(P,S.parkedStone)<55){
ctx.fillStyle="#ffcc00cc";ctx.fillText("[Leertaste] Aufheben",S.parkedStone.x,S.parkedStone.y-STONE_R-14);
}
if(S.rollingStone&&S.rollingStone.isCystine){
ctx.fillStyle="#88aaffcc";ctx.font="10px sans-serif";ctx.fillText("[Leertaste] Parken",S.rollingStone.x,S.rollingStone.y-STONE_R-14);
}
if(dist(P,net.apo)<65){
ctx.fillStyle="#00ff88cc";ctx.fillText("[Leertaste] Auff\u00FCllen",net.apo.x,net.apo.y-48);
}
for(var ki=0;ki<S.keims.length;ki++){
var k=S.keims[ki];
if(dist(P,k)<70&&S.meds[MEDS[S.selMed].id]>0){
ctx.fillStyle="#ffcc44cc";ctx.font="10px sans-serif";
ctx.fillText("[Leertaste] Spr\u00FChen",k.x,k.y-k.size*30-12);
break;
}
}
}
// ── Minimap ──
drawMinimap(ctx,cam);
ctx.restore();
}
function drawStone(ctx,x,y,shape,angle){
ctx.save();ctx.translate(x,y);ctx.rotate(angle||0);
ctx.beginPath();
if(shape===0)ctx.ellipse(0,0,STONE_R,STONE_R*0.72,0,0,Math.PI*2);
else if(shape===1){ctx.moveTo(-STONE_R,STONE_R*0.6);ctx.lineTo(-STONE_R*0.5,-STONE_R*0.8);ctx.lineTo(STONE_R*0.8,-STONE_R*0.5);ctx.lineTo(STONE_R,STONE_R*0.6);ctx.closePath();}
else ctx.arc(0,0,STONE_R,0,Math.PI*2);
ctx.fill();ctx.strokeStyle="#00000030";ctx.lineWidth=1;ctx.stroke();
ctx.fillStyle="#00000015";ctx.beginPath();ctx.arc(STONE_R*0.2,-STONE_R*0.2,STONE_R*0.3,0,Math.PI*2);ctx.fill();
ctx.fillStyle="#ffffff10";ctx.beginPath();ctx.arc(-STONE_R*0.3,-STONE_R*0.3,STONE_R*0.25,0,Math.PI*2);ctx.fill();
ctx.restore();
}
function drawCrystal(ctx,x,y,r){
ctx.beginPath();
var spikes=7;
for(var i=0;i<spikes;i++){
var a=(i/spikes)*Math.PI*2-Math.PI/2;
var outerR=r*(0.6+(i%2)*0.4);
var px=x+Math.cos(a)*outerR,py=y+Math.sin(a)*outerR;
if(i===0)ctx.moveTo(px,py);else ctx.lineTo(px,py);
var a2=((i+0.5)/spikes)*Math.PI*2-Math.PI/2;
ctx.lineTo(x+Math.cos(a2)*r*0.3,y+Math.sin(a2)*r*0.3);
}
ctx.closePath();ctx.fill();
}
function drawBldg(ctx,x,y,emoji,label,col){
ctx.fillStyle="#00000025";ctx.beginPath();ctx.ellipse(x,y+28,32,8,0,0,Math.PI*2);ctx.fill();
ctx.fillStyle=col;ctx.fillRect(x-28,y-22,56,44);
ctx.fillStyle=col+"cc";ctx.beginPath();ctx.moveTo(x-32,y-22);ctx.lineTo(x,y-38);ctx.lineTo(x+32,y-22);ctx.closePath();ctx.fill();
ctx.fillStyle="#1a1a1a";ctx.fillRect(x-6,y+6,12,16);
ctx.font="22px sans-serif";ctx.textAlign="center";ctx.fillText(emoji,x,y+2);
ctx.fillStyle="#ffffffbb";ctx.font="bold 10px sans-serif";ctx.fillText(label,x,y+40);
}
function drawMinimap(ctx,cam){
var mmW=130,mmH=100,mmX=cam.x+CW-mmW-10,mmY=cam.y+10;
var sx=mmW/S.net.mapW,sy=mmH/S.net.mapH;
ctx.fillStyle="rgba(0,0,0,0.55)";ctx.fillRect(mmX-2,mmY-2,mmW+4,mmH+4);
ctx.fillStyle="rgba(40,60,30,0.8)";ctx.fillRect(mmX,mmY,mmW,mmH);
ctx.strokeStyle="#9a8a6a50";ctx.lineWidth=1.5;
S.net.edges.forEach(function(e){
var a=S.net.nodes[e[0]],b=S.net.nodes[e[1]];
ctx.beginPath();ctx.moveTo(mmX+a.x*sx,mmY+a.y*sy);ctx.lineTo(mmX+b.x*sx,mmY+b.y*sy);ctx.stroke();
});
ctx.fillStyle="#4488ff";ctx.fillRect(mmX+S.net.lab.x*sx-2,mmY+S.net.lab.y*sy-2,5,5);
ctx.fillStyle="#44dd44";ctx.fillRect(mmX+S.net.apo.x*sx-2,mmY+S.net.apo.y*sy-2,5,5);
ctx.fillStyle="#ffffff";ctx.fillRect(mmX+S.net.peak.x*sx-2,mmY+S.net.peak.y*sy-2,5,5);
S.keims.forEach(function(k){
ctx.fillStyle="rgba(220,200,50,"+(0.4+k.size*0.5)+")";
ctx.beginPath();ctx.arc(mmX+k.x*sx,mmY+k.y*sy,1.5+k.size*2,0,Math.PI*2);ctx.fill();
});
if(S.parkedStone){ctx.fillStyle="#ffcc00";ctx.fillRect(mmX+S.parkedStone.x*sx-2,mmY+S.parkedStone.y*sy-2,4,4);}
ctx.fillStyle="#ff4444";ctx.beginPath();ctx.arc(mmX+S.player.x*sx,mmY+S.player.y*sy,3,0,Math.PI*2);ctx.fill();
ctx.strokeStyle="#ffffff35";ctx.lineWidth=1;ctx.strokeRect(mmX+cam.x*sx,mmY+cam.y*sy,CW*sx,CH*sy);
ctx.fillStyle="#ffffff55";ctx.font="7px sans-serif";ctx.textAlign="left";
ctx.fillText("Lab",mmX+S.net.lab.x*sx+5,mmY+S.net.lab.y*sy+3);
ctx.fillText("Apo",mmX+S.net.apo.x*sx+5,mmY+S.net.apo.y*sy+3);
ctx.fillText("Gipfel",mmX+S.net.peak.x*sx+5,mmY+S.net.peak.y*sy+3);
}