kitchen: README + MISSIONS/engine-c keep-drop notes

This commit is contained in:
Hernâni Marques 2026-09-17 21:48:48 +02:00
parent 1d351918da
commit 575d7d29b8
No known key found for this signature in database
130 changed files with 9817 additions and 1 deletions

148
engine-c/src/snapshot.c Normal file
View file

@ -0,0 +1,148 @@
/*
* Software snapshot renderer - draws the game world into an RGBA buffer using
* only primitive shapes (no SDL gpu readback, which is broken on this box due
* to an SDL2/SDL3 conflict). Output is saved as PNG via png_save().
*/
#include "kknd.h"
#define SW VIEW_W
#define SH VIEW_H
static uint8_t *g_buf;
static void px(int x, int y, uint8_t r, uint8_t g, uint8_t b) {
if (x < 0 || y < 0 || x >= SW || y >= SH) return;
int i = (y * SW + x) * 4;
g_buf[i] = r; g_buf[i+1] = g; g_buf[i+2] = b; g_buf[i+3] = 255;
}
static void rectf(int x0, int y0, int x1, int y1, uint8_t r, uint8_t g, uint8_t b) {
if (x0 > x1) { int t = x0; x0 = x1; x1 = t; }
if (y0 > y1) { int t = y0; y0 = y1; y1 = t; }
for (int y = y0; y <= y1; y++)
for (int x = x0; x <= x1; x++)
px(x, y, r, g, b);
}
static void disc(int cx, int cy, int rad, uint8_t r, uint8_t g, uint8_t b) {
for (int y = -rad; y <= rad; y++)
for (int x = -rad; x <= rad; x++)
if (x*x + y*y <= rad*rad) px(cx+x, cy+y, r, g, b);
}
static uint8_t faction_r(Faction f){ return f==FACTION_SURVIVOR?70 : f==FACTION_EVOLVED?200 : 230; }
static uint8_t faction_g(Faction f){ return f==FACTION_SURVIVOR?180: f==FACTION_EVOLVED?70 : 60; }
static uint8_t faction_b(Faction f){ return f==FACTION_SURVIVOR?90 : f==FACTION_EVOLVED?210 : 230; }
static void terrain_color(TerrainType t, uint8_t *r, uint8_t *g, uint8_t *b) {
switch (t) {
case T_GRASS: *r=46; *g=92; *b=46; break;
case T_ROAD: *r=90; *g=90; *b=80; break;
case T_RUBBLE:*r=80; *g=72; *b=64; break;
case T_ROCK: *r=80; *g=80; *b=86; break;
case T_WATER: *r=40; *g=60; *b=120; break;
case T_SCRAP: *r=70; *g=64; *b=40; break;
default: *r=50; *g=50; *b=50; break;
}
}
void snapshot_capture(Game *g, const char *path) {
uint8_t *buf = (uint8_t *)malloc((size_t)SW * SH * 4);
if (!buf) return;
g_buf = buf;
for (int i = 0; i < SW*SH; i++) { buf[i*4]=0; buf[i*4+1]=0; buf[i*4+2]=0; buf[i*4+3]=255; }
/* camera: centre on centroid of human units, else map centre */
float cx = MAP_PIX_W/2, cy = MAP_PIX_H/2;
int nc = 0;
for (int i = 0; i < g->unit_count; i++)
if (!g->units[i].dead && g->units[i].faction == g->human) { cx += g->units[i].x; cy += g->units[i].y; nc++; }
if (nc) { cx /= nc; cy /= nc; }
float camx = cx - SW/2, camy = cy - SH/2;
if (camx < 0) camx = 0; if (camy < 0) camy = 0;
if (camx > MAP_PIX_W - SW) camx = MAP_PIX_W - SW;
if (camy > MAP_PIX_H - SH) camy = MAP_PIX_H - SH;
/* terrain */
int tx0 = (int)camx / TILE, ty0 = (int)camy / TILE;
int tx1 = (int)(camx + SW) / TILE, ty1 = (int)(camy + SH) / TILE;
for (int ty = ty0; ty <= ty1; ty++) {
for (int tx = tx0; tx <= tx1; tx++) {
if (tx < 0 || ty < 0 || tx >= MAP_W || ty >= MAP_W) continue;
Tile *t = map_tile(&g->map, tx, ty);
uint8_t r,g,b; terrain_color(t->terrain, &r,&g,&b);
int sx = tx*TILE - (int)camx, sy = ty*TILE - (int)camy;
rectf(sx, sy, sx+TILE-1, sy+TILE-1, r, g, b);
if (t->terrain == T_SCRAP && t->scrap > 0) {
int cc = (sx+TILE/2), cr = (sy+TILE/2);
for (int k=0;k<t->scrap/20;k++)
disc(cc + ((k*7)%10)-5, cr + ((k*5)%10)-5, 2, 150,140,90);
}
}
}
/* fog overlay */
for (int ty = ty0; ty <= ty1; ty++)
for (int tx = tx0; tx <= tx1; tx++) {
if (tx < 0 || ty < 0 || tx >= MAP_W || ty >= MAP_W) continue;
int f = g->map.fog[ty*MAP_W + tx];
if (f == 0) { int sx=tx*TILE-(int)camx, sy=ty*TILE-(int)camy; rectf(sx,sy,sx+TILE-1,sy+TILE-1,0,0,0); }
else if (f == 1) { int sx=tx*TILE-(int)camx, sy=ty*TILE-(int)camy; rectf(sx,sy,sx+TILE-1,sy+TILE-1,0,0,30); }
}
/* buildings */
for (int i = 0; i < g->bld_count; i++) {
Building *b = &g->buildings[i];
if (b->dead) continue;
int sx = (int)(b->tx*TILE - camx), sy = (int)(b->ty*TILE - camy);
int w = b->w*TILE, h = b->h*TILE;
if (sx+w < 0 || sy+h < 0 || sx > SW || sy > SH) continue;
uint8_t r=faction_r(b->faction),gg=faction_g(b->faction),bb=faction_b(b->faction);
rectf(sx, sy, sx+w-1, sy+h-1, r/2+30, gg/2+30, bb/2+30);
rectf(sx+2, sy+2, sx+w-3, sy+h-3, r, gg, bb);
if (b->build < 1.0f) rectf(sx, sy, sx+w-1, sy+(int)(h*b->build)-1, 255,255,255);
}
/* units */
for (int i = 0; i < g->unit_count; i++) {
Unit *u = &g->units[i];
if (u->dead) continue;
int sx = (int)(u->x - camx), sy = (int)(u->y - camy);
if (sx < -10 || sy < -10 || sx > SW+10 || sy > SH+10) continue;
uint8_t r=faction_r(u->faction),gg=faction_g(u->faction),bb=faction_b(u->faction);
int rad = u->type==UT_TANK||u->type==UT_BEAST?9:u->type==UT_HARVESTER?8:6;
disc(sx, sy, rad, r, gg, bb);
disc(sx, sy, 2, 255,255,255);
int hx = sx + (int)(cosf(u->heading)*rad), hy = sy + (int)(sinf(u->heading)*rad);
for (int k=0;k<rad;k++){ int xx=sx+(hx-sx)*k/rad, yy=sy+(hy-sy)*k/rad; px(xx,yy,230,230,230); }
if (u->selected) { rectf(sx-rad-2,sy-rad-2,sx+rad+2,sy+rad+2,255,255,120); }
}
/* projectiles */
for (int i = 0; i < g->bullet_count; i++) {
Bullet *p = &g->bullets[i];
int sx=(int)(p->x-camx), sy=(int)(p->y-camy);
px(sx,sy,255,230,120); px(sx+1,sy,255,230,120);
}
/* minimap */
int mmx=SW-210, mmy=10, mms=200;
rectf(mmx-2,mmy-2,mmx+mms+1,mmy+mms+1,0,0,0);
for (int ty=0;ty<MAP_W;ty+=2) for (int tx=0;tx<MAP_W;tx+=2) {
int f=g->map.fog[ty*MAP_W+tx];
if (f==0) continue;
Tile *t=map_tile(&g->map,tx,ty);
uint8_t r,g,b; terrain_color(t->terrain,&r,&g,&b);
int dx=mmx + tx*mms/MAP_W, dy=mmy + ty*mms/MAP_W;
px(dx,dy,r,g,b);
}
for (int i=0;i<g->bld_count;i++){ Building*b=&g->buildings[i]; if(b->dead)continue;
int dx=mmx+b->tx*TILE*mms/(MAP_W*TILE), dy=mmy+b->ty*TILE*mms/(MAP_W*TILE);
px(dx,dy,faction_r(b->faction),faction_g(b->faction),faction_b(b->faction)); }
for (int i=0;i<g->unit_count;i++){ Unit*u=&g->units[i]; if(u->dead)continue;
int dx=mmx+(int)(u->x*mms/MAP_PIX_W), dy=mmy+(int)(u->y*mms/MAP_PIX_H);
px(dx,dy,faction_r(u->faction),faction_g(u->faction),faction_b(u->faction)); }
png_save(path, SW, SH, buf);
free(buf);
}