engine-c: scrap mounds + lingering FX + secondary SE clash

This commit is contained in:
local-model/engine-L2-grok-4.5 2026-09-19 14:20:56 +02:00
parent 0897293f51
commit 4411169cc3
No known key found for this signature in database
5 changed files with 243 additions and 22 deletions

View file

@ -357,8 +357,82 @@ static void place_showcase(Game *g, Faction human, Faction enemy) {
}
}
}
/* scrap mound fields: SE of HQ + corridor toward primary clash */
{
int hx_t = sx, hy_t = sy;
for (int dy = -2; dy <= 8; dy++) {
for (int dx = -2; dx <= 10; dx++) {
int tx = hx_t + dx, ty = hy_t + dy;
if (!map_in_bounds(&g->map, tx, ty)) continue;
Tile *t = map_tile(&g->map, tx, ty);
if (!t || t->occupied || !t->walkable) continue;
if (t->terrain == T_ROAD) continue;
int h = (dx * 11 + dy * 9) & 7;
if (h == 0 || h == 3) {
t->terrain = T_SCRAP;
t->scrap = (uint8_t)(110 + ((dx * 17 + dy * 13) & 127));
}
}
}
}
}
/* secondary clash front SE of HQ (second fight plate in crop) */
float rx2 = wx + 40.0f, ry2 = wy + 70.0f;
{
int ctx2, cty2;
map_world_to_tile(rx2, ry2, &ctx2, &cty2);
for (int dy = -5; dy <= 5; dy++) {
for (int dx = -6; dx <= 6; dx++) {
int tx = ctx2 + dx, ty = cty2 + dy;
if (!map_in_bounds(&g->map, tx, ty)) continue;
Tile *t = map_tile(&g->map, tx, ty);
if (!t || !t->walkable) continue;
int d2 = dx * dx + dy * dy;
if (d2 <= 2) {
t->terrain = T_ROAD;
t->scrap = 0;
} else if (d2 <= 10) {
t->terrain = T_RUBBLE;
t->scrap = 0;
} else if (d2 <= 24 && ((dx + dy * 2) & 3) == 0) {
t->terrain = T_SCRAP;
t->scrap = (uint8_t)(100 + ((dx * 19 + dy * 11) & 127));
}
}
}
/* short approach from HQ south gate toward secondary */
{
int steps = abs(ctx2 - sx) + abs(cty2 - sy);
if (steps < 1) steps = 1;
for (int s = 0; s <= steps; s++) {
int tx = sx + (ctx2 - sx) * s / steps;
int ty = sy + (cty2 - sy) * s / steps;
if (!map_in_bounds(&g->map, tx, ty)) continue;
Tile *t = map_tile(&g->map, tx, ty);
if (!t || !t->walkable) continue;
if (t->occupied) continue;
t->terrain = T_ROAD;
t->scrap = 0;
}
}
bld_spawn(g, BT_TURRET, human, ctx2 - 2, cty2);
bld_spawn(g, BT_TURRET, human, ctx2 + 1, cty2 + 1);
bld_spawn(g, BT_WALL, human, ctx2 - 3, cty2);
bld_spawn(g, BT_WALL, human, ctx2 - 3, cty2 + 1);
bld_force_complete(g);
}
/* Survivor SE defenders */
unit_spawn(g, UT_TANK, human, rx2 - 18, ry2 - 8);
unit_spawn(g, UT_TANK, human, rx2 - 6, ry2 + 10);
unit_spawn(g, UT_JEEP, human, rx2 - 28, ry2 + 4);
unit_spawn(g, UT_FLAME, human, rx2 - 22, ry2 + 18);
unit_spawn(g, UT_BUGGY, human, rx2 - 34, ry2 - 12);
for (int i = 0; i < 5; i++)
unit_spawn(g, UT_INFANTRY, human,
rx2 - 12 + (i % 3) * 12, ry2 - 16 + (i / 3) * 14);
int raid[56];
int rn = 0;
for (int i = 0; i < 8; i++)
@ -389,6 +463,24 @@ static void place_showcase(Game *g, Faction human, Faction enemy) {
raid[rn++] = unit_spawn(g, UT_INFANTRY, enemy,
rx - 28 + (i % 4) * 14, ry - 8 + (i / 4) * 14);
/* secondary Evolved pack at SE clash (room left in raid[56]) */
int rn_pri = rn;
for (int i = 0; i < 4; i++)
raid[rn++] = unit_spawn(g, UT_MUTANT, enemy,
rx2 + 10 + (i % 2) * 16, ry2 + 8 + (i / 2) * 14);
for (int i = 0; i < 2; i++)
raid[rn++] = unit_spawn(g, UT_BEAST, enemy, rx2 + 28 + i * 14, ry2 + 4 + i * 10);
raid[rn++] = unit_spawn(g, UT_BUGGY, enemy, rx2 + 18, ry2 - 10);
raid[rn++] = unit_spawn(g, UT_BUGGY, enemy, rx2 + 34, ry2 + 16);
raid[rn++] = unit_spawn(g, UT_JEEP, enemy, rx2 + 42, ry2 + 2);
raid[rn++] = unit_spawn(g, UT_TANK, enemy, rx2 + 50, ry2 + 12);
raid[rn++] = unit_spawn(g, UT_TANK, enemy, rx2 + 58, ry2 - 6);
raid[rn++] = unit_spawn(g, UT_RAVAGER, enemy, rx2 + 46, ry2 + 22);
raid[rn++] = unit_spawn(g, UT_FLAME, enemy, rx2 + 22, ry2 + 26);
raid[rn++] = unit_spawn(g, UT_MISSILE, enemy, rx2 + 64, ry2 + 8);
for (int i = 0; i < 2; i++)
raid[rn++] = unit_spawn(g, UT_INFANTRY, enemy,
rx2 + 6 + i * 12, ry2 + 20 + i * 6);
/* seed Survivor harvester beds so cargo silhouette is visible in shot */
{
@ -404,66 +496,104 @@ static void place_showcase(Game *g, Faction human, Faction enemy) {
}
}
/* pre-damage for HP-bar variety (sim may add more) */
/* pre-damage for HP-bar variety at both clash loci */
for (int i = 0; i < g->unit_count; i++) {
Unit *u = &g->units[i];
if (u->dead || u->max_hp <= 0) continue;
float dx = u->x - rx, dy = u->y - ry;
if (dx * dx + dy * dy > 140.0f * 140.0f) continue;
float dx2 = u->x - rx2, dy2 = u->y - ry2;
int near = (dx * dx + dy * dy <= 140.0f * 140.0f)
|| (dx2 * dx2 + dy2 * dy2 <= 110.0f * 110.0f);
if (!near) continue;
float f = 0.35f + 0.45f * ((i * 17) % 100) / 100.0f;
u->hp = u->max_hp * f;
}
/* FX seeds at the clash locus */
/* FX seeds at primary + secondary clash loci */
particle_burst(g, rx, ry, 28, 1, 255, 140, 40);
particle_burst(g, rx + 20, ry - 10, 18, 0, 90, 90, 90);
particle_burst(g, rx - 15, ry + 12, 22, 2, 255, 220, 80);
particle_burst(g, rx + 40, ry + 5, 14, 1, 255, 100, 30);
particle_burst(g, rx + 10, ry - 25, 16, 3, 80, 70, 60);
particle_burst(g, rx2, ry2, 24, 1, 255, 130, 35);
particle_burst(g, rx2 + 16, ry2 - 8, 16, 0, 100, 95, 85);
particle_burst(g, rx2 - 12, ry2 + 10, 18, 2, 255, 210, 70);
particle_burst(g, rx2 + 28, ry2 + 6, 12, 1, 255, 90, 25);
particle_burst(g, rx2 + 8, ry2 + 20, 14, 3, 85, 75, 55);
/* point raid at nearest human combat units / HQ */
/* point primary raid at nearest human combat / HQ; secondary at SE prey */
int hq = -1;
for (int i = 0; i < g->bld_count; i++)
if (!g->buildings[i].dead && g->buildings[i].faction == human
&& g->buildings[i].type == BT_BASE) { hq = i; break; }
int prey = -1;
int prey = -1, prey2 = -1;
float prey_d2 = 1e12f, prey2_d2 = 1e12f;
for (int i = 0; i < g->unit_count; i++) {
Unit *u = &g->units[i];
if (u->dead || u->faction != human) continue;
if (u->type == UT_HARVESTER || u->type == UT_MEDIC) continue;
prey = i; break;
float d1 = (u->x - rx) * (u->x - rx) + (u->y - ry) * (u->y - ry);
float d2 = (u->x - rx2) * (u->x - rx2) + (u->y - ry2) * (u->y - ry2);
if (d1 < prey_d2) { prey_d2 = d1; prey = i; }
if (d2 < prey2_d2) { prey2_d2 = d2; prey2 = i; }
}
int tur2 = -1;
for (int i = 0; i < g->bld_count; i++) {
Building *b = &g->buildings[i];
if (b->dead || b->faction != human || b->type != BT_TURRET) continue;
float bx = (float)(b->tx * TILE + b->w * TILE / 2);
float by = (float)(b->ty * TILE + b->h * TILE / 2);
float d2 = (bx - rx2) * (bx - rx2) + (by - ry2) * (by - ry2);
if (d2 < 90.0f * 90.0f) { tur2 = i; break; }
}
for (int i = 0; i < rn; i++) {
if (raid[i] < 0) continue;
if (prey >= 0) unit_issue_attack_unit(g, raid[i], prey);
else if (hq >= 0) unit_issue_attack_bld(g, raid[i], hq);
if (i < rn_pri) {
if (prey >= 0) unit_issue_attack_unit(g, raid[i], prey);
else if (hq >= 0) unit_issue_attack_bld(g, raid[i], hq);
} else {
if (prey2 >= 0) unit_issue_attack_unit(g, raid[i], prey2);
else if (tur2 >= 0) unit_issue_attack_bld(g, raid[i], tur2);
else if (hq >= 0) unit_issue_attack_bld(g, raid[i], hq);
}
}
/* human combat units engage nearest raiders (spread targets) */
/* human combat units engage nearest raiders (both fronts) */
int ridx = 0;
for (int i = 0; i < g->unit_count; i++) {
Unit *u = &g->units[i];
if (u->dead || u->faction != human) continue;
if (u->type == UT_HARVESTER || u->type == UT_MEDIC) continue;
float dx = u->x - rx, dy = u->y - ry;
if (dx * dx + dy * dy > 220.0f * 220.0f) continue;
float dx2 = u->x - rx2, dy2 = u->y - ry2;
int near = (dx * dx + dy * dy <= 220.0f * 220.0f)
|| (dx2 * dx2 + dy2 * dy2 <= 160.0f * 160.0f);
if (!near) continue;
int prefer_sec = (dx2 * dx2 + dy2 * dy2) < (dx * dx + dy * dy);
int lo = prefer_sec ? rn_pri : 0;
int hi = prefer_sec ? rn : rn_pri;
if (hi <= lo) { lo = 0; hi = rn; }
int tgt = -1;
for (int k = 0; k < rn; k++) {
int ri = raid[(ridx + k) % rn];
int span = hi - lo;
for (int k = 0; k < span; k++) {
int ri = raid[lo + (ridx + k) % span];
if (ri >= 0 && !g->units[ri].dead) { tgt = ri; ridx += k + 1; break; }
}
if (tgt >= 0) unit_issue_attack_unit(g, i, tgt);
}
/* select a front-line squad for yellow selection boxes in the shot */
/* select front-line squads on both clashes for yellow selection boxes */
unit_clear_selection(g);
int nsel = 0;
for (int i = 0; i < g->unit_count && nsel < 8; i++) {
for (int i = 0; i < g->unit_count && nsel < 10; i++) {
Unit *u = &g->units[i];
if (u->dead || u->faction != human) continue;
if (u->type == UT_HARVESTER || u->type == UT_MEDIC) continue;
float dx = u->x - rx, dy = u->y - ry;
if (dx * dx + dy * dy > 120.0f * 120.0f) continue;
float dx2 = u->x - rx2, dy2 = u->y - ry2;
int near = (dx * dx + dy * dy <= 120.0f * 120.0f)
|| (dx2 * dx2 + dy2 * dy2 <= 90.0f * 90.0f);
if (!near) continue;
unit_select_single(g, i, 1);
nsel++;
}