diff options
| author | Xavier Del Campo Romero <xavi.dcr@tutanota.com> | 2021-07-03 00:49:03 +0200 |
|---|---|---|
| committer | Xavier Del Campo Romero <xavi.dcr@tutanota.com> | 2022-03-30 08:20:20 +0200 |
| commit | 6b9f686913efc3725b2690033cd4f398e07076ba (patch) | |
| tree | e9aa91a6b9f617d78123ebe7ad272fc42a60d306 /src/gui | |
| parent | c9e6ae44a9aeb89b3f48f3443d6baa80103f7445 (diff) | |
| download | jancity-6b9f686913efc3725b2690033cd4f398e07076ba.tar.gz | |
Add project source code
Diffstat (limited to 'src/gui')
| -rw-r--r-- | src/gui/CMakeLists.txt | 3 | ||||
| -rw-r--r-- | src/gui/inc/gui.h | 36 | ||||
| -rw-r--r-- | src/gui/src/gui.c | 473 |
3 files changed, 512 insertions, 0 deletions
diff --git a/src/gui/CMakeLists.txt b/src/gui/CMakeLists.txt new file mode 100644 index 0000000..59ee94d --- /dev/null +++ b/src/gui/CMakeLists.txt @@ -0,0 +1,3 @@ +add_library(gui "src/gui.c") +target_include_directories(gui PUBLIC "inc") +target_link_libraries(gui PUBLIC gfx player PRIVATE font unit building) diff --git a/src/gui/inc/gui.h b/src/gui/inc/gui.h new file mode 100644 index 0000000..254fd47 --- /dev/null +++ b/src/gui/inc/gui.h @@ -0,0 +1,36 @@ +#ifndef GUI_H +#define GUI_H + +#include <gfx.h> +#include <human_player.h> + +#ifdef __cplusplus +extern "C" +{ +#endif + +enum +{ + GUI_BAR_LEFT, + GUI_BAR_MID, + GUI_BAR_RIGHT, + GUI_SELECTION_UP_LEFT, + GUI_SELECTION_UP_RIGHT, + GUI_SELECTION_MID_VERT, + GUI_SELECTION_DOWN_LEFT, + GUI_SELECTION_DOWN_RIGHT, + GUI_SELECTION_MID, + + MAX_GUI_SPRITES +}; + +void gui_update(struct human_player *h); +int gui_render(const struct human_player *h); + +extern struct sprite gui_sprites[MAX_GUI_SPRITES]; + +#ifdef __cplusplus +} +#endif + +#endif /* GUI_H */ diff --git a/src/gui/src/gui.c b/src/gui/src/gui.c new file mode 100644 index 0000000..2a5e53b --- /dev/null +++ b/src/gui/src/gui.c @@ -0,0 +1,473 @@ +#include <gui.h> +#include <building.h> +#include <font.h> +#include <gfx.h> +#include <human_player.h> +#include <player.h> +#include <unit.h> +#include <limits.h> +#include <stddef.h> + +struct sprite gui_sprites[MAX_GUI_SPRITES]; + +static int render_topleft(void) +{ + struct sprite *const s = sprite_get(); + + if (!s + || sprite_clone(&gui_sprites[GUI_BAR_LEFT], s)) + return -1; + + sprite_sort(s); + return 0; +} + +static int render_topright(void) +{ + struct sprite *const s = sprite_get(); + + if (!s || sprite_clone(&gui_sprites[GUI_BAR_RIGHT], s)) + return -1; + + s->x = screen_w - s->w; + sprite_sort(s); + return 0; +} + +static int render_topmid(void) +{ + const uint16_t mid_w = gui_sprites[GUI_BAR_MID].w; + const uint16_t lw = gui_sprites[GUI_BAR_LEFT].w; + const size_t w = screen_w - lw - lw; + const size_t rem_mid = w % mid_w; + const size_t whole_mid = w / mid_w; + const size_t n_mid = rem_mid ? whole_mid + 1 : whole_mid; + + for (struct + { + size_t i; + short x; + } a = {.i = 0, .x = lw}; + a.i < n_mid; + a.i++, a.x += mid_w) + { + struct sprite *const m = sprite_get(); + + if (!m + || sprite_clone(&gui_sprites[GUI_BAR_MID], m)) + return -1; + + m->x = a.x; + + if (rem_mid && a.i + 1 == n_mid) + m->w = rem_mid; + else + m->w = mid_w; + + sprite_sort(m); + } + + return 0; +} + +static int render_top(void) +{ + if (render_topleft() + || render_topright() + || render_topmid()) + return -1; + + return 0; +} + +static int render_seltop(struct sprite *const up) +{ + enum {OFFSET = 48}; + + if (sprite_clone(&gui_sprites[GUI_SELECTION_UP_LEFT], up)) + return -1; + + up->y = screen_h - up->h - OFFSET; + up->x = 16; + sprite_sort(up); + + struct sprite *const right = sprite_get(); + + if (!right + || sprite_clone(&gui_sprites[GUI_SELECTION_UP_RIGHT], right)) + return -1; + + right->x = screen_w - right->w - up->x; + right->y = up->y; + sprite_sort(right); + return 0; +} + +static int render_selvert(const struct sprite *const up, const short x) +{ + const uint16_t vert_h = gui_sprites[GUI_SELECTION_MID_VERT].h; + const size_t h = screen_h - up->y - up->h - up->h; + const size_t rem_vert = h % vert_h; + const size_t whole_vert = h / vert_h; + const size_t n_vert = rem_vert ? whole_vert + 1 : whole_vert; + + for (struct + { + size_t i; + short y; + } a = {.i = 0, .y = up->y + up->h}; + a.i < n_vert; + a.i++, a.y += vert_h) + { + struct sprite *const v = sprite_get(); + + if (!v) + return -1; + + *v = gui_sprites[GUI_SELECTION_MID_VERT]; + v->y = a.y; + v->x = x; + + if (rem_vert && a.i + 1 == n_vert) + v->h = rem_vert; + else + v->h = vert_h; + + sprite_sort(v); + } + + return 0; +} + +static int render_selvertleft(const struct sprite *const up) +{ + return render_selvert(up, up->x); +} + +static int render_selvertright(const struct sprite *const up) +{ + return render_selvert(up, screen_w - gui_sprites[GUI_SELECTION_MID_VERT].w - up->x); +} + +static int render_seldown(const struct sprite *const up) +{ + { + struct sprite *const left = sprite_get(); + + if (!left) + return -1; + + *left = gui_sprites[GUI_SELECTION_DOWN_LEFT]; + left->x = up->x; + left->y = screen_h - left->h; + sprite_sort(left); + } + + { + struct sprite *const right = sprite_get(); + + if (!right) + return -1; + + *right = gui_sprites[GUI_SELECTION_DOWN_RIGHT]; + right->x = screen_w - right->w - up->x; + right->y = screen_h - right->h; + sprite_sort(right); + } + + return 0; +} + +static int render_selrect(const struct sprite *const up) +{ + struct rect *const sel = rect_get(true); + + if (!sel) + return -1; + + const struct sprite *const mid = &gui_sprites[GUI_SELECTION_MID], + *const vert = &gui_sprites[GUI_SELECTION_MID_VERT]; + sel->x = up->x + vert->w; + sel->y = up->y + mid->h; + sel->w = screen_w - sel->x - vert->w - up->x; + sel->h = screen_h - sel->y - mid->h; + sel->r = 72; + sel->g = 66; + sel->b = 56; + rect_sort(sel); + return 0; +} + +static int render_selmid(const struct sprite *const up, const short y) +{ + const uint16_t mid_w = gui_sprites[GUI_SELECTION_MID].w; + const size_t w = screen_w - up->x - up->x - up->w - up->w; + const size_t rem_mid = w % mid_w; + const size_t whole_mid = w / mid_w; + const size_t n_mid = rem_mid ? whole_mid + 1 : whole_mid; + + for (struct + { + size_t i; + short x; + } a = {.i = 0, .x = up->x + up->w}; + a.i < n_mid; + a.i++, a.x += mid_w) + { + struct sprite *const m = sprite_get(); + + if (!m) + return -1; + + *m = gui_sprites[GUI_SELECTION_MID]; + m->x = a.x; + m->y = y; + + if (rem_mid && a.i + 1 == n_mid) + m->w = rem_mid; + else + m->w = mid_w; + + sprite_sort(m); + } + + return 0; +} + +static int render_selmidtop(const struct sprite *const up) +{ + return render_selmid(up, up->y); +} + +static int render_selmiddown(const struct sprite *const up) +{ + return render_selmid(up, screen_h - gui_sprites[GUI_SELECTION_MID].h); +} + +static int render_topmenu(const struct human_player *const h) +{ + const struct player *const pl = &h->pl; + + if (render_top() + || (font_printf(FONT, 16, 6, "Wood=%u", + h->gui_res[RESOURCE_TYPE_WOOD]) < 0) + || (font_printf(FONT, 108, 6, "Gold=%u", + h->gui_res[RESOURCE_TYPE_GOLD]) < 0) + || (font_printf(FONT, 212, 6, "Pop.=%u/%zu", + pl->pop, sizeof pl->units / sizeof *pl->units) < 0)) + return -1; + + return 0; +} + +static int draw_hp(const struct instance *const i, const short x, const short y, + const instance_hp max_hp) +{ + enum {OFFSET = 4, WIDTH = 64, HEIGHT = 4}; + const short ry = y - OFFSET - HEIGHT; + + if (ry < 0) + return 0; + + const short gw = (WIDTH * i->hp) / max_hp; + + { + struct rect *const gr = rect_get(true); + + if (!gr) + return -1; + + gr->x = x; + gr->y = ry; + gr->w = gw; + gr->h = HEIGHT; + gr->g = UCHAR_MAX >> 1; + rect_sort(gr); + } + + { + struct rect *const rr = rect_get(true); + + if (!rr) + return -1; + + rr->x = x + gw; + rr->y = ry; + rr->w = WIDTH - gw; + rr->h = HEIGHT; + rr->r = UCHAR_MAX >> 1; + rect_sort(rr); + } + + return 0; +} + +static int draw_miners(const struct resource *const r) +{ + const struct resource_gold *const g = &r->res.gold; + + if (!g->n_miners) + return 0; + + for (size_t i = 0, n = 0; i < sizeof g->miners / sizeof *g->miners; i++) + { + if (g->miners[i]) + { + enum {OFFSET = 112, SZ = 16, GAP = 4}; + struct rect *const r = rect_get(true); + + if (!r) + return -1; + + r->x = OFFSET + n * (SZ + GAP); + r->y = screen_h - 40; + r->r = r->g = r->b = 127; + r->w = r->h = SZ; + rect_sort(r); + + if (++n >= g->n_miners) + break; + } + } + + return 0; +} + +static int draw_carry(const enum font f, const short x, const short y, + const struct unit *const u) +{ + if (unit_can_harvest(u)) + { + const struct unit_harvester *const uh = &u->us.harvester; + + if (uh->carry) + return font_printf(f, x, y, "%d", uh->carry) < 0; + } + + return 0; +} + +static int render_selsingle(const struct sprite *const up, + const struct human_player *const h) +{ + enum {X_OFF = 8, Y_OFF = 8, HP_Y = 32}; + const short x = up->x + X_OFF, y = up->y + Y_OFF; + + for (size_t i = 0; i < sizeof h->sel / sizeof *h->sel; i++) + { + const struct sel_instance *const sel = &h->sel[i]; + + if (sel) + { + switch (sel->type) + { + case INSTANCE_TYPE_BUILDING: + { + const struct building *const b = sel->d.b; + const struct instance *const in = &b->instance; + const instance_hp hp = in->hp, max_hp = building_maxhp(b); + + if ((font_printf(FONT, x, y, "%s", building_str(b)) < 0) + || (font_printf(FONT, x, y + HP_Y, "%u/%u", hp, max_hp) < 0) + || draw_hp(in, x, y + HP_Y - 4, max_hp)) + return -1; + + return 0; + } + break; + + case INSTANCE_TYPE_UNIT: + { + const struct unit *const u = sel->d.u; + const struct instance *const in = &u->instance; + const instance_hp hp = in->hp, max_hp = unit_maxhp(u); + enum {CARRY_X = 96, CARRY_Y = 8}; + + if ((font_printf(FONT, x, y, "%s", unit_str(u)) < 0) + || (font_printf(FONT, x, y + HP_Y, "%u/%u", hp, max_hp) < 0) + || draw_carry(FONT, x + CARRY_X, y, u) + || draw_hp(in, x, y + HP_Y - 4, max_hp)) + return -1; + + return 0; + } + break; + + case INSTANCE_TYPE_RESOURCE: + { + const struct resource *const r = sel->d.r; + const struct instance *const in = &r->instance; + const instance_hp hp = in->hp, max_hp = resource_maxhp(r); + + if ((font_printf(FONT, x, y, "%s", resource_str(r)) < 0) + || (font_printf(FONT, x, y + HP_Y, "%u/%u", hp, max_hp) < 0) + || draw_hp(in, x, y + HP_Y - 4, max_hp) + || (r->type == RESOURCE_TYPE_GOLD && draw_miners(r))) + return -1; + + return 0; + } + break; + } + + return 0; + } + } + + /* Unreachable. */ + return -1; +} + +static int render_selinfo(const struct sprite *const up, + const struct human_player *const h) +{ + enum {X_OFF = 8, Y_OFF = 8}; + + if (h->n_sel == 1) + return render_selsingle(up, h); + else if (font_printf(FONT, up->x + X_OFF, up->y + Y_OFF, + "%u units selected", h->n_sel) < 0) + return -1; + + return 0; +} + +static int render_sel(const struct human_player *const h) +{ + struct sprite *const up = sprite_get(); + + if (!up + || render_seltop(up) + || render_selrect(up) + || render_selmidtop(up) + || render_selmiddown(up) + || render_selvertleft(up) + || render_selvertright(up) + || render_seldown(up) + || render_selinfo(up, h)) + return -1; + + return 0; +} + +void gui_update(struct human_player *const h) +{ + struct player *const pl = &h->pl; + + for (size_t i = 0; i < sizeof pl->resources / sizeof *pl->resources; i++) + { + if (h->gui_res[i] > pl->resources[i]) + h->gui_res[i]--; + else if (h->gui_res[i] < pl->resources[i]) + h->gui_res[i]++; + } +} + +int gui_render(const struct human_player *const h) +{ + if ((h->top_gui && render_topmenu(h)) + || (h->n_sel && render_sel(h))) + return -1; + + return 0; +} |
