engine-c: lasting death RUBBLE/SCRAP scars + denser scorch

This commit is contained in:
local-model/engine-L2-grok-4.5 2026-09-19 11:50:41 +02:00
parent 3fb17411dc
commit bab388723f
No known key found for this signature in database
4 changed files with 96 additions and 9 deletions

View file

@ -216,6 +216,11 @@ void map_world_to_tile(float wx, float wy, int *tx, int *ty);
void map_tile_to_world(int tx, int ty, float *wx, float *wy);
int map_find_nearest_scrap(GameMap *m, float wx, float wy, float *outx, float *outy);
void map_deplete_scrap(GameMap *m, int tx, int ty, int amount);
/* lasting battlefield scars — soft only (no WATER/ROCK overwrite; stay walkable) */
void map_scar_rubble(GameMap *m, int tx, int ty);
void map_scar_scrap_fleck(GameMap *m, int tx, int ty, uint8_t amount);
void map_scar_unit_death(GameMap *m, float wx, float wy, UnitType type);
void map_scar_bld_death(GameMap *m, int tx, int ty, int w, int h);
typedef struct Game Game;
void map_update_fog(Game *g, Faction f);

View file

@ -73,14 +73,18 @@ void bld_apply_damage(Game *g, Building *b, float dmg) {
(float)(b->ty*TILE+b->h*TILE/2), 2, 2, 255, 200, 80);
if (b->hp <= 0 && !b->dead) {
b->dead = 1;
particle_burst(g, (float)(b->tx*TILE+b->w*TILE/2),
(float)(b->ty*TILE+b->h*TILE/2), 20, 1, 255, 140, 40);
particle_burst(g, (float)(b->tx*TILE+b->w*TILE/2),
(float)(b->ty*TILE+b->h*TILE/2), 12, 3, 90, 80, 70);
float cx = (float)(b->tx*TILE+b->w*TILE/2);
float cy = (float)(b->ty*TILE+b->h*TILE/2);
particle_burst(g, cx, cy, 28, 1, 255, 140, 40);
particle_burst(g, cx, cy, 16, 3, 90, 80, 70);
particle_burst(g, cx + 10, cy - 8, 10, 0, 100, 90, 80);
particle_burst(g, cx - 8, cy + 10, 8, 1, 55, 45, 40); /* scorch */
audio_sfx(2);
if (g->cam.shake < 9) g->cam.shake = 9;
if (b->faction == g->human)
game_log(g, "Structure lost: %s", bld_def(b->type)->name);
/* lasting rubble under footprint; occupied cleared later by bld_remove */
map_scar_bld_death(&g->map, b->tx, b->ty, b->w, b->h);
}
}

View file

