Big rushed update
|
@ -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).
|
||||
|
||||
|
|
After Width: | Height: | Size: 9.5 KiB |
|
@ -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
|
||||
)
|
||||
|
|
BIN
res/btn_left.bmp
Before Width: | Height: | Size: 586 B |
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 1.6 KiB |
BIN
res/btn_mid.bmp
Before Width: | Height: | Size: 542 B |
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 586 B |
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 1.6 KiB |
After Width: | Height: | Size: 490 B |
After Width: | Height: | Size: 1.7 KiB |
After Width: | Height: | Size: 9.1 KiB |
After Width: | Height: | Size: 9.1 KiB |
After Width: | Height: | Size: 2.0 KiB |
|
@ -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
|
||||
|
|
After Width: | Height: | Size: 8.0 KiB |
After Width: | Height: | Size: 47 KiB |
|
@ -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()
|
||||
|
|
After Width: | Height: | Size: 1.6 KiB |
After Width: | Height: | Size: 1.6 KiB |
After Width: | Height: | Size: 1.6 KiB |
After Width: | Height: | Size: 822 B |
After Width: | Height: | Size: 822 B |
After Width: | Height: | Size: 822 B |
After Width: | Height: | Size: 150 B |
After Width: | Height: | Size: 182 B |
After Width: | Height: | Size: 822 B |
After Width: | Height: | Size: 822 B |
BIN
res/unit5_24.bmp
Before Width: | Height: | Size: 9.1 KiB After Width: | Height: | Size: 9.1 KiB |
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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],
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -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");
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@ struct mouse
|
|||
{
|
||||
short x, y, dx, dy;
|
||||
int mask, oldmask;
|
||||
bool first_clicked, hovering;
|
||||
};
|
||||
|
||||
void mouse_init(struct mouse *m);
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -25,7 +25,7 @@ union peripheral
|
|||
struct peripheral_common
|
||||
{
|
||||
enum peripheral_type type;
|
||||
bool exit;
|
||||
bool init, exit;
|
||||
} common;
|
||||
|
||||
struct peripheral_pad
|
||||
|
|
|
@ -18,4 +18,5 @@ target_link_libraries(player
|
|||
util
|
||||
PRIVATE
|
||||
pad
|
||||
gui)
|
||||
gui
|
||||
terrain)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -18,7 +18,7 @@ typedef unsigned player_team;
|
|||
|
||||
enum
|
||||
{
|
||||
PLAYER_MAX_UNITS = 5,
|
||||
PLAYER_MAX_UNITS = 10,
|
||||
PLAYER_MAX_BUILDINGS = 5
|
||||
};
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
};
|
||||
|
|
|
@ -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,
|
||||
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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
|
||||
};
|
||||
|
||||
|
|
|
@ -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
|
||||
};
|
||||
|
|
|
@ -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
|
||||
};
|
||||
|
||||
|
|
|
@ -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];
|
||||
}
|
||||
|
|