124 lines
4.4 KiB
C
124 lines
4.4 KiB
C
#include "kknd.h"
|
|
|
|
/* =========================================================================
|
|
* ai.c - Enemy/human commander. Grows an economy and launches attack waves.
|
|
* ========================================================================= */
|
|
|
|
static Building *ai_find_bld(Game *g, Faction f, BuildingType t) {
|
|
for (int i = 0; i < g->bld_count; i++) {
|
|
Building *b = &g->buildings[i];
|
|
if (b->dead || b->faction != f || b->type != t) continue;
|
|
if (b->build < 1.0f) continue;
|
|
return b;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
static int ai_count_units(Game *g, Faction f, int combat_only) {
|
|
int n = 0;
|
|
for (int i = 0; i < g->unit_count; i++) {
|
|
Unit *u = &g->units[i];
|
|
if (u->dead || u->faction != f) continue;
|
|
if (combat_only && (u->type == UT_HARVESTER)) continue;
|
|
n++;
|
|
}
|
|
return n;
|
|
}
|
|
|
|
static int ai_count_harvesters(Game *g, Faction f) {
|
|
int n = 0;
|
|
for (int i = 0; i < g->unit_count; i++) {
|
|
Unit *u = &g->units[i];
|
|
if (u->dead || u->faction != f) continue;
|
|
if (u->type == UT_HARVESTER) n++;
|
|
}
|
|
return n;
|
|
}
|
|
|
|
static void ai_run_faction(Game *g, Faction f) {
|
|
Building *base = ai_find_bld(g, f, BT_BASE);
|
|
Building *wf = ai_find_bld(g, f, BT_WARFACTORY);
|
|
Building *ref = ai_find_bld(g, f, BT_REFINERY);
|
|
if (!base) return;
|
|
|
|
/* early defensive turret */
|
|
if (g->time < 60 && g->scrap[f] > 600) {
|
|
int bx = base->tx + 3, by = base->ty - 2;
|
|
if (bld_can_place(g, BT_TURRET, bx, by)) {
|
|
if (bld_spawn(g, BT_TURRET, f, bx, by) >= 0)
|
|
g->scrap[f] -= bld_def(BT_TURRET)->cost;
|
|
}
|
|
}
|
|
|
|
/* research lab + upgrades */
|
|
if (!ai_find_bld(g, f, BT_RESEARCH) && g->scrap[f] > 400) {
|
|
int bx = base->tx - 3, by = base->ty + 2;
|
|
if (bld_can_place(g, BT_RESEARCH, bx, by)) {
|
|
int r = bld_spawn(g, BT_RESEARCH, f, bx, by);
|
|
if (r >= 0) g->scrap[f] -= bld_def(BT_RESEARCH)->cost;
|
|
}
|
|
}
|
|
if (g->research_lab[f] > 0 && g->research_cur[f] < 0) {
|
|
int best = -1, bestlv = 99;
|
|
for (int u = 0; u < UP_COUNT; u++) {
|
|
if (g->upg[f].lvl[u] >= UP_MAX_LVL) continue;
|
|
if (g->upg[f].lvl[u] < bestlv) { bestlv = g->upg[f].lvl[u]; best = u; }
|
|
}
|
|
if (best >= 0) bld_research(g, f, best);
|
|
}
|
|
|
|
/* keep harvesters flowing */
|
|
if (ref && ai_count_harvesters(g, f) < 4 && g->scrap[f] >= 300)
|
|
bld_queue_unit(g, (int)(ref - g->buildings), UT_HARVESTER);
|
|
|
|
/* pump combat units */
|
|
if (wf) {
|
|
int combat = ai_count_units(g, f, 1);
|
|
int cap = (g->diff == DIFF_HARD) ? 40 : (g->diff == DIFF_NORMAL ? 28 : 18);
|
|
if (combat < cap) {
|
|
int r = rng_range(&(RNG){0}, 0, 6);
|
|
UnitType pick = (r == 0) ? UT_BUGGY : (r == 1) ? UT_TANK
|
|
: (r == 2) ? UT_ARTILLERY : (r == 3) ? UT_JEEP
|
|
: (r == 4) ? UT_RAVAGER : (r == 5) ? UT_FLAME
|
|
: UT_MISSILE;
|
|
bld_queue_unit(g, (int)(wf - g->buildings), pick);
|
|
}
|
|
}
|
|
|
|
/* attack wave every ~35s once we have a force */
|
|
g->ai_wave[f] += (g->diff == DIFF_HARD ? 4.0f : (g->diff == DIFF_NORMAL ? 6.0f : 9.0f));
|
|
if (g->ai_wave[f] >= 35.0f) {
|
|
g->ai_wave[f] = 0;
|
|
Faction foe = (f == g->human) ? g->enemy : g->human;
|
|
int hx = g->map.spawn_x[foe], hy = g->map.spawn_y[foe];
|
|
float tx, ty; map_tile_to_world(hx, hy, &tx, &ty);
|
|
int launched = 0;
|
|
for (int i = 0; i < g->unit_count; i++) {
|
|
Unit *u = &g->units[i];
|
|
if (u->dead || u->faction != f) continue;
|
|
if (u->type == UT_HARVESTER) continue;
|
|
unit_issue_move(g, (int)(u - g->units), tx, ty, 1);
|
|
launched++;
|
|
}
|
|
if (launched > 0) {
|
|
engine_log("%s warband (%d) advances on the %s!",
|
|
faction_name(f), launched, faction_name(foe));
|
|
if (f == g->human)
|
|
game_log(g, "Warband (%d units) sent to attack!", launched);
|
|
}
|
|
}
|
|
}
|
|
|
|
void ai_command(Faction f, int diff) { (void)f; (void)diff; }
|
|
|
|
void ai_update(Game *g, float dt) {
|
|
g->ai_timer -= dt;
|
|
if (g->ai_timer > 0) return;
|
|
|
|
float interval = (g->diff == DIFF_HARD) ? 4.0f :
|
|
(g->diff == DIFF_NORMAL ? 6.0f : 9.0f);
|
|
g->ai_timer = interval;
|
|
|
|
ai_run_faction(g, g->enemy);
|
|
if (g_auto) ai_run_faction(g, g->human);
|
|
}
|