engine-c: arid KKND2-like showcase shot + kitchen claim DONE
This commit is contained in:
parent
575d7d29b8
commit
b5a89c9b47
11 changed files with 739 additions and 84 deletions
|
|
@ -57,6 +57,15 @@ void engine_shutdown(Game *g) {
|
|||
map_free(&g->map);
|
||||
}
|
||||
|
||||
static void bld_force_complete(Game *g) {
|
||||
for (int i = 0; i < g->bld_count; i++) {
|
||||
Building *b = &g->buildings[i];
|
||||
if (b->dead) continue;
|
||||
b->build = 1.0f;
|
||||
b->hp = b->max_hp;
|
||||
}
|
||||
}
|
||||
|
||||
static void place_start(Game *g, Faction f) {
|
||||
int sx = g->map.spawn_x[f], sy = g->map.spawn_y[f];
|
||||
int bx = sx - 1, by = sy - 1;
|
||||
|
|
@ -71,12 +80,216 @@ static void place_start(Game *g, Faction f) {
|
|||
unit_spawn(g, UT_HARVESTER, f, wx + (i*24-12), wy + 30);
|
||||
/* starting infantry */
|
||||
for (int i = 0; i < 4; i++)
|
||||
unit_spawn(g, (f==FACTION_SURVIVOR?UT_INFANTRY:UT_INFANTRY), f,
|
||||
wx - 40 + i*20, wy - 20);
|
||||
unit_spawn(g, UT_INFANTRY, f, wx - 40 + i*20, wy - 20);
|
||||
/* a couple of buggies */
|
||||
for (int i = 0; i < 2; i++)
|
||||
unit_spawn(g, (f==FACTION_SURVIVOR?UT_BUGGY:UT_BUGGY), f,
|
||||
wx - 30 + i*30, wy - 40);
|
||||
unit_spawn(g, UT_BUGGY, f, wx - 30 + i*30, wy - 40);
|
||||
}
|
||||
|
||||
/* KKND2-like showcase: extra human base structures + diverse roster +
|
||||
* enemy raid pack near the camera so fog/snapshot show combat. */
|
||||
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);
|
||||
|
||||
/* extra structures in the cleared spawn pad (±8) */
|
||||
bld_spawn(g, BT_REPAIR, human, sx - 4, sy - 1);
|
||||
bld_spawn(g, BT_RESEARCH, human, sx - 4, sy + 2);
|
||||
bld_spawn(g, BT_POWER, human, sx + 3, sy + 2);
|
||||
bld_spawn(g, BT_POWER, human, sx + 5, sy + 2);
|
||||
bld_spawn(g, BT_WARFACTORY, human, sx + 3, sy - 4);
|
||||
|
||||
/* turrets covering approaches */
|
||||
bld_spawn(g, BT_TURRET, human, sx - 2, sy - 3);
|
||||
bld_spawn(g, BT_TURRET, human, sx + 1, sy - 3);
|
||||
bld_spawn(g, BT_TURRET, human, sx + 4, sy);
|
||||
bld_spawn(g, BT_TURRET, human, sx + 4, sy + 2);
|
||||
bld_spawn(g, BT_TURRET, human, sx - 2, sy + 4);
|
||||
bld_spawn(g, BT_TURRET, human, sx + 2, sy + 4);
|
||||
bld_spawn(g, BT_TURRET, human, sx - 4, sy);
|
||||
|
||||
/* blast-wall spur (north + west + east stub) */
|
||||
for (int dx = -3; dx <= 3; dx++) {
|
||||
if (dx >= -1 && dx <= 1) continue; /* gate */
|
||||
bld_spawn(g, BT_WALL, human, sx + dx, sy - 4);
|
||||
}
|
||||
for (int dy = -3; dy <= 3; dy++) {
|
||||
if (dy >= -1 && dy <= 1) continue;
|
||||
bld_spawn(g, BT_WALL, human, sx - 5, sy + dy);
|
||||
}
|
||||
for (int dy = -2; dy <= 2; dy++) {
|
||||
if (dy == 0) continue;
|
||||
bld_spawn(g, BT_WALL, human, sx + 6, sy + dy);
|
||||
}
|
||||
|
||||
/* dense Survivor battle line NE of HQ (tight combat camera) */
|
||||
unit_spawn(g, UT_TANK, human, wx + 48, wy - 8);
|
||||
unit_spawn(g, UT_TANK, human, wx + 68, wy + 8);
|
||||
unit_spawn(g, UT_TANK, human, wx + 82, wy - 38);
|
||||
unit_spawn(g, UT_TANK, human, wx + 58, wy - 48);
|
||||
unit_spawn(g, UT_RAVAGER, human, wx + 92, wy - 22);
|
||||
unit_spawn(g, UT_RAVAGER, human, wx + 78, wy - 58);
|
||||
unit_spawn(g, UT_ARTILLERY, human, wx + 18, wy + 48);
|
||||
unit_spawn(g, UT_ARTILLERY, human, wx + 38, wy + 62);
|
||||
unit_spawn(g, UT_FLAME, human, wx - 40, wy + 12);
|
||||
unit_spawn(g, UT_FLAME, human, wx + 105, wy - 5);
|
||||
unit_spawn(g, UT_MISSILE, human, wx - 55, wy - 8);
|
||||
unit_spawn(g, UT_MISSILE, human, wx + 110, wy - 40);
|
||||
unit_spawn(g, UT_JEEP, human, wx + 32, wy - 52);
|
||||
unit_spawn(g, UT_JEEP, human, wx + 48, wy - 68);
|
||||
unit_spawn(g, UT_BUGGY, human, wx + 55, wy - 78);
|
||||
unit_spawn(g, UT_BUGGY, human, wx + 72, wy - 72);
|
||||
unit_spawn(g, UT_MEDIC, human, wx - 12, wy + 40);
|
||||
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);
|
||||
|
||||
/* Evolved raid pack — close NE, overlapping Survivor line */
|
||||
float rx = wx + 88.0f, ry = wy - 48.0f;
|
||||
|
||||
/* forward fortifications at the clash so a tight combat crop still shows buildings */
|
||||
{
|
||||
int ftx, fty;
|
||||
map_world_to_tile(rx, ry, &ftx, &fty);
|
||||
bld_spawn(g, BT_TURRET, human, ftx - 2, fty + 1);
|
||||
bld_spawn(g, BT_TURRET, human, ftx + 1, fty + 2);
|
||||
bld_spawn(g, BT_TURRET, human, ftx - 1, fty - 2);
|
||||
bld_spawn(g, BT_TURRET, human, ftx + 2, fty - 1);
|
||||
bld_spawn(g, BT_WALL, human, ftx - 3, fty);
|
||||
bld_spawn(g, BT_WALL, human, ftx - 3, fty + 1);
|
||||
bld_spawn(g, BT_WALL, human, ftx - 3, fty - 1);
|
||||
bld_spawn(g, BT_WALL, human, ftx + 2, fty + 1);
|
||||
bld_spawn(g, BT_WALL, human, ftx + 2, fty);
|
||||
bld_spawn(g, BT_WALL, human, ftx + 3, fty - 1);
|
||||
bld_spawn(g, BT_POWER, human, ftx - 4, fty + 2);
|
||||
bld_force_complete(g); /* complete any partial builds from spawn */
|
||||
}
|
||||
|
||||
/* denser clash scars: road core + rubble ring + scrap flecks (arid fight plate) */
|
||||
{
|
||||
int ctx, cty;
|
||||
map_world_to_tile(rx, ry, &ctx, &cty);
|
||||
for (int dy = -6; dy <= 6; dy++) {
|
||||
for (int dx = -7; dx <= 7; dx++) {
|
||||
int tx = ctx + dx, ty = cty + 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 <= 3) {
|
||||
t->terrain = T_ROAD;
|
||||
t->scrap = 0;
|
||||
} else if (d2 <= 12) {
|
||||
t->terrain = T_RUBBLE;
|
||||
t->scrap = 0;
|
||||
} else if (d2 <= 28 && ((dx + dy * 3) & 3) == 0) {
|
||||
t->terrain = T_SCRAP;
|
||||
t->scrap = (uint8_t)(90 + ((dx * 13 + dy * 7) & 127));
|
||||
} else if (d2 <= 32 && ((dx * 5 + dy) & 2) == 0) {
|
||||
t->terrain = T_RUBBLE;
|
||||
t->scrap = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* approach road from HQ toward clash */
|
||||
int hx_t = sx, hy_t = sy;
|
||||
int steps = abs(ctx - hx_t) + abs(cty - hy_t);
|
||||
if (steps < 1) steps = 1;
|
||||
for (int s = 0; s <= steps; s++) {
|
||||
int tx = hx_t + (ctx - hx_t) * s / steps;
|
||||
int ty = hy_t + (cty - hy_t) * s / steps;
|
||||
if (!map_in_bounds(&g->map, tx, ty)) continue;
|
||||
Tile *t = map_tile(&g->map, tx, ty);
|
||||
if (!t || !t->walkable) continue;
|
||||
t->terrain = T_ROAD;
|
||||
t->scrap = 0;
|
||||
}
|
||||
}
|
||||
|
||||
int raid[40];
|
||||
int rn = 0;
|
||||
for (int i = 0; i < 8; i++)
|
||||
raid[rn++] = unit_spawn(g, UT_MUTANT, enemy,
|
||||
rx + (i % 4) * 18 - 10, ry + (i / 4) * 16 - 8);
|
||||
for (int i = 0; i < 4; i++)
|
||||
raid[rn++] = unit_spawn(g, UT_BEAST, enemy, rx + 30 + i * 16, ry - 14 + (i & 1) * 18);
|
||||
raid[rn++] = unit_spawn(g, UT_BUGGY, enemy, rx + 8, ry - 28);
|
||||
raid[rn++] = unit_spawn(g, UT_BUGGY, enemy, rx + 28, ry - 34);
|
||||
raid[rn++] = unit_spawn(g, UT_BUGGY, enemy, rx + 48, ry - 22);
|
||||
raid[rn++] = unit_spawn(g, UT_TANK, enemy, rx + 52, ry + 4);
|
||||
raid[rn++] = unit_spawn(g, UT_TANK, enemy, rx + 68, ry - 12);
|
||||
raid[rn++] = unit_spawn(g, UT_FLAME, enemy, rx + 22, ry + 28);
|
||||
raid[rn++] = unit_spawn(g, UT_FLAME, enemy, rx + 40, ry + 34);
|
||||
raid[rn++] = unit_spawn(g, UT_MISSILE, enemy, rx + 62, ry - 28);
|
||||
raid[rn++] = unit_spawn(g, UT_MISSILE, enemy, rx + 78, ry - 8);
|
||||
raid[rn++] = unit_spawn(g, UT_ARTILLERY, enemy, rx + 85, ry + 10);
|
||||
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);
|
||||
|
||||
/* pre-damage for HP-bar variety (sim may add more) */
|
||||
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 f = 0.35f + 0.45f * ((i * 17) % 100) / 100.0f;
|
||||
u->hp = u->max_hp * f;
|
||||
}
|
||||
|
||||
/* FX seeds at the clash locus */
|
||||
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);
|
||||
|
||||
/* point raid at nearest human combat units / HQ */
|
||||
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;
|
||||
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;
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
/* human combat units engage nearest raiders (spread targets) */
|
||||
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;
|
||||
int tgt = -1;
|
||||
for (int k = 0; k < rn; k++) {
|
||||
int ri = raid[(ridx + k) % rn];
|
||||
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 */
|
||||
unit_clear_selection(g);
|
||||
int nsel = 0;
|
||||
for (int i = 0; i < g->unit_count && nsel < 8; 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;
|
||||
unit_select_single(g, i, 1);
|
||||
nsel++;
|
||||
}
|
||||
}
|
||||
|
||||
void engine_setup_match(Game *g, int mission_id) {
|
||||
|
|
@ -116,6 +329,8 @@ void engine_setup_match(Game *g, int mission_id) {
|
|||
|
||||
place_start(g, g->human);
|
||||
place_start(g, enemy);
|
||||
place_showcase(g, g->human, enemy);
|
||||
bld_force_complete(g);
|
||||
|
||||
/* fortress theme: wall the enemy base (leave a gate on the far edge) */
|
||||
if (m->map_style == 3) {
|
||||
|
|
@ -127,6 +342,7 @@ void engine_setup_match(Game *g, int mission_id) {
|
|||
if (dy == 4) continue; /* gate on the far edge */
|
||||
bld_spawn(g, BT_WALL, enemy, sx + dx, sy + dy);
|
||||
}
|
||||
bld_force_complete(g);
|
||||
}
|
||||
|
||||
/* centre camera on player base */
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue