engine-c: richer snapshot/live HUD (scrap/power/minimap/command strip)
This commit is contained in:
parent
57acaa430f
commit
d983fbb0d7
2 changed files with 325 additions and 25 deletions
|
|
@ -650,16 +650,79 @@ void render_build_menu(Game *g) {
|
|||
}
|
||||
|
||||
void render_hud(Game *g) {
|
||||
/* top resource bar */
|
||||
SDL_SetRenderDrawColor(g->ren, 16, 16, 20, 220);
|
||||
SDL_RenderFillRect(g->ren, &(SDL_Rect){0, 0, VIEW_W, 28});
|
||||
char buf[128];
|
||||
snprintf(buf, sizeof buf, "%s - Scrap: %d", faction_name(g->human),
|
||||
g->scrap[g->human]);
|
||||
render_text(&g->spr, g->ren, g->spr.font_med, buf, 10, 4,
|
||||
(SDL_Color){230,230,230,255});
|
||||
/* KKND2-like chrome: top scrap/power bars + bottom command strip */
|
||||
Faction hf = g->human;
|
||||
SDL_Color hc = faction_color(hf);
|
||||
SDL_Color ec = faction_color(enemy_of(hf));
|
||||
|
||||
/* selection summary */
|
||||
int scrap_h = g->scrap[hf];
|
||||
if (scrap_h < 0) scrap_h = 0;
|
||||
int scrap_cap = 8000;
|
||||
if (scrap_h > scrap_cap) scrap_cap = scrap_h + 500;
|
||||
float scrap_frac = (float)scrap_h / (float)scrap_cap;
|
||||
if (scrap_frac > 1.0f) scrap_frac = 1.0f;
|
||||
|
||||
int pwr_gen = 0, pwr_use = 0;
|
||||
for (int i = 0; i < g->bld_count; i++) {
|
||||
Building *b = &g->buildings[i];
|
||||
if (b->dead || b->faction != hf || b->build < 1.0f) continue;
|
||||
if (b->type == BT_POWER) pwr_gen += 100;
|
||||
else if (b->type == BT_BASE) pwr_use += 20;
|
||||
else if (b->type == BT_WARFACTORY || b->type == BT_REFINERY) pwr_use += 40;
|
||||
else if (b->type == BT_RESEARCH || b->type == BT_REPAIR) pwr_use += 30;
|
||||
else if (b->type == BT_TURRET) pwr_use += 15;
|
||||
else pwr_use += 5;
|
||||
}
|
||||
if (pwr_gen < 1) pwr_gen = 1;
|
||||
float pwr_frac = (float)pwr_gen / (float)(pwr_gen + pwr_use);
|
||||
if (pwr_frac > 1.0f) pwr_frac = 1.0f;
|
||||
int pwr_ok = (pwr_gen >= pwr_use);
|
||||
|
||||
int bar_h = 28;
|
||||
SDL_SetRenderDrawColor(g->ren, 22, 26, 32, 230);
|
||||
SDL_RenderFillRect(g->ren, &(SDL_Rect){0, 0, VIEW_W, bar_h});
|
||||
SDL_SetRenderDrawColor(g->ren, 55, 62, 70, 255);
|
||||
SDL_RenderFillRect(g->ren, &(SDL_Rect){0, 0, VIEW_W, 2});
|
||||
SDL_SetRenderDrawColor(g->ren, 90, 110, 70, 255);
|
||||
SDL_RenderFillRect(g->ren, &(SDL_Rect){0, bar_h - 1, VIEW_W, 1});
|
||||
|
||||
/* faction badge */
|
||||
SDL_SetRenderDrawColor(g->ren, 12, 14, 16, 255);
|
||||
SDL_RenderFillRect(g->ren, &(SDL_Rect){4, 4, 20, 20});
|
||||
SDL_SetRenderDrawColor(g->ren, hc.r, hc.g, hc.b, 255);
|
||||
SDL_RenderFillRect(g->ren, &(SDL_Rect){6, 6, 16, 16});
|
||||
|
||||
/* scrap bar */
|
||||
int scrap_x = 48, scrap_w = (int)(VIEW_W * 0.22f);
|
||||
if (scrap_w < 80) scrap_w = 80;
|
||||
SDL_SetRenderDrawColor(g->ren, 28, 26, 18, 255);
|
||||
SDL_RenderFillRect(g->ren, &(SDL_Rect){scrap_x, 8, scrap_w, 12});
|
||||
SDL_SetRenderDrawColor(g->ren, 230, 200, 70, 255);
|
||||
SDL_RenderFillRect(g->ren, &(SDL_Rect){scrap_x, 8, (int)(scrap_w * scrap_frac), 12});
|
||||
for (int s = 1; s < 8; s++) {
|
||||
int sx = scrap_x + (scrap_w * s) / 8;
|
||||
SDL_SetRenderDrawColor(g->ren, 18, 16, 12, 255);
|
||||
SDL_RenderDrawLine(g->ren, sx, 8, sx, 19);
|
||||
}
|
||||
|
||||
/* power bar */
|
||||
int pwr_bx = scrap_x + scrap_w + 16, pwr_bw = (int)(VIEW_W * 0.14f);
|
||||
if (pwr_bw < 50) pwr_bw = 50;
|
||||
SDL_SetRenderDrawColor(g->ren, 24, 28, 24, 255);
|
||||
SDL_RenderFillRect(g->ren, &(SDL_Rect){pwr_bx, 8, pwr_bw, 12});
|
||||
if (pwr_ok) SDL_SetRenderDrawColor(g->ren, 70, 210, 90, 255);
|
||||
else SDL_SetRenderDrawColor(g->ren, 220, 70, 60, 255);
|
||||
SDL_RenderFillRect(g->ren, &(SDL_Rect){pwr_bx, 8, (int)(pwr_bw * pwr_frac), 12});
|
||||
|
||||
char buf[128];
|
||||
snprintf(buf, sizeof buf, "Scrap %d", scrap_h);
|
||||
render_text(&g->spr, g->ren, g->spr.font_small, buf, scrap_x + 4, 8,
|
||||
(SDL_Color){255,245,200,255});
|
||||
snprintf(buf, sizeof buf, "Pwr %d/%d", pwr_gen, pwr_use);
|
||||
render_text(&g->spr, g->ren, g->spr.font_small, buf, pwr_bx + 4, 8,
|
||||
(SDL_Color){220,255,220,255});
|
||||
|
||||
/* selection summary + threat pip */
|
||||
int n_units = 0, n_bld = 0;
|
||||
for (int i = 0; i < g->sel_count; i++) {
|
||||
int id = g->selection[i];
|
||||
|
|
@ -667,16 +730,69 @@ void render_hud(Game *g) {
|
|||
else if (bld_by_id(g, id)) n_bld++;
|
||||
}
|
||||
if (n_units > 0 || n_bld > 0) {
|
||||
snprintf(buf, sizeof buf, "Selected: %d units, %d buildings",
|
||||
n_units, n_bld);
|
||||
snprintf(buf, sizeof buf, "Sel %dU/%dB", n_units, n_bld);
|
||||
render_text(&g->spr, g->ren, g->spr.font_small, buf,
|
||||
VIEW_W - 260, 6, (SDL_Color){200,220,200,255});
|
||||
VIEW_W - 280, 6, (SDL_Color){200,220,200,255});
|
||||
}
|
||||
{
|
||||
int eth = 0;
|
||||
for (int i = 0; i < g->unit_count; i++)
|
||||
if (!g->units[i].dead && g->units[i].faction != hf) eth++;
|
||||
if (eth > 36) eth = 36;
|
||||
SDL_SetRenderDrawColor(g->ren, 36, 22, 28, 255);
|
||||
SDL_RenderFillRect(g->ren, &(SDL_Rect){VIEW_W - 56, 5, 48, 18});
|
||||
SDL_SetRenderDrawColor(g->ren, ec.r, ec.g, ec.b, 255);
|
||||
SDL_RenderFillRect(g->ren, &(SDL_Rect){VIEW_W - 52, 8, 8, 12});
|
||||
SDL_RenderFillRect(g->ren, &(SDL_Rect){VIEW_W - 40, 10, eth, 8});
|
||||
}
|
||||
|
||||
/* hints */
|
||||
/* bottom command strip */
|
||||
int bot_h = 36, bot_y = VIEW_H - bot_h;
|
||||
SDL_SetRenderDrawColor(g->ren, 18, 20, 24, 230);
|
||||
SDL_RenderFillRect(g->ren, &(SDL_Rect){0, bot_y, VIEW_W, bot_h});
|
||||
SDL_SetRenderDrawColor(g->ren, 70, 90, 70, 255);
|
||||
SDL_RenderFillRect(g->ren, &(SDL_Rect){0, bot_y, VIEW_W, 1});
|
||||
SDL_SetRenderDrawColor(g->ren, 12, 14, 16, 255);
|
||||
SDL_RenderFillRect(g->ren, &(SDL_Rect){6, bot_y + 4, 28, 28});
|
||||
SDL_SetRenderDrawColor(g->ren, hc.r, hc.g, hc.b, 255);
|
||||
SDL_RenderFillRect(g->ren, &(SDL_Rect){8, bot_y + 6, 24, 24});
|
||||
int slots = (n_units > 0 || n_bld > 0) ? (n_units + n_bld) : 6;
|
||||
if (slots > 10) slots = 10;
|
||||
for (int s = 0; s < slots; s++) {
|
||||
int sx = 42 + s * 28;
|
||||
SDL_SetRenderDrawColor(g->ren, 28, 32, 28, 255);
|
||||
SDL_RenderFillRect(g->ren, &(SDL_Rect){sx, bot_y + 4, 24, 28});
|
||||
if (s < n_units || (n_units == 0 && n_bld == 0 && s < 4)) {
|
||||
SDL_SetRenderDrawColor(g->ren, hc.r, hc.g, hc.b, 255);
|
||||
SDL_RenderFillRect(g->ren, &(SDL_Rect){sx + 5, bot_y + 9, 14, 16});
|
||||
} else if (s < n_units + n_bld) {
|
||||
SDL_SetRenderDrawColor(g->ren, hc.r, hc.g, hc.b, 255);
|
||||
SDL_RenderFillRect(g->ren, &(SDL_Rect){sx + 4, bot_y + 8, 16, 16});
|
||||
}
|
||||
}
|
||||
for (int s = 0; s < 4; s++) {
|
||||
int sx = VIEW_W - 120 + s * 28;
|
||||
SDL_SetRenderDrawColor(g->ren, 32, 28, 22, 255);
|
||||
SDL_RenderFillRect(g->ren, &(SDL_Rect){sx, bot_y + 4, 24, 28});
|
||||
if (s == 0) {
|
||||
SDL_SetRenderDrawColor(g->ren, 200, 180, 60, 255);
|
||||
SDL_RenderFillRect(g->ren, &(SDL_Rect){sx + 8, bot_y + 12, 8, 10});
|
||||
} else if (s == 1) {
|
||||
SDL_SetRenderDrawColor(g->ren, 255, 80, 40, 255);
|
||||
SDL_RenderFillRect(g->ren, &(SDL_Rect){sx + 8, bot_y + 12, 8, 8});
|
||||
} else if (s == 2) {
|
||||
SDL_SetRenderDrawColor(g->ren, 80, 180, 255, 255);
|
||||
SDL_RenderFillRect(g->ren, &(SDL_Rect){sx + 6, bot_y + 14, 12, 6});
|
||||
} else {
|
||||
SDL_SetRenderDrawColor(g->ren, 180, 255, 120, 255);
|
||||
SDL_RenderDrawRect(g->ren, &(SDL_Rect){sx + 6, bot_y + 10, 12, 12});
|
||||
}
|
||||
}
|
||||
|
||||
/* hints above command strip */
|
||||
render_text(&g->spr, g->ren, g->spr.font_small,
|
||||
"LMB select/drag RMB move/attack A select-all [B] build Space pause F5 save",
|
||||
10, VIEW_H - 90, (SDL_Color){150,150,150,255});
|
||||
10, bot_y - 18, (SDL_Color){150,150,150,255});
|
||||
|
||||
/* objective */
|
||||
const Mission *m = mission_get(g->mission_id);
|
||||
|
|
@ -693,7 +809,7 @@ void render_hud(Game *g) {
|
|||
else
|
||||
snprintf(obuf, sizeof obuf, "Objective: %s", obj);
|
||||
render_text(&g->spr, g->ren, g->spr.font_small, obuf,
|
||||
VIEW_W/2 - 90, 6, (SDL_Color){230,230,160,255});
|
||||
pwr_bx + pwr_bw + 16, 6, (SDL_Color){230,230,160,255});
|
||||
|
||||
if (g->state == GAME_PAUSED)
|
||||
render_text(&g->spr, g->ren, g->spr.font_big, "PAUSED",
|
||||
|
|
|
|||
|
|
@ -736,17 +736,201 @@ void snapshot_capture(Game *g, const char *path) {
|
|||
if (p->kind == 0 || p->kind == 1) disc(sx, sy, sz + 1, r, gv, b);
|
||||
else fill_rect(sx - sz/2, sy - sz/2, sz + 1, sz + 1, r, gv, b);
|
||||
}
|
||||
/* No shot minimap — keeps the crop on the fight plate. */
|
||||
/* KKND2-like chrome: top resource bar + corner minimap + bottom command strip.
|
||||
* Procedural bars (no font) so the shot still reads as classic RTS UI. */
|
||||
{
|
||||
Faction hf = g->human;
|
||||
uint8_t hr = faction_r(hf), hg = faction_g(hf), hb = faction_b(hf);
|
||||
Faction ef = enemy_of(hf);
|
||||
uint8_t er = faction_r(ef), eg = faction_g(ef), eb = faction_b(ef);
|
||||
|
||||
/* Simple top HUD strip (resource/faction cue like classic RTS). */
|
||||
fill_rect(0, 0, g_sw, 14, 18, 22, 28);
|
||||
fill_rect(0, 13, g_sw, 1, 70, 90, 70);
|
||||
fill_rect(4, 3, 28, 8, 40, 210, 70);
|
||||
fill_rect(36, 3, 28, 8, 235, 55, 235);
|
||||
fill_rect(68, 4, (int)(g_sw * 0.22f), 6, 200, 180, 60);
|
||||
fill_rect(68, 4, (int)(g_sw * 0.14f), 6, 255, 220, 80);
|
||||
disc(g_sw - 18, 7, 5, 255, 90, 40);
|
||||
disc(g_sw - 18, 7, 2, 255, 220, 120);
|
||||
int scrap_h = g->scrap[hf];
|
||||
if (scrap_h < 0) scrap_h = 0;
|
||||
int scrap_cap = 8000;
|
||||
if (scrap_h > scrap_cap) scrap_cap = scrap_h + 500;
|
||||
float scrap_frac = (float)scrap_h / (float)scrap_cap;
|
||||
if (scrap_frac > 1.0f) scrap_frac = 1.0f;
|
||||
|
||||
int pwr_gen = 0, pwr_use = 0;
|
||||
for (int i = 0; i < g->bld_count; i++) {
|
||||
Building *b = &g->buildings[i];
|
||||
if (b->dead || b->faction != hf || b->build < 1.0f) continue;
|
||||
if (b->type == BT_POWER) pwr_gen += 100;
|
||||
else if (b->type == BT_BASE) pwr_use += 20;
|
||||
else if (b->type == BT_WARFACTORY || b->type == BT_REFINERY) pwr_use += 40;
|
||||
else if (b->type == BT_RESEARCH || b->type == BT_REPAIR) pwr_use += 30;
|
||||
else if (b->type == BT_TURRET) pwr_use += 15;
|
||||
else pwr_use += 5;
|
||||
}
|
||||
if (pwr_gen < 1) pwr_gen = 1;
|
||||
float pwr_frac = (float)pwr_gen / (float)(pwr_gen + pwr_use);
|
||||
if (pwr_frac > 1.0f) pwr_frac = 1.0f;
|
||||
int pwr_ok = (pwr_gen >= pwr_use);
|
||||
|
||||
int n_sel_u = 0, n_sel_b = 0;
|
||||
for (int i = 0; i < g->sel_count; i++) {
|
||||
if (unit_by_id(g, g->selection[i])) n_sel_u++;
|
||||
else if (bld_by_id(g, g->selection[i])) n_sel_b++;
|
||||
}
|
||||
|
||||
/* —— top bar —— */
|
||||
int bar_h = 22;
|
||||
fill_rect(0, 0, g_sw, bar_h, 22, 26, 32);
|
||||
fill_rect(0, 0, g_sw, 2, 55, 62, 70);
|
||||
fill_rect(0, bar_h - 1, g_sw, 1, 90, 110, 70);
|
||||
fill_rect(0, bar_h, g_sw, 1, 40, 48, 40);
|
||||
|
||||
/* faction badge */
|
||||
fill_rect(3, 3, 16, 16, 12, 14, 16);
|
||||
fill_rect(5, 5, 12, 12, hr, hg, hb);
|
||||
fill_rect(7, 7, 8, 8, (uint8_t)(hr / 2 + 40), (uint8_t)(hg / 2 + 40),
|
||||
(uint8_t)(hb / 2 + 40));
|
||||
|
||||
/* scrap icon (gold nugget) + segmented bar */
|
||||
fill_rect(24, 5, 8, 12, 40, 34, 18);
|
||||
fill_rect(26, 7, 4, 8, 220, 190, 70);
|
||||
disc(28, 11, 3, 255, 220, 90);
|
||||
int scrap_x = 36, scrap_w = (int)(g_sw * 0.28f);
|
||||
if (scrap_w < 60) scrap_w = 60;
|
||||
fill_rect(scrap_x, 6, scrap_w, 10, 28, 26, 18);
|
||||
fill_rect(scrap_x, 6, (int)(scrap_w * scrap_frac), 10, 230, 200, 70);
|
||||
/* segment ticks */
|
||||
for (int s = 1; s < 8; s++) {
|
||||
int sx = scrap_x + (scrap_w * s) / 8;
|
||||
line(sx, 6, sx, 15, 18, 16, 12);
|
||||
}
|
||||
fill_rect(scrap_x, 6, scrap_w, 1, 255, 240, 160);
|
||||
fill_rect(scrap_x, 15, scrap_w, 1, 80, 60, 20);
|
||||
|
||||
/* power bolt + bar (green surplus / red deficit) */
|
||||
int pwr_x = scrap_x + scrap_w + 10;
|
||||
fill_rect(pwr_x, 5, 3, 5, 240, 240, 120);
|
||||
fill_rect(pwr_x - 1, 9, 5, 3, 240, 240, 120);
|
||||
fill_rect(pwr_x + 1, 11, 3, 5, 240, 240, 120);
|
||||
int pwr_bx = pwr_x + 10, pwr_bw = (int)(g_sw * 0.16f);
|
||||
if (pwr_bw < 40) pwr_bw = 40;
|
||||
fill_rect(pwr_bx, 6, pwr_bw, 10, 24, 28, 24);
|
||||
uint8_t pr = pwr_ok ? 70 : 220, pg = pwr_ok ? 210 : 70, pb = pwr_ok ? 90 : 60;
|
||||
fill_rect(pwr_bx, 6, (int)(pwr_bw * pwr_frac), 10, pr, pg, pb);
|
||||
for (int s = 1; s < 5; s++) {
|
||||
int sx = pwr_bx + (pwr_bw * s) / 5;
|
||||
line(sx, 6, sx, 15, 14, 16, 14);
|
||||
}
|
||||
|
||||
/* unit / building count chips */
|
||||
int chip_x = pwr_bx + pwr_bw + 12;
|
||||
fill_rect(chip_x, 4, 34, 14, 30, 36, 30);
|
||||
fill_rect(chip_x + 2, 6, 6, 10, hr, hg, hb); /* unit glyph */
|
||||
disc(chip_x + 5, 8, 2, 255, 255, 255);
|
||||
int ufill = alive_h;
|
||||
if (ufill > 20) ufill = 20;
|
||||
fill_rect(chip_x + 12, 8, ufill, 6, hr, hg, hb);
|
||||
fill_rect(chip_x + 38, 4, 34, 14, 30, 36, 30);
|
||||
fill_rect(chip_x + 40, 7, 8, 8, hr, hg, hb); /* bld glyph */
|
||||
int bfill = 0;
|
||||
for (int i = 0; i < g->bld_count; i++)
|
||||
if (!g->buildings[i].dead && g->buildings[i].faction == hf) bfill++;
|
||||
if (bfill > 20) bfill = 20;
|
||||
fill_rect(chip_x + 52, 8, bfill, 6, 180, 160, 70);
|
||||
|
||||
/* enemy threat pip */
|
||||
fill_rect(g_sw - 48, 4, 42, 14, 36, 22, 28);
|
||||
fill_rect(g_sw - 44, 6, 8, 10, er, eg, eb);
|
||||
int eth = alive_e;
|
||||
if (eth > 28) eth = 28;
|
||||
fill_rect(g_sw - 34, 8, eth, 6, er, eg, eb);
|
||||
disc(g_sw - 10, 11, 4, 255, 90, 40);
|
||||
disc(g_sw - 10, 11, 2, 255, 220, 120);
|
||||
|
||||
/* —— corner minimap (compact, fight-plate friendly) —— */
|
||||
int mw = 72, mh = 72;
|
||||
int mx = g_sw - mw - 6, my = bar_h + 6;
|
||||
fill_rect(mx - 2, my - 2, mw + 4, mh + 4, 8, 10, 12);
|
||||
fill_rect(mx - 1, my - 1, mw + 2, mh + 2, 70, 90, 70);
|
||||
fill_rect(mx, my, mw, mh, 28, 32, 28);
|
||||
/* sample terrain around camera */
|
||||
float map_sx = (float)mw / (float)g_sw;
|
||||
float map_sy = (float)mh / (float)g_sh;
|
||||
for (int py = 0; py < mh; py += 2) {
|
||||
for (int px_ = 0; px_ < mw; px_ += 2) {
|
||||
float wx = camx + (float)px_ / map_sx;
|
||||
float wy = camy + (float)py / map_sy;
|
||||
int tx = (int)(wx / TILE), ty = (int)(wy / TILE);
|
||||
if (!map_in_bounds(&g->map, tx, ty)) continue;
|
||||
Tile *t = map_tile(&g->map, tx, ty);
|
||||
uint8_t cr = 120, cg = 104, cb = 78;
|
||||
switch (t->terrain) {
|
||||
case T_WATER: cr = 44; cg = 78; cb = 120; break;
|
||||
case T_ROCK: cr = 110; cg = 104; cb = 98; break;
|
||||
case T_SCRAP: cr = 200; cg = 170; cb = 70; break;
|
||||
case T_GRASS: cr = 210; cg = 170; cb = 78; break;
|
||||
case T_RUBBLE: cr = 90; cg = 78; cb = 60; break;
|
||||
default: break;
|
||||
}
|
||||
fill_rect(mx + px_, my + py, 2, 2, cr, cg, cb);
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < g->bld_count; i++) {
|
||||
Building *b = &g->buildings[i];
|
||||
if (b->dead) continue;
|
||||
int bx = mx + (int)((b->tx * TILE - camx) * map_sx);
|
||||
int by = my + (int)((b->ty * TILE - camy) * map_sy);
|
||||
if (bx < mx || by < my || bx >= mx + mw || by >= my + mh) continue;
|
||||
uint8_t br = faction_r(b->faction), bg = faction_g(b->faction),
|
||||
bb = faction_b(b->faction);
|
||||
fill_rect(bx, by, 3, 3, br, bg, bb);
|
||||
}
|
||||
for (int i = 0; i < g->unit_count; i++) {
|
||||
Unit *u = &g->units[i];
|
||||
if (u->dead) continue;
|
||||
int ux = mx + (int)((u->x - camx) * map_sx);
|
||||
int uy = my + (int)((u->y - camy) * map_sy);
|
||||
if (ux < mx || uy < my || ux >= mx + mw || uy >= my + mh) continue;
|
||||
px(ux, uy, faction_r(u->faction), faction_g(u->faction),
|
||||
faction_b(u->faction));
|
||||
}
|
||||
/* viewport outline = full minimap (crop view) */
|
||||
line(mx, my, mx + mw - 1, my, 255, 255, 255);
|
||||
line(mx, my + mh - 1, mx + mw - 1, my + mh - 1, 255, 255, 255);
|
||||
line(mx, my, mx, my + mh - 1, 255, 255, 255);
|
||||
line(mx + mw - 1, my, mx + mw - 1, my + mh - 1, 255, 255, 255);
|
||||
|
||||
/* —— bottom command / selection strip —— */
|
||||
int bot_h = 28;
|
||||
int bot_y = g_sh - bot_h;
|
||||
fill_rect(0, bot_y, g_sw, bot_h, 18, 20, 24);
|
||||
fill_rect(0, bot_y, g_sw, 1, 70, 90, 70);
|
||||
fill_rect(0, bot_y + 1, g_sw, 1, 40, 48, 40);
|
||||
/* portrait panel */
|
||||
fill_rect(4, bot_y + 3, 22, 22, 12, 14, 16);
|
||||
fill_rect(6, bot_y + 5, 18, 18, hr, hg, hb);
|
||||
disc(15, bot_y + 12, 4, 255, 255, 255);
|
||||
fill_rect(13, bot_y + 16, 4, 5, 40, 40, 40);
|
||||
/* selection count bars */
|
||||
int slots = (n_sel_u > 0 || n_sel_b > 0) ? (n_sel_u + n_sel_b) : 6;
|
||||
if (slots > 10) slots = 10;
|
||||
for (int s = 0; s < slots; s++) {
|
||||
int sx = 32 + s * 22;
|
||||
fill_rect(sx, bot_y + 4, 18, 20, 28, 32, 28);
|
||||
fill_rect(sx + 1, bot_y + 5, 16, 18, 40, 48, 40);
|
||||
if (s < n_sel_u || (n_sel_u == 0 && n_sel_b == 0 && s < 4)) {
|
||||
fill_rect(sx + 4, bot_y + 8, 10, 12, hr, hg, hb);
|
||||
disc(sx + 9, bot_y + 11, 2, 255, 255, 255);
|
||||
} else if (s < n_sel_u + n_sel_b) {
|
||||
fill_rect(sx + 3, bot_y + 8, 12, 12, hr, hg, hb);
|
||||
}
|
||||
}
|
||||
/* ability / build button stubs (right) */
|
||||
for (int s = 0; s < 4; s++) {
|
||||
int sx = g_sw - 96 + s * 22;
|
||||
fill_rect(sx, bot_y + 4, 18, 20, 32, 28, 22);
|
||||
fill_rect(sx + 2, bot_y + 6, 14, 16, 70, 60, 40);
|
||||
if (s == 0) fill_rect(sx + 6, bot_y + 10, 6, 8, 200, 180, 60); /* build */
|
||||
if (s == 1) disc(sx + 9, bot_y + 14, 4, 255, 80, 40); /* attack */
|
||||
if (s == 2) fill_rect(sx + 5, bot_y + 11, 8, 6, 80, 180, 255); /* move */
|
||||
if (s == 3) ring(sx + 9, bot_y + 14, 5, 2, 180, 255, 120); /* stop */
|
||||
}
|
||||
}
|
||||
|
||||
/* Nearest-neighbour upscale → full VIEW (chunky KKND pixels) */
|
||||
uint8_t *big = (uint8_t *)malloc((size_t)SW * SH * 4);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue