+1
include/keraforge.h
+1
include/keraforge.h
+31
include/keraforge/state.h
+31
include/keraforge/state.h
···
1
+
#ifndef __kf_state__
2
+
#define __kf_state__
3
+
4
+
5
+
#include <keraforge/actor.h>
6
+
7
+
8
+
#define KF_NPCPOOL_SIZE 1024
9
+
10
+
11
+
/* Stores global variables to be saved alongside the world. Use this for save data.
12
+
Do not use pointers here! This gets transmuted into a u8 array for serialization. */
13
+
struct kf_state
14
+
{
15
+
/* Do not modify this and do not relocate it. See kf_world for an explanation. */
16
+
u16 revision;
17
+
/* Player data */
18
+
struct {
19
+
struct kf_vec2(f32) pos;
20
+
} player;
21
+
// struct kf_actor npc[KF_NPCPOOL_SIZE];
22
+
};
23
+
24
+
25
+
/* Save a state. */
26
+
int kf_state_save(struct kf_state *state);
27
+
/* Load a state. Returns 1 if the state was freshly created and 0 if an existing state was loaded. */
28
+
int kf_state_load(struct kf_state **pstate);
29
+
30
+
31
+
#endif
+82
-63
src/main.c
+82
-63
src/main.c
···
1
+
#include "keraforge/world.h"
1
2
#include <keraforge.h>
2
3
#include <raylib.h>
3
4
#include <raymath.h>
···
19
20
} modal;
20
21
static char *modals[] = { "play", "edit" };
21
22
static bool dirty = false;
22
-
static bool preserve_mapdotbin = false;
23
23
24
24
static kf_inputbind_t
25
25
inputbind_move_up,
···
44
44
45
45
46
46
static
47
-
void loadbinds()
47
+
void loadbinds(void)
48
48
{
49
49
inputbind_move_up = kf_addinput("move_up", KEY_W, KEY_NULL, MOUSE_BUTTON_UNKNOWN, GAMEPAD_BUTTON_UNKNOWN, GAMEPAD_AXIS_LEFT_Y);
50
50
inputbind_move_down = kf_addinput("move_down", KEY_S, KEY_NULL, MOUSE_BUTTON_UNKNOWN, GAMEPAD_BUTTON_UNKNOWN, GAMEPAD_AXIS_LEFT_Y);
···
69
69
70
70
inputbind_toggle_fps_limit = kf_addinput("toggle_fps_limit", KEY_NINE, KEY_NULL, MOUSE_BUTTON_UNKNOWN, GAMEPAD_BUTTON_UNKNOWN, GAMEPAD_AXIS_UNKNOWN);
71
71
inputbind_toggle_editor = kf_addinput("toggle_editor", KEY_EIGHT, KEY_NULL, MOUSE_BUTTON_UNKNOWN, GAMEPAD_BUTTON_UNKNOWN, GAMEPAD_AXIS_UNKNOWN);
72
+
}
73
+
74
+
static
75
+
void loadtiles(struct kf_spritesheet *terrain)
76
+
{
77
+
KF_ADDTILE(
78
+
.key = "grass",
79
+
.mapcol = GREEN,
80
+
.sheet = terrain,
81
+
.sprite = {0, 0},
82
+
);
83
+
KF_ADDTILE(
84
+
.key = "sand",
85
+
.mapcol = YELLOW,
86
+
.sheet = terrain,
87
+
.sprite = {4, 0},
88
+
);
89
+
KF_ADDTILE(
90
+
.key = "stone",
91
+
.mapcol = GRAY,
92
+
.sheet = terrain,
93
+
.sprite = {0, 4},
94
+
);
95
+
KF_ADDTILE(
96
+
.key = "debug",
97
+
.mapcol = BLUE,
98
+
.sheet = terrain,
99
+
.sprite = {4, 4},
100
+
);
101
+
KF_ADDTILE(
102
+
.key = "brick",
103
+
.mapcol = RED,
104
+
.sheet = terrain,
105
+
.sprite = {8, 0},
106
+
.collide = true,
107
+
);
108
+
KF_ADDTILE(
109
+
.key = "ice",
110
+
.mapcol = BLUE,
111
+
.sheet = terrain,
112
+
.sprite = {8, 4},
113
+
.transparent = true,
114
+
);
115
+
KF_ADDTILE(
116
+
.key = "dirt",
117
+
.mapcol = BROWN,
118
+
.sheet = terrain,
119
+
.sprite = {12, 0},
120
+
);
121
+
KF_ADDTILE(
122
+
.key = "torch",
123
+
.mapcol = ORANGE,
124
+
.sheet = terrain,
125
+
.sprite = {12, 4},
126
+
.transparent = true,
127
+
);
128
+
kf_logdbg("loaded %d tiles", kf_tiles.count);
72
129
}
73
130
74
131
static
···
207
264
loadbinds();
208
265
209
266
struct kf_spritesheet terrain = kf_loadspritesheet("data/res/img/tile/terrain.png", 16, 16);
210
-
KF_ADDTILE(
211
-
.key = "grass",
212
-
.mapcol = GREEN,
213
-
.sheet = &terrain,
214
-
.sprite = {0, 0},
215
-
);
216
-
KF_ADDTILE(
217
-
.key = "sand",
218
-
.mapcol = YELLOW,
219
-
.sheet = &terrain,
220
-
.sprite = {4, 0},
221
-
);
222
-
KF_ADDTILE(
223
-
.key = "stone",
224
-
.mapcol = GRAY,
225
-
.sheet = &terrain,
226
-
.sprite = {0, 4},
227
-
);
228
-
KF_ADDTILE(
229
-
.key = "debug",
230
-
.mapcol = BLUE,
231
-
.sheet = &terrain,
232
-
.sprite = {4, 4},
233
-
);
234
-
KF_ADDTILE(
235
-
.key = "brick",
236
-
.mapcol = RED,
237
-
.sheet = &terrain,
238
-
.sprite = {8, 0},
239
-
.collide = true,
240
-
);
241
-
KF_ADDTILE(
242
-
.key = "ice",
243
-
.mapcol = BLUE,
244
-
.sheet = &terrain,
245
-
.sprite = {8, 4},
246
-
.transparent = true,
247
-
);
248
-
KF_ADDTILE(
249
-
.key = "dirt",
250
-
.mapcol = BROWN,
251
-
.sheet = &terrain,
252
-
.sprite = {12, 0},
253
-
);
254
-
kf_logdbg("loaded %d tiles", kf_tiles.count);
267
+
loadtiles(&terrain);
255
268
256
269
struct kf_uiconfig *uiconfig = kf_ui_getconfig();
257
270
uiconfig->select = inputbind_select;
···
262
275
if (!DirectoryExists("data"))
263
276
MakeDirectory("data");
264
277
278
+
struct kf_state *state = NULL;
279
+
int is_new_state = kf_state_load(&state);
280
+
265
281
struct kf_world *world = NULL;
266
282
kf_world_load(&world, true);
267
283
if (!world)
268
-
KF_THROW("failed to load world: %p", world);
284
+
KF_THROW("failed to load world");
269
285
270
286
struct kf_actor *player = kf_actor_new(kf_actor_loadspritesheet("data/res/img/char/template.png"), 10, 10, true);
271
287
player->sizeoffset.y = 6;
272
-
player->pos.x = world->width / 4.0f * KF_TILE_SIZE_PX;
273
-
player->pos.y = world->height / 4.0f * KF_TILE_SIZE_PX;
274
288
player->tick = _player_tick;
275
289
player->draw = _player_draw;
276
290
player->controlled = true;
291
+
if (is_new_state)
292
+
{
293
+
state->player.pos.x = world->width * KF_TILE_SIZE_PX / 2.0f;
294
+
state->player.pos.y = world->width * KF_TILE_SIZE_PX / 2.0f;
295
+
}
296
+
player->pos.x = state->player.pos.x;
297
+
player->pos.y = state->player.pos.y;
298
+
kf_loginfo("pos: %f,%f", player->pos.x, player->pos.y);
277
299
278
300
cam = (Camera2D){0};
279
301
cam.offset.x = GetScreenWidth() / 2.0f;
280
302
cam.offset.y = GetScreenHeight() / 2.0f;
303
+
cam.target.x = player->pos.x + (player->size.x / 2);
304
+
cam.target.y = player->pos.y + (player->size.y / 2);
281
305
cam.zoom = 2;
282
306
283
307
int running = 1;
···
368
392
kf_s += kf_dts;
369
393
}
370
394
371
-
if (world)
372
-
{
373
-
if (dirty)
374
-
{
375
-
if (!kf_writebin("data/tmp/map.bin", (u8 *)world, kf_world_getsize(world)))
376
-
KF_THROW("failed to save map.bin");
377
-
if (!kf_compress("data/tmp/map.bin", "data/map.bin.xz"))
378
-
KF_THROW("failed to compress map.bin into map.bin.xz");
379
-
if (!preserve_mapdotbin)
380
-
remove("data/tmp/map.bin");
381
-
}
382
-
free(world);
383
-
}
395
+
state->player.pos = player->pos;
396
+
kf_state_save(state);
397
+
free(state);
398
+
399
+
if (dirty)
400
+
kf_world_save(world, true);
401
+
free(world);
402
+
384
403
CloseWindow();
385
404
386
405
return 0;
+43
src/state.c
+43
src/state.c
···
1
+
#include <keraforge.h>
2
+
3
+
4
+
#define _KF_STATEFILE "data/state.bin"
5
+
6
+
int kf_state_save(struct kf_state *state)
7
+
{
8
+
if (!kf_writebin(_KF_STATEFILE, (u8 *)state, sizeof(*state)))
9
+
{
10
+
KF_THROW("failed to write to %s", _KF_STATEFILE);
11
+
return 0; /* unreachable */
12
+
}
13
+
14
+
return 1;
15
+
}
16
+
17
+
int kf_state_load(struct kf_state **pstate)
18
+
{
19
+
char *infile = _KF_STATEFILE;
20
+
kf_logdbg("loading state: %s", infile);
21
+
22
+
int res = 0;
23
+
24
+
if (!kf_exists(infile))
25
+
{
26
+
kf_logdbg("creating state...");
27
+
struct kf_state s = {0};
28
+
kf_state_save(&s);
29
+
res = 1;
30
+
}
31
+
32
+
size_t len = 0;
33
+
*pstate = (struct kf_state *)kf_readbin(infile, &len);
34
+
kf_logdbg("loaded state (%p): len=%lu (res=%d)", *pstate, len, res);
35
+
36
+
if (!*pstate)
37
+
{
38
+
KF_THROW("failed to load state");
39
+
return -1; /* unreachable */
40
+
}
41
+
42
+
return res;
43
+
}
+4
-3
src/world.c
+4
-3
src/world.c
···
35
35
{
36
36
const size_t len = sizeof(struct kf_world) + sizeof(struct kf_tile)*width*height;
37
37
struct kf_world *world = malloc(len);
38
-
kf_loginfo("creating world: %lu bytes: %p\n", len, world);
38
+
kf_loginfo("creating world: %lu bytes: %p", len, world);
39
39
world->revision = 0;
40
40
world->width = width;
41
41
world->height = height;
···
215
215
216
216
tile++; /* shift tile pointer to the right */
217
217
}
218
+
218
219
tile += down; /* shift tile pointer down */
219
220
}
220
221
}
···
269
270
270
271
size_t len = 0;
271
272
*pworld = (struct kf_world *)kf_readbin(infile, &len);
272
-
kf_logdbg("loaded world (%p): r=%d, wh=%dx%d, len=%lu", pworld, (*pworld)->revision, (*pworld)->width, (*pworld)->height, len);
273
+
kf_logdbg("loaded world (%p): r=%d, wh=%dx%d, len=%lu", *pworld, (*pworld)->revision, (*pworld)->width, (*pworld)->height, len);
273
274
274
275
if (compressed)
275
276
{
···
277
278
remove(_KF_MAPFILE_TMP);
278
279
}
279
280
280
-
if (!pworld)
281
+
if (!*pworld)
281
282
{
282
283
KF_THROW("failed to load world");
283
284
return 0; /* unreachable */