diff --git a/engine-c/src/engine.c b/engine-c/src/engine.c index 0e295bd..0b8c604 100644 --- a/engine-c/src/engine.c +++ b/engine-c/src/engine.c @@ -67,12 +67,13 @@ static void bld_force_complete(Game *g) { } /* After force-complete: leave a few incomplete yards + battle-worn - * fortifications near the raid locus so scaffold/damage FX show in KKND_SHOT. */ + * fortifications near both raid loci so scaffold/damage FX show in KKND_SHOT. */ static void showcase_bld_battle_wear(Game *g) { int incomplete_n = 0, damaged_n = 0; float wx, wy; map_tile_to_world(g->map.spawn_x[g->human], g->map.spawn_y[g->human], &wx, &wy); float rx = wx + 88.0f, ry = wy - 48.0f; + float rx2 = wx + 140.0f, ry2 = wy + 96.0f; for (int i = 0; i < g->bld_count; i++) { Building *b = &g->buildings[i]; if (b->dead) continue; @@ -80,6 +81,9 @@ static void showcase_bld_battle_wear(Game *g) { float cy = (b->ty + b->h * 0.5f) * (float)TILE; float dx = cx - rx, dy = cy - ry; float d2 = dx * dx + dy * dy; + float dx2 = cx - rx2, dy2 = cy - ry2; + float d2b = dx2 * dx2 + dy2 * dy2; + float dmin = d2 < d2b ? d2 : d2b; /* mid-base construction yards (away from clash) */ if (incomplete_n < 2 && b->faction == g->human && d2 > 180.0f * 180.0f && (b->type == BT_REPAIR || b->type == BT_RESEARCH || b->type == BT_WARFACTORY)) { @@ -88,11 +92,13 @@ static void showcase_bld_battle_wear(Game *g) { incomplete_n++; continue; } - /* clash fortifications: turrets / walls / power take hits */ - if (damaged_n < 6 && d2 < 160.0f * 160.0f && - (b->type == BT_TURRET || b->type == BT_WALL || b->type == BT_POWER)) { - float frac = (damaged_n % 3 == 0) ? 0.35f - : (damaged_n % 3 == 1) ? 0.55f : 0.72f; + /* clash fortifications + economy pads take hits at both fronts */ + if (damaged_n < 16 && dmin < 220.0f * 220.0f && + (b->type == BT_TURRET || b->type == BT_WALL || b->type == BT_POWER || + b->type == BT_REFINERY || b->type == BT_BASE || b->type == BT_WARFACTORY)) { + float frac = (damaged_n % 4 == 0) ? 0.22f + : (damaged_n % 4 == 1) ? 0.40f + : (damaged_n % 4 == 2) ? 0.58f : 0.74f; b->hp = b->max_hp * frac; damaged_n++; } @@ -216,6 +222,10 @@ static void place_showcase(Game *g, Faction human, Faction enemy) { unit_spawn(g, UT_MEDIC, human, wx + 20, wy + 28); for (int i = 0; i < 10; i++) unit_spawn(g, UT_INFANTRY, human, wx + 88 + (i % 5) * 14, wy + 8 + (i / 5) * 16); + /* dense melee screen at primary clash (riflemen packed for KKND2 crop) */ + for (int i = 0; i < 12; i++) + unit_spawn(g, UT_INFANTRY, human, + wx + 72 + (i % 6) * 11, wy - 28 + (i / 6) * 12); /* Evolved raid pack — close NE, overlapping Survivor line */ float rx = wx + 88.0f, ry = wy - 48.0f; @@ -602,8 +612,12 @@ static void place_showcase(Game *g, Faction human, Faction enemy) { for (int i = 0; i < 5; i++) unit_spawn(g, UT_INFANTRY, human, rx2 - 12 + (i % 3) * 12, ry2 - 16 + (i / 3) * 14); + /* denser Survivor melee at SE clash */ + for (int i = 0; i < 8; i++) + unit_spawn(g, UT_INFANTRY, human, + rx2 - 22 + (i % 4) * 10, ry2 - 6 + (i / 4) * 11); - int raid[56]; + int raid[96]; int rn = 0; for (int i = 0; i < 8; i++) raid[rn++] = unit_spawn(g, UT_MUTANT, enemy, @@ -632,8 +646,18 @@ static void place_showcase(Game *g, Faction human, Faction enemy) { for (int i = 0; i < 8; i++) raid[rn++] = unit_spawn(g, UT_INFANTRY, enemy, rx - 28 + (i % 4) * 14, ry - 8 + (i / 4) * 14); + /* dense Evolved melee wedge into Survivor rifle screen */ + for (int i = 0; i < 6; i++) + raid[rn++] = unit_spawn(g, UT_MUTANT, enemy, + rx - 8 + (i % 3) * 12, ry + 6 + (i / 3) * 11); + for (int i = 0; i < 4; i++) + raid[rn++] = unit_spawn(g, UT_BEAST, enemy, + rx + 4 + i * 13, ry + 18 + (i & 1) * 8); + for (int i = 0; i < 8; i++) + raid[rn++] = unit_spawn(g, UT_INFANTRY, enemy, + rx - 18 + (i % 4) * 10, ry + 10 + (i / 4) * 9); - /* secondary Evolved pack at SE clash (room left in raid[56]) */ + /* secondary Evolved pack at SE clash — melee-heavy */ int rn_pri = rn; for (int i = 0; i < 4; i++) raid[rn++] = unit_spawn(g, UT_MUTANT, enemy, @@ -651,6 +675,15 @@ static void place_showcase(Game *g, Faction human, Faction enemy) { for (int i = 0; i < 2; i++) raid[rn++] = unit_spawn(g, UT_INFANTRY, enemy, rx2 + 6 + i * 12, ry2 + 20 + i * 6); + for (int i = 0; i < 4; i++) + raid[rn++] = unit_spawn(g, UT_MUTANT, enemy, + rx2 - 4 + (i % 2) * 14, ry2 + 14 + (i / 2) * 12); + for (int i = 0; i < 2; i++) + raid[rn++] = unit_spawn(g, UT_BEAST, enemy, + rx2 + 12 + i * 16, ry2 + 28 + i * 6); + for (int i = 0; i < 6; i++) + raid[rn++] = unit_spawn(g, UT_INFANTRY, enemy, + rx2 - 10 + (i % 3) * 11, ry2 + 8 + (i / 3) * 10); /* seed Survivor harvester beds so cargo silhouette is visible in shot */ { diff --git a/engine-c/src/render.c b/engine-c/src/render.c index ef7ad97..83d8736 100644 --- a/engine-c/src/render.c +++ b/engine-c/src/render.c @@ -128,23 +128,37 @@ void render_buildings(Game *g) { } else { SDL_RenderCopy(g->ren, tex, NULL, &r); } - /* battle wear: scorch + crack lines when damaged */ + /* battle wear: scorch + cracks + rubble + ember (parity w/ snapshot) */ if (b->build >= 1.0f && b->max_hp > 0 && b->hp < b->max_hp * 0.95f) { float dmg = 1.0f - (b->hp / b->max_hp); int pw = W / 4; if (pw < 4) pw = 4; int ph = H / 5; if (ph < 3) ph = 3; SDL_SetRenderDrawColor(g->ren, 42, 32, 22, (Uint8)(90 + (int)(dmg * 110))); SDL_RenderFillRect(g->ren, &(SDL_Rect){ sx + W / 4, sy + H / 3, pw, ph }); - if (dmg > 0.3f) + if (dmg > 0.25f) SDL_RenderFillRect(g->ren, &(SDL_Rect){ sx + W / 2, sy + H / 2, pw, ph }); + if (dmg > 0.45f) + SDL_RenderFillRect(g->ren, &(SDL_Rect){ sx + W / 6, sy + (H * 2) / 3, pw - 1, ph - 1 }); SDL_SetRenderDrawColor(g->ren, 25, 22, 18, 255); SDL_RenderDrawLine(g->ren, sx + 4, sy + H / 4, sx + W / 2, sy + (H * 2) / 3); SDL_RenderDrawLine(g->ren, sx + W / 2, sy + (H * 2) / 3, sx + W - 4, sy + H / 3); + SDL_RenderDrawLine(g->ren, sx + W / 5, sy + 4, sx + (W * 3) / 5, sy + H / 2); if (dmg > 0.5f) { SDL_RenderDrawLine(g->ren, sx + W / 3, sy + 2, sx + W / 3 + 4, sy + H - 2); + SDL_RenderDrawLine(g->ren, sx + (W * 2) / 3, sy + H / 5, sx + W / 4, sy + H - 3); SDL_SetRenderDrawColor(g->ren, 90, 75, 55, 255); SDL_RenderFillRect(g->ren, &(SDL_Rect){ sx + 2, sy + H - 4, 6, 4 }); SDL_RenderFillRect(g->ren, &(SDL_Rect){ sx + W - 10, sy + H - 5, 8, 5 }); + SDL_RenderFillRect(g->ren, &(SDL_Rect){ sx + W / 2 - 2, sy + H - 3, 6, 3 }); + } + if (dmg > 0.65f) { + SDL_SetRenderDrawColor(g->ren, 220, 110, 40, 220); + SDL_RenderFillRect(g->ren, &(SDL_Rect){ sx + W / 2 - 1, sy + H / 2 - 1, 3, 3 }); + SDL_SetRenderDrawColor(g->ren, 255, 160, 60, 200); + SDL_RenderFillRect(g->ren, &(SDL_Rect){ sx + W / 3 + 1, sy + (H * 2) / 3, 2, 2 }); + SDL_SetRenderDrawColor(g->ren, 40, 32, 24, 255); + SDL_RenderFillRect(g->ren, &(SDL_Rect){ sx + 4, sy + 3, 3, 2 }); + SDL_RenderFillRect(g->ren, &(SDL_Rect){ sx + W - 8, sy + 4, 4, 3 }); } } /* outlined HP strip (green→red) when damaged or selected */ diff --git a/engine-c/src/snapshot.c b/engine-c/src/snapshot.c index 617d622..2f34ab9 100644 --- a/engine-c/src/snapshot.c +++ b/engine-c/src/snapshot.c @@ -717,20 +717,37 @@ static void draw_bld(Building *b, int sx, int sy) { fill_rect(sx, sy - 7, W, 4, 55, 50, 40); fill_rect(sx, sy - 7, (int)(W * b->build + 0.5f), 4, 120, 220, 120); } - /* battle damage: scorch patches + crack lines + rubble chips */ + /* battle damage: scorch + cracks + rubble + ember (reads in KKND_SHOT) */ if (b->max_hp > 0 && b->hp < b->max_hp * 0.95f) { float dmg = 1.0f - (b->hp / b->max_hp); int pw = W / 4; if (pw < 3) pw = 3; int ph = H / 5; if (ph < 2) ph = 2; fill_rect(sx + W / 4, sy + H / 3, pw, ph, 45, 35, 25); - if (dmg > 0.3f) + disc(sx + W / 3, sy + H / 2, pw / 2 + 1, 38, 30, 22); + if (dmg > 0.25f) { fill_rect(sx + W / 2, sy + H / 2, pw, ph, 55, 40, 28); + disc(sx + (W * 2) / 3, sy + H / 3, pw / 3 + 1, 48, 36, 24); + } + if (dmg > 0.45f) { + fill_rect(sx + W / 6, sy + (H * 2) / 3, pw - 1, ph - 1, 50, 38, 26); + disc(sx + W / 5, sy + H / 4, 2, 60, 42, 28); + } line(sx + 3, sy + H / 4, sx + W / 2, sy + (H * 2) / 3, 28, 24, 18); line(sx + W / 2, sy + (H * 2) / 3, sx + W - 3, sy + H / 3, 28, 24, 18); + line(sx + W / 5, sy + 4, sx + (W * 3) / 5, sy + H / 2, 32, 26, 20); if (dmg > 0.5f) { line(sx + W / 3, sy + 2, sx + W / 3 + 3, sy + H - 2, 22, 18, 14); + line(sx + (W * 2) / 3, sy + H / 5, sx + W / 4, sy + H - 3, 24, 20, 16); fill_rect(sx + 2, sy + H - 4, 5, 3, 95, 78, 55); fill_rect(sx + W - 9, sy + H - 5, 7, 4, 85, 70, 50); + fill_rect(sx + W / 2 - 2, sy + H - 3, 6, 3, 90, 72, 48); + } + if (dmg > 0.65f) { + /* ember glow in heavy breaches */ + disc(sx + W / 2, sy + H / 2, 2, 220, 110, 40); + disc(sx + W / 3 + 2, sy + (H * 2) / 3, 1, 255, 160, 60); + fill_rect(sx + 4, sy + 3, 3, 2, 40, 32, 24); + fill_rect(sx + W - 8, sy + 4, 4, 3, 35, 28, 20); } /* thin HP bar so damage reads in KKND_SHOT */ {