kitchen: README + MISSIONS/engine-c keep-drop notes
This commit is contained in:
parent
1d351918da
commit
575d7d29b8
130 changed files with 9817 additions and 1 deletions
188
engine-c/src/engine.c
Normal file
188
engine-c/src/engine.c
Normal file
|
|
@ -0,0 +1,188 @@
|
|||
#include "kknd.h"
|
||||
|
||||
/* =========================================================================
|
||||
* engine.c - Match setup, main simulation step and win/lose logic.
|
||||
* ========================================================================= */
|
||||
|
||||
int g_headless = 0;
|
||||
int g_auto = 0;
|
||||
|
||||
void engine_log(const char *fmt, ...) {
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
char buf[512];
|
||||
vsnprintf(buf, sizeof buf, fmt, ap);
|
||||
va_end(ap);
|
||||
printf("[kknd] %s\n", buf);
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
void game_log(Game *g, const char *fmt, ...) {
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
vsnprintf(g->log_msg[g->log_next], 96, fmt, ap);
|
||||
va_end(ap);
|
||||
g->log_next = (g->log_next + 1) % 32;
|
||||
if (g->log_count < 32) g->log_count++;
|
||||
}
|
||||
|
||||
void engine_init(Game *g, const char *title) {
|
||||
memset(g, 0, sizeof(Game));
|
||||
g->wrecks = (Wreck *)calloc(MAX_WRECKS, sizeof(Wreck));
|
||||
config_init();
|
||||
if (!g_headless) {
|
||||
audio_init();
|
||||
if (!render_init(g)) {
|
||||
fprintf(stderr, "Failed to initialise renderer\n");
|
||||
exit(1);
|
||||
}
|
||||
} else {
|
||||
(void)title;
|
||||
}
|
||||
g->state = GAME_MENU;
|
||||
g->human = FACTION_SURVIVOR;
|
||||
g->diff = DIFF_NORMAL;
|
||||
g->speed_mul = 1.0f;
|
||||
g->unlocked = 1;
|
||||
g->menu_sel = 0;
|
||||
}
|
||||
|
||||
void engine_shutdown(Game *g) {
|
||||
free(g->wrecks);
|
||||
sprites_free(&g->spr);
|
||||
if (g->ren) SDL_DestroyRenderer(g->ren);
|
||||
if (g->win) SDL_DestroyWindow(g->win);
|
||||
audio_shutdown();
|
||||
SDL_Quit();
|
||||
map_free(&g->map);
|
||||
}
|
||||
|
||||
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;
|
||||
bld_spawn(g, BT_BASE, f, bx, by);
|
||||
bld_spawn(g, BT_REFINERY, f, bx, sy + 2);
|
||||
bld_spawn(g, BT_WARFACTORY, f, sx + 2, by);
|
||||
bld_spawn(g, BT_POWER, f, sx + 2, sy + 2);
|
||||
|
||||
float wx, wy; map_tile_to_world(sx, sy, &wx, &wy);
|
||||
/* harvesters */
|
||||
for (int i = 0; i < 2; i++)
|
||||
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);
|
||||
/* 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);
|
||||
}
|
||||
|
||||
void engine_setup_match(Game *g, int mission_id) {
|
||||
const Mission *m = mission_get(mission_id);
|
||||
g->mission_id = m->id;
|
||||
g->objective = m->objective;
|
||||
g->diff = (Difficulty)m->diff;
|
||||
g->obj_timer = 0;
|
||||
|
||||
/* resolve the enemy faction (never the player's own side) */
|
||||
Faction enemy = m->enemy;
|
||||
if (enemy == g->human)
|
||||
enemy = (g->human == FACTION_SURVIVOR) ? FACTION_EVOLVED : FACTION_SURVIVOR;
|
||||
g->enemy = enemy;
|
||||
|
||||
RNG rng;
|
||||
rng_seed(&rng, (uint64_t)m->seed ^ 0x4B4B4E44ULL);
|
||||
g->map.style = m->map_style;
|
||||
map_init(&g->map, &rng);
|
||||
|
||||
g->unit_count = 0; g->unit_next_id = 1;
|
||||
g->bld_count = 0; g->bld_next_id = 1;
|
||||
g->bullet_count = 0; g->particle_count = 0;
|
||||
g->sel_count = 0; g->placing = 0;
|
||||
g->time = 0; g->frames = 0; g->winner = 0;
|
||||
g->ai_timer = 5.0f;
|
||||
g->log_count = 0; g->log_next = 0;
|
||||
|
||||
for (int f = 1; f < MAX_FACTIONS; f++) {
|
||||
g->scrap[f] = START_SCRAP;
|
||||
g->power[f] = 0; g->pop[f] = 0; g->pop_cap[f] = 0;
|
||||
for (int u = 0; u < UP_COUNT; u++) g->upg[f].lvl[u] = 0;
|
||||
g->research_lab[f] = 0;
|
||||
g->research_cur[f] = -1;
|
||||
g->research_prog[f] = 0;
|
||||
}
|
||||
|
||||
place_start(g, g->human);
|
||||
place_start(g, enemy);
|
||||
|
||||
/* fortress theme: wall the enemy base (leave a gate on the far edge) */
|
||||
if (m->map_style == 3) {
|
||||
int sx = g->map.spawn_x[enemy], sy = g->map.spawn_y[enemy];
|
||||
for (int dx = -2; dx <= 4; dx++)
|
||||
for (int dy = -2; dy <= 4; dy++) {
|
||||
int perimeter = (dx == -2 || dx == 4 || dy == -2 || dy == 4);
|
||||
if (!perimeter) continue;
|
||||
if (dy == 4) continue; /* gate on the far edge */
|
||||
bld_spawn(g, BT_WALL, enemy, sx + dx, sy + dy);
|
||||
}
|
||||
}
|
||||
|
||||
/* centre camera on player base */
|
||||
int hx = g->map.spawn_x[g->human], hy = g->map.spawn_y[g->human];
|
||||
g->cam.x = (float)(hx*TILE - VIEW_W/2);
|
||||
g->cam.y = (float)(hy*TILE - VIEW_H/2);
|
||||
if (g->cam.x < 0) g->cam.x = 0;
|
||||
if (g->cam.y < 0) g->cam.y = 0;
|
||||
|
||||
g->state = GAME_PLAYING;
|
||||
engine_log("Mission %d '%s': %s vs %s (%s)",
|
||||
m->id, m->name, faction_name(g->human), faction_name(enemy),
|
||||
m->diff==DIFF_EASY?"Easy":m->diff==DIFF_HARD?"Hard":"Normal");
|
||||
}
|
||||
|
||||
void engine_check_win(Game *g) {
|
||||
Faction human = g->human;
|
||||
Faction enemy = g->enemy;
|
||||
int human_base = 0, enemy_base = 0;
|
||||
int human_bld = 0, enemy_bld = 0;
|
||||
for (int i = 0; i < g->bld_count; i++) {
|
||||
Building *b = &g->buildings[i];
|
||||
if (b->dead) continue;
|
||||
if (b->faction == human) { human_bld++; if (b->type==BT_BASE) human_base=1; }
|
||||
if (b->faction == enemy) { enemy_bld++; if (b->type==BT_BASE) enemy_base=1; }
|
||||
}
|
||||
if (!human_base || human_bld == 0) { g->state = GAME_LOST; g->winner = enemy; return; }
|
||||
|
||||
switch (g->objective) {
|
||||
case OBJ_SURVIVE:
|
||||
if (g->time >= ((const Mission*)mission_get(g->mission_id))->survive_time)
|
||||
{ g->state = GAME_WON; g->winner = human; }
|
||||
break;
|
||||
case OBJ_GATHER:
|
||||
if (g->scrap[human] >= ((const Mission*)mission_get(g->mission_id))->scrap_goal)
|
||||
{ g->state = GAME_WON; g->winner = human; }
|
||||
break;
|
||||
default: /* OBJ_DESTROY_ALL */
|
||||
if (!enemy_base || enemy_bld == 0) { g->state = GAME_WON; g->winner = human; }
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void engine_update(Game *g, float dt) {
|
||||
if (g->state != GAME_PLAYING) return;
|
||||
dt *= g->speed_mul;
|
||||
g->time += dt;
|
||||
g->frames++;
|
||||
|
||||
unit_update(g, dt);
|
||||
bld_update(g, dt);
|
||||
bullet_update(g, dt);
|
||||
particle_update(g, dt);
|
||||
ai_update(g, dt);
|
||||
map_update_fog(g, g->human);
|
||||
audio_music_tick(dt);
|
||||
if (g->cam.shake > 0) { g->cam.shake -= dt * 24.0f; if (g->cam.shake < 0) g->cam.shake = 0; }
|
||||
engine_check_win(g);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue