Compare commits

...

6 Commits

39 changed files with 366 additions and 95 deletions

1
.gitignore vendored
View File

@ -1,5 +1,4 @@
build/
build-*/
.vscode/
*.code-workspace
cdimg/

View File

@ -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
)

BIN
res/btn_left.bmp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 586 B

BIN
res/btn_left_24.bmp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

BIN
res/btn_mid.bmp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 542 B

BIN
res/btn_mid_24.bmp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

BIN
res/btn_right.bmp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 586 B

BIN
res/btn_right_24.bmp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

BIN
res/building1_24.bmp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

BIN
res/building2_24.bmp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

21
res/city1.txt Normal file
View File

@ -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

BIN
res/cursor.bmp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 550 B

BIN
res/cursor_24.bmp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

@ -77,6 +77,18 @@ function(sound)
endif()
endfunction()
function(level)
set(options "")
set(multiValueArgs "")
set(oneValueArgs NAME)
cmake_parse_arguments(LEVEL "${options}" "${oneValueArgs}"
"${multiValueArgs}" ${ARGN})
file(COPY ${LEVEL_NAME}.txt DESTINATION ${cdroot})
add_custom_target(${LEVEL_NAME}_lvl
DEPENDS ${cdroot}/${LEVEL_NAME})
endfunction()
function(container)
set(options "")
set(multiValueArgs SPRITES SOUNDS)

BIN
res/grass.bmp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

BIN
res/grass_24.bmp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

BIN
res/pavement.bmp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

BIN
res/pavement_24.bmp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

BIN
res/roof1.bmp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

BIN
res/roof1_24.bmp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

BIN
res/roof2.bmp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

BIN
res/roof2_24.bmp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

BIN
res/sidewalk.bmp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

BIN
res/sidewalk_24.bmp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

BIN
res/tileset1.bmp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 192 KiB

BIN
res/tileset_24.bmp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 192 KiB

BIN
res/water.bmp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

BIN
res/water_24.bmp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

View File

@ -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);

View File

@ -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);

View File

@ -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,

View File

@ -30,6 +30,7 @@ struct game_cfg
size_t n;
union peripheral *p;
const char *map;
};
int game_resinit(void);

View File

@ -14,8 +14,7 @@ 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);
terrain_init(cfg->map, &map);
const struct human_player_cfg hcfg =
{

View File

@ -12,7 +12,45 @@
#include <unit.h>
#include <stdbool.h>
static const struct container c[1];
static const struct container c[] =
{
{
.path = "sidewalk",
.type = CONTAINER_TYPE_SPRITE,
.data.sprite = &terrain_sprites[SIDEWALK]
},
{
.path = "roof1",
.type = CONTAINER_TYPE_SPRITE,
.data.sprite = &terrain_sprites[ROOF1]
},
{
.path = "roof2",
.type = CONTAINER_TYPE_SPRITE,
.data.sprite = &terrain_sprites[ROOF2]
},
{
.path = "cursor",
.type = CONTAINER_TYPE_SPRITE,
.data.sprite = &cursor_sprite
},
{
.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]
},
};
static bool init;
void game_free(void)

View File

@ -50,9 +50,6 @@ int menu_update(struct menu_common *const c,
case PERIPHERAL_TYPE_TOUCH:
break;
default:
return -1;
}
if (gfx_draw())

View File

@ -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})

View File

@ -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);

View File

@ -21,26 +21,64 @@ enum
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,
ROOF1_START = ROOF1_1_NW,
ROOF1_END = ROOF1_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
}

View File

@ -2,11 +2,16 @@
#include <camera.h>
#include <gfx.h>
#include <util.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>
struct sprite grass_sprite;
struct sprite terrain_sprites[MAX_TERRAIN_SPRITES];
void terrain_update(struct terrain_map *const map)
{
@ -27,56 +32,6 @@ void terrain_update(struct terrain_map *const map)
}
}
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)
{
@ -105,28 +60,172 @@ int terrain_render(const struct terrain_map *const map,
for (struct m y = {.i = start_y, .p = remy};
y.i < ny + start_y; y.i++, y.p += TERRAIN_SZ)
{
static const struct tile
{
const struct sprite *s;
int start, end;
} tiles[] =
{
{
.s = &terrain_sprites[ROOF1],
.start = ROOF1_START,
.end = ROOF1_END
}
};
const struct terrain_tile *const t = &map->m[y.i][x.i];
sprite_get_or_ret(s, -1);
switch (t->t)
for (size_t i = 0; i < sizeof tiles / sizeof *tiles; i++)
{
case TERRAIN_TYPE_GRASS:
if (sprite_clone(&grass_sprite, s))
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))
return -1;
break;
s->x = x.p;
s->y = y.p;
sprite_sort(s);
return 0;
}
}
}
s->x = x.p;
s->y = y.p;
sprite_sort(s);
return -1;
}
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) && i)
break;
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 *const 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, 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__, s);
return -1;
}
else if (value > limit)
{
fprintf(stderr, "%s: %lu exceeds maximum range %d\n", __func__, value,
limit);
return -1;
}
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;
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;
}
void terrain_init(struct terrain_map *const map)
int terrain_init(const char *const path, struct terrain_map *const map)
{
*map = (const struct terrain_map){0};
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;
}