Big rushed update

This commit is contained in:
Xavier Del Campo Romero 2024-01-28 03:01:13 +01:00
parent e49e3073c6
commit fd53c7da8c
Signed by: xavi
GPG Key ID: 84FF3612A9BF43F2
59 changed files with 1033 additions and 375 deletions

View File

@ -4,6 +4,8 @@
`jancity` is a cross-platform, tile-based sandbox video game.
![Screenshot](jancity.png)
Mostly written during the Global Game Jam 2024 event, reusing its engine
from [`rts`](https://gitea.privatedns.org/xavi/rts).

BIN
jancity.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.5 KiB

View File

@ -128,10 +128,143 @@ sprite(NAME unit6
CY 48
TRANSPARENT TRUE)
sprite(NAME sel_down_left
X 384
Y 0
BPP 4
CX 0
CY 0
TRANSPARENT TRUE)
sprite(NAME sel_down_right
X 384
Y 0
BPP 4
CX 0
CY 0
TRANSPARENT TRUE)
sprite(NAME sel_mid_down
X 384
Y 0
BPP 4
CX 0
CY 0
TRANSPARENT TRUE)
sprite(NAME sel_mid_top
X 384
Y 0
BPP 4
CX 0
CY 0
TRANSPARENT TRUE)
sprite(NAME sel_mid_v
X 384
Y 0
BPP 4
CX 0
CY 0
TRANSPARENT TRUE)
sprite(NAME sel_up_left
X 384
Y 0
BPP 4
CX 0
CY 0
TRANSPARENT TRUE)
sprite(NAME sel_up_right
X 384
Y 0
BPP 4
CX 0
CY 0
TRANSPARENT TRUE)
sprite(NAME checkbox
X 384
Y 0
BPP 4
CX 0
CY 0
TRANSPARENT TRUE)
sprite(NAME line_edit_left
X 0
Y 0
BPP 4
CX 0
CY 0
TRANSPARENT TRUE)
sprite(NAME line_edit_mid
X 0
Y 0
BPP 4
CX 0
CY 0
TRANSPARENT FALSE)
sprite(NAME line_edit_right
X 0
Y 0
BPP 4
CX 0
CY 0
TRANSPARENT TRUE)
sprite(NAME car1
X 0
Y 0
BPP 4
CX 0
CY 0
TRANSPARENT TRUE)
sprite(NAME pavement
X 0
Y 0
BPP 4
CX 0
CY 0
TRANSPARENT FALSE)
sprite(NAME car2
X 0
Y 0
BPP 4
CX 0
CY 0
TRANSPARENT TRUE)
sprite(NAME building1
X 0
Y 0
BPP 4
CX 0
CY 0
TRANSPARENT TRUE)
sprite(NAME building2
X 0
Y 0
BPP 4
CX 0
CY 0
TRANSPARENT TRUE)
level(NAME city1)
container(NAME jancity
SPRITES
building1
building2
car1
car2
checkbox
grass
sidewalk
roof1
@ -148,4 +281,15 @@ container(NAME jancity
unit4
unit5
unit6
sel_down_left
sel_down_right
sel_mid_down
sel_mid_top
sel_mid_v
sel_up_left
sel_up_right
line_edit_left
line_edit_mid
line_edit_right
pavement
)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 586 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 542 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 586 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

BIN
res/btn_small.bmp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 490 B

BIN
res/btn_small_24.bmp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

BIN
res/car1_24.bmp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.1 KiB

BIN
res/car2_24.bmp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.1 KiB

BIN
res/checkbox_24.bmp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

@ -1,21 +1,31 @@
24 16
24 24
0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000
0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000
0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000
0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000
0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00
0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00
0009 0009 0009 0009 0009 0009 0009 0009 0009 0009 0009 0009 0009 0009 0009 0009 0009 0009 0009 0009 0009 0009 0009 0009
0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011
0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000
0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000
0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000
0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000
0053 0054 0054 0054 0054 0054 0054 0054 0053 0054 0054 0054 0054 0054 0054 0054 0054 0054 0054 0053 0054 0054 0054 0054
0048 0049 0049 0049 0049 0049 0049 0049 0048 0049 0049 0049 0049 0049 0049 0049 0049 0049 0049 0048 0049 0049 0049 0049
0055 0056 0056 0056 0056 0056 0056 0056 0055 0056 0056 0056 0056 0056 0056 0056 0050 005e 0051 0055 0056 0056 0056 0056
0001 0001 0001 0001 0001 0001 0001 0001 0001 0001 0001 0001 0001 0001 0001 0002 004a 004b 004c 0000 0001 0001 0001 0001
0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000
0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000
0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000
0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000
0009 0009 0009 0009 0009 0009 0009 0009 0009 0009 0009 0009 0009 0009 0009 000a 0057 0058 0059 0008 0000 0000 0000 0000
0030 0031 0031 0032 0000 0000 0000 0000 0030 0031 0031 0032 0000 0000 0009 000a 0057 0058 0059 0008 0000 0000 0000 0000
0038 0039 0039 003a 0000 0000 0000 0000 0038 0039 0039 003a 0000 0000 0009 000a 0057 0058 0059 0008 0000 0000 0000 0000
0040 0041 0041 0042 0000 0000 0000 0000 0040 0041 0041 0042 0000 0000 0009 000a 0057 0058 0059 0008 0000 0000 0000 0000
0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000
0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000
0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000
0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000
0062 0063 0064 0062 0a00 0a00 0a00 0a00 0062 0063 0064 0062 0a00 0a00 0a00 0a00 0057 0058 0059 0008 0a00 0a00 0a00 0a00
0069 006a 006c 0069 0a00 0a00 0a00 0a00 0069 006a 006c 0069 0a00 0a00 0a00 0a00 0057 0058 0059 0008 0a00 0a00 0a00 0a00
0070 0071 0073 0070 0a00 0a00 0a00 0a00 0070 0071 0073 0070 0a00 0a00 0a00 0a00 0057 0058 0059 0008 0a00 0a00 0a00 0a00
0077 0078 007a 0077 0a00 0a00 0a00 0a00 0077 0078 007a 0077 0a00 0a00 0a00 0a00 0057 0058 0059 0008 0a00 0a00 0a00 0a00
0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00
0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00
0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00
0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00
0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00
0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00
0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00
0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00 0a00

BIN
res/font.bmp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.0 KiB

BIN
res/font_24.bmp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

View File

@ -35,6 +35,7 @@ function(sprite)
VERBATIM)
add_custom_target(${SPRITE_NAME}_img
DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${SPRITE_NAME})
add_dependencies(${PROJECT_NAME} ${SPRITE_NAME}_img)
add_dependencies(${SPRITE_NAME}_img tools)
endif()
endfunction()
@ -73,6 +74,7 @@ function(sound)
VERBATIM)
add_custom_target(${SOUND_NAME}_snd
DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${SOUND_NAME})
add_dependencies(${PROJECT_NAME} ${SOUND_NAME}_snd)
add_dependencies(${SOUND_NAME}_snd tools)
endif()
endfunction()

BIN
res/line_edit_left_24.bmp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

BIN
res/line_edit_mid_24.bmp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

BIN
res/line_edit_right_24.bmp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

