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
292
engine-c/src/input.c
Normal file
292
engine-c/src/input.c
Normal file
|
|
@ -0,0 +1,292 @@
|
|||
#include "kknd.h"
|
||||
|
||||
/* =========================================================================
|
||||
* input.c - Mouse / keyboard handling and camera control.
|
||||
* ========================================================================= */
|
||||
|
||||
static int g_keys[SDL_NUM_SCANCODES];
|
||||
|
||||
int input_screen_to_world(Game *g, int sx, int sy, float *wx, float *wy) {
|
||||
*wx = (float)sx + g->cam.x;
|
||||
*wy = (float)sy + g->cam.y;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int pick_unit(Game *g, int sx, int sy, float *wx, float *wy) {
|
||||
input_screen_to_world(g, sx, sy, wx, wy);
|
||||
int best = -1; float bestd = 18*18;
|
||||
for (int i = 0; i < g->unit_count; i++) {
|
||||
Unit *u = &g->units[i];
|
||||
if (u->dead) continue;
|
||||
float d = kknd_dist2(*wx, *wy, u->x, u->y);
|
||||
if (d < bestd) { bestd = d; best = i; }
|
||||
}
|
||||
return best;
|
||||
}
|
||||
|
||||
static int pick_building(Game *g, float wx, float wy) {
|
||||
for (int i = 0; i < g->bld_count; i++) {
|
||||
Building *b = &g->buildings[i];
|
||||
if (b->dead) continue;
|
||||
float bx = (float)(b->tx * TILE), by = (float)(b->ty * TILE);
|
||||
if (wx >= bx && wx <= bx + b->w*TILE && wy >= by && wy <= by + b->h*TILE)
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void issue_orders(Game *g, float wx, float wy) {
|
||||
/* attack if enemy unit under cursor */
|
||||
int ei = -1; float bestd = 22*22;
|
||||
for (int i = 0; i < g->unit_count; i++) {
|
||||
Unit *u = &g->units[i];
|
||||
if (u->dead || u->faction == g->human) continue;
|
||||
float d = kknd_dist2(wx, wy, u->x, u->y);
|
||||
if (d < bestd) { bestd = d; ei = i; }
|
||||
}
|
||||
int bi = pick_building(g, wx, wy);
|
||||
if (bi >= 0 && g->buildings[bi].faction != g->human) ei = -2;
|
||||
|
||||
int issued = 0;
|
||||
if (ei >= 0 || ei == -2) {
|
||||
for (int s = 0; s < g->sel_count; s++) {
|
||||
Unit *u = unit_by_id(g, g->selection[s]);
|
||||
if (!u) continue;
|
||||
if (ei >= 0) unit_issue_attack_unit(g, (int)(u - g->units), ei);
|
||||
else unit_issue_attack_bld(g, (int)(u - g->units), g->buildings[bi].id);
|
||||
issued++;
|
||||
}
|
||||
} else {
|
||||
/* gather selection and issue a formation move */
|
||||
int sel[MAX_SELECTION], sn = 0;
|
||||
for (int s = 0; s < g->sel_count; s++) {
|
||||
Unit *u = unit_by_id(g, g->selection[s]);
|
||||
if (!u) continue;
|
||||
if (u->type == UT_HARVESTER) {
|
||||
int tx, ty; map_world_to_tile(wx, wy, &tx, &ty);
|
||||
Tile *t = map_tile(&g->map, tx, ty);
|
||||
if (t && t->terrain == T_SCRAP) unit_issue_gather(g, (int)(u - g->units), wx, wy);
|
||||
else unit_issue_move(g, (int)(u - g->units), wx, wy, 0);
|
||||
} else {
|
||||
sel[sn++] = (int)(u - g->units);
|
||||
}
|
||||
issued++;
|
||||
}
|
||||
if (sn > 0) unit_issue_move_group(g, sel, sn, wx, wy, 1);
|
||||
}
|
||||
if (issued) audio_sfx(0);
|
||||
}
|
||||
|
||||
static void handle_hud_click(Game *g, int sx, int sy) {
|
||||
HudButton btns[64]; int n = 0;
|
||||
hud_layout(g, btns, &n);
|
||||
for (int i = 0; i < n; i++) {
|
||||
if (sx >= btns[i].x && sx <= btns[i].x + btns[i].w &&
|
||||
sy >= btns[i].y && sy <= btns[i].y + btns[i].h) {
|
||||
if (!btns[i].enabled) { audio_sfx(5); return; }
|
||||
if (btns[i].kind == 0) {
|
||||
g->placing = 1; g->place_type = (BuildingType)btns[i].id;
|
||||
audio_sfx(4);
|
||||
} else if (btns[i].kind == 2) {
|
||||
bld_research(g, g->human, btns[i].id);
|
||||
} else if (btns[i].kind == 3) {
|
||||
Faction enemy = g->enemy;
|
||||
int ex = g->map.spawn_x[enemy], ey = g->map.spawn_y[enemy];
|
||||
float tx, ty; map_tile_to_world(ex, ey, &tx, &ty);
|
||||
int sel[MAX_SELECTION], sn = 0;
|
||||
for (int s = 0; s < g->sel_count; s++) {
|
||||
Unit *u = unit_by_id(g, g->selection[s]);
|
||||
if (!u || u->faction != g->human) continue;
|
||||
int idx = (int)(u - g->units);
|
||||
if (btns[i].id == 0) unit_issue_stop(g, idx);
|
||||
else if (btns[i].id == 4) unit_issue_hold(g, idx);
|
||||
else if (btns[i].id == 2 && u->type == UT_HARVESTER)
|
||||
unit_issue_gather_nearest(g, idx);
|
||||
else if (btns[i].id == 3 && u->type == UT_HARVESTER)
|
||||
unit_issue_return(g, idx);
|
||||
else if (btns[i].id == 1 && u->type != UT_HARVESTER)
|
||||
sel[sn++] = idx;
|
||||
}
|
||||
if (sn > 0 && btns[i].id == 1) unit_issue_move_group(g, sel, sn, tx, ty, 1);
|
||||
audio_sfx(0);
|
||||
} else if (btns[i].kind == 4) {
|
||||
for (int s = 0; s < g->sel_count; s++) {
|
||||
Unit *u = unit_by_id(g, g->selection[s]);
|
||||
if (u && u->faction == g->human && u->ability == (AbilityType)btns[i].id)
|
||||
unit_ability_use(g, (int)(u - g->units));
|
||||
}
|
||||
audio_sfx(4);
|
||||
} else {
|
||||
/* queue unit on selected production building */
|
||||
for (int j = 0; j < g->bld_count; j++) {
|
||||
Building *b = &g->buildings[j];
|
||||
if (b->dead || !b->selected || b->faction != g->human) continue;
|
||||
const BldDef *d = bld_def(b->type);
|
||||
for (int k = 0; k < d->produces_count; k++)
|
||||
if (d->produces[k] == btns[i].id)
|
||||
bld_queue_unit(g, (int)(b - g->buildings), (UnitType)btns[i].id);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void try_place(Game *g, int sx, int sy) {
|
||||
float wx, wy; input_screen_to_world(g, sx, sy, &wx, &wy);
|
||||
int tx, ty; map_world_to_tile(wx, wy, &tx, &ty);
|
||||
const BldDef *d = bld_def(g->place_type);
|
||||
if (g->scrap[g->human] < d->cost) { audio_sfx(5); return; }
|
||||
int ret = bld_spawn(g, g->place_type, g->human, tx, ty);
|
||||
if (ret == -2) { audio_sfx(5); return; }
|
||||
if (ret >= 0) {
|
||||
g->scrap[g->human] -= d->cost;
|
||||
audio_sfx(3);
|
||||
}
|
||||
g->placing = 0;
|
||||
}
|
||||
|
||||
void input_handle(Game *g, SDL_Event *e) {
|
||||
switch (e->type) {
|
||||
case SDL_KEYDOWN:
|
||||
g_keys[e->key.keysym.scancode] = 1;
|
||||
if (g->state == GAME_MENU) {
|
||||
int n = mission_count();
|
||||
if (e->key.keysym.sym == SDLK_f) {
|
||||
g->human = (g->human == FACTION_SURVIVOR) ? FACTION_EVOLVED
|
||||
: (g->human == FACTION_EVOLVED) ? FACTION_SERIES9
|
||||
: FACTION_SURVIVOR;
|
||||
audio_sfx(4);
|
||||
} else if (e->key.keysym.sym == SDLK_UP) {
|
||||
g->menu_sel = (g->menu_sel > 0) ? g->menu_sel - 1 : n - 1;
|
||||
audio_sfx(6);
|
||||
} else if (e->key.keysym.sym == SDLK_DOWN) {
|
||||
g->menu_sel = (g->menu_sel < n - 1) ? g->menu_sel + 1 : 0;
|
||||
audio_sfx(6);
|
||||
} else if (e->key.keysym.sym == SDLK_RETURN
|
||||
|| e->key.keysym.sym == SDLK_KP_ENTER) {
|
||||
if (g->menu_sel < g->unlocked) { engine_setup_match(g, g->menu_sel); audio_sfx(3); }
|
||||
} else if (e->key.keysym.sym >= SDLK_0 && e->key.keysym.sym <= SDLK_9) {
|
||||
int mid = e->key.keysym.sym - SDLK_0;
|
||||
if (mid < g->unlocked) { engine_setup_match(g, mid); audio_sfx(3); }
|
||||
}
|
||||
break;
|
||||
}
|
||||
if ((g->state == GAME_WON || g->state == GAME_LOST) &&
|
||||
e->key.keysym.sym == SDLK_m) {
|
||||
g->state = GAME_MENU;
|
||||
break;
|
||||
}
|
||||
if (e->key.keysym.sym == SDLK_a && g->state == GAME_PLAYING) {
|
||||
unit_select_all(g, g->human);
|
||||
audio_sfx(4);
|
||||
break;
|
||||
}
|
||||
if (e->key.keysym.sym >= SDLK_1 && e->key.keysym.sym <= SDLK_9 &&
|
||||
g->state == GAME_PLAYING) {
|
||||
int gi = e->key.keysym.sym - SDLK_1;
|
||||
if (SDL_GetModState() & KMOD_CTRL) {
|
||||
g->group_len[gi] = g->sel_count;
|
||||
for (int s = 0; s < g->sel_count; s++) g->groups[gi][s] = g->selection[s];
|
||||
audio_sfx(4);
|
||||
} else if (g->group_len[gi] > 0) {
|
||||
unit_clear_selection(g);
|
||||
for (int s = 0; s < g->group_len[gi]; s++) {
|
||||
Unit *u = unit_by_id(g, g->groups[gi][s]);
|
||||
if (u && !u->dead) { g->selection[g->sel_count++] = g->groups[gi][s]; u->selected = 1; }
|
||||
}
|
||||
if (g->sel_count > 0) audio_sfx(4);
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (e->key.keysym.sym == SDLK_SPACE) {
|
||||
if (g->state == GAME_PLAYING) g->state = GAME_PAUSED;
|
||||
else if (g->state == GAME_PAUSED) g->state = GAME_PLAYING;
|
||||
} else if (e->key.keysym.sym == SDLK_F5) {
|
||||
save_game(g, "savegame.kknd");
|
||||
} else if (e->key.keysym.sym == SDLK_ESCAPE) {
|
||||
g->placing = 0;
|
||||
}
|
||||
break;
|
||||
case SDL_KEYUP:
|
||||
g_keys[e->key.keysym.scancode] = 0;
|
||||
break;
|
||||
case SDL_MOUSEBUTTONDOWN:
|
||||
if (e->button.button == SDL_BUTTON_LEFT) {
|
||||
if (g->placing) { try_place(g, e->button.x, e->button.y); break; }
|
||||
if (e->button.y > VIEW_H - 140) { handle_hud_click(g, e->button.x, e->button.y); break; }
|
||||
/* minimap click */
|
||||
if (e->button.x > VIEW_W - 212 && e->button.x < VIEW_W - 8 &&
|
||||
e->button.y > 34 && e->button.y < 238) {
|
||||
int mx = VIEW_W - 210, my = 36;
|
||||
g->cam.x = (e->button.x - mx) / 200.0f * MAP_PIX_W - VIEW_W/2;
|
||||
g->cam.y = (e->button.y - my) / 200.0f * MAP_PIX_H - VIEW_H/2;
|
||||
break;
|
||||
}
|
||||
g->dragging = 1;
|
||||
g->drag_x0 = g->drag_x1 = e->button.x;
|
||||
g->drag_y0 = g->drag_y1 = e->button.y;
|
||||
} else if (e->button.button == SDL_BUTTON_RIGHT) {
|
||||
if (g->placing) { g->placing = 0; break; }
|
||||
if (g->sel_count > 0) {
|
||||
float wx, wy; input_screen_to_world(g, e->button.x, e->button.y, &wx, &wy);
|
||||
issue_orders(g, wx, wy);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SDL_MOUSEBUTTONUP:
|
||||
if (e->button.button == SDL_BUTTON_LEFT && g->dragging) {
|
||||
g->dragging = 0;
|
||||
int dx = abs(e->button.x - g->drag_x0);
|
||||
int dy = abs(e->button.y - g->drag_y0);
|
||||
if (dx < 6 && dy < 6) {
|
||||
/* click select */
|
||||
float wx, wy;
|
||||
int ui = pick_unit(g, e->button.x, e->button.y, &wx, &wy);
|
||||
if (ui >= 0 && g->units[ui].faction == g->human) {
|
||||
unit_select_single(g, ui, g_keys[SDL_SCANCODE_LSHIFT]);
|
||||
audio_sfx(4);
|
||||
} else {
|
||||
int bi = pick_building(g, wx, wy);
|
||||
if (bi >= 0 && g->buildings[bi].faction == g->human) {
|
||||
if (!g_keys[SDL_SCANCODE_LSHIFT]) unit_clear_selection(g);
|
||||
g->buildings[bi].selected = 1;
|
||||
g->selection[g->sel_count++] = g->buildings[bi].id;
|
||||
audio_sfx(4);
|
||||
} else if (!g_keys[SDL_SCANCODE_LSHIFT]) {
|
||||
unit_clear_selection(g);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
unit_select_in_rect(g, g->drag_x0, g->drag_y0,
|
||||
e->button.x, e->button.y,
|
||||
g_keys[SDL_SCANCODE_LSHIFT]);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SDL_MOUSEMOTION:
|
||||
if (g->dragging) { g->drag_x1 = e->motion.x; g->drag_y1 = e->motion.y; }
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void input_camera(Game *g, float dt) {
|
||||
float sp = 600 * dt;
|
||||
if (g_keys[SDL_SCANCODE_W] || g_keys[SDL_SCANCODE_UP]) g->cam.y -= sp;
|
||||
if (g_keys[SDL_SCANCODE_S] || g_keys[SDL_SCANCODE_DOWN]) g->cam.y += sp;
|
||||
if (g_keys[SDL_SCANCODE_A] || g_keys[SDL_SCANCODE_LEFT]) g->cam.x -= sp;
|
||||
if (g_keys[SDL_SCANCODE_D] || g_keys[SDL_SCANCODE_RIGHT])g->cam.x += sp;
|
||||
/* edge scroll */
|
||||
int mx, my; SDL_GetMouseState(&mx, &my);
|
||||
if (mx < 8) g->cam.x -= sp;
|
||||
if (mx > VIEW_W - 8) g->cam.x += sp;
|
||||
if (my < 8) g->cam.y -= sp;
|
||||
if (my > VIEW_H - 80 && my < VIEW_H - 8) g->cam.y += sp;
|
||||
|
||||
if (g->cam.x < 0) g->cam.x = 0;
|
||||
if (g->cam.y < 0) g->cam.y = 0;
|
||||
if (g->cam.x > MAP_PIX_W - VIEW_W) g->cam.x = MAP_PIX_W - VIEW_W;
|
||||
if (g->cam.y > MAP_PIX_H - VIEW_H + 72) g->cam.y = MAP_PIX_H - VIEW_H + 72;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue