Compare commits
11 Commits
d851f969fd
...
3525f89a9f
Author | SHA1 | Date |
---|---|---|
Xavier Del Campo Romero | 3525f89a9f | |
Xavier Del Campo Romero | fcb7324d01 | |
Xavier Del Campo Romero | dbf3955809 | |
Xavier Del Campo Romero | aeea544e67 | |
Xavier Del Campo Romero | fdecbe830b | |
Xavier Del Campo Romero | e3cfea51aa | |
Xavier Del Campo Romero | b477328154 | |
Xavier Del Campo Romero | 190d676877 | |
Xavier Del Campo Romero | d315cf316c | |
Xavier Del Campo Romero | a80f5f6a3a | |
Xavier Del Campo Romero | 8e6091629b |
|
@ -1,5 +1,4 @@
|
|||
build/
|
||||
build-*/
|
||||
.vscode/
|
||||
*.code-workspace
|
||||
cdimg/
|
||||
|
|
|
@ -1 +1,70 @@
|
|||
include(${CMAKE_CURRENT_LIST_DIR}/functions.cmake)
|
||||
|
||||
sprite(NAME sidewalk
|
||||
X 384
|
||||
Y 0
|
||||
BPP 4
|
||||
CX 384
|
||||
CY 48
|
||||
TRANSPARENT FALSE)
|
||||
|
||||
sprite(NAME roof1
|
||||
X 384
|
||||
Y 0
|
||||
BPP 4
|
||||
CX 384
|
||||
CY 48
|
||||
TRANSPARENT FALSE)
|
||||
|
||||
sprite(NAME roof2
|
||||
X 384
|
||||
Y 0
|
||||
BPP 4
|
||||
CX 384
|
||||
CY 48
|
||||
TRANSPARENT FALSE)
|
||||
|
||||
sprite(NAME cursor
|
||||
X 384
|
||||
Y 0
|
||||
BPP 4
|
||||
CX 384
|
||||
CY 48
|
||||
TRANSPARENT TRUE)
|
||||
|
||||
sprite(NAME btn_left
|
||||
X 384
|
||||
Y 0
|
||||
BPP 4
|
||||
CX 384
|
||||
CY 48
|
||||
TRANSPARENT TRUE)
|
||||
|
||||
sprite(NAME btn_mid
|
||||
X 384
|
||||
Y 0
|
||||
BPP 4
|
||||
CX 384
|
||||
CY 48
|
||||
TRANSPARENT FALSE)
|
||||
|
||||
sprite(NAME btn_right
|
||||
X 384
|
||||
Y 0
|
||||
BPP 4
|
||||
CX 384
|
||||
CY 48
|
||||
TRANSPARENT TRUE)
|
||||
|
||||
level(NAME city1)
|
||||
|
||||
container(NAME jancity
|
||||
SPRITES
|
||||
sidewalk
|
||||
roof1
|
||||
roof2
|
||||
cursor
|
||||
btn_left
|
||||
btn_mid
|
||||
btn_right
|
||||
)
|
||||
|
|
After Width: | Height: | Size: 586 B |
After Width: | Height: | Size: 2.3 KiB |
After Width: | Height: | Size: 542 B |
After Width: | Height: | Size: 2.3 KiB |
After Width: | Height: | Size: 586 B |
After Width: | Height: | Size: 2.3 KiB |
After Width: | Height: | Size: 21 KiB |
After Width: | Height: | Size: 21 KiB |
|
@ -0,0 +1,21 @@
|
|||
24 16
|
||||
|
||||
0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000
|
||||
0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000
|
||||
0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000
|
||||
0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000
|
||||
|
||||
0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000
|
||||
0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000
|
||||
0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000
|
||||
0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000
|
||||
|
||||
0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000
|
||||
0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000
|
||||
0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000
|
||||
0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000
|
||||
|
||||
0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000
|
||||
0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000
|
||||
0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000
|
||||
0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000
|
After Width: | Height: | Size: 550 B |
After Width: | Height: | Size: 2.1 KiB |
|
@ -77,6 +77,23 @@ function(sound)
|
|||
endif()
|
||||
endfunction()
|
||||
|
||||
function(level)
|
||||
set(options "")
|
||||
set(multiValueArgs "")
|
||||
set(oneValueArgs NAME)
|
||||
cmake_parse_arguments(LEVEL "${options}" "${oneValueArgs}"
|
||||
"${multiValueArgs}" ${ARGN})
|
||||
|
||||
add_custom_command(OUTPUT ${cdroot}/${LEVEL_NAME}.txt
|
||||
COMMAND cp ${LEVEL_NAME}.txt ${cdroot}/${LEVEL_NAME}.txt
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
DEPENDS ${LEVEL_NAME}.txt
|
||||
VERBATIM)
|
||||
add_custom_target(${LEVEL_NAME}_lvl
|
||||
DEPENDS ${cdroot}/${LEVEL_NAME}.txt)
|
||||
add_dependencies(${PROJECT_NAME} ${LEVEL_NAME}_lvl)
|
||||
endfunction()
|
||||
|
||||
function(container)
|
||||
set(options "")
|
||||
set(multiValueArgs SPRITES SOUNDS)
|
||||
|
|
After Width: | Height: | Size: 3.2 KiB |
After Width: | Height: | Size: 18 KiB |
After Width: | Height: | Size: 3.4 KiB |
After Width: | Height: | Size: 20 KiB |
After Width: | Height: | Size: 3.2 KiB |
After Width: | Height: | Size: 18 KiB |
After Width: | Height: | Size: 3.2 KiB |
After Width: | Height: | Size: 18 KiB |
After Width: | Height: | Size: 3.2 KiB |
After Width: | Height: | Size: 18 KiB |
After Width: | Height: | Size: 192 KiB |
After Width: | Height: | Size: 192 KiB |
After Width: | Height: | Size: 3.2 KiB |
After Width: | Height: | Size: 18 KiB |
|
@ -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})
|
||||
|
|
|
@ -31,7 +31,6 @@ struct building_cfg
|
|||
void building_create(const struct building_cfg *cfg, struct building *b);
|
||||
void building_set_alive_cb(void (*f)(const struct util_rect *dim, bool alive, void *p), void *p);
|
||||
int building_render(const struct building *b, const struct camera *cam, bool sel);
|
||||
instance_hp building_maxhp(const struct building *b);
|
||||
const char *building_str(const struct building *b);
|
||||
|
||||
extern struct sprite building_sprites[MAX_BUILDING_TYPES];
|
||||
|
|
|
@ -3,8 +3,6 @@
|
|||
|
||||
enum building_type
|
||||
{
|
||||
BUILDING_TYPE_BARRACKS,
|
||||
|
||||
MAX_BUILDING_TYPES
|
||||
};
|
||||
|
||||
|
|
|
@ -6,16 +6,6 @@
|
|||
|
||||
struct sprite building_sprites[MAX_BUILDING_TYPES];
|
||||
|
||||
instance_hp building_maxhp(const struct building *const b)
|
||||
{
|
||||
static const instance_hp hp[] =
|
||||
{
|
||||
[BUILDING_TYPE_BARRACKS] = 100
|
||||
};
|
||||
|
||||
return hp[b->type];
|
||||
}
|
||||
|
||||
int building_render(const struct building *const b,
|
||||
const struct camera *const cam, const bool sel)
|
||||
{
|
||||
|
@ -33,8 +23,7 @@ int building_render(const struct building *const b,
|
|||
.prim_type = INSTANCE_RENDER_CFG_SPRITE,
|
||||
.prim = {.s = s},
|
||||
.cam = cam,
|
||||
.sel = sel,
|
||||
.max_hp = building_maxhp(b)
|
||||
.sel = sel
|
||||
};
|
||||
|
||||
return instance_render(&cfg);
|
||||
|
@ -46,10 +35,7 @@ static void get_dimensions(const enum building_type type, short *const w,
|
|||
static const struct dim
|
||||
{
|
||||
short w, h;
|
||||
} dim[] =
|
||||
{
|
||||
[BUILDING_TYPE_BARRACKS] = {.w = 68, .h = 66}
|
||||
};
|
||||
} dim[1];
|
||||
|
||||
const struct dim *const d = &dim[type];
|
||||
*w = d->w;
|
||||
|
@ -69,7 +55,6 @@ void building_create(const struct building_cfg *const cfg,
|
|||
i->r.x = cfg->x;
|
||||
i->r.y = cfg->y;
|
||||
i->alive = true;
|
||||
i->hp = building_maxhp(b);
|
||||
|
||||
if (cb)
|
||||
cb(&i->r, i->alive, op);
|
||||
|
@ -84,10 +69,7 @@ void building_set_alive_cb(void (*const f)(const struct util_rect *, bool, void
|
|||
|
||||
const char *building_str(const struct building *const b)
|
||||
{
|
||||
static const char *const str[] =
|
||||
{
|
||||
[BUILDING_TYPE_BARRACKS] = "Barracks"
|
||||
};
|
||||
static const char *const str[1];
|
||||
|
||||
return str[b->type];
|
||||
}
|
||||
|
|
|
@ -19,12 +19,12 @@ struct camera
|
|||
} dim;
|
||||
|
||||
int x, y, x_speed, y_speed;
|
||||
unsigned int xt, yt;
|
||||
unsigned xt, yt;
|
||||
bool pan;
|
||||
|
||||
struct cursor
|
||||
{
|
||||
unsigned int x, y, x_init, y_init;
|
||||
unsigned x, y, x_init, y_init;
|
||||
enum
|
||||
{
|
||||
CURSOR_STATE_IDLE,
|
||||
|
|
|
@ -13,8 +13,8 @@ extern "C"
|
|||
|
||||
enum
|
||||
{
|
||||
CAMERA_CURSOR_WIDTH = 20,
|
||||
CAMERA_CURSOR_HEIGHT = 20
|
||||
CAMERA_CURSOR_WIDTH = 16,
|
||||
CAMERA_CURSOR_HEIGHT = 16
|
||||
};
|
||||
|
||||
void camera_update_pos(struct camera *cam);
|
||||
|
|
|
@ -40,7 +40,10 @@ int cursor_render(const struct cursor *const c)
|
|||
sprite_get_or_ret(s, -1);
|
||||
|
||||
if (sprite_clone(&cursor_sprite, s))
|
||||
{
|
||||
fprintf(stderr, "%s: sprite_clone failed\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
s->x = c->x;
|
||||
s->y = c->y;
|
||||
|
@ -57,13 +60,17 @@ int cursor_render(const struct cursor *const c)
|
|||
break;
|
||||
}
|
||||
|
||||
sprite_sort(s);
|
||||
return 0;
|
||||
const int ret = sprite_sort(s);
|
||||
|
||||
if (ret)
|
||||
fprintf(stderr, "%s: sprite_sort failed\n", __func__);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void cursor_init(struct cursor *const c)
|
||||
{
|
||||
const unsigned int x = (screen_w / 2) - CAMERA_CURSOR_WIDTH,
|
||||
const unsigned x = (screen_w / 2) - CAMERA_CURSOR_WIDTH,
|
||||
y = (screen_h / 2) - CAMERA_CURSOR_HEIGHT;
|
||||
|
||||
*c = (const struct cursor)
|
||||
|
|
|
@ -26,11 +26,6 @@ struct container
|
|||
struct sprite *sprite;
|
||||
struct sound *sound;
|
||||
} data;
|
||||
|
||||
struct container_rt
|
||||
{
|
||||
struct container *c;
|
||||
} *rt;
|
||||
};
|
||||
|
||||
int container_load_ex(const char *path, const struct container *list, size_t n);
|
||||
|
|
|
@ -41,13 +41,19 @@ static int get_file_size(size_t *const sz, FILE *const f)
|
|||
return -1;
|
||||
|
||||
errno = 0;
|
||||
const unsigned long val = strtoul(szstr, NULL, 10);
|
||||
char *end;
|
||||
const unsigned long val = strtoul(szstr, &end, 10);
|
||||
|
||||
if (errno)
|
||||
{
|
||||
fprintf(stderr, "%s: strtoul(3): %s\n", __func__, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
else if (*end)
|
||||
{
|
||||
fprintf(stderr, "%s: invalid number %s\n", __func__, szstr);
|
||||
return -1;
|
||||
}
|
||||
|
||||
*sz = val;
|
||||
return 0;
|
||||
|
@ -123,29 +129,24 @@ static const struct container *find_element(const struct container *const list,
|
|||
static int read_element(const struct container *const list, const size_t n,
|
||||
FILE *const f, bool *const done)
|
||||
{
|
||||
int ret = -1;
|
||||
long init_off;
|
||||
const struct container *el = NULL;
|
||||
size_t sz;
|
||||
|
||||
if (!(el = find_element(list, n, f)))
|
||||
goto end;
|
||||
else if (get_file_size(&sz, f))
|
||||
goto end;
|
||||
if (!(el = find_element(list, n, f))
|
||||
|| get_file_size(&sz, f))
|
||||
return -1;
|
||||
else if ((init_off = ftell(f)) < 0)
|
||||
{
|
||||
fprintf(stderr, "%s:%d: fseek failed: %s\n",
|
||||
__func__, __LINE__, strerror(errno));
|
||||
goto end;
|
||||
return -1;
|
||||
}
|
||||
else if (read_file_contents(el, f, init_off, sz))
|
||||
goto end;
|
||||
return -1;
|
||||
|
||||
done[el - list] = true;
|
||||
ret = 0;
|
||||
|
||||
end:
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int read_all_elements(const struct container *const list, const size_t n,
|
||||
|
|
|
@ -86,7 +86,12 @@ static int renderstr(const enum font f, const short x, short y,
|
|||
s->v += v;
|
||||
s->x = rx;
|
||||
s->y = y;
|
||||
sprite_sort(s);
|
||||
|
||||
if (sprite_sort(s))
|
||||
{
|
||||
fprintf(stderr, "%s: sprite_sort failed\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
rx += cfg->fs;
|
||||
|
|
|
@ -9,7 +9,6 @@ target_link_libraries(game PUBLIC peripheral PRIVATE
|
|||
instance
|
||||
pad
|
||||
player
|
||||
resource
|
||||
system
|
||||
terrain
|
||||
unit)
|
||||
|
|
|
@ -30,6 +30,7 @@ struct game_cfg
|
|||
|
||||
size_t n;
|
||||
union peripheral *p;
|
||||
const char *map;
|
||||
};
|
||||
|
||||
int game_resinit(void);
|
||||
|
|
|
@ -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>
|
||||
|
@ -15,8 +14,11 @@ int game(const struct game_cfg *const cfg)
|
|||
struct human_player human;
|
||||
struct terrain_map map;
|
||||
|
||||
terrain_init(&map);
|
||||
building_set_alive_cb(terrain_block_update, &map);
|
||||
if (terrain_init(cfg->map, &map))
|
||||
{
|
||||
fprintf(stderr, "%s: terrain_init failed\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
const struct human_player_cfg hcfg =
|
||||
{
|
||||
|
@ -38,30 +40,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 +48,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;
|
||||
|
|
|
@ -8,7 +8,6 @@
|
|||
#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>
|
||||
|
@ -16,274 +15,40 @@
|
|||
static const struct container c[] =
|
||||
{
|
||||
{
|
||||
.path = "barracks",
|
||||
.path = "sidewalk",
|
||||
.type = CONTAINER_TYPE_SPRITE,
|
||||
.data =
|
||||
{
|
||||
.sprite = &building_sprites[BUILDING_TYPE_BARRACKS]
|
||||
}
|
||||
.data.sprite = &terrain_sprites[SIDEWALK]
|
||||
},
|
||||
|
||||
{
|
||||
.path = "worker_n",
|
||||
.path = "roof1",
|
||||
.type = CONTAINER_TYPE_SPRITE,
|
||||
.data =
|
||||
{
|
||||
.sprite = &unit_sprites[UNIT_SPRITE_N]
|
||||
}
|
||||
.data.sprite = &terrain_sprites[ROOF1]
|
||||
},
|
||||
|
||||
{
|
||||
.path = "worker_ne",
|
||||
.path = "roof2",
|
||||
.type = CONTAINER_TYPE_SPRITE,
|
||||
.data =
|
||||
{
|
||||
.sprite = &unit_sprites[UNIT_SPRITE_NE]
|
||||
}
|
||||
.data.sprite = &terrain_sprites[ROOF2]
|
||||
},
|
||||
|
||||
{
|
||||
.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
|
||||
}
|
||||
.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]
|
||||
}
|
||||
.data.sprite = &gui_button_sprites[GUI_BUTTON_LEFT]
|
||||
},
|
||||
|
||||
{
|
||||
.path = "btn_mid",
|
||||
.type = CONTAINER_TYPE_SPRITE,
|
||||
.data =
|
||||
{
|
||||
.sprite = &gui_button_sprites[GUI_BUTTON_MID]
|
||||
}
|
||||
.data.sprite = &gui_button_sprites[GUI_BUTTON_MID]
|
||||
},
|
||||
|
||||
{
|
||||
.path = "btn_right",
|
||||
.type = CONTAINER_TYPE_SPRITE,
|
||||
.data =
|
||||
{
|
||||
.sprite = &gui_button_sprites[GUI_BUTTON_RIGHT]
|
||||
}
|
||||
.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 bool init;
|
||||
|
@ -301,7 +66,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;
|
||||
|
|
|
@ -17,14 +17,14 @@ int gfx_set_fullscreen(short w, short h);
|
|||
bool gfx_fullscreen_available(void);
|
||||
bool gfx_fullscreen(void);
|
||||
int gfx_display_size(short *w, short *h);
|
||||
void sprite_sort(struct sprite *s);
|
||||
int sprite_sort(struct sprite *s);
|
||||
int sprite_clone(const struct sprite *src, struct sprite *dst);
|
||||
void rect_init(struct rect *r);
|
||||
void semitrans_rect_init(struct rect *r);
|
||||
void stp_4line_init(struct stp_4line *l);
|
||||
void quad_sort(struct quad *q);
|
||||
void rect_sort(struct rect *r);
|
||||
void stp_4line_sort(struct stp_4line *l);
|
||||
int quad_sort(struct quad *q);
|
||||
int rect_sort(struct rect *r);
|
||||
int stp_4line_sort(struct stp_4line *l);
|
||||
int sprite_from_fp(struct sprite *s, FILE *f);
|
||||
int quad_from_sprite(const struct sprite *s, struct quad *q);
|
||||
bool gfx_inside_drawenv(short x, short y, short w, short h);
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
#include <gfx_private.h>
|
||||
#include <stddef.h>
|
||||
|
||||
static unsigned int sel;
|
||||
static unsigned sel;
|
||||
static size_t heap_i;
|
||||
|
||||
void gfx_swapheap(void)
|
||||
|
|
|
@ -19,24 +19,28 @@ static void add_to_list(union gfx_sznext *const p)
|
|||
last = p;
|
||||
}
|
||||
|
||||
void sprite_sort(struct sprite *const s)
|
||||
int sprite_sort(struct sprite *const s)
|
||||
{
|
||||
add_to_list(&s->sznext);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void quad_sort(struct quad *const q)
|
||||
int quad_sort(struct quad *const q)
|
||||
{
|
||||
add_to_list(&q->sznext);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void rect_sort(struct rect *const r)
|
||||
int rect_sort(struct rect *const r)
|
||||
{
|
||||
add_to_list(&r->sznext);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void stp_4line_sort(struct stp_4line *const l)
|
||||
int stp_4line_sort(struct stp_4line *const l)
|
||||
{
|
||||
add_to_list(&l->sznext);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void gfx_sync(void)
|
||||
|
@ -61,7 +65,7 @@ int gfx_draw(void)
|
|||
|
||||
add_to_list(&term);
|
||||
|
||||
void gpu_ctrl(unsigned int command, unsigned int param);
|
||||
void gpu_ctrl(unsigned command, unsigned param);
|
||||
|
||||
gfx_sync();
|
||||
gfx_swapbuffers();
|
||||
|
|
|
@ -98,7 +98,10 @@ static int resize_screen(int w, int h, const bool full_screen)
|
|||
|
||||
for (size_t i = 0; i < list_len; i++)
|
||||
if (sprite_screen_resize_ev(list[i]))
|
||||
{
|
||||
fprintf(stderr, "%s: sprite_screen_resize_ev failed\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
screen_w = w;
|
||||
screen_h = h;
|
||||
|
@ -152,14 +155,16 @@ static int get_resize_events(void)
|
|||
const SDL_ResizeEvent *const res = &ev.resize;
|
||||
|
||||
if (resize_screen(res->w, res->h, false))
|
||||
{
|
||||
fprintf(stderr, "%s: resize_screen failed\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (n < 0)
|
||||
{
|
||||
fprintf(stderr, "%s: SDL_PeepEvents: %s\n",
|
||||
__func__, SDL_GetError());
|
||||
fprintf(stderr, "%s: SDL_PeepEvents: %s\n", __func__, SDL_GetError());
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -208,6 +213,5 @@ int gfx_draw(void)
|
|||
return -1;
|
||||
}
|
||||
|
||||
get_resize_events();
|
||||
return 0;
|
||||
return get_resize_events();
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@ void semitrans_stp_4line_init(struct stp_4line *r)
|
|||
{
|
||||
}
|
||||
|
||||
void stp_4line_sort(struct stp_4line *const r)
|
||||
int stp_4line_sort(struct stp_4line *const r)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@ int quad_from_sprite(const struct sprite *const s, struct quad *const q)
|
|||
return 0;
|
||||
}
|
||||
|
||||
void quad_sort(struct quad *const q)
|
||||
int quad_sort(struct quad *const q)
|
||||
{
|
||||
const bool xflip = q->x0 > q->x1;
|
||||
|
||||
|
@ -40,5 +40,10 @@ void quad_sort(struct quad *const q)
|
|||
SDL_Surface *const s = xflip ? q->s_x : q->s;
|
||||
|
||||
if (SDL_BlitSurface(s, &clip, gfx_screen(), &r))
|
||||
{
|
||||
fprintf(stderr, "SDL_BlitSurface: %s\n", SDL_GetError());
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
#include <sdl-1.2/gfx_private.h>
|
||||
#include <SDL.h>
|
||||
|
||||
void rect_sort(struct rect *const r)
|
||||
int rect_sort(struct rect *const r)
|
||||
{
|
||||
SDL_Rect rct =
|
||||
{
|
||||
|
@ -19,8 +19,10 @@ void rect_sort(struct rect *const r)
|
|||
if (SDL_FillRect(screen, &rct, map))
|
||||
{
|
||||
fprintf(stderr, "SDL_FillRect: %s\n", SDL_GetError());
|
||||
return;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void rect_init(struct rect *const r)
|
||||
|
|
|
@ -126,7 +126,7 @@ int sprite_from_fp(struct sprite *const s, FILE *const f)
|
|||
return 0;
|
||||
}
|
||||
|
||||
void sprite_sort(struct sprite *const s)
|
||||
int sprite_sort(struct sprite *const s)
|
||||
{
|
||||
SDL_Rect r =
|
||||
{
|
||||
|
@ -143,5 +143,10 @@ void sprite_sort(struct sprite *const s)
|
|||
};
|
||||
|
||||
if (SDL_BlitSurface(s->s, &clip, gfx_screen(), &r))
|
||||
{
|
||||
fprintf(stderr, "SDL_BlitSurface: %s\n", SDL_GetError());
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -15,8 +15,13 @@ static int render_topleft(const struct gui_bar *const b, const short x,
|
|||
|
||||
s->x = x;
|
||||
s->y = y;
|
||||
sprite_sort(s);
|
||||
return 0;
|
||||
|
||||
const int ret = sprite_sort(s);
|
||||
|
||||
if (ret)
|
||||
fprintf(stderr, "%s: sprite_sort failed\n", __func__);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int render_topright(const struct gui_bar *const b, const short x,
|
||||
|
@ -29,7 +34,12 @@ static int render_topright(const struct gui_bar *const b, const short x,
|
|||
|
||||
s->x = x + b->w - s->w;
|
||||
s->y = y;
|
||||
sprite_sort(s);
|
||||
|
||||
const int ret = sprite_sort(s);
|
||||
|
||||
if (ret)
|
||||
fprintf(stderr, "%s: sprite_sort failed\n", __func__);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -66,7 +76,11 @@ static int render_topmid(const struct gui_bar *const b, const short x,
|
|||
else
|
||||
m->w = mid_w;
|
||||
|
||||
sprite_sort(m);
|
||||
if (sprite_sort(m))
|
||||
{
|
||||
fprintf(stderr, "%s: sprite_sort failed\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -13,8 +13,13 @@ int gui_button_render_sprite(const struct gui_button *const b)
|
|||
return -1;
|
||||
|
||||
gui_coords(&b->common, &s->x, &s->y);
|
||||
sprite_sort(s);
|
||||
return 0;
|
||||
|
||||
const int ret = sprite_sort(s);
|
||||
|
||||
if (ret)
|
||||
fprintf(stderr, "%s: sprite_sort failed\n", __func__);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void gui_button_get_dim_sprite(const struct gui_button *const b,
|
||||
|
|
|
@ -19,7 +19,13 @@ static int render_left(const struct gui_button *const b,
|
|||
|
||||
s->x = *x;
|
||||
s->y = y;
|
||||
sprite_sort(s);
|
||||
|
||||
if (sprite_sort(s))
|
||||
{
|
||||
fprintf(stderr, "%s: sprite_sort failed\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
*x = s->x + s->w;
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -26,7 +26,13 @@ static int render_left(const struct gui_line_edit *const l,
|
|||
|
||||
s->x = *x;
|
||||
s->y = y;
|
||||
sprite_sort(s);
|
||||
|
||||
if (sprite_sort(s))
|
||||
{
|
||||
fprintf(stderr, "%s: sprite_sort failed\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
*x = s->x + s->w;
|
||||
return 0;
|
||||
}
|
||||
|
@ -66,7 +72,12 @@ static int render_mid(const struct gui_line_edit *const l,
|
|||
else
|
||||
m->w = mid_w;
|
||||
|
||||
sprite_sort(m);
|
||||
if (sprite_sort(m))
|
||||
{
|
||||
fprintf(stderr, "%s: sprite_sort failed\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
*x += m->w;
|
||||
}
|
||||
}
|
||||
|
@ -85,8 +96,13 @@ static int render_right(const short x, const short y)
|
|||
|
||||
s->x = x;
|
||||
s->y = y;
|
||||
sprite_sort(s);
|
||||
return 0;
|
||||
|
||||
const int ret = sprite_sort(s);
|
||||
|
||||
if (ret)
|
||||
fprintf(stderr, "%s: sprite_sort failed\n", __func__);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int render(const struct gui_common *const g)
|
||||
|
|
|
@ -19,7 +19,12 @@ static int render_top(const struct gui_rounded_rect *const r,
|
|||
|
||||
left->x = x;
|
||||
left->y = y;
|
||||
sprite_sort(left);
|
||||
|
||||
if (sprite_sort(left))
|
||||
{
|
||||
fprintf(stderr, "%s: sprite_sort failed\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
|
@ -33,7 +38,12 @@ static int render_top(const struct gui_rounded_rect *const r,
|
|||
|
||||
right->x = x + r->w - ref->w;
|
||||
right->y = y;
|
||||
sprite_sort(right);
|
||||
|
||||
if (sprite_sort(right))
|
||||
{
|
||||
fprintf(stderr, "%s: sprite_sort failed\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -12,17 +12,12 @@ extern "C"
|
|||
{
|
||||
#endif
|
||||
|
||||
typedef unsigned int instance_hp;
|
||||
|
||||
struct instance
|
||||
{
|
||||
bool alive, dying;
|
||||
unsigned int hp;
|
||||
bool alive;
|
||||
struct util_rect r;
|
||||
};
|
||||
|
||||
typedef bool (*instance_attacked_cb)(struct instance *i, unsigned int ap);
|
||||
typedef bool (*instance_sheltered_cb)(struct instance *self, struct instance *other);
|
||||
typedef void (*instance_done_cb)(struct instance *i, void *op);
|
||||
|
||||
struct instance_render_cfg
|
||||
|
@ -48,15 +43,12 @@ struct instance_render_cfg
|
|||
} prim;
|
||||
|
||||
bool sel;
|
||||
instance_hp max_hp;
|
||||
const struct instance_render_off
|
||||
{
|
||||
short x, y;
|
||||
} *off;
|
||||
};
|
||||
|
||||
bool instance_attacked(struct instance *self, unsigned int ap);
|
||||
void instance_clear_pools(void);
|
||||
int instance_render(const struct instance_render_cfg *cfg);
|
||||
int instance_render_target(const struct instance *const i, const struct camera *cam);
|
||||
void instance_cyclic(void);
|
||||
|
|
|
@ -8,19 +8,6 @@
|
|||
static unsigned char line_g;
|
||||
static bool line_g_flip;
|
||||
|
||||
bool instance_attacked(struct instance *const self, const instance_hp ap)
|
||||
{
|
||||
if (self->hp > ap)
|
||||
self->hp -= ap;
|
||||
else
|
||||
{
|
||||
self->hp = 0;
|
||||
self->alive = false;
|
||||
}
|
||||
|
||||
return !self->alive;
|
||||
}
|
||||
|
||||
void instance_cyclic(void)
|
||||
{
|
||||
if (!line_g_flip)
|
||||
|
|
|
@ -50,9 +50,6 @@ int menu_update(struct menu_common *const c,
|
|||
|
||||
case PERIPHERAL_TYPE_TOUCH:
|
||||
break;
|
||||
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (gfx_draw())
|
||||
|
@ -75,5 +72,11 @@ 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,
|
||||
.map = "city1.txt"
|
||||
};
|
||||
|
||||
return game(&gcfg);
|
||||
}
|
||||
|
|
|
@ -40,7 +40,7 @@ union peripheral
|
|||
struct mouse mouse;
|
||||
struct keyboard keyboard;
|
||||
bool long_press;
|
||||
unsigned int lp_t;
|
||||
unsigned lp_t;
|
||||
} kbm;
|
||||
};
|
||||
|
||||
|
|
|
@ -14,8 +14,6 @@ target_link_libraries(player
|
|||
input
|
||||
mouse
|
||||
pad
|
||||
resource
|
||||
tech
|
||||
unit
|
||||
util
|
||||
PRIVATE
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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>
|
||||
|
@ -16,7 +14,7 @@ extern "C"
|
|||
{
|
||||
#endif
|
||||
|
||||
typedef unsigned int player_team;
|
||||
typedef unsigned player_team;
|
||||
|
||||
enum
|
||||
{
|
||||
|
@ -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);
|
||||
|
|
|
@ -9,7 +9,6 @@
|
|||
#include <input.h>
|
||||
#include <keyboard.h>
|
||||
#include <pad.h>
|
||||
#include <resource.h>
|
||||
#include <unit.h>
|
||||
#include <util.h>
|
||||
#include <stdbool.h>
|
||||
|
@ -42,61 +41,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 +148,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 +158,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 +168,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 +180,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 +203,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 +219,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 +246,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);
|
||||
|
@ -505,10 +279,8 @@ 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))))
|
||||
if (si->d.i
|
||||
&& (!si->d.i->alive || si->type == INSTANCE_TYPE_UNIT))
|
||||
{
|
||||
si->d.i = NULL;
|
||||
h->n_sel--;
|
||||
|
@ -552,8 +324,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,
|
||||
|
@ -686,30 +456,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 +494,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;
|
||||
}
|
||||
|
|
|
@ -17,76 +17,14 @@
|
|||
|
||||
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);
|
||||
|
@ -95,30 +33,13 @@ static int render_sel_single_building(const struct human_player *const h,
|
|||
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);
|
||||
return gui_render(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;
|
||||
|
@ -129,75 +50,7 @@ static int render_sel_single_unit(const struct human_player *const h,
|
|||
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);
|
||||
return gui_render(r);
|
||||
}
|
||||
|
||||
static int render_sel_single(const struct human_player *const h,
|
||||
|
@ -216,14 +69,11 @@ static int render_sel_single(const struct human_player *const h,
|
|||
|
||||
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. */
|
||||
fprintf(stderr, "%s: unreachable\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -262,83 +112,8 @@ static int render_sel(const struct human_player *const h)
|
|||
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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -61,50 +61,6 @@ int player_create_building(const struct building_cfg *const cfg, struct player *
|
|||
|
||||
int player_init(const struct player_cfg *const cfg, struct player *const pl)
|
||||
{
|
||||
const unsigned long x = cfg->x, y = cfg->y;
|
||||
|
||||
const struct building_cfg bcfg =
|
||||
{
|
||||
.type = BUILDING_TYPE_BARRACKS,
|
||||
.x = x,
|
||||
.y = y
|
||||
};
|
||||
|
||||
const struct unit_cfg cfgs[] =
|
||||
{
|
||||
{
|
||||
.type = UNIT_TYPE_PEASANT,
|
||||
.x = x + 80,
|
||||
.y = y
|
||||
},
|
||||
|
||||
{
|
||||
.type = UNIT_TYPE_PEASANT,
|
||||
.x = x + 80,
|
||||
.y = y + 40
|
||||
},
|
||||
|
||||
{
|
||||
.type = UNIT_TYPE_PEASANT,
|
||||
.x = x + 100,
|
||||
.y = y + 20
|
||||
}
|
||||
};
|
||||
|
||||
if (player_create_building(&bcfg, pl))
|
||||
return -1;
|
||||
|
||||
for (size_t i = 0; i < sizeof cfgs / sizeof *cfgs; i++)
|
||||
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;
|
||||
|
|
|
@ -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)
|
|
@ -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 */
|
|
@ -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 */
|
|
@ -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];
|
||||
}
|
|
@ -10,6 +10,7 @@ elseif(SDL1_2_BUILD)
|
|||
set(inc ${inc} "sdl-1.2/inc")
|
||||
set(privinc ${privinc} "sdl-1.2/privinc")
|
||||
set(privdeps ${privdeps} SDL::SDL)
|
||||
set(privdefs ${privdefs} "PROJECT_NAME=\"${PROJECT_NAME}\"")
|
||||
|
||||
if(WIN9X_BUILD)
|
||||
set(src ${src} "win9x/src/system.c")
|
||||
|
@ -21,3 +22,4 @@ endif()
|
|||
add_library(system ${src})
|
||||
target_include_directories(system PUBLIC ${inc} PRIVATE ${privinc})
|
||||
target_link_libraries(system PRIVATE ${privdeps})
|
||||
target_compile_definitions(system PRIVATE ${privdefs})
|
||||
|
|
|
@ -37,7 +37,7 @@ int system_init(void)
|
|||
else if (gfx_init() || sfx_init() || net_init())
|
||||
goto failure;
|
||||
|
||||
SDL_WM_SetCaption("rts", NULL);
|
||||
SDL_WM_SetCaption(PROJECT_NAME, NULL);
|
||||
SDL_ShowCursor(0);
|
||||
/* SDL_WM_GrabInput(SDL_GRAB_ON); */
|
||||
SDL_EnableUNICODE(1);
|
||||
|
|
|
@ -1,2 +0,0 @@
|
|||
add_library(tech INTERFACE)
|
||||
target_include_directories(tech INTERFACE "inc")
|
|
@ -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 */
|
|
@ -1,3 +1,7 @@
|
|||
add_library(terrain "src/terrain.c")
|
||||
add_library(terrain
|
||||
"src/init.c"
|
||||
"src/render.c"
|
||||
"src/update.c"
|
||||
)
|
||||
target_include_directories(terrain PUBLIC "inc")
|
||||
target_link_libraries(terrain PUBLIC container camera gfx util)
|
||||
|
|
|
@ -14,33 +14,102 @@ extern "C"
|
|||
enum
|
||||
{
|
||||
MAP_TILES = 64,
|
||||
TERRAIN_SZ = 32,
|
||||
TERRAIN_SZ = 16,
|
||||
MAP_W = MAP_TILES * TERRAIN_SZ,
|
||||
MAP_H = MAP_TILES * TERRAIN_SZ
|
||||
};
|
||||
|
||||
enum terrain_type
|
||||
{
|
||||
TERRAIN_TYPE_GRASS
|
||||
ROOF1_1_NW,
|
||||
ROOF1_1_N,
|
||||
ROOF1_1_NE,
|
||||
ROOF1_2_NW,
|
||||
ROOF1_2_NE,
|
||||
ROOF1_3_NW,
|
||||
ROOF1_3_N,
|
||||
ROOF1_3_NE,
|
||||
ROOF1_4_N,
|
||||
|
||||
ROOF1_1_W,
|
||||
ROOF1_1_C,
|
||||
ROOF1_1_E,
|
||||
ROOF1_2_SW,
|
||||
ROOF1_2_SE,
|
||||
ROOF1_3_SW,
|
||||
ROOF1_3_S,
|
||||
ROOF1_3_SE,
|
||||
ROOF1_4_C,
|
||||
|
||||
ROOF1_1_SW,
|
||||
ROOF1_1_S,
|
||||
ROOF1_1_SE,
|
||||
ROOF1_5_W,
|
||||
ROOF1_5_C,
|
||||
ROOF1_5_E,
|
||||
ROOF1_6,
|
||||
ROOF1_4_S,
|
||||
|
||||
ROOF2_1_NW,
|
||||
ROOF2_1_N,
|
||||
ROOF2_1_NE,
|
||||
ROOF2_2_NW,
|
||||
ROOF2_2_NE,
|
||||
ROOF2_3_NW,
|
||||
ROOF2_3_N,
|
||||
ROOF2_3_NE,
|
||||
ROOF2_4_N,
|
||||
|
||||
ROOF2_1_W,
|
||||
ROOF2_1_C,
|
||||
ROOF2_1_E,
|
||||
ROOF2_2_SW,
|
||||
ROOF2_2_SE,
|
||||
ROOF2_3_SW,
|
||||
ROOF2_3_S,
|
||||
ROOF2_3_SE,
|
||||
ROOF2_4_C,
|
||||
|
||||
ROOF2_1_SW,
|
||||
ROOF2_1_S,
|
||||
ROOF2_1_SE,
|
||||
ROOF2_5_W,
|
||||
ROOF2_5_C,
|
||||
ROOF2_5_E,
|
||||
ROOF2_6,
|
||||
ROOF2_4_S,
|
||||
|
||||
ROOF1_START = ROOF1_1_NW,
|
||||
ROOF1_END = ROOF1_4_S,
|
||||
ROOF2_START = ROOF2_1_NW,
|
||||
ROOF2_END = ROOF2_4_S
|
||||
};
|
||||
|
||||
struct terrain_map
|
||||
{
|
||||
struct terrain_tile
|
||||
{
|
||||
enum terrain_type t;
|
||||
unsigned char bl;
|
||||
unsigned char t, obj;
|
||||
} m[MAP_TILES][MAP_TILES];
|
||||
|
||||
int nx, ny, last_w, last_h;
|
||||
};
|
||||
|
||||
void terrain_init(struct terrain_map *map);
|
||||
int terrain_init(const char *path, struct terrain_map *map);
|
||||
void terrain_update(struct terrain_map *map);
|
||||
int terrain_render(const struct terrain_map *map, const struct camera *cam);
|
||||
void terrain_block_update(const struct util_rect *dim, bool alive, void *p);
|
||||
|
||||
extern struct sprite grass_sprite;
|
||||
enum
|
||||
{
|
||||
SIDEWALK,
|
||||
ROOF1,
|
||||
ROOF2,
|
||||
BUILDING1,
|
||||
|
||||
MAX_TERRAIN_SPRITES
|
||||
};
|
||||
|
||||
extern struct sprite terrain_sprites[MAX_TERRAIN_SPRITES];
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
@ -0,0 +1,154 @@
|
|||
#include <terrain.h>
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
static int read_token(FILE *const f, char *const s, const size_t n)
|
||||
{
|
||||
uint8_t c;
|
||||
size_t i = 0;
|
||||
|
||||
while (fread(&c, sizeof c, 1, f))
|
||||
{
|
||||
if (isspace(c))
|
||||
{
|
||||
if (i)
|
||||
break;
|
||||
else
|
||||
continue;
|
||||
}
|
||||
else if (!isalnum(c))
|
||||
{
|
||||
fprintf(stderr, "%s: invalid character %" PRIx8 " at offset %ld\n",
|
||||
__func__, c, ftell(f));
|
||||
return -1;
|
||||
}
|
||||
else if (i + 1 >= n)
|
||||
{
|
||||
fprintf(stderr, "%s: exceeded maximum token size %zu\n",
|
||||
__func__, n);
|
||||
return -1;
|
||||
}
|
||||
|
||||
s[i++] = c;
|
||||
}
|
||||
|
||||
if (!i)
|
||||
{
|
||||
fprintf(stderr, "%s: feof=%d, ferror=%d\n", __func__, feof(f),
|
||||
ferror(f));
|
||||
return -1;
|
||||
}
|
||||
|
||||
s[i] = '\0';
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int read_num(FILE *const f, char *s, const size_t n,
|
||||
unsigned *const out, const int base, const int limit)
|
||||
{
|
||||
if (read_token(f, s, n))
|
||||
return -1;
|
||||
|
||||
errno = 0;
|
||||
|
||||
char *end;
|
||||
const unsigned long value = strtoul(s, &end, base);
|
||||
|
||||
if (errno)
|
||||
{
|
||||
fprintf(stderr, "%s: strtoul(3): %s\n", __func__, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
else if (*end)
|
||||
{
|
||||
fprintf(stderr, "%s: invalid number %s\n", __func__, s);
|
||||
return -1;
|
||||
}
|
||||
else if (value > limit)
|
||||
{
|
||||
fprintf(stderr, "%s: %lu exceeds maximum range %d\n", __func__, value,
|
||||
limit);
|
||||
return -1;
|
||||
}
|
||||
|
||||
*out = value;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int read_dec(FILE *const f, unsigned *const out)
|
||||
{
|
||||
char s[sizeof "65535"];
|
||||
|
||||
return read_num(f, s, sizeof s, out, 10, UINT16_MAX);
|
||||
}
|
||||
|
||||
static int read_hex(FILE *const f, unsigned *const out)
|
||||
{
|
||||
char s[sizeof "0000"];
|
||||
|
||||
return read_num(f, s, sizeof s, out, 16, UINT16_MAX);
|
||||
}
|
||||
|
||||
static int read_dimensions(FILE *const f, unsigned *const w, unsigned *const h)
|
||||
{
|
||||
if (read_dec(f, w) || read_dec(f, h))
|
||||
return -1;
|
||||
else if (*w > MAP_TILES || *h > MAP_TILES)
|
||||
{
|
||||
fprintf(stderr, "%s: map size (%ux%u) exceeded, max %dx%d\n",
|
||||
__func__, *w, *h, MAP_TILES, MAP_TILES);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int read_map(FILE *const f, const unsigned w, const unsigned h,
|
||||
struct terrain_map *const map)
|
||||
{
|
||||
for (unsigned j = 0; j < h; j++)
|
||||
for (unsigned i = 0; i < w; i++)
|
||||
{
|
||||
unsigned tile;
|
||||
|
||||
if (read_hex(f, &tile))
|
||||
return -1;
|
||||
|
||||
map->m[j][i].t = tile;
|
||||
map->m[j][i].obj = tile >> 8;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int terrain_init(const char *const path, struct terrain_map *const map)
|
||||
{
|
||||
int ret = -1;
|
||||
FILE *const f = fopen(path, "rb");
|
||||
unsigned w, h;
|
||||
|
||||
if (!f)
|
||||
{
|
||||
fprintf(stderr, "%s: fopen(3): %s\n", __func__, strerror(errno));
|
||||
goto end;
|
||||
}
|
||||
else if (read_dimensions(f, &w, &h) || read_map(f, w, h, map))
|
||||
goto end;
|
||||
|
||||
ret = 0;
|
||||
|
||||
end:
|
||||
if (f && fclose(f))
|
||||
{
|
||||
fprintf(stderr, "%s: fclose(3): %s\n", __func__, strerror(errno));
|
||||
ret = -1;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
|
@ -0,0 +1,109 @@
|
|||
#include <terrain.h>
|
||||
#include <camera.h>
|
||||
#include <gfx.h>
|
||||
#include <util.h>
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
struct sprite terrain_sprites[MAX_TERRAIN_SPRITES];
|
||||
|
||||
static int render_tile(const struct terrain_tile *const t, const short x,
|
||||
const short y)
|
||||
{
|
||||
static const struct tile
|
||||
{
|
||||
const struct sprite *s;
|
||||
int start, end;
|
||||
} tiles[] =
|
||||
{
|
||||
{
|
||||
.s = &terrain_sprites[ROOF1],
|
||||
.start = ROOF1_START,
|
||||
.end = ROOF1_END
|
||||
},
|
||||
|
||||
{
|
||||
.s = &terrain_sprites[ROOF2],
|
||||
.start = ROOF2_START,
|
||||
.end = ROOF2_END
|
||||
}
|
||||
};
|
||||
|
||||
for (size_t i = 0; i < sizeof tiles / sizeof *tiles; i++)
|
||||
{
|
||||
const struct tile *const rt = &tiles[i];
|
||||
|
||||
if (t->t >= rt->start && t->t <= rt->end)
|
||||
{
|
||||
sprite_get_or_ret(s, -1);
|
||||
|
||||
if (sprite_clone(rt->s, s))
|
||||
{
|
||||
fprintf(stderr, "%s: sprite_clone failed\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
const unsigned char pos = t->t - rt->start;
|
||||
const short tx = pos % TERRAIN_SZ, ty = pos / TERRAIN_SZ;
|
||||
|
||||
s->x = x;
|
||||
s->y = y;
|
||||
s->w = TERRAIN_SZ;
|
||||
s->h = TERRAIN_SZ;
|
||||
s->u = tx * TERRAIN_SZ;
|
||||
s->v = ty * TERRAIN_SZ;
|
||||
|
||||
const int ret = sprite_sort(s);
|
||||
|
||||
if (ret)
|
||||
fprintf(stderr, "%s: sprite_sort failed\n", __func__);
|
||||
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
fprintf(stderr, "%s: unknown tile %#hhx\n", __func__, t->t);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int terrain_render(const struct terrain_map *const map,
|
||||
const struct camera *const cam)
|
||||
{
|
||||
const int start_x = abs(cam->x / TERRAIN_SZ),
|
||||
start_y = abs(cam->y / TERRAIN_SZ);
|
||||
|
||||
const int remx = cam->x % TERRAIN_SZ,
|
||||
remy = cam->y % TERRAIN_SZ;
|
||||
|
||||
int nx = map->nx, ny = map->ny;
|
||||
|
||||
if (abs(remx))
|
||||
nx++;
|
||||
|
||||
if (abs(remy))
|
||||
ny++;
|
||||
|
||||
struct m
|
||||
{
|
||||
size_t i;
|
||||
long p;
|
||||
};
|
||||
|
||||
for (struct m x = {.i = start_x, .p = remx};
|
||||
x.i < nx + start_x; x.i++, x.p += TERRAIN_SZ)
|
||||
for (struct m y = {.i = start_y, .p = remy};
|
||||
y.i < ny + start_y; y.i++, y.p += TERRAIN_SZ)
|
||||
{
|
||||
const struct terrain_tile *const t = &map->m[y.i][x.i];
|
||||
|
||||
if (render_tile(t, x.p, y.p))
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -1,132 +0,0 @@
|
|||
#include <terrain.h>
|
||||
#include <camera.h>
|
||||
#include <gfx.h>
|
||||
#include <util.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
struct sprite grass_sprite;
|
||||
|
||||
void terrain_update(struct terrain_map *const map)
|
||||
{
|
||||
if (map->last_w != screen_w)
|
||||
{
|
||||
const int extra = !!(screen_w % TERRAIN_SZ);
|
||||
|
||||
map->nx = screen_w / TERRAIN_SZ + extra;
|
||||
map->last_w = screen_w;
|
||||
}
|
||||
|
||||
if (map->last_h != screen_h)
|
||||
{
|
||||
const int extra = !!(screen_h % TERRAIN_SZ);
|
||||
|
||||
map->ny = screen_h / TERRAIN_SZ + extra;
|
||||
map->last_h = screen_h;
|
||||
}
|
||||
}
|
||||
|
||||
struct block
|
||||
{
|
||||
size_t x0, x1, y0, y1;
|
||||
};
|
||||
|
||||
void terrain_block_update(const struct util_rect *const dim, const bool alive,
|
||||
void *const p)
|
||||
{
|
||||
const struct block b =
|
||||
{
|
||||
.x0 = dim->x / TERRAIN_SZ,
|
||||
.x1 = (dim->x + dim->w) / TERRAIN_SZ,
|
||||
.y0 = dim->y / TERRAIN_SZ,
|
||||
.y1 = (dim->y + dim->h) / TERRAIN_SZ
|
||||
};
|
||||
|
||||
for (size_t x = b.x0; x <= b.x1; x++)
|
||||
for (size_t y = b.y0; y <= b.y1; y++)
|
||||
for (size_t i = 0; i < 2; i++)
|
||||
for (size_t j = 0; j < 2; j++)
|
||||
{
|
||||
const struct util_rect sub =
|
||||
{
|
||||
.x = x * TERRAIN_SZ + i * (TERRAIN_SZ / 2),
|
||||
.y = y * TERRAIN_SZ + j * (TERRAIN_SZ / 2),
|
||||
.w = TERRAIN_SZ / 2,
|
||||
.h = TERRAIN_SZ / 2
|
||||
};
|
||||
|
||||
if (util_collision(dim, &sub))
|
||||
{
|
||||
const enum
|
||||
{
|
||||
NO_SUB = 0,
|
||||
UPPER_LEFT = 1 << 0,
|
||||
UPPER_RIGHT = 1 << 1,
|
||||
LOWER_LEFT = 1 << 2,
|
||||
LOWER_RIGHT = 1 << 3,
|
||||
ALL_BLOCKS = UPPER_LEFT | UPPER_RIGHT
|
||||
| LOWER_LEFT | LOWER_RIGHT
|
||||
} sub = 1 << (i + j * 2);
|
||||
|
||||
struct terrain_map *const map = p;
|
||||
unsigned char *const bl = &map->m[y][x].bl;
|
||||
|
||||
*bl = alive ? *bl | sub : *bl & ~sub;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int terrain_render(const struct terrain_map *const map,
|
||||
const struct camera *const cam)
|
||||
{
|
||||
const int start_x = abs(cam->x / TERRAIN_SZ),
|
||||
start_y = abs(cam->y / TERRAIN_SZ);
|
||||
|
||||
const int remx = cam->x % TERRAIN_SZ,
|
||||
remy = cam->y % TERRAIN_SZ;
|
||||
|
||||
int nx = map->nx, ny = map->ny;
|
||||
|
||||
if (abs(remx))
|
||||
nx++;
|
||||
|
||||
if (abs(remy))
|
||||
ny++;
|
||||
|
||||
struct m
|
||||
{
|
||||
size_t i;
|
||||
long p;
|
||||
};
|
||||
|
||||
for (struct m x = {.i = start_x, .p = remx};
|
||||
x.i < nx + start_x; x.i++, x.p += TERRAIN_SZ)
|
||||
for (struct m y = {.i = start_y, .p = remy};
|
||||
y.i < ny + start_y; y.i++, y.p += TERRAIN_SZ)
|
||||
{
|
||||
const struct terrain_tile *const t = &map->m[y.i][x.i];
|
||||
|
||||
sprite_get_or_ret(s, -1);
|
||||
|
||||
switch (t->t)
|
||||
{
|
||||
case TERRAIN_TYPE_GRASS:
|
||||
if (sprite_clone(&grass_sprite, s))
|
||||
return -1;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
s->x = x.p;
|
||||
s->y = y.p;
|
||||
sprite_sort(s);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void terrain_init(struct terrain_map *const map)
|
||||
{
|
||||
*map = (const struct terrain_map){0};
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
#include <terrain.h>
|
||||
|
||||
void terrain_update(struct terrain_map *const map)
|
||||
{
|
||||
if (map->last_w != screen_w)
|
||||
{
|
||||
const int extra = !!(screen_w % TERRAIN_SZ);
|
||||
|
||||
map->nx = screen_w / TERRAIN_SZ + extra;
|
||||
map->last_w = screen_w;
|
||||
}
|
||||
|
||||
if (map->last_h != screen_h)
|
||||
{
|
||||
const int extra = !!(screen_h % TERRAIN_SZ);
|
||||
|
||||
map->ny = screen_h / TERRAIN_SZ + extra;
|
||||
map->last_h = screen_h;
|
||||
}
|
||||
}
|
|
@ -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
|
||||
)
|
||||
|
|
|
@ -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,27 +16,15 @@ 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
|
||||
{
|
||||
struct instance *ins;
|
||||
enum unit_state state;
|
||||
instance_sheltered_cb shelter;
|
||||
instance_attacked_cb attack;
|
||||
instance_done_cb done;
|
||||
void *op;
|
||||
};
|
||||
|
@ -67,18 +53,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;
|
||||
};
|
||||
|
||||
|
@ -96,9 +71,7 @@ bool unit_can_harvest(const struct unit *u);
|
|||
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);
|
||||
instance_hp unit_maxhp(const struct unit *u);
|
||||
void unit_update(struct unit *u);
|
||||
const char *unit_str(const struct unit *u);
|
||||
|
||||
enum
|
||||
|
|
|
@ -3,8 +3,6 @@
|
|||
|
||||
enum unit_type
|
||||
{
|
||||
UNIT_TYPE_PEASANT,
|
||||
|
||||
MAX_UNIT_TYPES
|
||||
};
|
||||
|
||||
|
|
|
@ -64,14 +64,7 @@ static void get_speed(const struct unit *const u, fix16_t *const x,
|
|||
static const struct speed
|
||||
{
|
||||
fix16_t x, y;
|
||||
} speed[] =
|
||||
{
|
||||
[UNIT_TYPE_PEASANT] =
|
||||
{
|
||||
.x = FIX16_C_FROM_INT(1),
|
||||
.y = FIX16_C_FROM_INT(1)
|
||||
}
|
||||
};
|
||||
} speed[1];
|
||||
|
||||
const struct speed *const s = &speed[u->type];
|
||||
const int dx = abs(u->rx - u->tx);
|
||||
|
@ -115,16 +108,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 +134,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 +153,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)
|
||||
|
@ -400,16 +209,6 @@ void unit_move_to(struct unit *const u, const unsigned long x, const unsigned lo
|
|||
u->ty = y > y_off ? fix16_from_int(y - y_off) : 0;
|
||||
}
|
||||
|
||||
instance_hp unit_maxhp(const struct unit *const u)
|
||||
{
|
||||
static const instance_hp hp[] =
|
||||
{
|
||||
[UNIT_TYPE_PEASANT] = 25
|
||||
};
|
||||
|
||||
return hp[u->type];
|
||||
}
|
||||
|
||||
static int get_ux(const struct unit *const u)
|
||||
{
|
||||
switch (u->dir)
|
||||
|
@ -452,6 +251,7 @@ typedef const struct
|
|||
|
||||
static anim_dim *peasant_anim(const struct unit *const u)
|
||||
{
|
||||
#if 0
|
||||
static anim_dim t[] =
|
||||
{
|
||||
{
|
||||
|
@ -506,6 +306,9 @@ static anim_dim *peasant_anim(const struct unit *const u)
|
|||
return NULL;
|
||||
|
||||
return &t[ux];
|
||||
#else
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
struct render_cfg
|
||||
|
@ -561,10 +364,7 @@ static int unit_quad(const struct unit *const u, struct render_cfg *const rcfg)
|
|||
{
|
||||
struct instance_render_quad *const qcfg = &rcfg->qcfg;
|
||||
|
||||
static anim_dim *(*const f[])(const struct unit *) =
|
||||
{
|
||||
[UNIT_TYPE_PEASANT] = peasant_quad
|
||||
};
|
||||
static anim_dim *(*const f[1])(const struct unit *);
|
||||
|
||||
anim_dim *const dim = f[u->type](u);
|
||||
|
||||
|
@ -582,9 +382,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;
|
||||
|
@ -602,7 +400,6 @@ int unit_render(const struct unit *const u, const struct camera *const cam,
|
|||
.prim = {.quad = &rcfg.qcfg},
|
||||
.cam = cam,
|
||||
.sel = sel,
|
||||
.max_hp = unit_maxhp(u),
|
||||
.off = &rcfg.off
|
||||
};
|
||||
|
||||
|
@ -615,10 +412,7 @@ static void get_dimensions(const enum unit_type type, short *const w,
|
|||
static const struct dim
|
||||
{
|
||||
short w, h;
|
||||
} dim[] =
|
||||
{
|
||||
[UNIT_TYPE_PEASANT] = {.w = 36, .h = 36}
|
||||
};
|
||||
} dim[1];
|
||||
|
||||
const struct dim *const d = &dim[type];
|
||||
*w = d->w;
|
||||
|
@ -634,7 +428,6 @@ void unit_create(const struct unit_cfg *const cfg, struct unit *const u)
|
|||
.instance =
|
||||
{
|
||||
.alive = true,
|
||||
.hp = unit_maxhp(u)
|
||||
},
|
||||
|
||||
.type = cfg->type,
|
||||
|
@ -649,10 +442,7 @@ void unit_create(const struct unit_cfg *const cfg, struct unit *const u)
|
|||
|
||||
const char *unit_str(const struct unit *const u)
|
||||
{
|
||||
static const char *const str[] =
|
||||
{
|
||||
[UNIT_TYPE_PEASANT] = "Peasant"
|
||||
};
|
||||
static const char *const str[1];
|
||||
|
||||
return str[u->type];
|
||||
}
|
||||
|
|