BIN
res/sel_down_left_24.bmp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 822 B

BIN
res/sel_down_right_24.bmp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 822 B

BIN
res/sel_mid_down_24.bmp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 822 B

BIN
res/sel_mid_top_24.bmp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 150 B

BIN
res/sel_mid_v_24.bmp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 182 B

BIN
res/sel_up_left_24.bmp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 822 B

BIN
res/sel_up_right_24.bmp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 822 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.1 KiB

After

Width:  |  Height:  |  Size: 9.1 KiB

View File

@ -33,7 +33,7 @@ void building_set_alive_cb(void (*f)(const struct util_rect *dim, bool alive, vo
int building_render(const struct building *b, const struct camera *cam, bool sel);
const char *building_str(const struct building *b);
extern struct sprite building_sprites[MAX_BUILDING_TYPES];
extern struct sprite building_sprites[1];
#ifdef __cplusplus
}

View File

@ -4,7 +4,7 @@
#include <stdbool.h>
#include <stddef.h>
struct sprite building_sprites[MAX_BUILDING_TYPES];
struct sprite building_sprites[1];
int building_render(const struct building *const b,
const struct camera *const cam, const bool sel)

View File

@ -18,7 +18,7 @@ struct camera
long w, h;
} dim;
int x, y, x_speed, y_speed;
long x, y, x_speed, y_speed;
unsigned xt, yt;
bool pan;
@ -28,6 +28,7 @@ struct camera
enum
{
CURSOR_STATE_IDLE,
CURSOR_STATE_HOVERING,
CURSOR_STATE_PRESSED
} state;
struct

View File

@ -55,9 +55,13 @@ int cursor_render(const struct cursor *const c)
case CURSOR_STATE_IDLE:
break;
case CURSOR_STATE_PRESSED:
case CURSOR_STATE_HOVERING:
s->u += CAMERA_CURSOR_WIDTH;
break;
case CURSOR_STATE_PRESSED:
s->u += CAMERA_CURSOR_WIDTH * 2;
break;
}
const int ret = sprite_sort(s);
@ -89,23 +93,24 @@ void cursor_init(struct cursor *const c)
void camera_update_pos(struct camera *const cam)
{
const int x = cam->x + cam->x_speed;
const struct camera_dim *const d = &cam->dim;
cam->x = x;
if (!d->w || !d->h)
return;
cam->x += cam->x_speed;
if (cam->x > 0)
cam->x = 0;
else if (cam->x < -cam->dim.w)
cam->x = -cam->dim.w;
else if (cam->x < -d->w + screen_w)
cam->x = -d->w + screen_w;
const int y = cam->y + cam->y_speed;
cam->y = y;
cam->y += cam->y_speed;
if (cam->y > 0)
cam->y = 0;
else if (cam->y < -cam->dim.h)
cam->y = -cam->dim.h;
else if (cam->y < -d->h + screen_h)
cam->y = -d->h + screen_h;
}
bool camera_translate(const struct camera *const cam, const struct util_rect *const dim,

View File

@ -13,9 +13,14 @@ static void cursor_update(struct cursor *const c, const struct mouse *const m)
c->x = m->x;
c->y = m->y;
c->state = mouse_pressed(m, MOUSE_BUTTON_LEFT) ||
mouse_pressed(m, MOUSE_BUTTON_RIGHT) ?
CURSOR_STATE_PRESSED: CURSOR_STATE_IDLE;
if (mouse_pressed(m, MOUSE_BUTTON_LEFT)
|| mouse_pressed(m, MOUSE_BUTTON_RIGHT))
c->state = CURSOR_STATE_PRESSED;
else if (m->hovering)
c->state = CURSOR_STATE_HOVERING;
else
c->state = CURSOR_STATE_IDLE;
}
static void update_speed(struct camera *const cam, const struct mouse *const m)
@ -24,34 +29,55 @@ static void update_speed(struct camera *const cam, const struct mouse *const m)
{
MAX_SPEED = 10,
STEP = 1,
THRESHOLD_X = CAMERA_CURSOR_WIDTH / 2,
THRESHOLD_Y = CAMERA_CURSOR_HEIGHT / 2
T_STEP = 10,
THRESHOLD_X = CAMERA_CURSOR_WIDTH,
THRESHOLD_Y = CAMERA_CURSOR_HEIGHT
};
const struct cursor *const c = &cam->cursor;
if (c->x >= screen_w - THRESHOLD_X)
{
if (cam->x_speed - STEP > -MAX_SPEED)
cam->x_speed -= STEP;
if (++cam->xt >= T_STEP)
{
cam->xt = 0;
if (cam->x_speed - STEP > -MAX_SPEED)
cam->x_speed -= STEP;
}
}
else if (c->x < THRESHOLD_X)
{
if (cam->x_speed + STEP < MAX_SPEED)
cam->x_speed += STEP;
if (++cam->xt >= T_STEP)
{
cam->xt = 0;
if (cam->x_speed + STEP < MAX_SPEED)
cam->x_speed += STEP;
}
}
else
cam->x_speed = 0;
if (c->y >= screen_h - THRESHOLD_Y)
{
if (cam->y_speed - STEP > -MAX_SPEED)
cam->y_speed -= STEP;
if (++cam->yt >= T_STEP)
{
cam->yt = 0;
if (cam->y_speed - STEP > -MAX_SPEED)
cam->y_speed -= STEP;
}
}
else if (c->y < THRESHOLD_Y)
{
if (cam->y_speed + STEP < MAX_SPEED)
cam->y_speed += STEP;
if (++cam->yt >= T_STEP)
{
cam->yt = 0;
if (cam->y_speed + STEP < MAX_SPEED)
cam->y_speed += STEP;
}
}
else
cam->y_speed = 0;

View File

@ -48,7 +48,7 @@ static void update_speed(struct camera *const cam,
{
MAX_SPEED = 10,
STEP = 1,
T_STEP = 3
T_STEP = 2
};
const struct cursor *const c = &cam->cursor;

View File

@ -108,6 +108,102 @@ static const struct container c[] =
.path = "unit6",
.type = CONTAINER_TYPE_SPRITE,
.data.sprite = &unit_sprites[UNIT_6_SPRITE]
},
{
.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_down",
.type = CONTAINER_TYPE_SPRITE,
.data.sprite = &gui_rounded_rect_sprites[GUI_ROUNDED_RECT_MID_DOWN]
},
{
.path = "sel_mid_top",
.type = CONTAINER_TYPE_SPRITE,
.data.sprite = &gui_rounded_rect_sprites[GUI_ROUNDED_RECT_MID_TOP]
},
{
.path = "sel_mid_v",
.type = CONTAINER_TYPE_SPRITE,
.data.sprite = &gui_rounded_rect_sprites[GUI_ROUNDED_RECT_MID_VERT]
},
{
.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 = "checkbox",
.type = CONTAINER_TYPE_SPRITE,
.data.sprite = &gui_checkbox_sprite
},
{
.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 = "car1",
.type = CONTAINER_TYPE_SPRITE,
.data.sprite = &unit_sprites[UNIT_CAR_1_SPRITE]
},
{
.path = "pavement",
.type = CONTAINER_TYPE_SPRITE,
.data.sprite = &terrain_sprites[PAVEMENT]
},
{
.path = "car2",
.type = CONTAINER_TYPE_SPRITE,
.data.sprite = &unit_sprites[UNIT_CAR_2_SPRITE]
},
{
.path = "building1",
.type = CONTAINER_TYPE_SPRITE,
.data.sprite = &terrain_sprites[BUILDING1],
},
{
.path = "building2",
.type = CONTAINER_TYPE_SPRITE,
.data.sprite = &terrain_sprites[BUILDING2],
}
};