@ -254,6 +254,80 @@ void map_deplete_scrap(GameMap *m, int tx, int ty, int amount) {
}
}
/* Soft scar: never overwrite WATER/ROCK; never clear walkable. */
static int map_scar_ok(Tile *t) {
if (!t) return 0;
if (t->terrain == T_WATER || t->terrain == T_ROCK) return 0;
return 1;
}
void map_scar_rubble(GameMap *m, int tx, int ty) {
Tile *t = map_tile(m, tx, ty);
if (!map_scar_ok(t)) return;
/* keep ROAD as approach cue; scrap fields stay harvestable */
if (t->terrain == T_ROAD || t->terrain == T_SCRAP) return;
t->terrain = T_RUBBLE;
t->scrap = 0;
t->walkable = 1;
}
void map_scar_scrap_fleck(GameMap *m, int tx, int ty, uint8_t amount) {
Tile *t = map_tile(m, tx, ty);
if (!map_scar_ok(t)) return;
if (t->terrain == T_ROAD) return;
if (t->terrain == T_SCRAP && t->scrap > 0) return; /* leave live fields alone */
t->terrain = T_SCRAP;
t->scrap = amount ? amount : 40;
t->walkable = 1;
}
void map_scar_unit_death(GameMap *m, float wx, float wy, UnitType type) {
int tx, ty;
map_world_to_tile(wx, wy, &tx, &ty);
map_scar_rubble(m, tx, ty);
int vehicle = (type == UT_BUGGY || type == UT_TANK || type == UT_HARVESTER
|| type == UT_ARTILLERY || type == UT_JEEP || type == UT_RAVAGER
|| type == UT_MISSILE || type == UT_BEAST);
int heavy = (type == UT_TANK || type == UT_RAVAGER || type == UT_ARTILLERY
|| type == UT_HARVESTER);
if (!vehicle) return;
/* adjacent rubble ring — still soft / walkable */
static const int ox[8] = { 1,-1, 0, 0, 1, 1,-1,-1 };
static const int oy[8] = { 0, 0, 1,-1, 1,-1, 1,-1 };
int n = heavy ? 6 : 3;
for (int i = 0; i < n; i++)
map_scar_rubble(m, tx + ox[i], ty + oy[i]);
/* small scrap flecks from wrecked chassis */
if (heavy) {
map_scar_scrap_fleck(m, tx + 1, ty - 1, (uint8_t)(55 + ((tx * 7 + ty) & 63)));
map_scar_scrap_fleck(m, tx - 1, ty + 1, (uint8_t)(40 + ((tx * 3 + ty * 5) & 47)));
} else {
map_scar_scrap_fleck(m, tx + ox[tx & 3], ty + oy[ty & 3],
(uint8_t)(35 + ((tx + ty) & 31)));
}
}
void map_scar_bld_death(GameMap *m, int tx, int ty, int w, int h) {
if (w < 1) w = 1;
if (h < 1) h = 1;
for (int y = ty; y < ty + h; y++) {
for (int x = tx; x < tx + w; x++) {
map_scar_rubble(m, x, y);
/* outer flecks just outside footprint */
if (x == tx) map_scar_rubble(m, x - 1, y);
if (x == tx + w - 1) map_scar_rubble(m, x + 1, y);
if (y == ty) map_scar_rubble(m, x, y - 1);
if (y == ty + h - 1) map_scar_rubble(m, x, y + 1);
}
}
/* one scrap pile from collapsed structure */
map_scar_scrap_fleck(m, tx + w / 2, ty + h / 2,
(uint8_t)(70 + ((tx * 11 + ty * 13) & 80)));
}
/* ----------------------------- A* ----------------------------- */
/* Binary heap of tile indices keyed by f-score in a parallel array. */
#define ASTAR_NODES (MAP_W * MAP_H)

View file

@ -66,15 +66,19 @@ void unit_apply_damage(Game *g, Unit *u, float dmg) {
if (u->hp <= 0 && !u->dead) {
u->dead = 1;
u->state = STATE_DEAD;
/* denser KKND2-like death: fire core + debris ring + smoke */
particle_burst(g, u->x, u->y, 18, 1, 255, 140, 40);
particle_burst(g, u->x, u->y, 10, 3, 90, 80, 70);
particle_burst(g, u->x + 6, u->y - 4, 8, 0, 110, 100, 90);
particle_burst(g, u->x - 5, u->y + 5, 6, 2, 255, 220, 90);
/* denser KKND2-like death: fire core + debris ring + smoke + scorch */
particle_burst(g, u->x, u->y, 22, 1, 255, 140, 40);
particle_burst(g, u->x, u->y, 14, 3, 90, 80, 70);
particle_burst(g, u->x + 6, u->y - 4, 10, 0, 110, 100, 90);
particle_burst(g, u->x - 5, u->y + 5, 8, 2, 255, 220, 90);
particle_burst(g, u->x + 3, u->y + 7, 8, 1, 60, 50, 45); /* scorch soot */
particle_burst(g, u->x - 4, u->y - 6, 6, 0, 70, 55, 40);
audio_sfx(2);
if (g->cam.shake < 7) g->cam.shake = 7;
if (u->faction == g->human)
game_log(g, "Unit lost: %s", unit_def(u->type, u->faction)->name);
/* lasting terrain scar under corpse (RUBBLE/SCRAP, soft/walkable) */
map_scar_unit_death(&g->map, u->x, u->y, u->type);
/* leave a wreck decal on the battlefield */
if (g->wreck_count < MAX_WRECKS) {
Wreck *w = &g->wrecks[g->wreck_next];