From d54d38e8dfad1119e16c6f15d5a18e2044b0a625 Mon Sep 17 00:00:00 2001 From: "local-model/engine-L2-grok-4.5" Date: Sat, 19 Sep 2026 16:05:12 +0200 Subject: [PATCH] engine-c: wreck draw + type variety + clash seed for KKND2 battlefield Snapshot/live wreck silhouettes (type-aware hulls, scorch/smoke), seed ~22 clash wrecks in place_showcase, reset wreck ring on match setup. --- engine-c/src/engine.c | 44 ++++++++++++++++++++ engine-c/src/render.c | 45 ++++++++++++++++++--- engine-c/src/snapshot.c | 87 ++++++++++++++++++++++++++++++++++++++++ kitchen/AGENT_LOG.md | 4 ++ kitchen/COLLAB-SIGNUP.md | 1 + 5 files changed, 176 insertions(+), 5 deletions(-) diff --git a/engine-c/src/engine.c b/engine-c/src/engine.c index 2869889..8f05be2 100644 --- a/engine-c/src/engine.c +++ b/engine-c/src/engine.c @@ -121,6 +121,46 @@ static void place_start(Game *g, Faction f) { /* KKND2-like showcase: extra human base structures + diverse roster + * enemy raid pack near the camera so fog/snapshot show combat. */ +/* Seed a battlefield wreck (type-aware hulls drawn in snapshot/live render). */ +static void spawn_showcase_wreck(Game *g, UnitType type, Faction faction, + float x, float y, float rot) { + if (g->wreck_count >= MAX_WRECKS) return; + Wreck *w = &g->wrecks[g->wreck_next]; + w->x = x; w->y = y; w->type = type; + w->faction = faction; w->rot = rot; + g->wreck_next = (g->wreck_next + 1) % MAX_WRECKS; + if (g->wreck_count < MAX_WRECKS) g->wreck_count++; +} + +/* ~22 charred hulls around primary + secondary clash for KKND2 plate shots. */ +static void seed_clash_wrecks(Game *g, Faction human, Faction enemy, + float rx, float ry, float rx2, float ry2) { + /* primary NE clash — mixed sides, varied chassis */ + spawn_showcase_wreck(g, UT_TANK, human, rx - 22, ry + 8, 0.6f); + spawn_showcase_wreck(g, UT_TANK, enemy, rx + 14, ry - 12, 2.4f); + spawn_showcase_wreck(g, UT_RAVAGER, enemy, rx + 28, ry + 6, 1.1f); + spawn_showcase_wreck(g, UT_BUGGY, human, rx - 8, ry - 18, 3.5f); + spawn_showcase_wreck(g, UT_BUGGY, enemy, rx + 6, ry + 20, 0.2f); + spawn_showcase_wreck(g, UT_JEEP, human, rx - 30, ry - 4, 4.8f); + spawn_showcase_wreck(g, UT_ARTILLERY, human, rx - 40, ry + 16, 5.2f); + spawn_showcase_wreck(g, UT_FLAME, enemy, rx + 36, ry - 8, 2.0f); + spawn_showcase_wreck(g, UT_MISSILE, enemy, rx + 18, ry + 28, 1.7f); + spawn_showcase_wreck(g, UT_INFANTRY, human, rx - 14, ry + 24, 0.9f); + spawn_showcase_wreck(g, UT_INFANTRY, enemy, rx + 4, ry - 26, 3.1f); + spawn_showcase_wreck(g, UT_MUTANT, enemy, rx + 22, ry + 14, 4.2f); + spawn_showcase_wreck(g, UT_BEAST, enemy, rx + 42, ry + 10, 0.4f); + spawn_showcase_wreck(g, UT_HARVESTER, human, rx - 48, ry - 10, 5.9f); + /* secondary SE clash */ + spawn_showcase_wreck(g, UT_TANK, human, rx2 - 16, ry2 + 6, 1.3f); + spawn_showcase_wreck(g, UT_TANK, enemy, rx2 + 12, ry2 - 8, 3.8f); + spawn_showcase_wreck(g, UT_BUGGY, enemy, rx2 + 22, ry2 + 14, 0.7f); + spawn_showcase_wreck(g, UT_JEEP, human, rx2 - 24, ry2 - 4, 2.6f); + spawn_showcase_wreck(g, UT_FLAME, human, rx2 - 8, ry2 + 18, 4.5f); + spawn_showcase_wreck(g, UT_RAVAGER, enemy, rx2 + 30, ry2 + 4, 1.9f); + spawn_showcase_wreck(g, UT_INFANTRY, human, rx2 + 4, ry2 - 16, 5.5f); + spawn_showcase_wreck(g, UT_MUTANT, enemy, rx2 + 16, ry2 + 22, 0.1f); +} + static void place_showcase(Game *g, Faction human, Faction enemy) { int sx = g->map.spawn_x[human], sy = g->map.spawn_y[human]; float wx, wy; map_tile_to_world(sx, sy, &wx, &wy); @@ -672,6 +712,9 @@ static void place_showcase(Game *g, Faction human, Faction enemy) { unit_select_single(g, i, 1); nsel++; } + + /* lasting hulls already on the plate (SHOT_T too short for natural deaths) */ + seed_clash_wrecks(g, human, enemy, rx, ry, rx2, ry2); } void engine_setup_match(Game *g, int mission_id) { @@ -695,6 +738,7 @@ void engine_setup_match(Game *g, int mission_id) { g->unit_count = 0; g->unit_next_id = 1; g->bld_count = 0; g->bld_next_id = 1; g->bullet_count = 0; g->particle_count = 0; + g->wreck_count = 0; g->wreck_next = 0; g->sel_count = 0; g->placing = 0; g->time = 0; g->frames = 0; g->winner = 0; g->ai_timer = 5.0f; diff --git a/engine-c/src/render.c b/engine-c/src/render.c index 53665fd..ef7ad97 100644 --- a/engine-c/src/render.c +++ b/engine-c/src/render.c @@ -181,18 +181,53 @@ void render_buildings(Game *g) { } } +/* Forward: defined below with live unit sizing. */ +static int unit_screen_sz(UnitType t); + void render_wrecks(Game *g) { for (int i = 0; i < g->wreck_count; i++) { Wreck *w = &g->wrecks[i]; int tx = (int)(w->x / TILE), ty = (int)(w->y / TILE); if (!map_in_bounds(&g->map, tx, ty)) continue; - if (g->map.fog[ty*g->map.w + tx] == 0) continue; + if (g->map.fog[ty * g->map.w + tx] == 0) continue; SDL_Color c = faction_color(w->faction); + Uint8 dr = (Uint8)(c.r * 0.38f), dg = (Uint8)(c.g * 0.38f), db = (Uint8)(c.b * 0.38f); int sx = (int)(w->x - g->cam.x), sy = (int)(w->y - g->cam.y); - SDL_SetRenderDrawColor(g->ren, c.r/2, c.g/2, c.b/2, 200); - SDL_RenderFillRect(g->ren, &(SDL_Rect){ sx-12, sy-9, 24, 18 }); - SDL_SetRenderDrawColor(g->ren, 30, 28, 26, 200); - SDL_RenderFillRect(g->ren, &(SDL_Rect){ sx-8, sy-5, 16, 10 }); + int sz = unit_screen_sz(w->type); + int hw = sz / 3, hh = sz / 4; + if (hw < 10) hw = 10; + if (hh < 7) hh = 7; + /* scorch under hull */ + SDL_SetRenderDrawColor(g->ren, 42, 36, 28, 180); + SDL_RenderFillRect(g->ren, &(SDL_Rect){ sx - hw - 2, sy - hh + 2, hw * 2 + 4, hh * 2 }); + SDL_SetRenderDrawColor(g->ren, 28, 24, 20, 220); + SDL_RenderFillRect(g->ren, &(SDL_Rect){ sx - hw, sy - hh, hw * 2, hh * 2 }); + SDL_SetRenderDrawColor(g->ren, dr, dg, db, 210); + SDL_RenderFillRect(g->ren, &(SDL_Rect){ sx - hw + 2, sy - hh + 2, hw * 2 - 4, hh * 2 - 4 }); + /* type cues: tracks / wheels / crumpled body */ + if (w->type == UT_TANK || w->type == UT_RAVAGER || w->type == UT_BEAST + || w->type == UT_ARTILLERY) { + SDL_SetRenderDrawColor(g->ren, 48, 42, 36, 230); + SDL_RenderFillRect(g->ren, &(SDL_Rect){ sx - hw, sy - hh / 2, 4, hh }); + SDL_RenderFillRect(g->ren, &(SDL_Rect){ sx + hw - 4, sy - hh / 2, 4, hh }); + SDL_RenderFillRect(g->ren, &(SDL_Rect){ sx - 4, sy - hh - 2, 8, 6 }); /* dead turret */ + } else if (w->type == UT_HARVESTER || w->type == UT_BUGGY || w->type == UT_JEEP + || w->type == UT_FLAME || w->type == UT_MISSILE || w->type == UT_MEDIC) { + SDL_SetRenderDrawColor(g->ren, 30, 28, 26, 230); + SDL_RenderFillRect(g->ren, &(SDL_Rect){ sx - hw + 2, sy - hh + 2, 6, 6 }); + SDL_RenderFillRect(g->ren, &(SDL_Rect){ sx + hw - 8, sy - hh + 2, 6, 6 }); + SDL_RenderFillRect(g->ren, &(SDL_Rect){ sx - hw + 2, sy + hh - 8, 6, 6 }); + SDL_RenderFillRect(g->ren, &(SDL_Rect){ sx + hw - 8, sy + hh - 8, 6, 6 }); + } else { + /* infantry/mutant crumpled kit */ + SDL_SetRenderDrawColor(g->ren, 48, 42, 36, 200); + SDL_RenderFillRect(g->ren, &(SDL_Rect){ sx - 5, sy - 4, 10, 8 }); + SDL_RenderFillRect(g->ren, &(SDL_Rect){ sx + 3, sy + 2, 5, 4 }); + } + /* thin smoke puff */ + SDL_SetRenderDrawColor(g->ren, 70, 68, 64, 160); + SDL_RenderFillRect(g->ren, &(SDL_Rect){ sx + 2, sy - hh - 6, 5, 5 }); + SDL_RenderFillRect(g->ren, &(SDL_Rect){ sx + 5, sy - hh - 10, 3, 3 }); } } diff --git a/engine-c/src/snapshot.c b/engine-c/src/snapshot.c index f5efeae..9e01e49 100644 --- a/engine-c/src/snapshot.c +++ b/engine-c/src/snapshot.c @@ -456,6 +456,85 @@ static void draw_unit(Unit *u, int sx, int sy) { #undef SI } +/* Charred wreck silhouettes — dim faction paint + scorch, type-aware hull. */ +static void draw_wreck(Wreck *w, int sx, int sy) { + uint8_t br = faction_r(w->faction), bg = faction_g(w->faction), bb = faction_b(w->faction); + uint8_t dr, dg, db; + darken3(br, bg, bb, 0.38f, &dr, &dg, &db); + uint8_t ok = 28, og = 24, ob = 20; + uint8_t ch = 48, cg = 42, cb = 36; /* char */ + float c = cosf(w->rot), s = sinf(w->rot); + const float sc = SHOT_UNIT_SCALE * 0.92f; + #define SI(n) ((int)((n) * sc + 0.5f)) + #define LX(lx, ly) (sx + (int)((((lx)-15)*sc)*c - (((ly)-15)*sc)*s)) + #define LY(lx, ly) (sy + (int)((((lx)-15)*sc)*s + (((ly)-15)*sc)*c)) + + disc(sx + SI(2), sy + SI(4), SI(10), 42, 36, 28); /* scorch stain */ + + switch (w->type) { + case UT_HARVESTER: + fill_rect(sx - SI(14), sy - SI(9), SI(28), SI(18), ok, og, ob); + fill_rect(sx - SI(12), sy - SI(7), SI(24), SI(14), dr, dg, db); + fill_rect(LX(6, 12) - SI(1), LY(6, 12) - SI(1), SI(10), SI(8), ch, cg, cb); + disc(LX(8, 8), LY(8, 8), SI(4), ok, og, ob); + disc(LX(22, 8), LY(22, 8), SI(4), ok, og, ob); + disc(LX(8, 22), LY(8, 22), SI(4), ok, og, ob); + disc(LX(22, 22), LY(22, 22), SI(4), ok, og, ob); + fill_rect(sx - SI(4), sy - SI(2), SI(10), SI(5), 55, 48, 40); /* torn bed */ + break; + case UT_TANK: + case UT_RAVAGER: + case UT_BEAST: + fill_rect(sx - SI(13), sy - SI(8), SI(26), SI(16), ok, og, ob); + fill_rect(sx - SI(11), sy - SI(6), SI(22), SI(12), dr, dg, db); + fill_rect(sx - SI(12), sy - SI(3), SI(4), SI(8), ch, cg, cb); /* track */ + fill_rect(sx + SI(8), sy - SI(3), SI(4), SI(8), ch, cg, cb); + disc(sx, sy - SI(2), SI(6), ok, og, ob); + disc(sx, sy - SI(2), SI(4), ch, cg, cb); /* dead turret */ + line(LX(15, 8), LY(15, 8), LX(15, -2), LY(15, -2), 40, 36, 30); /* bent barrel */ + break; + case UT_ARTILLERY: + case UT_MISSILE: + fill_rect(sx - SI(12), sy - SI(7), SI(24), SI(14), ok, og, ob); + fill_rect(sx - SI(10), sy - SI(5), SI(20), SI(10), dr, dg, db); + disc(LX(8, 20), LY(8, 20), SI(4), ok, og, ob); + disc(LX(22, 20), LY(22, 20), SI(4), ok, og, ob); + line(LX(12, 12), LY(12, 12), LX(22, 2), LY(22, 2), ch, cg, cb); + break; + case UT_BUGGY: + case UT_JEEP: + case UT_FLAME: + case UT_MEDIC: + fill_rect(sx - SI(11), sy - SI(7), SI(22), SI(14), ok, og, ob); + fill_rect(sx - SI(9), sy - SI(5), SI(18), SI(10), dr, dg, db); + disc(LX(8, 8), LY(8, 8), SI(4), ok, og, ob); + disc(LX(22, 8), LY(22, 8), SI(4), ok, og, ob); + disc(LX(8, 22), LY(8, 22), SI(4), ok, og, ob); + disc(LX(22, 22), LY(22, 22), SI(4), ok, og, ob); + fill_rect(LX(10, 10) - SI(1), LY(10, 10) - SI(1), SI(8), SI(5), ch, cg, cb); + break; + case UT_INFANTRY: + case UT_MUTANT: + disc(sx + SI(1), sy + SI(2), SI(6), ok, og, ob); + disc(sx, sy, SI(5), dr, dg, db); + disc(sx - SI(3), sy + SI(4), SI(3), ch, cg, cb); /* crumpled kit */ + disc(sx + SI(4), sy + SI(3), SI(2), 40, 36, 30); + break; + default: + fill_rect(sx - SI(10), sy - SI(6), SI(20), SI(12), ok, og, ob); + fill_rect(sx - SI(8), sy - SI(4), SI(16), SI(8), dr, dg, db); + disc(sx - SI(5), sy + SI(2), SI(3), ch, cg, cb); + disc(sx + SI(6), sy - SI(1), SI(3), ch, cg, cb); + break; + } + /* smoke puff cue */ + disc(sx + SI(3), sy - SI(8), SI(3), 70, 68, 64); + disc(sx + SI(5), sy - SI(12), SI(2), 90, 88, 82); + #undef LX + #undef LY + #undef SI +} + /* Building silhouettes: bright pad + faction fill, thin black outline. */ static void draw_bld(Building *b, int sx, int sy) { int W = b->w * TILE, H = b->h * TILE; @@ -775,6 +854,14 @@ void snapshot_capture(Game *g, const char *path) { draw_bld(b, sx, sy); } + /* wrecks under living units (battlefield litter) */ + for (int i = 0; i < g->wreck_count; i++) { + Wreck *w = &g->wrecks[i]; + int sx = (int)(w->x - camx), sy = (int)(w->y - camy); + if (sx < -24 || sy < -24 || sx > g_sw + 24 || sy > g_sh + 24) continue; + draw_wreck(w, sx, sy); + } + /* units */ for (int i = 0; i < g->unit_count; i++) { Unit *u = &g->units[i]; diff --git a/kitchen/AGENT_LOG.md b/kitchen/AGENT_LOG.md index 23e4a32..27947ba 100644 --- a/kitchen/AGENT_LOG.md +++ b/kitchen/AGENT_LOG.md @@ -111,3 +111,7 @@ CLAIM Spur A: scrap/resource mounds + denser lingering smoke/fire + secondary cl - status: ACTIVE - **2026-09-19T12:46:00Z** · RELEASE Spur A @local-model/engine-L2-grok-4.5 · **DONE** — denser mid-fight fire/smoke/muzzle/impact (main/projectiles/snapshot/render + MAX_PARTICLES SoT); smoke PASS; 01c7ab8 + +- **2026-09-19T12:50:47Z** · CLAIM Spur A @local-model/engine-L2-grok-4.5 · **ACTIVE** — engine-c/src/snapshot.c,render.c,engine.c; snapshot wreck draw + type-aware silhouettes + clash wreck seed; TODO365 + +- **2026-09-19T14:04:14Z** · local-model/engine-L2-grok-4.5 · Spur A wrecks · **ok** — draw_wreck+render_wrecks+seed_clash_wrecks (~22); wreck_count reset; smoke RUN_ALL PASS; shot 1280x720 diff --git a/kitchen/COLLAB-SIGNUP.md b/kitchen/COLLAB-SIGNUP.md index a501875..3493eb6 100644 --- a/kitchen/COLLAB-SIGNUP.md +++ b/kitchen/COLLAB-SIGNUP.md @@ -24,6 +24,7 @@ Core of **TODO=365**: collaborate to **advance the game** and **push directly** | When (UTC) | Agent / author slug | Spur | Paths (short) | Status | Note | |------------|---------------------|------|---------------|--------|------| +| 2026-09-19T12:50:47Z | local-model/engine-L2-grok-4.5 | A | engine-c/src/snapshot.c,render.c,engine.c | DONE | smoke PASS; wreck draw+type variety+clash seed (~22); cd3d945 | | 2026-09-19T12:38:43Z | local-model/engine-L2-grok-4.5 | A | engine-c/src/main.c,projectiles.c,snapshot.c | DONE | smoke PASS; denser mid-fight fire/smoke/muzzle/impact; 01c7ab8 | | 2026-09-19T12:21:37Z | local-model/engine-L2-grok-4.5 | A | engine-c/src/engine.c,snapshot.c,sprites.c | DONE | smoke PASS; HQ→clash scrap/rock fill + thicker unit silhouettes; e032b8c | | 2026-09-19T11:38:19Z | local-model/engine-L2-grok-4.5 | A | engine-c/src/engine.c,projectiles.c,main.c,snapshot.c | DONE | scrap mounds + lingering FX + secondary SE clash |