View File

@ -15,6 +15,7 @@ struct gui_rounded_rect
{
struct gui_common common;
unsigned short w, h;
unsigned char r, g, b;
bool adjust;
};
@ -27,13 +28,15 @@ enum
GUI_ROUNDED_RECT_MID_VERT,
GUI_ROUNDED_RECT_DOWN_LEFT,
GUI_ROUNDED_RECT_DOWN_RIGHT,
GUI_ROUNDED_RECT_MID,
GUI_ROUNDED_RECT_MID_TOP,
GUI_ROUNDED_RECT_MID_DOWN,
MAX_GUI_ROUNDED_RECT_SPRITES
};
extern struct sprite gui_rounded_rect_sprites[MAX_GUI_ROUNDED_RECT_SPRITES];
/* Pad one line to avoid redefinition. */
UTIL_STATIC_ASSERT(!offsetof(struct gui_rounded_rect, common),
"unexpected offset for struct gui_rounded_rect");

View File

@ -134,30 +134,36 @@ static int render_rect(const struct gui_rounded_rect *const r,
rect_get_or_ret(sel, -1);
semitrans_rect_init(sel);
const struct sprite *const mid = &refs[GUI_ROUNDED_RECT_MID],
const struct sprite *const mid = &refs[GUI_ROUNDED_RECT_MID_TOP],
*const vert = &refs[GUI_ROUNDED_RECT_MID_VERT];
sel->x = x + vert->w;
sel->y = y + mid->h;
sel->w = r->w - (vert->w * 2);
sel->h = r->h - (mid->h * 2);
sel->r = 72;
sel->g = 66;
sel->b = 56;
sel->r = r->r;
sel->g = r->g;
sel->b = r->b;
rect_sort(sel);
return 0;
}
static int render_mid(const struct gui_rounded_rect *const r,
const short x, const short y)
const short x, const short y, const struct sprite *const s)
{
const short mid_w = refs[GUI_ROUNDED_RECT_MID].w,
const short mid_w = s->w,
top_w = refs[GUI_ROUNDED_RECT_UP_LEFT].w,
w = r->w - (top_w * 2),
rem_mid = w % mid_w,
whole_mid = w / mid_w,
n_mid = rem_mid ? whole_mid + 1 : whole_mid;
if (n_mid < 0)
{
fprintf(stderr, "%s: invalid dimensions\n", __func__);
return -1;
}
for (struct
{
size_t i;
@ -166,7 +172,7 @@ static int render_mid(const struct gui_rounded_rect *const r,
{
sprite_get_or_ret(m, -1);
if (sprite_clone(&refs[GUI_ROUNDED_RECT_MID], m))
if (sprite_clone(s, m))
return -1;
m->x = a.x;
@ -186,13 +192,15 @@ static int render_mid(const struct gui_rounded_rect *const r,
static int render_midtop(const struct gui_rounded_rect *const r,
const short x, const short y)
{
return render_mid(r, x, y);
return render_mid(r, x, y, &refs[GUI_ROUNDED_RECT_MID_TOP]);
}
static int render_middown(const struct gui_rounded_rect *const r,
const short x, const short y)
{
return render_mid(r, x, y + r->h - refs[GUI_ROUNDED_RECT_MID].h);
const struct sprite *const s = &refs[GUI_ROUNDED_RECT_MID_DOWN];
return render_mid(r, x, y + r->h - s->h, s);
}
static int render(const struct gui_common *const g)
@ -242,8 +250,8 @@ static void add_child(struct gui_common *const parent,
short w, h;
const short ref_w = refs[GUI_ROUNDED_RECT_MID_VERT].w,
ref_h = refs[GUI_ROUNDED_RECT_MID].h,
min_w = ref_w * 2 + refs[GUI_ROUNDED_RECT_MID].w,
ref_h = refs[GUI_ROUNDED_RECT_MID_TOP].h,
min_w = ref_w * 2 + refs[GUI_ROUNDED_RECT_MID_TOP].w,
min_h = ref_h * 2 + refs[GUI_ROUNDED_RECT_MID_VERT].h;
child->cb->get_dim(child, &w, &h);

View File

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

View File

@ -19,47 +19,18 @@ void instance_cyclic(void)
line_g_flip ^= true;
}
static int draw_sel(const struct instance *const i, const short x, const short y)
{
enum {R = 0, G = 255, B = 0};
stp_4line_get_or_ret(l, -1);
stp_4line_init(l);
l->x = l->vertices[2].x = l->vertices[3].x = x;
l->y = l->vertices[0].y = l->vertices[3].y = y;
l->vertices[0].x = l->vertices[1].x = x + i->r.w;
l->vertices[1].y = l->vertices[2].y = y + i->r.h;
l->r = R;
l->g = line_g;
l->b = B >> 2;
for (size_t i = 0; i < sizeof l->vertices / sizeof *l->vertices; i++)
{
struct stp_4line_vtx *const v = &l->vertices[i];
v->r = R;
v->b = B;
}
l->vertices[0].g = l->vertices[2].g = UCHAR_MAX - line_g;
l->vertices[1].g = l->vertices[3].g = line_g;
stp_4line_sort(l);
stp_4line_get_or_ret(ll, -1);
*ll = *l;
ll->x = ll->vertices[2].x = ll->vertices[3].x = l->x ? l->x - 1 : 0;
ll->y = ll->vertices[0].y = ll->vertices[3].y = l->y ? l->y - 1 : 0;
ll->vertices[0].x = ll->vertices[1].x = l->vertices[0].x + 1;
ll->vertices[1].y = ll->vertices[2].y = l->vertices[1].y + 1;
stp_4line_sort(ll);
return 0;
}
static void render_sprite(struct sprite *const s,
static int render_sprite(struct sprite *const s,
const struct instance_render_off *const off, const short x, const short y)
{
s->x = off ? x + off->x : x;
s->y = off ? y + off->y : y;
sprite_sort(s);
const int ret = sprite_sort(s);
if (ret)
fprintf(stderr, "%s: sprite_sort failed\n", __func__);
return ret;
}
static void render_quad(const struct instance_render_quad *const rq,
@ -99,9 +70,6 @@ int instance_render(const struct instance_render_cfg *const cfg)
{
const struct instance_render_off *const off = cfg->off;
if (cfg->sel && draw_sel(i, x, y))
return -1;
switch (cfg->prim_type)
{
case INSTANCE_RENDER_CFG_SPRITE:
@ -120,10 +88,5 @@ int instance_render(const struct instance_render_cfg *const cfg)
int instance_render_target(const struct instance *const i,
const struct camera *const cam)
{
short x, y;
if (camera_translate(cam, &i->r, &x, &y))
return draw_sel(i, x, y);
return -1;
return 0;
}

View File

@ -736,9 +736,10 @@ int menu_gamecfg(struct menu_common *const c, struct net_host *const h,
if (start)
{
struct game_cfg cfg =
const struct game_cfg cfg =
{
.p = &c->p
.p = &c->p,
.map = "city1.txt"
};
return game(&cfg);

View File

@ -4,14 +4,27 @@
#include <gui/button.h>
#include <gui/container.h>
#include <gui/rounded_rect.h>
#include <util.h>
#include <system.h>
#include <stdbool.h>
enum role
{
CREDITS_NAME_COPYRIGHT,
CREDITS_ROLE_GFX,
CREDITS_ROLE_PROGRAMMING,
CREDITS_ROLE_ENGINE,
CREDITS_ROLE_LANGUAGE,
MAX_CREDIT_ROLES
};
struct main_menu
{
bool start, settings, exit;
struct gui_button play, settings_btn, exit_btn;
struct gui_container cnt;
struct gui_label title, roles[MAX_CREDIT_ROLES];
};
static int update(struct menu_common *const c, void *const arg)
@ -34,6 +47,32 @@ static int render(const struct menu_common *const c, void *const arg)
return 0;
}
static void update_roles(struct main_menu *const m)
{
static const char *const roles[] =
{
[CREDITS_NAME_COPYRIGHT] = "(C) 2024 Xavier Del Campo Romero",
[CREDITS_ROLE_GFX] = "Gfx: Kenney, Ivan Voirol",
[CREDITS_ROLE_PROGRAMMING] = "Coding: me",
[CREDITS_ROLE_ENGINE] = "Engine: also me lol",
[CREDITS_ROLE_LANGUAGE] = "Written in good old C"
};
UTIL_STATIC_ASSERT(sizeof roles / sizeof *roles
== sizeof m->roles / sizeof *m->roles,
"unexpected sizes");
for (size_t i = 0; i < sizeof roles / sizeof *roles; i++)
{
struct gui_label *const l = &m->roles[i];
gui_label_init(l);
l->common.hcentered = true;
l->text = roles[i];
gui_add_child(&m->cnt.common, &l->common);
}
}
int menu_main(struct menu_common *const c)
{
do
@ -50,6 +89,15 @@ int menu_main(struct menu_common *const c)
c->spacing = 4;
}
{
struct gui_label *const l = &m.title;
gui_label_init(l);
l->common.hcentered = true;
l->text = "Jancity, a city sandbox";
gui_add_child(&m.cnt.common, &l->common);
}
{
struct gui_button *const b = &m.play;
@ -87,6 +135,8 @@ int menu_main(struct menu_common *const c)
gui_add_child(&m.cnt.common, &b->common);
}
update_roles(&m);
while (!m.start && !m.settings && !c->p.common.exit)
{
if (menu_update(c, update, render, &m))

View File

@ -34,9 +34,15 @@ int menu_update(struct menu_common *const c,
rect_sort(r);
if (render && render(c, arg))
{
fprintf(stderr, "%s: render cb failed\n", __func__);
return -1;
}
else if (input_render(&c->in, &c->p))
{
fprintf(stderr, "%s: input_render failed\n", __func__);
return -1;
}
switch (c->p.common.type)
{
@ -53,7 +59,10 @@ int menu_update(struct menu_common *const c,
}
if (gfx_draw())
{
fprintf(stderr, "%s: gfx_draw failed\n", __func__);
return -1;
}
return 0;
}
@ -72,11 +81,16 @@ int menu(void)
peripheral_init(&cfg, &c.p);
settings_load("settings.ini", &c.s);
const struct game_cfg gcfg =
#if 1
struct game_cfg gcfg =
{
.p = &c.p,
.map = "city1.txt"
.map = "city1.txt",
.p = &c.p
};
return game(&gcfg);
#else
return menu_main(&c);
#endif
}

View File

@ -18,6 +18,7 @@ struct mouse
{
short x, y, dx, dy;
int mask, oldmask;
bool first_clicked, hovering;
};
void mouse_init(struct mouse *m);

View File

@ -3,13 +3,21 @@
#include <stdint.h>
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
static void mouse_click(const SDL_MouseButtonEvent *const ev,
struct mouse *const m)
{
int mask;
if (!m->first_clicked)
{
srand(time(NULL));
m->first_clicked = true;
}
switch (ev->button)
{
case 1:

View File

@ -25,7 +25,7 @@ union peripheral
struct peripheral_common
{
enum peripheral_type type;
bool exit;
bool init, exit;
} common;
struct peripheral_pad

View File

@ -18,4 +18,5 @@ target_link_libraries(player
util
PRIVATE
pad
gui)
gui
terrain)

View File

@ -2,6 +2,9 @@
#define HUMAN_PLAYER_H
#include <camera.h>
#include <gui/button.h>
#include <gui/container.h>
#include <gui/rounded_rect.h>
#include <keyboard.h>
#include <instance.h>
#include <input.h>
@ -34,6 +37,15 @@ struct human_player
union peripheral *periph;
struct input in;
struct human_player_item
{
bool show;
struct gui_button show_btn;
struct gui_rounded_rect rr;
struct gui_container topcnt;
struct gui_button add_walker, add_car, exit;
} item;
struct sel_instance
{
enum sel_type

View File

@ -18,7 +18,7 @@ typedef unsigned player_team;
enum
{
PLAYER_MAX_UNITS = 5,
PLAYER_MAX_UNITS = 10,
PLAYER_MAX_BUILDINGS = 5
};

View File

@ -279,8 +279,7 @@ static void update_selected(struct human_player *const h)
{
struct sel_instance *const si = &h->sel[i];
if (si->d.i
&& (!si->d.i->alive || si->type == INSTANCE_TYPE_UNIT))
if (si->d.i && !si->d.i->alive)
{
si->d.i = NULL;
h->n_sel--;
@ -357,10 +356,26 @@ static void update_from_touch(struct human_player *const h,
}
}
static bool hovering_units(const struct human_player *const h)
{
const struct player *const pl = &h->pl;
for (size_t i = 0; i < sizeof pl->units / sizeof *pl->units; i++)
{
const struct unit *const u = &pl->units[i];
const struct instance *const in = &u->instance;
if (in->alive && cursor_collision(&h->cam, &in->r))
return true;
}
return false;
}
static void update_from_keyboard_mouse(struct human_player *const h,
struct player_others *const o)
{
const struct mouse *const m = &h->periph->kbm.mouse;
struct mouse *const m = &h->periph->kbm.mouse;
const struct keyboard *const k = &h->periph->kbm.keyboard;
const struct input *const in = &h->in;
@ -377,6 +392,8 @@ static void update_from_keyboard_mouse(struct human_player *const h,
}
else if (input_mouse_justreleased(in, m, MOUSE_BUTTON_RIGHT))
move_units(h, o);
else
m->hovering = hovering_units(h);
}
void human_player_update(struct human_player *const h,

View File

@ -10,16 +10,146 @@
#include <gui/label.h>
#include <gui/progress_bar.h>
#include <gui/rounded_rect.h>
#include <terrain.h>
#include <inttypes.h>
#include <limits.h>
#include <stddef.h>
#include <stdio.h>
#include <stdint.h>
enum {X_OFF = 8, Y_OFF = 8, HP_Y = 32};
enum {X_OFF = 8, Y_OFF = 8};
static void on_item_pressed(void *const arg)
{
bool *const show = arg;
*show ^= true;
}
static void on_add_car(void *const arg)
{
struct human_player *const h = arg;
struct human_player_item *const it = &h->item;
const struct unit_cfg cfg =
{
.type = UNIT_CFG_TYPE_CAR,
.x = rand() % (MAP_W - 32),
.y = rand() % (MAP_H - 32),
};
player_create_unit(&cfg, &h->pl);
it->show = false;
}
static void on_add_walker(void *const arg)
{
struct human_player *const h = arg;
struct human_player_item *const it = &h->item;
const struct unit_cfg cfg =
{
.type = UNIT_CFG_TYPE_WALKER,
.x = rand() % (MAP_W - 32),
.y = rand() % (MAP_H - 32),
};
player_create_unit(&cfg, &h->pl);
it->show = false;
}
static void on_exit(void *const arg)
{
struct human_player *const h = arg;
h->periph->common.exit = true;
}
static void update_items(struct human_player *const h)
{
struct human_player_item *const it = &h->item;
{
struct gui_rounded_rect *const r = &it->rr;
gui_rounded_rect_init(r);
r->common.hcentered = r->common.vcentered = true;
r->adjust = true;
}
{
struct gui_container *const c = &it->topcnt;
gui_container_init(c);
c->common.vcentered = true;
c->common.hcentered = true;
c->mode = GUI_CONTAINER_MODE_V;
c->spacing = 4;
gui_add_child(&it->rr.common, &c->common);
}
{
struct gui_button *const b = &it->add_car;
gui_button_init(b, GUI_BUTTON_TYPE_1);
b->common.hcentered = true;
b->u.type1.w = 80;
b->u.type1.label.text = "Add car";
b->on_pressed = on_add_car;
b->arg = h;
gui_add_child(&it->topcnt.common, &b->common);
}
{
struct gui_button *const b = &it->add_walker;
gui_button_init(b, GUI_BUTTON_TYPE_1);
b->u.type1.w = 80;
b->common.hcentered = true;
b->u.type1.label.text = "Add walker";
b->on_pressed = on_add_walker;
b->arg = h;
gui_add_child(&it->topcnt.common, &b->common);
}
{
struct gui_button *const b = &it->exit;
gui_button_init(b, GUI_BUTTON_TYPE_1);
b->u.type1.w = 80;
b->common.hcentered = true;
b->u.type1.label.text = "Exit";
b->on_pressed = on_exit;
b->arg = h;
gui_add_child(&it->topcnt.common, &b->common);
}
struct camera cam =
{
.cursor = h->cam.cursor
};
gui_update(&it->rr.common, h->periph, &cam, &h->in);
}
void human_player_gui_update(struct human_player *const h)
{
struct human_player_item *const it = &h->item;
struct gui_button *const b = &it->show_btn;
gui_button_init(b, GUI_BUTTON_TYPE_SPRITE);
b->on_pressed = on_item_pressed;
b->arg = &it->show;
b->u.sprite.s = &gui_button_sprites[GUI_BUTTON_SMALL];
b->common.x = screen_w - b->u.sprite.s->w;
if (it->show)
update_items(h);
struct camera cam =
{
.cursor = h->cam.cursor
};
gui_update(&b->common, h->periph, &cam, &h->in);
}
static int render_sel_single_building(const struct human_player *const h,
@ -41,14 +171,13 @@ 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;
enum {CARRY_X = 96, CARRY_Y = 8};
struct gui_label ul;
gui_label_init(&ul);
ul.common.x = X_OFF;
ul.common.y = Y_OFF;
ul.text = unit_str(u);
ul.common.hcentered = true;
ul.common.vcentered = true;
ul.text = u->name;
gui_add_child(r, &ul.common);
return gui_render(r);
@ -99,37 +228,44 @@ static int render_sel_multiple(const struct human_player *const h,
static int render_top(const struct human_player *const h)
{
struct gui_button b;
gui_button_init(&b, GUI_BUTTON_TYPE_SPRITE);
b.on_pressed = NULL;
b.arg = NULL;
b.u.sprite.s = &gui_button_sprites[GUI_BUTTON_SMALL];
b.common.x = screen_w - b.u.sprite.s->w;
return gui_render(&b.common);
return gui_render(&h->item.show_btn.common);
}
static int render_sel(const struct human_player *const h)
{
const short wlim = 120;
struct gui_rounded_rect r;
short exp_w;
gui_rounded_rect_init(&r);
r.common.x = 16;
r.w = screen_w - (r.common.x * 2);
r.h = screen_h / 4;
r.common.hcentered = true;
exp_w = screen_w - 32;
r.w = exp_w > wlim ? wlim : exp_w;
r.h = 40;
r.r = 10;
r.g = 137;
r.b = 225;
r.common.y = screen_h - r.h;
return h->n_sel == 1 ? render_sel_single(h, &r.common)
: render_sel_multiple(h, &r.common);
}
static int render_items(const struct human_player *const h)
{
const struct human_player_item *const it = &h->item;
return gui_render(&it->rr.common);
}
int human_player_gui_render(const struct human_player *const h)
{
if (render_top(h))
return -1;
else if (h->n_sel && render_sel(h))
return -1;
else if (h->item.show && render_items(h))
return -1;
return 0;
}

View File

@ -1,6 +1,7 @@
#include <player.h>
#include <building.h>
#include <unit.h>
#include <terrain.h>
#include <stddef.h>
void player_update(struct player *const p)
@ -61,6 +62,22 @@ 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)
{
for (size_t i = 0; i < sizeof pl->units / sizeof *pl->units; i++)
{
const struct unit_cfg ucfg =
{
.type = rand() & 1 ? UNIT_CFG_TYPE_WALKER : UNIT_CFG_TYPE_CAR,
.x = rand() % (MAP_W - 32),
.y = rand() % (MAP_H - 32),
};
if (player_create_unit(&ucfg, pl))
{
fprintf(stderr, "%s: player_create_unit failed\n", __func__);
return -1;
}
}
pl->alive = true;
pl->color = cfg->color;
pl->team = cfg->team;

View File

@ -13,7 +13,7 @@ extern "C"
enum
{
MAP_TILES = 120,
MAP_TILES = 24,
TERRAIN_SZ = 16,
MAP_W = MAP_TILES * TERRAIN_SZ,
MAP_H = MAP_TILES * TERRAIN_SZ
@ -39,7 +39,9 @@ enum
GRASS,
ROOF1,
ROOF2,
PAVEMENT,
BUILDING1,
BUILDING2,
MAX_TERRAIN_SPRITES
};

View File

@ -15,7 +15,6 @@ enum
SIDEWALK_2_NW,
SIDEWALK_2_NE,
SIDEWALK_3_NW,
SIDEWALK_3_N,
SIDEWALK_3_NE,
SIDEWALK_4_N,
@ -25,7 +24,6 @@ enum
SIDEWALK_2_SW,
SIDEWALK_2_SE,
SIDEWALK_3_SW,
SIDEWALK_3_S,
SIDEWALK_3_SE,
SIDEWALK_4_C,
@ -49,7 +47,6 @@ enum
ROOF1_2_NE,
ROOF1_3_NW,
ROOF1_3_N,
ROOF1_3_NE,
ROOF1_4_N,
ROOF1_1_W,
@ -58,7 +55,6 @@ enum
ROOF1_2_SW,
ROOF1_2_SE,
ROOF1_3_SW,
ROOF1_3_S,
ROOF1_3_SE,
ROOF1_4_C,
@ -82,7 +78,6 @@ enum
ROOF2_2_NE,
ROOF2_3_NW,
ROOF2_3_N,
ROOF2_3_NE,
ROOF2_4_N,
ROOF2_1_W,
@ -91,7 +86,6 @@ enum
ROOF2_2_SW,
ROOF2_2_SE,
ROOF2_3_SW,
ROOF2_3_S,
ROOF2_3_SE,
ROOF2_4_C,
@ -105,7 +99,111 @@ enum
ROOF2_4_S,
ROOF2_START = ROOF2_1_NW,
ROOF2_END = ROOF2_4_S
ROOF2_END = ROOF2_4_S,
/* PAVEMENT */
PAVEMENT_CW_H_MID,
PAVEMENT_STR_MID_H_1,
PAVEMENT_CW_V_LEFT,
PAVEMENT_CW_V_MID,
PAVEMENT_CW_V_RIGHT,
PAVEMENT_RND_NW,
PAVEMENT_RND_NE,
PAVEMENT_SP_NW,
PAVEMENT_SP_NE,
PAVEMENT_1,
PAVEMENT_P,
PAVEMENT_CW_H_TOP,
PAVEMENT_STR_H_TOP,
PAVEMENT_CW_H_DOWN,
PAVEMENT_STR_H_DOWN,
PAVEMENT_STR_V_LEFT,
PAVEMENT_STR_V_MID,
PAVEMENT_STR_V_RIGHT,
PAVEMENT_RND_SW,
PAVEMENT_RND_SE,
PAVEMENT_SP_SW,
PAVEMENT_SP_SE,
PAVEMENT_2,
PAVEMENT_BIKE,
PAVEMENT_PLUS,
PAVEMENT_EMPTY,
PAVEMENT_START = PAVEMENT_CW_H_MID,
PAVEMENT_END = PAVEMENT_EMPTY,
/* BUILDING1 */
BUILDING1_1_N,
BUILDING1_2_NW,
BUILDING1_2_N,
BUILDING1_2_NE,
BUILDING1_3_NW,
BUILDING1_3_N,
BUILDING1_3_NE,
BUILDING1_1_C_1,
BUILDING1_2_W_1,
BUILDING1_2_C_1,
BUILDING1_2_E_1,
BUILDING1_3_W_1,
BUILDING1_3_C_1,
BUILDING1_3_E_1,
BUILDING1_1_C_2,
BUILDING1_2_W_2,
BUILDING1_2_C_2,
BUILDING1_2_E_2,
BUILDING1_3_W_2,
BUILDING1_3_C_2,
BUILDING1_3_E_2,
BUILDING1_1_S,
BUILDING1_2_SW,
BUILDING1_2_S,
BUILDING1_2_SE,
BUILDING1_3_SW,
BUILDING1_3_S,
BUILDING1_3_SE,
BUILDING1_START = BUILDING1_1_N,
BUILDING1_END = BUILDING1_2_SE,
/* BUILDING2 */
BUILDING2_1_N,
BUILDING2_2_NW,
BUILDING2_2_N,
BUILDING2_2_NE,
BUILDING2_3_NW,
BUILDING2_3_N,
BUILDING2_3_NE,
BUILDING2_1_C_1,
BUILDING2_2_W_1,
BUILDING2_2_C_1,
BUILDING2_2_E_1,
BUILDING2_3_W_1,
BUILDING2_3_C_1,
BUILDING2_3_E_1,
BUILDING2_1_C_2,
BUILDING2_2_W_2,
BUILDING2_2_C_2,
BUILDING2_2_E_2,
BUILDING2_3_W_2,
BUILDING2_3_C_2,
BUILDING2_3_E_2,
BUILDING2_1_S,
BUILDING2_2_SW,
BUILDING2_2_S,
BUILDING2_2_SE,
BUILDING2_3_SW,
BUILDING2_3_S,
BUILDING2_3_SE,
BUILDING2_START = BUILDING2_1_N,
BUILDING2_END = BUILDING2_3_SE
};
enum
@ -119,7 +217,6 @@ enum
GRASS_2_NW,
GRASS_2_NE,
GRASS_3_NW,
GRASS_3_N,
GRASS_3_NE,
GRASS_4_N,
@ -129,7 +226,6 @@ enum
GRASS_2_SW,
GRASS_2_SE,
GRASS_3_SW,
GRASS_3_S,
GRASS_3_SE,
GRASS_4_C,

View File

@ -133,6 +133,8 @@ int terrain_init(const char *const path, struct terrain_map *const map)
FILE *const f = fopen(path, "rb");
unsigned w, h;
*map = (const struct terrain_map){0};
if (!f)
{
fprintf(stderr, "%s: fopen(3): %s\n", __func__, strerror(errno));

View File

@ -22,7 +22,7 @@ struct tile
static int render_tile(const unsigned char id, const short x,
const short y, const struct tile *const tiles, const size_t n)
{
for (size_t i = 0; i < n / n; i++)
for (size_t i = 0; i < n; i++)
{
const struct tile *const rt = &tiles[i];
@ -37,7 +37,8 @@ static int render_tile(const unsigned char id, const short x,
}
const unsigned char pos = id - rt->start;
const short tx = pos % TERRAIN_SZ, ty = pos / TERRAIN_SZ;
const short tx = pos % (s->w / TERRAIN_SZ),
ty = (pos * TERRAIN_SZ) / s->w;
s->x = x;
s->y = y;
@ -67,7 +68,10 @@ static int render_ground(const struct terrain_tile *const t, const short x,
#define TILE(t) {.s = &terrain_sprites[t], .start = t##_START, .end = t##_END}
TILE(SIDEWALK),
TILE(ROOF1),
TILE(ROOF2)
TILE(ROOF2),
TILE(PAVEMENT),
TILE(BUILDING1),
TILE(BUILDING2)
#undef TILE
};

View File

@ -33,17 +33,14 @@ struct unit
{
struct instance instance;
enum unit_type type;
const char *name;
enum unit_dir
{
UNIT_DIR_N,
UNIT_DIR_NE,
UNIT_DIR_E,
UNIT_DIR_SE,
UNIT_DIR_S,
UNIT_DIR_SW,
UNIT_DIR_W,
UNIT_DIR_NW
UNIT_DIR_S,
UNIT_DIR_N,
UNIT_DIR_E
} dir;
enum unit_state state;
@ -61,7 +58,12 @@ UTIL_STATIC_ASSERT(!offsetof(struct unit, instance), "must be at offset zero");
struct unit_cfg
{
enum unit_type type;
enum
{
UNIT_CFG_TYPE_WALKER,
UNIT_CFG_TYPE_CAR
} type;
unsigned long x, y;
};
@ -72,7 +74,6 @@ 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);
void unit_update(struct unit *u);
const char *unit_str(const struct unit *u);
enum
{
@ -82,6 +83,8 @@ enum
UNIT_4_SPRITE,
UNIT_5_SPRITE,
UNIT_6_SPRITE,
UNIT_CAR_1_SPRITE,
UNIT_CAR_2_SPRITE,
MAX_UNIT_SPRITES
};

View File

@ -3,6 +3,15 @@
enum unit_type
{
UNIT_TYPE_1,
UNIT_TYPE_2,
UNIT_TYPE_3,
UNIT_TYPE_4,
UNIT_TYPE_5,
UNIT_TYPE_6,
UNIT_TYPE_CAR_1,
UNIT_TYPE_CAR_2,
MAX_UNIT_TYPES
};

View File

@ -11,7 +11,7 @@
struct sprite unit_sprites[MAX_UNIT_SPRITES];
struct sound unit_sounds[MAX_UNIT_SOUNDS];
enum {N_FRAMES = 5};
static const unsigned char anim[] = {0, 1, 0, 2};
static void move_unit(struct unit *const u, const fix16_t sx, const fix16_t sy)
{
@ -21,38 +21,18 @@ static void move_unit(struct unit *const u, const fix16_t sx, const fix16_t sy)
u->ry -= sy;
break;
case UNIT_DIR_NE:
u->rx += sx;
u->ry -= sy;
break;
case UNIT_DIR_E:
u->rx += sx;
break;
case UNIT_DIR_SE:
u->rx += sx;
u->ry += sy;
break;
case UNIT_DIR_S:
u->ry += sy;
break;
case UNIT_DIR_SW:
u->rx -= sx;
u->ry += sy;
break;
case UNIT_DIR_W:
u->rx -= sx;
break;
case UNIT_DIR_NW:
u->rx -= sx;
u->ry -= sy;
break;
default:
break;
}
@ -61,17 +41,51 @@ static void move_unit(struct unit *const u, const fix16_t sx, const fix16_t sy)
static void get_speed(const struct unit *const u, fix16_t *const x,
fix16_t *const y)
{
static const struct speed
struct speed
{
fix16_t x, y;
} speed[1];
} s;
switch (u->type)
{
case UNIT_TYPE_1:
case UNIT_TYPE_2:
case UNIT_TYPE_3:
case UNIT_TYPE_4:
case UNIT_TYPE_5:
case UNIT_TYPE_6:
{
static const struct speed ref =
{
.x = FIX16_C_FROM_FLOAT(0.4),
.y = FIX16_C_FROM_FLOAT(0.4)
};
s = ref;
}
break;
case UNIT_TYPE_CAR_1:
case UNIT_TYPE_CAR_2:
{
static const struct speed ref =
{
.x = FIX16_C_FROM_FLOAT(1.5),
.y = FIX16_C_FROM_FLOAT(1.5)
};
s = ref;
}
case MAX_UNIT_TYPES:
break;
}
const struct speed *const s = &speed[u->type];
const int dx = abs(u->rx - u->tx);
const int dy = abs(u->ry - u->ty);
*x = dx < s->x ? dx : s->x;
*y = dy < s->y ? dy : s->y;
*x = dx < s.x ? dx : s.x;
*y = dy < s.y ? dy : s.y;
}
static enum unit_dir get_direction(const struct unit *const u)
@ -79,18 +93,7 @@ static enum unit_dir get_direction(const struct unit *const u)
const fix16_t x = u->rx, y = u->ry, tx = u->tx, ty = u->ty;
enum unit_dir dir = 0;
if (x != tx && y != ty)
{
if (x > tx && y > ty)
dir = UNIT_DIR_NW;
else if (x < tx && y > ty)
dir = UNIT_DIR_NE;
else if (x < tx && y < ty)
dir = UNIT_DIR_SE;
else
dir = UNIT_DIR_SW;
}
else if (x != tx)
if (x != tx)
{
if (x > tx)
dir = UNIT_DIR_W;
@ -155,7 +158,7 @@ static bool must_move(const struct unit *const u)
void unit_update(struct unit *const u)
{
const struct instance *const i = &u->instance;
struct instance *const i = &u->instance;
if (!i->alive)
return;
@ -170,13 +173,13 @@ void unit_update(struct unit *const u)
get_speed(u, &x_step, &y_step);
move_unit(u, x_step, y_step);
enum {FRAME_RATE = 6};
enum {FRAME_RATE = 10};
if (++u->frame.t >= FRAME_RATE)
{
u->frame.t = 0;
if (++u->frame.i >= N_FRAMES)
if (++u->frame.i >= sizeof anim / sizeof *anim)
u->frame.i = 0;
}
@ -185,8 +188,8 @@ void unit_update(struct unit *const u)
else
u->frame.i = 0;
u->instance.r.x = fix16_to_int(u->rx);
u->instance.r.y = fix16_to_int(u->ry);
i->r.x = fix16_to_int(u->rx);
i->r.y = fix16_to_int(u->ry);
}
void unit_set_target(struct unit *const u, const struct unit_target *const t)
@ -209,198 +212,101 @@ 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;
}
static int get_ux(const struct unit *const u)
static void adjust_walker(const struct unit *const u, struct sprite *const s,
struct instance_render_off *const off)
{
s->w = u->instance.r.w;
s->h = u->instance.r.h;
s->u += u->dir * s->w;
s->v += anim[u->frame.i] * s->h;
off->x = 0;
off->y = -2;
}
static void adjust_car(const struct unit *const u, struct sprite *const s,
struct instance_render_off *const off)
{
switch (u->dir)
{
case UNIT_DIR_N:
return 0;
case UNIT_DIR_NE:
/* Fall through. */
case UNIT_DIR_NW:
return 1;
case UNIT_DIR_E:
/* Fall through. */
case UNIT_DIR_W:
return 2;
case UNIT_DIR_SE:
/* Fall through. */
case UNIT_DIR_SW:
return 3;
s->w = s->h = 32;
s->u += 32;
off->x = -5;
break;
case UNIT_DIR_S:
return 4;
s->w = 16;
s->h = 32;
off->x = 2;
break;
default:
case UNIT_DIR_N:
s->u += 16;
s->w = 16;
s->h = 32;
off->x = 2;
break;
case UNIT_DIR_E:
s->w = s->h = 32;
s->u += 64;
off->x = -5;
break;
}
return -1;
off->y = -10;
}
typedef const struct
static void adjust_sprite(const struct unit *const u, struct sprite *const s,
struct instance_render_off *const off)
{
const struct sprite *s;
char xo, x[N_FRAMES], w[N_FRAMES];
short y;
short h;
} anim_dim;
static anim_dim *peasant_anim(const struct unit *const u)
{
#if 0
static anim_dim t[] =
switch (u->type)
{
{
.s = &unit_sprites[UNIT_SPRITE_N],
.xo = 5,
.x = {0, 1, 1, 2, 1},
.w = {25, 22, 24, 22, 24},
.y = 2,
.h = 31
},
{
.s = &unit_sprites[UNIT_SPRITE_NE],
.xo = 11,
.x = {0, -4, -1, -4, -2},
.w = {18, 26, 22, 23, 20},
.y = 2,
.h = 31
},
{
.s = &unit_sprites[UNIT_SPRITE_E],
.xo = 10,
.x = {0, -6, -1, -6, -3},
.w = {14, 26, 17, 24, 19},
.y = 2,
.h = 33
},
{
.s = &unit_sprites[UNIT_SPRITE_SE],
.xo = 6,
.x = {0, 1, 2, 0, 0},
.w = {20, 22, 18, 21, 21},
.y = 2,
.h = 31
},
{
.s = &unit_sprites[UNIT_SPRITE_S],
.xo = 7,
.x = {0, 1, 0, 0, 0},
.w = {24, 23, 24, 23, 24},
.y = 2,
.h = 33
}
};
const int ux = get_ux(u);
if (ux < 0)
return NULL;
return &t[ux];
#else
return NULL;
#endif
}
struct render_cfg
{
struct instance_render_off off;
struct instance_render_quad qcfg;
};
static anim_dim *peasant_quad(const struct unit *const u)
{
return peasant_anim(u);
}
static void adjust_quad(const struct unit *const u, anim_dim *const dim,
struct render_cfg *const rcfg)
{
const unsigned char n = u->frame.i;
short u_off = 0;
for (unsigned char i = 0; i < n; i++)
u_off += dim->w[i];
struct instance_render_quad *const qcfg = &rcfg->qcfg;
qcfg->u = u_off;
qcfg->w = dim->w[n];
qcfg->h = dim->h;
struct instance_render_off *const off = &rcfg->off;
off->x = dim->xo;
off->y = dim->y;
switch (u->dir)
{
case UNIT_DIR_SW:
/* Fall through. */
case UNIT_DIR_W:
/* Fall through. */
case UNIT_DIR_NW:
qcfg->xflip = true;
off->x += dim->x[n];
case UNIT_TYPE_1:
case UNIT_TYPE_2:
case UNIT_TYPE_3:
case UNIT_TYPE_4:
case UNIT_TYPE_5:
case UNIT_TYPE_6:
adjust_walker(u, s, off);
break;
default:
qcfg->xflip = false;
off->x += dim->x[n];
case UNIT_TYPE_CAR_1:
case UNIT_TYPE_CAR_2:
adjust_car(u, s, off);
break;
case MAX_UNIT_TYPES:
break;
}
}
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[1])(const struct unit *);
anim_dim *const dim = f[u->type](u);
if (!dim)
return -1;
adjust_quad(u, dim, rcfg);
if (quad_from_sprite(dim->s, qcfg->q))
return -1;
return 0;
}
int unit_render(const struct unit *const u, const struct camera *const cam,
const bool sel)
{
if (!u->instance.alive)
return 0;
struct render_cfg rcfg;
sprite_get_or_ret(s, -1);
quad_get_or_ret(q, -1);
rcfg.qcfg.q = q;
struct instance_render_off off;
if (unit_quad(u, &rcfg))
if (sprite_clone(&unit_sprites[u->type], s))
{
fprintf(stderr, "%s: sprite_clone failed\n", __func__);
return -1;
}
adjust_sprite(u, s, &off);
const struct instance_render_cfg cfg =
{
.i = &u->instance,
.prim_type = INSTANCE_RENDER_CFG_QUAD,
.prim = {.quad = &rcfg.qcfg},
.prim_type = INSTANCE_RENDER_CFG_SPRITE,
.prim.s = s,
.off = &off,
.cam = cam,
.sel = sel,
.off = &rcfg.off
.sel = sel
};
return instance_render(&cfg);
@ -409,40 +315,159 @@ int unit_render(const struct unit *const u, const struct camera *const cam,
static void get_dimensions(const enum unit_type type, short *const w,
short *const h)
{
static const struct dim
switch (type)
{
short w, h;
} dim[1];
case UNIT_TYPE_1:
case UNIT_TYPE_2:
case UNIT_TYPE_3:
case UNIT_TYPE_4:
case UNIT_TYPE_5:
case UNIT_TYPE_6:
*w = *h = 16;
break;
const struct dim *const d = &dim[type];
*w = d->w;
*h = d->h;
case UNIT_TYPE_CAR_1:
case UNIT_TYPE_CAR_2:
*w = *h = 22;
break;
case MAX_UNIT_TYPES:
break;
}
}
static const char *get_walker_name(const enum unit_type type)
{
enum {FEMALE, MALE} gender = 0;
switch (type)
{
case UNIT_TYPE_2:
case UNIT_TYPE_5:
gender = FEMALE;
break;
case UNIT_TYPE_1:
case UNIT_TYPE_3:
case UNIT_TYPE_4:
case UNIT_TYPE_6:
gender = MALE;
break;
default:
return NULL;
}
static const char *const female[] =
{
"Amelia",
"Asher",
"Aurora",
"Ava",
"Charlotte",
"Dana",
"Ellie",
"Emma",
"Ezra",
"Haley",
"Harper",
"Isabella",
"Luna",
"Mire",
"Olivia",
"Sophia",
};
static const char *const male[] =
{
"Oliver",
"Xavi",
"Benjamin",
"Elijah",
"Ethan",
"Jack",
"James",
"Jan",
"Kyte",
"Leo",
"Levi",
"Liam",
"Luca",
"Lucas",
"Michael",
"Noah",
};
switch (gender)
{
case FEMALE:
{
const size_t i = rand() % (sizeof female / sizeof *female);
return female[i];
}
case MALE:
{
const size_t i = rand() % (sizeof male / sizeof *male);
return male[i];
}
}
return NULL;
}
static const char *get_name(const enum unit_type type)
{
switch (type)
{
case UNIT_TYPE_1:
case UNIT_TYPE_2:
case UNIT_TYPE_3:
case UNIT_TYPE_4:
case UNIT_TYPE_5:
case UNIT_TYPE_6:
return get_walker_name(type);
case UNIT_TYPE_CAR_1:
case UNIT_TYPE_CAR_2:
return "Car";
case MAX_UNIT_TYPES:
break;
}
return NULL;
}
void unit_create(const struct unit_cfg *const cfg, struct unit *const u)
{
struct instance *const i = &u->instance;
enum unit_type type = 0;
switch (cfg->type)
{
case UNIT_CFG_TYPE_WALKER:
type = UNIT_TYPE_1 + (rand() % (UNIT_TYPE_6 + 1));
break;
case UNIT_CFG_TYPE_CAR:
type = UNIT_TYPE_CAR_1 + (rand()
% (UNIT_TYPE_CAR_2 - UNIT_TYPE_CAR_1 + 1));
break;
}
*u = (const struct unit)
{
.instance =
{
.alive = true,
},
.type = cfg->type,
.instance.alive = true,
.dir = UNIT_DIR_S,
.rx = fix16_from_int(cfg->x),
.ry = fix16_from_int(cfg->y)
.ry = fix16_from_int(cfg->y),
.type = type,
.name = get_name(type)
};
get_dimensions(cfg->type, &i->r.w, &i->r.h);
get_dimensions(u->type, &i->r.w, &i->r.h);
unit_stop(u);
}
const char *unit_str(const struct unit *const u)
{
static const char *const str[1];
return str[u->type];
}