Remove tech and resources

This commit is contained in:
Xavier Del Campo Romero 2024-01-26 22:28:32 +01:00
parent b9f1fe1b75
commit 0333e1e27e
Signed by: xavi
GPG Key ID: 84FF3612A9BF43F2
22 changed files with 100 additions and 1521 deletions

View File

@ -20,7 +20,6 @@ set(components
pad
peripheral
player
resource
settings
sfx
system
@ -31,7 +30,6 @@ set(components
)
set(interfaces
tech
)
target_compile_options(${PROJECT_NAME} PUBLIC ${cflags})

View File

@ -9,7 +9,6 @@ target_link_libraries(game PUBLIC peripheral PRIVATE
instance
pad
player
resource
system
terrain
unit)

View File

@ -3,7 +3,6 @@
#include <gfx.h>
#include <human_player.h>
#include <player.h>
#include <resource.h>
#include <system.h>
#include <terrain.h>
#include <stddef.h>
@ -38,30 +37,6 @@ int game(const struct game_cfg *const cfg)
if (human_player_init(&hcfg, &human))
goto end;
struct resource res[MAP_RESOURCES] = {0};
resource_set_alive_cb(terrain_block_update, &map);
if (resource_create(&(const struct resource_cfg)
{
.type = RESOURCE_TYPE_GOLD,
.x = 50,
.y = 200
}, res, sizeof res / sizeof *res)
|| resource_create(&(const struct resource_cfg)
{
.type = RESOURCE_TYPE_WOOD,
.x = 180,
.y = 200
}, res, sizeof res / sizeof *res)
|| resource_create(&(const struct resource_cfg)
{
.type = RESOURCE_TYPE_WOOD,
.x = 240,
.y = 200
}, res, sizeof res / sizeof *res))
goto end;
bool exit = false;
while (!exit)
@ -70,11 +45,7 @@ int game(const struct game_cfg *const cfg)
if (human.pl.alive)
{
struct player_others o =
{
.res = res,
.n_res = sizeof res / sizeof *res
};
struct player_others o;
human_player_update(&human, &o);
exit |= human.periph->common.exit;

View File

@ -8,284 +8,11 @@
#include <gui/line_edit.h>
#include <gui/rounded_rect.h>
#include <gui/checkbox.h>
#include <resource.h>
#include <terrain.h>
#include <unit.h>
#include <stdbool.h>
static const struct container c[] =
{
{
.path = "barracks",
.type = CONTAINER_TYPE_SPRITE,
.data =
{
.sprite = &building_sprites[BUILDING_TYPE_BARRACKS]
}
},
{
.path = "worker_n",
.type = CONTAINER_TYPE_SPRITE,
.data =
{
.sprite = &unit_sprites[UNIT_SPRITE_N]
}
},
{
.path = "worker_ne",
.type = CONTAINER_TYPE_SPRITE,
.data =
{
.sprite = &unit_sprites[UNIT_SPRITE_NE]
}
},
{
.path = "worker_e",
.type = CONTAINER_TYPE_SPRITE,
.data =
{
.sprite = &unit_sprites[UNIT_SPRITE_E]
}
},
{
.path = "worker_se",
.type = CONTAINER_TYPE_SPRITE,
.data =
{
.sprite = &unit_sprites[UNIT_SPRITE_SE]
}
},
{
.path = "worker_s",
.type = CONTAINER_TYPE_SPRITE,
.data =
{
.sprite = &unit_sprites[UNIT_SPRITE_S]
}
},
{
.path = "grass",
.type = CONTAINER_TYPE_SPRITE,
.data =
{
.sprite = &grass_sprite
}
},
{
.path = "cursor",
.type = CONTAINER_TYPE_SPRITE,
.data =
{
.sprite = &cursor_sprite
}
},
{
.path = "gui_bar_left",
.type = CONTAINER_TYPE_SPRITE,
.data =
{
.sprite = &gui_bar_sprites[GUI_BAR_LEFT]
}
},
{
.path = "gui_bar_mid",
.type = CONTAINER_TYPE_SPRITE,
.data =
{
.sprite = &gui_bar_sprites[GUI_BAR_MID]
}
},
{
.path = "gui_bar_right",
.type = CONTAINER_TYPE_SPRITE,
.data =
{
.sprite = &gui_bar_sprites[GUI_BAR_RIGHT]
}
},
{
.path = "sel_up_left",
.type = CONTAINER_TYPE_SPRITE,
.data =
{
.sprite = &gui_rounded_rect_sprites[GUI_ROUNDED_RECT_UP_LEFT]
}
},
{
.path = "sel_up_right",
.type = CONTAINER_TYPE_SPRITE,
.data =
{
.sprite = &gui_rounded_rect_sprites[GUI_ROUNDED_RECT_UP_RIGHT]
}
},
{
.path = "sel_down_left",
.type = CONTAINER_TYPE_SPRITE,
.data =
{
.sprite = &gui_rounded_rect_sprites[GUI_ROUNDED_RECT_DOWN_LEFT]
}
},
{
.path = "sel_down_right",
.type = CONTAINER_TYPE_SPRITE,
.data =
{
.sprite = &gui_rounded_rect_sprites[GUI_ROUNDED_RECT_DOWN_RIGHT]
}
},
{
.path = "sel_mid",
.type = CONTAINER_TYPE_SPRITE,
.data =
{
.sprite = &gui_rounded_rect_sprites[GUI_ROUNDED_RECT_MID]
}
},
{
.path = "sel_mid_v",
.type = CONTAINER_TYPE_SPRITE,
.data =
{
.sprite = &gui_rounded_rect_sprites[GUI_ROUNDED_RECT_MID_VERT]
}
},
{
.path = "font",
.type = CONTAINER_TYPE_SPRITE,
.data =
{
.sprite = &font_sprite
}
},
{
.path = "gold_mine",
.type = CONTAINER_TYPE_SPRITE,
.data =
{
.sprite = &resource_sprites[RESOURCE_TYPE_GOLD]
}
},
{
.path = "tree",
.type = CONTAINER_TYPE_SPRITE,
.data =
{
.sprite = &resource_sprites[RESOURCE_TYPE_WOOD]
}
},
{
.path = "acknowledge_01",
.type = CONTAINER_TYPE_SOUND,
.data =
{
.sound = &unit_sounds[UNIT_SOUND_MOVE]
}
},
{
.path = "acknowledge_02",
.type = CONTAINER_TYPE_SOUND,
.data =
{
.sound = &unit_sounds[UNIT_SOUND_MOVE_2]
}
},
{
.path = "selected_01",
.type = CONTAINER_TYPE_SOUND,
.data =
{
.sound = &unit_sounds[UNIT_SOUND_SELECTED]
}
},
{
.path = "btn_left",
.type = CONTAINER_TYPE_SPRITE,
.data =
{
.sprite = &gui_button_sprites[GUI_BUTTON_LEFT]
}
},
{
.path = "btn_mid",
.type = CONTAINER_TYPE_SPRITE,
.data =
{
.sprite = &gui_button_sprites[GUI_BUTTON_MID]
}
},
{
.path = "btn_right",
.type = CONTAINER_TYPE_SPRITE,
.data =
{
.sprite = &gui_button_sprites[GUI_BUTTON_RIGHT]
}
},
{
.path = "line_edit_left",
.type = CONTAINER_TYPE_SPRITE,
.data =
{
.sprite = &gui_line_edit_sprites[GUI_LINE_EDIT_LEFT]
}
},
{
.path = "line_edit_mid",
.type = CONTAINER_TYPE_SPRITE,
.data =
{
.sprite = &gui_line_edit_sprites[GUI_LINE_EDIT_MID]
}
},
{
.path = "line_edit_right",
.type = CONTAINER_TYPE_SPRITE,
.data =
{
.sprite = &gui_line_edit_sprites[GUI_LINE_EDIT_RIGHT]
}
},
{
.path = "checkbox",
.type = CONTAINER_TYPE_SPRITE,
.data =
{
.sprite = &gui_checkbox_sprite
}
}
};
static const struct container c[1];
static bool init;
void game_free(void)
@ -301,7 +28,7 @@ int game_resinit(void)
{
if (!init)
{
if (container_load("rts.cnt", c, sizeof c / sizeof *c))
if (container_load("jancity.cnt", c, sizeof c / sizeof *c))
{
perror("container_load");
return -1;

View File

@ -75,5 +75,10 @@ int menu(void)
peripheral_init(&cfg, &c.p);
settings_load("settings.ini", &c.s);
return menu_main(&c);
const struct game_cfg gcfg =
{
.p = &c.p
};
return game(&gcfg);
}

View File

@ -1,7 +1,6 @@
add_library(player
"src/player.c"
"src/human_player.c"
"src/human_player_gui.c"
)
target_include_directories(player PUBLIC "inc" PRIVATE "privinc")
target_link_libraries(player
@ -14,8 +13,6 @@ target_link_libraries(player
input
mouse
pad
resource
tech
unit
util
PRIVATE

View File

@ -39,8 +39,7 @@ struct human_player
enum sel_type
{
INSTANCE_TYPE_UNIT,
INSTANCE_TYPE_BUILDING,
INSTANCE_TYPE_RESOURCE
INSTANCE_TYPE_BUILDING
} type;
union sel_data
@ -61,8 +60,6 @@ struct human_player
} target;
size_t n_sel;
bool top_gui;
uint32_t gui_res[MAX_RESOURCE_TYPES];
};
int human_player_init(const struct human_player_cfg *cfg, struct human_player *h);

View File

@ -5,8 +5,6 @@
#include <camera.h>
#include <instance.h>
#include <pad.h>
#include <resource.h>
#include <tech.h>
#include <unit.h>
#include <stdbool.h>
#include <stddef.h>
@ -36,13 +34,7 @@ struct player
bool alive;
struct unit units[PLAYER_MAX_UNITS];
struct building buildings[PLAYER_MAX_BUILDINGS];
uint32_t resources[MAX_RESOURCE_TYPES];
unsigned char pop, bpop;
struct
{
struct unit_tech u;
} tree;
};
struct player_cfg
@ -55,8 +47,7 @@ struct player_cfg
struct player_others
{
struct player *pl;
struct resource *res;
size_t n_pl, n_res;
size_t n_pl;
};
int player_init(const struct player_cfg *cfg, struct player *pl);

View File

@ -1,18 +0,0 @@
#ifndef HUMAN_PLAYER_PRIVATE_H
#define HUMAN_PLAYER_PRIVATE_H
#include <human_player.h>
#ifdef __cplusplus
extern "C"
{
#endif
void human_player_gui_update(struct human_player *h);
int human_player_gui_render(const struct human_player *h);
#ifdef __cplusplus
}
#endif
#endif /* HUMAN_PLAYER_PRIVATE_H */

View File

@ -1,5 +1,4 @@
#include <human_player.h>
#include <human_player_private.h>
#include <player.h>
#include <building.h>
#include <camera.h>
@ -9,7 +8,6 @@
#include <input.h>
#include <keyboard.h>
#include <pad.h>
#include <resource.h>
#include <unit.h>
#include <util.h>
#include <stdbool.h>
@ -42,61 +40,49 @@ static bool select_units(struct human_player *const h, const short x,
const struct unit *const u = &pl->units[i];
const struct instance *const in = &u->instance;
if (in->alive)
if (!in->alive)
continue;
const union sel_data d = {.u = u};
if (!instance_selected(h, &d)
&& cursor_collision(&h->cam, &in->r)
&& h->n_sel < sizeof h->sel / sizeof *h->sel)
{
switch (u->state)
struct sel_instance *sel = NULL;
if (excl)
{
default:
sel = h->sel;
h->n_sel = 1;
for (size_t i = 1; i < sizeof h->sel / sizeof *h->sel; i++)
h->sel[i].d.u = NULL;
}
else
{
for (size_t i = 0; i < sizeof h->sel / sizeof *h->sel; i++)
{
const union sel_data d = {.u = u};
struct sel_instance *const s = &h->sel[i];
if (!instance_selected(h, &d)
&& cursor_collision(&h->cam, &in->r)
&& h->n_sel < sizeof h->sel / sizeof *h->sel)
if (!s->d.u)
{
struct sel_instance *sel = NULL;
if (excl)
{
sel = h->sel;
h->n_sel = 1;
for (size_t i = 1; i < sizeof h->sel / sizeof *h->sel; i++)
h->sel[i].d.u = NULL;
}
else
{
for (size_t i = 0; i < sizeof h->sel / sizeof *h->sel; i++)
{
struct sel_instance *const s = &h->sel[i];
if (!s->d.u)
{
sel = s;
h->n_sel++;
break;
}
}
}
if (sel)
{
sel->type = INSTANCE_TYPE_UNIT;
sel->d.u = u;
sfx_play(&unit_sounds[UNIT_SOUND_SELECTED]);
return true;
}
return false;
sel = s;
h->n_sel++;
break;
}
}
break;
case UNIT_STATE_SHELTERED:
/* Fall through. */
case UNIT_STATE_HARVESTING_GOLD:
break;
}
if (sel)
{
sel->type = INSTANCE_TYPE_UNIT;
sel->d.u = u;
sfx_play(&unit_sounds[UNIT_SOUND_SELECTED]);
return true;
}
return false;
}
}
@ -161,62 +147,6 @@ static bool select_buildings(struct human_player *const h, const short x,
return false;
}
static bool select_resources(struct human_player *const h, const short x,
const short y, const struct player_others *const o, const bool excl)
{
for (size_t i = 0; i < o->n_res; i++)
{
const struct resource *const r = &o->res[i];
const struct instance *const in = &r->instance;
if (in->alive)
{
const union sel_data d = {.r = r};
if (!instance_selected(h, &d)
&& cursor_collision(&h->cam, &in->r)
&& h->n_sel < sizeof h->sel / sizeof *h->sel)
{
struct sel_instance *sel = NULL;
if (excl)
{
sel = h->sel;
h->n_sel = 1;
for (size_t i = 1; i < sizeof h->sel / sizeof *h->sel; i++)
h->sel[i].d.r = NULL;
}
else
{
for (size_t i = 0; i < sizeof h->sel / sizeof *h->sel; i++)
{
struct sel_instance *const s = &h->sel[i];
if (!s->d.r)
{
sel = s;
h->n_sel++;
break;
}
}
}
if (sel)
{
sel->type = INSTANCE_TYPE_RESOURCE;
sel->d.r = r;
return true;
}
return false;
}
}
}
return false;
}
static bool select_instances(struct human_player *const h,
const struct player_others *const o, const bool excl,
const bool same_type)
@ -227,8 +157,7 @@ static bool select_instances(struct human_player *const h,
if (!same_type || !h->n_sel)
return select_buildings(h, x, y, excl)
|| select_units(h, x, y, excl)
|| select_resources(h, x, y, o, excl);
|| select_units(h, x, y, excl);
else
{
switch (h->sel->type)
@ -238,9 +167,6 @@ static bool select_instances(struct human_player *const h,
case INSTANCE_TYPE_BUILDING:
return select_buildings(h, x, y, excl);
case INSTANCE_TYPE_RESOURCE:
select_resources(h, x, y, o, excl);
}
}
@ -253,62 +179,6 @@ static bool instance_collision(const struct camera *const cam,
return in->alive && cursor_collision(cam, &in->r);
}
static void resources_stored(struct instance *const i, void *const op)
{
struct player *const p = op;
struct unit *const u = (struct unit *)i;
struct unit_harvester *const uh = &u->us.harvester;
p->resources[uh->type] += uh->carry;
uh->carry = 0;
unit_set_target(u, &uh->prev_target);
}
static void harvest_done(struct instance *const ins, void *const op)
{
struct player *const p = op;
struct unit *const u = (struct unit *)ins;
struct resource *const res = (struct resource *)u->target.ins;
if (res->type == RESOURCE_TYPE_GOLD)
{
struct resource_gold *const g = &res->res.gold;
for (size_t i = 0; i < sizeof g->miners / sizeof *g->miners; i++)
{
struct instance **const pi = &g->miners[i];
if (*pi == ins)
{
*pi = NULL;
g->n_miners--;
break;
}
}
}
for (size_t i = 0; i < sizeof p->buildings / sizeof *p->buildings; i++)
{
struct building *const b = &p->buildings[i];
if (b->instance.alive && b->type == BUILDING_TYPE_BARRACKS)
{
const struct unit_target t =
{
.ins = &b->instance,
.state = UNIT_STATE_CARRYING,
.done = resources_stored,
.op = p
/* TODO .state = UNIT_STATE_SHELTERED */
};
u->us.harvester.prev_target = u->target;
unit_set_target(u, &t);
break;
}
}
}
static bool target_from_own(struct player *const p,
const struct camera *const cam, struct unit_target *const t)
{
@ -332,101 +202,6 @@ static bool target_from_own(struct player *const p,
return false;
}
static bool target_from_others(const struct player *const p,
const struct player_others *const o,
const struct camera *const cam, struct unit_target *const t)
{
for (size_t i = 0; i < o->n_pl; i++)
{
struct player *const pl = &o->pl[i];
if (p->team != pl->team)
{
for (size_t i = 0; i < sizeof pl->units / sizeof *pl->units; i++)
{
struct unit *const u = &pl->units[i];
struct instance *const in = &u->instance;
if (instance_collision(cam, in))
{
*t = (const struct unit_target)
{
.ins = in,
.attack = unit_attacked,
.state = UNIT_STATE_ATTACKING
};
return true;
}
}
for (size_t i = 0; i < sizeof pl->buildings / sizeof *pl->buildings; i++)
{
struct building *const b = &pl->buildings[i];
struct instance *const in = &b->instance;
if (instance_collision(cam, in))
{
*t = (const struct unit_target)
{
.ins = in,
.state = UNIT_STATE_ATTACKING
};
return true;
}
}
}
}
return false;
}
static enum unit_state target_state_from_res(const struct resource *const res)
{
switch (res->type)
{
case RESOURCE_TYPE_GOLD:
return UNIT_STATE_HARVESTING_GOLD;
case RESOURCE_TYPE_WOOD:
return UNIT_STATE_HARVESTING_WOOD;
default:
break;
}
return UNIT_STATE_IDLE_MOVING;
}
static bool target_from_res(struct player *const p,
const struct player_others *const o,
const struct camera *const cam, struct unit_target *const t)
{
for (size_t i = 0; i < o->n_res; i++)
{
struct resource *const res = &o->res[i];
struct instance *const in = &res->instance;
if (instance_collision(cam, in))
{
*t = (const struct unit_target)
{
.ins = in,
.attack = resource_harvested,
.shelter = resource_shelter(res),
.state = target_state_from_res(res),
.done = harvest_done,
.op = p
};
return true;
}
}
return false;
}
static void set_target(struct human_player *const h, struct unit *const u,
const struct unit_target *const t)
{
@ -443,9 +218,7 @@ static void target_from_pos(struct player *const p,
const struct player_others *const o,
const struct camera *const cam, struct unit_target *const t)
{
if (!target_from_own(p, cam, t)
&& !target_from_others(p, o, cam, t)
&& !target_from_res(p, o, cam, t))
if (!target_from_own(p, cam, t))
t->ins = NULL;
}
@ -472,7 +245,7 @@ static void move_units(struct human_player *const h,
{
struct unit *const u = si->d.rw_u;
if (!t.ins || !unit_target_valid(u, &t))
if (!t.ins)
unit_move_to(u, x, y);
else
set_target(h, u, &t);
@ -506,9 +279,7 @@ static void update_selected(struct human_player *const h)
struct sel_instance *const si = &h->sel[i];
if (si->d.i && (!si->d.i->alive || si->d.i->dying
|| (si->type == INSTANCE_TYPE_UNIT
&& (si->d.u->state == UNIT_STATE_HARVESTING_GOLD
|| si->d.u->state == UNIT_STATE_SHELTERED))))
|| si->type == INSTANCE_TYPE_UNIT))
{
si->d.i = NULL;
h->n_sel--;
@ -552,8 +323,6 @@ static void update_from_pad(struct human_player *const h,
move_units(h, o);
else if (input_pad_justpressed(in, p, PAD_KEY_C))
deselect_instances(h);
else if (input_pad_justpressed(in, p, PAD_KEY_E))
h->top_gui ^= true;
}
static void update_from_touch(struct human_player *const h,
@ -616,7 +385,6 @@ void human_player_update(struct human_player *const h,
if (p->alive)
{
human_player_gui_update(h);
update_selected(h);
update_target(h);
peripheral_update(h->periph);
@ -686,30 +454,12 @@ static int render_own_buildings(const struct human_player *const h)
return 0;
}
static int render_resources(const struct human_player *const h,
const struct resource *const res, const size_t n)
{
for (size_t i = 0; i < n; i++)
{
const struct resource *const r = &res[i];
const union sel_data d = {.r = r};
const bool sel = instance_selected(h, &d);
if (resource_render(r, &h->cam, sel))
return -1;
}
return 0;
}
int human_player_render(const struct human_player *const h,
const struct player_others *const o)
{
if (render_target(h)
|| render_own_units(h)
|| render_own_buildings(h)
|| render_resources(h, o->res, o->n_res)
|| human_player_gui_render(h)
|| input_render(&h->in, h->periph))
return -1;
@ -742,9 +492,5 @@ int human_player_init(const struct human_player_cfg *const cfg,
cursor_init(&h->cam.cursor);
h->periph = cfg->p;
h->cam.dim = cfg->dim;
h->top_gui = true;
UTIL_STATIC_ASSERT(sizeof h->gui_res == sizeof h->pl.resources,
"unexpected sizeof for h->gui_res");
memmove(h->gui_res, h->pl.resources, sizeof h->gui_res);
return 0;
}

View File

@ -1,346 +0,0 @@
#include <building.h>
#include <gfx.h>
#include <human_player.h>
#include <player.h>
#include <unit.h>
#include <gui.h>
#include <gui/bar.h>
#include <gui/container.h>
#include <gui/label.h>
#include <gui/progress_bar.h>
#include <gui/rounded_rect.h>
#include <inttypes.h>
#include <limits.h>
#include <stddef.h>
#include <stdio.h>
#include <stdint.h>
enum {X_OFF = 8, Y_OFF = 8, HP_Y = 32};
static int draw_hp(const struct instance *const i, const instance_hp max_hp,
struct gui_common *const r)
{
enum {WIDTH = 64, HEIGHT = 4};
struct gui_progress_bar pb;
gui_progress_bar_init(&pb);
pb.common.x = X_OFF;
pb.common.y = HP_Y - 8;
pb.progress = ((unsigned)GUI_PROGRESS_BAR_MAX * i->hp) / max_hp;
pb.fg.g = UCHAR_MAX >> 1;
pb.bg.r = UCHAR_MAX >> 1;
pb.w = WIDTH;
pb.h = HEIGHT;
pb.stp = true;
gui_add_child(r, &pb.common);
return gui_render(r);
}
#if 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};
rect_get_or_ret(r, -1);
semitrans_rect_init(r);
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;
}
#endif
void human_player_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]++;
}
}
static int render_sel_single_building(const struct human_player *const h,
const struct sel_instance *const sel, struct gui_common *const r)
{
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);
struct gui_label bl;
gui_label_init(&bl);
bl.common.x = X_OFF;
bl.common.y = Y_OFF;
bl.text = building_str(b);
gui_add_child(r, &bl.common);
char hp_str[sizeof "65535/65535"];
const int rs = snprintf(hp_str, sizeof hp_str, "%u/%u", hp, max_hp);
if (rs < 0 || rs >= sizeof hp_str)
return -1;
struct gui_label hpl;
gui_label_init(&hpl);
hpl.common.x = X_OFF;
hpl.common.y = HP_Y;
hpl.text = hp_str;
gui_add_child(r, &hpl.common);
return draw_hp(in, max_hp, r);
}
static int render_sel_single_unit(const struct human_player *const h,
const struct sel_instance *const sel, struct gui_common *const r)
{
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};
struct gui_label ul;
gui_label_init(&ul);
ul.common.x = X_OFF;
ul.common.y = Y_OFF;
ul.text = unit_str(u);
gui_add_child(r, &ul.common);
char hp_str[sizeof "65535/65535"];
const int rs = snprintf(hp_str, sizeof hp_str, "%u/%u", hp, max_hp);
if (rs < 0 || rs >= sizeof hp_str)
return -1;
struct gui_label hpl;
gui_label_init(&hpl);
hpl.common.x = X_OFF;
hpl.common.y = HP_Y;
hpl.text = hp_str;
gui_add_child(r, &hpl.common);
char c_str[sizeof "255"];
struct gui_label cl;
if (unit_can_harvest(u))
{
const struct unit_harvester *const uh = &u->us.harvester;
if (uh->carry)
{
const int rs = snprintf(c_str, sizeof c_str, "%hhu", uh->carry);
if (rs < 0 || rs >= sizeof c_str)
return -1;
gui_label_init(&cl);
cl.common.x = CARRY_X;
cl.common.y = CARRY_Y;
cl.text = c_str;
gui_add_child(r, &cl.common);
}
}
return draw_hp(in, max_hp, r);
}
static int render_sel_single_resource(const struct human_player *const h,
const struct sel_instance *const sel, struct gui_common *const r)
{
const struct resource *const res = sel->d.r;
const struct instance *const in = &res->instance;
const instance_hp hp = in->hp, max_hp = resource_maxhp(res);
struct gui_label rl;
gui_label_init(&rl);
rl.common.x = X_OFF;
rl.common.y = Y_OFF;
rl.text = resource_str(res);
gui_add_child(r, &rl.common);
char hp_str[sizeof "65535/65535"];
const int rs = snprintf(hp_str, sizeof hp_str, "%u/%u", hp, max_hp);
if (rs < 0 || rs >= sizeof hp_str)
return -1;
struct gui_label hpl;
gui_label_init(&hpl);
hpl.common.x = X_OFF;
hpl.common.y = HP_Y;
hpl.text = hp_str;
gui_add_child(r, &hpl.common);
return draw_hp(in, max_hp, r);
}
static int render_sel_single(const struct human_player *const h,
struct gui_common *const r)
{
for (size_t i = 0; i < sizeof h->sel / sizeof *h->sel; i++)
{
const struct sel_instance *const sel = &h->sel[i];
if (sel->d.i)
{
switch (sel->type)
{
case INSTANCE_TYPE_BUILDING:
return render_sel_single_building(h, sel, r);
case INSTANCE_TYPE_UNIT:
return render_sel_single_unit(h, sel, r);
case INSTANCE_TYPE_RESOURCE:
return render_sel_single_resource(h, sel, r);
}
}
}
/* Unreachable. */
return -1;
}
static int render_sel_multiple(const struct human_player *const h,
struct gui_common *const r)
{
struct gui_label l;
char str[sizeof "4294967295 units selected"];
const int rs = snprintf(str, sizeof str, "%zu units selected", h->n_sel);
if (rs < 0 || rs >= sizeof str)
return -1;
gui_label_init(&l);
l.common.x = X_OFF;
l.common.y = Y_OFF;
l.text = str;
gui_add_child(r, &l.common);
return gui_render(r);
}
static int render_sel(const struct human_player *const h)
{
struct gui_rounded_rect r;
gui_rounded_rect_init(&r);
r.common.x = 16;
r.w = screen_w - (r.common.x * 2);
r.h = screen_h / 4;
r.common.y = screen_h - r.h;
if (h->n_sel == 1)
return render_sel_single(h, &r.common);
return render_sel_multiple(h, &r.common);
}
static int render_top(const struct human_player *const h)
{
const struct player *const pl = &h->pl;
struct gui_container c;
struct gui_bar b;
gui_bar_init(&b);
b.w = screen_w;
gui_container_init(&c);
c.mode = GUI_CONTAINER_MODE_H;
c.spacing = 16;
c.common.hcentered = true;
c.common.vcentered = true;
gui_add_child(&b.common, &c.common);
char wood_str[sizeof "Wood=429496729"];
{
const int rs = snprintf(wood_str, sizeof wood_str,
"Wood=%" PRIu32, h->gui_res[RESOURCE_TYPE_WOOD]);
if (rs < 0 || rs >= sizeof wood_str)
return -1;
}
struct gui_label wl;
gui_label_init(&wl);
wl.common.vcentered = true;
wl.text = wood_str;
gui_add_child(&c.common, &wl.common);
char gold_str[sizeof "Gold=429496729"];
{
const int rs = snprintf(gold_str, sizeof gold_str,
"Gold=%" PRIu32, h->gui_res[RESOURCE_TYPE_GOLD]);
if (rs < 0 || rs >= sizeof wood_str)
return -1;
}
struct gui_label gl;
gui_label_init(&gl);
wl.common.vcentered = true;
gl.text = gold_str;
gui_add_child(&c.common, &gl.common);
char pop_str[sizeof "Pop.=255/255"];
{
const int rs = snprintf(pop_str, sizeof pop_str,
"Pop.=%hhu/%zu", pl->pop, sizeof pl->units / sizeof *pl->units);
if (rs < 0 || rs >= sizeof wood_str)
return -1;
}
struct gui_label popl;
gui_label_init(&popl);
wl.common.vcentered = true;
popl.text = pop_str;
gui_add_child(&c.common, &popl.common);
if (gui_render(&b.common))
return -1;
return 0;
}
int human_player_gui_render(const struct human_player *const h)
{
if (h->top_gui && render_top(h))
return -1;
if (h->n_sel && render_sel(h))
return -1;
return 0;
}

View File

@ -9,7 +9,7 @@ void player_update(struct player *const p)
{
struct unit *const u = &p->units[i];
unit_update(&p->tree.u, u);
unit_update(u);
}
}
@ -98,13 +98,6 @@ int player_init(const struct player_cfg *const cfg, struct player *const pl)
if (player_create_unit(&cfgs[i], pl))
return -1;
for (size_t i = 0; i < sizeof pl->resources / sizeof *pl->resources; i++)
{
enum {DEFAULT_RES = 120};
pl->resources[i] = DEFAULT_RES;
}
pl->alive = true;
pl->color = cfg->color;
pl->team = cfg->team;

View File

@ -1,3 +0,0 @@
add_library(resource "src/resource.c")
target_include_directories(resource PUBLIC "inc")
target_link_libraries(resource PUBLIC camera gfx instance util)

View File

@ -1,58 +0,0 @@
#ifndef RESOURCE_H
#define RESOURCE_H
#include <camera.h>
#include <container.h>
#include <gfx.h>
#include <instance.h>
#include <resource_type.h>
#include <util.h>
#include <stdbool.h>
#include <stddef.h>
#ifdef __cplusplus
extern "C"
{
#endif
enum {RESOURCE_GOLD_CAPACITY = 2};
struct resource
{
struct instance instance;
enum resource_type type;
union
{
struct resource_gold
{
struct instance *miners[RESOURCE_GOLD_CAPACITY];
size_t n_miners;
} gold;
} res;
};
UTIL_STATIC_ASSERT(!offsetof(struct resource, instance), "must be at offset zero");
struct resource_cfg
{
enum resource_type type;
unsigned long x, y;
};
const struct container_list *resource_res(void);
void resource_set_alive_cb(void (*f)(const struct util_rect *dim, bool alive, void *p), void *p);
int resource_create(const struct resource_cfg *cfg, struct resource *list, size_t n);
int resource_render(const struct resource *res, const struct camera *cam, bool sel);
instance_sheltered_cb resource_shelter(const struct resource *res);
bool resource_harvested(struct instance *i, instance_hp ap);
instance_hp resource_maxhp(const struct resource *res);
const char *resource_str(const struct resource *res);
extern struct sprite resource_sprites[MAX_RESOURCE_TYPES];
#ifdef __cplusplus
}
#endif
#endif /* RESOURCE_H */

View File

@ -1,21 +0,0 @@
#ifndef RESOURCE_TYPE_H
#define RESOURCE_TYPE_H
#ifdef __cplusplus
extern "C"
{
#endif
enum resource_type
{
RESOURCE_TYPE_WOOD,
RESOURCE_TYPE_GOLD,
MAX_RESOURCE_TYPES
};
#ifdef __cplusplus
}
#endif
#endif /* RESOURCE_TYPE_H */

View File

@ -1,177 +0,0 @@
#include <resource.h>
#include <gfx.h>
#include <instance.h>
#include <stdbool.h>
#include <stddef.h>
struct sprite resource_sprites[MAX_RESOURCE_TYPES];
static void (*cb)(const struct util_rect *, bool, void *);
static void *op;
static bool gold_shelter(struct instance *const self,
struct instance *const other)
{
struct resource *const res = (struct resource *)self;
struct resource_gold *const g = &res->res.gold;
for (size_t i = 0; i < sizeof g->miners / sizeof *g->miners; i++)
{
struct instance **const ins = &g->miners[i];
if (!*ins)
{
*ins = other;
g->n_miners++;
return true;
}
}
return false;
}
instance_sheltered_cb resource_shelter(const struct resource *res)
{
static const instance_sheltered_cb s[] =
{
[RESOURCE_TYPE_GOLD] = gold_shelter
};
return s[res->type];
}
bool resource_harvested(struct instance *const self, const instance_hp ap)
{
const bool ret = instance_attacked(self, ap);
if (ret && cb)
cb(&self->r, self->alive, op);
return ret;
}
instance_hp resource_maxhp(const struct resource *const res)
{
static const instance_hp hp[] =
{
[RESOURCE_TYPE_GOLD] = 1000,
[RESOURCE_TYPE_WOOD] = 45
};
return hp[res->type];
}
int resource_render(const struct resource *const res,
const struct camera *const cam, const bool sel)
{
const struct instance *const in = &res->instance;
if (!in->alive)
return 0;
sprite_get_or_ret(s, -1);
if (sprite_clone(&resource_sprites[res->type], s))
return -1;
const struct instance_render_off *off = NULL;
switch (res->type)
{
case RESOURCE_TYPE_GOLD:
s->h = in->r.h;
if (res->res.gold.n_miners)
s->v += s->h;
break;
case RESOURCE_TYPE_WOOD:
{
static const struct instance_render_off w_off =
{
.y = -30
};
off = &w_off;
}
break;
default:
break;
}
const struct instance_render_cfg cfg =
{
.i = &res->instance,
.prim_type = INSTANCE_RENDER_CFG_SPRITE,
.prim = {.s = s},
.cam = cam,
.sel = sel,
.max_hp = resource_maxhp(res),
.off = off
};
return instance_render(&cfg);
}
static void get_dimensions(const enum resource_type type, short *const w,
short *const h)
{
static const struct dim
{
short w, h;
} dim[] =
{
[RESOURCE_TYPE_GOLD] = {.w = 96, .h = 96},
[RESOURCE_TYPE_WOOD] = {.w = 32, .h = 16}
};
const struct dim *const d = &dim[type];
*w = d->w;
*h = d->h;
}
int resource_create(const struct resource_cfg *const cfg, struct resource *const list,
const size_t n)
{
for (size_t i = 0; i < n; i++)
{
struct resource *const r = &list[i];
struct instance *const in = &r->instance;
if (!in->alive)
{
get_dimensions(cfg->type, &in->r.w, &in->r.h);
r->type = cfg->type;
in->r.x = cfg->x;
in->r.y = cfg->y;
in->alive = true;
in->hp = resource_maxhp(r);
if (cb)
cb(&in->r, in->alive, op);
return 0;
}
}
return -1;
}
void resource_set_alive_cb(void (*const f)(const struct util_rect *, bool, void *),
void *const p)
{
cb = f;
op = p;
}
const char *resource_str(const struct resource *const res)
{
static const char *const str[] =
{
[RESOURCE_TYPE_GOLD] = "Gold mine",
[RESOURCE_TYPE_WOOD] = "Pine tree"
};
return str[res->type];
}

View File

@ -1,2 +0,0 @@
add_library(tech INTERFACE)
target_include_directories(tech INTERFACE "inc")

View File

@ -1,20 +0,0 @@
#ifndef TECH_H
#define TECH_H
#ifdef __cplusplus
extern "C"
{
#endif
enum tech_level
{
TECH_LEVEL_1,
TECH_LEVEL_2,
TECH_LEVEL_3
};
#ifdef __cplusplus
}
#endif
#endif /* TECH_H */

View File

@ -14,7 +14,7 @@ extern "C"
enum
{
MAP_TILES = 64,
TERRAIN_SZ = 32,
TERRAIN_SZ = 16,
MAP_W = MAP_TILES * TERRAIN_SZ,
MAP_H = MAP_TILES * TERRAIN_SZ
};

View File

@ -1,3 +1,12 @@
add_library(unit "src/unit.c")
target_include_directories(unit PUBLIC "inc")
target_link_libraries(unit PUBLIC fixmath container camera gfx instance resource sfx tech util)
target_link_libraries(unit
PUBLIC
fixmath
container
camera
gfx
instance
sfx
util
)

View File

@ -5,8 +5,6 @@
#include <gfx.h>
#include <sfx.h>
#include <instance.h>
#include <resource_type.h>
#include <tech.h>
#include <unit_type.h>
#include <util.h>
#include <fixmath.h>
@ -18,19 +16,9 @@ extern "C"
{
#endif
struct unit_tech
{
enum tech_level carry;
};
enum unit_state
{
UNIT_STATE_IDLE_MOVING,
UNIT_STATE_SHELTERED,
UNIT_STATE_HARVESTING_WOOD,
UNIT_STATE_HARVESTING_GOLD,
UNIT_STATE_CARRYING,
UNIT_STATE_ATTACKING
UNIT_STATE_IDLE_MOVING
};
struct unit_target
@ -67,18 +55,7 @@ struct unit
unsigned char t, i;
} frame;
union
{
struct unit_harvester
{
enum resource_type type;
unsigned char carry, t;
struct unit_target prev_target;
} harvester;
} us;
fix16_t rx, ry, tx, ty;
struct unit_target target;
};
@ -97,7 +74,7 @@ bool unit_target_valid(const struct unit *u, const struct unit_target *t);
void unit_set_target(struct unit *u, const struct unit_target *t);
void unit_move_to(struct unit *u, unsigned long x, unsigned long y);
bool unit_attacked(struct instance *, instance_hp ap);
void unit_update(const struct unit_tech *t, struct unit *u);
void unit_update(struct unit *u);
instance_hp unit_maxhp(const struct unit *u);
const char *unit_str(const struct unit *u);

View File

@ -115,16 +115,6 @@ static enum unit_dir get_direction(const struct unit *const u)
return dir;
}
static instance_hp attack_points(const struct unit *const u)
{
static instance_hp ap[] =
{
[UNIT_TYPE_PEASANT] = 1
};
return ap[u->type];
}
static void unit_stop(struct unit *const u)
{
u->tx = u->rx;
@ -151,68 +141,18 @@ static void target_interact(struct unit *const u)
const struct instance *const ins = t->ins;
/* TODO: lose u->ti if not visible. */
if (ins->alive)
if (!ins->alive)
{
if (t->state != u->state)
{
struct instance *const ui = &u->instance;
if (util_collision(&ins->r, &ui->r))
{
switch (t->state)
{
case UNIT_STATE_CARRYING:
u->target.done(&u->instance, u->target.op);
break;
case UNIT_STATE_ATTACKING:
t->attack(t->ins, attack_points(u));
u->state = t->state;
break;
case UNIT_STATE_HARVESTING_WOOD:
{
struct unit_harvester *const uh = &u->us.harvester;
if (uh->type != RESOURCE_TYPE_WOOD)
uh->carry = 0;
uh->type = RESOURCE_TYPE_WOOD;
u->state = t->state;
unit_stop(u);
}
break;
case UNIT_STATE_HARVESTING_GOLD:
{
struct unit_harvester *const uh = &u->us.harvester;
if (uh->type != RESOURCE_TYPE_GOLD)
uh->carry = 0;
uh->type = RESOURCE_TYPE_GOLD;
if (t->shelter(t->ins, ui))
u->state = t->state;
else
unit_stop(u);
}
break;
case UNIT_STATE_SHELTERED:
u->state = t->state;
break;
default:
break;
}
}
else
unit_chase(ins, u);
}
}
else
target_reset(u);
return;
}
else if (t->state == u->state)
return;
struct instance *const ui = &u->instance;
if (!util_collision(&ins->r, &ui->r))
unit_chase(ins, u);
}
static bool must_move(const struct unit *const u)
@ -220,164 +160,40 @@ static bool must_move(const struct unit *const u)
return u->rx != u->tx || u->ry != u->ty;
}
static void update_harvest(const struct unit_tech *const t, struct unit *const u)
{
static const unsigned char carry[] =
{
[TECH_LEVEL_1] = 10,
[TECH_LEVEL_2] = 15,
[TECH_LEVEL_3] = 25
};
static const char inc[] =
{
[TECH_LEVEL_1] = 10,
[TECH_LEVEL_2] = 50,
[TECH_LEVEL_3] = 25
};
struct unit_harvester *const uh = &u->us.harvester;
bool ret = false;
if (++uh->t >= inc[t->carry])
{
if (uh->carry < carry[t->carry])
{
++uh->carry;
ret = u->target.attack(u->target.ins, 1);
}
uh->t = 0;
}
if (ret || uh->carry >= carry[t->carry])
{
u->state = UNIT_STATE_CARRYING;
u->target.done(&u->instance, u->target.op);
}
}
void unit_update(const struct unit_tech *const t, struct unit *const u)
void unit_update(struct unit *const u)
{
const struct instance *const i = &u->instance;
if (i->alive)
{
if (u->target.ins)
target_interact(u);
if (!i->alive)
return;
switch (u->state)
if (u->target.ins)
target_interact(u);
else if (must_move(u))
{
fix16_t x_step, y_step;
u->dir = get_direction(u);
get_speed(u, &x_step, &y_step);
move_unit(u, x_step, y_step);
enum {FRAME_RATE = 6};
if (++u->frame.t >= FRAME_RATE)
{
case UNIT_STATE_SHELTERED:
break;
u->frame.t = 0;
case UNIT_STATE_HARVESTING_GOLD:
/* Fall through. */
case UNIT_STATE_HARVESTING_WOOD:
update_harvest(t, u);
break;
case UNIT_STATE_ATTACKING:
if (must_move(u))
u->state = UNIT_STATE_IDLE_MOVING;
break;
case UNIT_STATE_CARRYING:
/* Fall through. */
case UNIT_STATE_IDLE_MOVING:
if (must_move(u))
{
fix16_t x_step, y_step;
u->dir = get_direction(u);
get_speed(u, &x_step, &y_step);
move_unit(u, x_step, y_step);
enum {FRAME_RATE = 6};
if (++u->frame.t >= FRAME_RATE)
{
u->frame.t = 0;
if (++u->frame.i >= N_FRAMES)
u->frame.i = 0;
}
u->state = UNIT_STATE_IDLE_MOVING;
}
else
u->frame.i = 0;
u->instance.r.x = fix16_to_int(u->rx);
u->instance.r.y = fix16_to_int(u->ry);
break;
if (++u->frame.i >= N_FRAMES)
u->frame.i = 0;
}
u->state = UNIT_STATE_IDLE_MOVING;
}
}
else
u->frame.i = 0;
bool can_attack(const struct unit *const u)
{
static const bool a[] =
{
[UNIT_TYPE_PEASANT] = true
};
return a[u->type];
}
static bool can_shelter(const struct unit *const u)
{
static const bool s[] =
{
[UNIT_TYPE_PEASANT] = true
};
return s[u->type];
}
bool unit_can_harvest(const struct unit *const u)
{
static const bool h[] =
{
[UNIT_TYPE_PEASANT] = true
};
return h[u->type];
}
bool unit_attacked(struct instance *const i, const instance_hp ap)
{
return instance_attacked(i, ap);
}
bool unit_target_valid(const struct unit *const u,
const struct unit_target *const t)
{
switch (t->state)
{
case UNIT_STATE_HARVESTING_GOLD:
/* Fall through. */
case UNIT_STATE_HARVESTING_WOOD:
return unit_can_harvest(u);
case UNIT_STATE_ATTACKING:
return can_attack(u);
case UNIT_STATE_SHELTERED:
if (t->shelter)
return can_shelter(u);
else
break;
case UNIT_STATE_IDLE_MOVING:
/* Fall through. */
case UNIT_STATE_CARRYING:
break;
}
return false;
u->instance.r.x = fix16_to_int(u->rx);
u->instance.r.y = fix16_to_int(u->ry);
}
void unit_set_target(struct unit *const u, const struct unit_target *const t)
@ -582,9 +398,7 @@ static int unit_quad(const struct unit *const u, struct render_cfg *const rcfg)
int unit_render(const struct unit *const u, const struct camera *const cam,
const bool sel)
{
if (!u->instance.alive
|| u->state == UNIT_STATE_SHELTERED
|| u->state == UNIT_STATE_HARVESTING_GOLD)
if (!u->instance.alive)
return 0;
struct render_cfg rcfg;