engine-c: lasting death RUBBLE/SCRAP scars + denser scorch
This commit is contained in:
parent
3fb17411dc
commit
bab388723f
4 changed files with 96 additions and 9 deletions
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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];
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue