+10
-1
.gitignore
+10
-1
.gitignore
+1
compile_flags.txt
+1
compile_flags.txt
+56
etc/style.c
+56
etc/style.c
···
1
+
#ifndef __main__
2
+
#define __main__
3
+
4
+
5
+
/*
6
+
Include order doesn't really matter to me, however I do like to keep them reasonably organized:
7
+
1. "Header" includes (i.e, keraforge/_header.h).
8
+
2. Macro/common headers (i.e, keraforge/log.h).
9
+
3. Internal library includes (i.e, keraforge/*.h).
10
+
4. External library includes (i.e, raylib.h, raymath.h, etc).
11
+
5. C standard library includes.
12
+
*/
13
+
#include <keraforge.h>
14
+
#include <stdio.h>
15
+
16
+
17
+
/*
18
+
Please follow good practice when defining macros:
19
+
- #undef after usage.
20
+
- Use do/while blocks for parameterized macros.
21
+
- Wrap constant macros in parenthesis, unless its a string that can be safely concatenated.
22
+
*/
23
+
24
+
25
+
/* Additional keywords (excl. const) should be on their own line. */
26
+
static
27
+
/* All public items should be prefixed with kf_. All static items should use _kf_. */
28
+
int _kf_parse(int argc, /* Attach pointers with the identifier, not the type. */ char *argv[])
29
+
/* Allman braces */
30
+
{
31
+
/* Tabs for indentation, spaces for alignment. */
32
+
33
+
/* Space out your semicolons in for loops. */
34
+
for (int i = 0 ; i < argc ; i++)
35
+
fprintf(stderr, "%s", argv[i]);
36
+
37
+
if (true)
38
+
{
39
+
/* ... */
40
+
}
41
+
else
42
+
{
43
+
/* ... */
44
+
}
45
+
46
+
return 1;
47
+
}
48
+
49
+
int main(void)
50
+
{
51
+
(void)_kf_parse(0, NULL);
52
+
return 0;
53
+
}
54
+
55
+
56
+
#endif
+73
etc/style.txt
+73
etc/style.txt
···
1
+
2
+
Style Guidelines
3
+
================
4
+
5
+
As a preface: I break these guidelines occasionally. It is
6
+
important to note that I often find myself up into the
7
+
early morning hours (sometimes even as early as 03:00)
8
+
developing Keraforge. Late-night coding sessions tend to
9
+
lead to mistakes that I accidentally push to prod. Feel
10
+
free to point these mistakes out to me!
11
+
12
+
Zen
13
+
---
14
+
15
+
1. Keep types simple.
16
+
- If your type is complex enough to be unreadable, maybe
17
+
you should change your type.
18
+
- Function pointers may be disgraceful to write, but if
19
+
you write your code in such a way that avoids writing
20
+
the type more than once then you'll be fine.
21
+
- See: `struct kf_actorregistry`. I use some quirky
22
+
types there, but nothing too unreadable. Notice how I
23
+
never rewrite those types again and notice that I am not
24
+
using a typedef either.
25
+
- Additionally, if the user is never going to use that
26
+
type then it almost definitely does not need to be
27
+
typedef'd.
28
+
2. Documentation is important.
29
+
- "Self-documenting code" is not sufficient. If the item
30
+
is public then it should have an explanation.
31
+
- The ONLY exceptions to this rule are blatantly obvious
32
+
struct fields, such as `position`, `velocity`, etc.
33
+
- A few lines of documentation will save you a massive
34
+
headache in the future.
35
+
3. Macro magic is garbage, but unmaintainable code is worse.
36
+
- Using macro magic sparingly can help prevent you from
37
+
being smitten by the DRY deities. Save yourself today!
38
+
- See: math.h, log.h, and bini.h for cases where macro
39
+
magic is acceptable.
40
+
4. Keep names terse but readable.
41
+
- I don't want to see stdlib-style function names, but I
42
+
would much rather that over a name ripped from an
43
+
object-oriented C.
44
+
- If you must use a stdlib-style function name to remain
45
+
terse, then please provide a sentence in its docs to
46
+
explain the name.
47
+
5. Most importantly: Be simple.
48
+
- This often means sitting at your screen pondering the
49
+
best implementation for something rather than simply
50
+
using the first one that comes to mind.
51
+
- It's okay to sacrifice a bit of performance for more
52
+
maintainable code.
53
+
- If you must write complex code, please explain why via
54
+
a brief comment.
55
+
56
+
Basics
57
+
------
58
+
59
+
See <etc/style.c> for a sample of the style with comments
60
+
explaining each main point.
61
+
62
+
For more specifics, please give a skim throughout the
63
+
codebase itself.
64
+
65
+
- Prefer [iuf](8|16|32|64) over (float|double|(u?int(8|16|32|64)_t)).
66
+
- Do not typedef function pointers (see Zen #1), structs, enums, or unions.
67
+
- Use global variables instead of requiring the user to maintain state.
68
+
See: kf_uiconfig, kf_actors, kf_actorregistry, kf_state, etc.
69
+
- Use `struct kf_vec2(type)` instead of `struct kf_vec2f32`.
70
+
- Do not modify libraries included in the source.
71
+
Those are: bini.h.
72
+
- I'm not afraid to postfix _t to typedef'd types. The standard is useless here since we prefix kf_ anyway.
73
+
(I think this standard is useless *to begin with*, but I digress)
+11
-9
include/keraforge/actor.h
+11
-9
include/keraforge/actor.h
···
2
2
#define __kf_actor__
3
3
4
4
5
-
#include "keraforge/bini.h"
6
5
#include <keraforge/_header.h>
7
6
#include <keraforge/math.h>
8
7
#include <keraforge/world.h>
9
8
#include <keraforge/math.h>
10
9
#include <keraforge/sprites.h>
10
+
#include <keraforge/bini.h>
11
11
#include <raylib.h>
12
12
13
13
···
19
19
TODO: This will probably be better as a hash table (especially for kf_actor_getregistryid). */
20
20
struct kf_actorregistry
21
21
{
22
+
/* Amount of actor types currently registered. */
22
23
int count;
24
+
/* Keys for each actor. */
23
25
char *key[KF_MAX_ACTOR_TYPES];
24
-
/* Save the actor to a binary stream. */
26
+
/* Save actor to a binary stream. */
25
27
void (*serialize[KF_MAX_ACTOR_TYPES])(struct kf_actor *self, struct bini_stream *bs);
26
-
/* Load the actor from a binary stream. */
28
+
/* Load actor from a binary stream. */
27
29
void (*deserialize[KF_MAX_ACTOR_TYPES])(struct kf_actor *self, struct bini_stream *bs);
28
-
/* Called every frame to update the actor. Don't forget about deltatime (kf_dts, kf_dtms)! */
30
+
/* Called every frame to update actor. Don't forget about deltatime (kf_dts, kf_dtms)! */
29
31
void (*tick[KF_MAX_ACTOR_TYPES])(struct kf_actor *self);
30
-
/* Called every frame to render the actor. */
32
+
/* Called every frame to render actor. */
31
33
void (*draw[KF_MAX_ACTOR_TYPES])(struct kf_actor *self);
32
-
/* Spritesheet for the actor. */
34
+
/* Spritesheet for actor. */
33
35
struct kf_spritesheet sprite[KF_MAX_ACTOR_TYPES];
34
36
};
35
37
/* Global actor registry instance. */
···
38
40
/* Represents any kinematic body in the world (players, NPCs, etc). */
39
41
struct kf_actor
40
42
{
41
-
/* Unique string identifier for this actor. */
42
-
char *key;
43
-
/* Unique integer identifier for this actor, comes from kf_actorregistry. */
43
+
/* Integer identifier for this actor, comes from kf_actorregistry.
44
+
This is unique per-actor-type, not per-actor. */
44
45
int id;
45
46
/* The actor's position. */
46
47
struct kf_vec2(f32) pos;
···
69
70
};
70
71
/* Linked list of actors. */
71
72
extern struct kf_actor *kf_actors, *kf_actors_last;
73
+
/* Number of actors currently in the world. */
72
74
extern u32 kf_actor_count;
73
75
74
76
+2
include/keraforge/error.h
+2
include/keraforge/error.h
+11
include/keraforge/graphics.h
+11
include/keraforge/graphics.h
···
10
10
/* Represents either a model or a menu. */
11
11
struct kf_modal
12
12
{
13
+
/* The title of this modal. */
13
14
char *name;
15
+
/* Called when this modal is closed. */
14
16
void (*exit)(void);
17
+
/* Called when this modal is opened/ */
15
18
void (*init)(void);
19
+
/* Called every frame before rendering anything. */
16
20
void (*update)(void);
21
+
/* Called every frame to render the world. */
17
22
void (*render_world)(void);
23
+
/* Called every frame to render the UI. */
18
24
void (*render_ui)(void);
25
+
/* Any extra data this needed.
26
+
You are expected to allocate and free this yourself in init/exit respectively. */
19
27
void *data;
20
28
};
21
29
···
63
71
extern f32 kf_dts;
64
72
65
73
74
+
/* Measure text using the default font. */
66
75
int kf_measuretext(int size, char *text);
76
+
/* Draw text using the default font. */
67
77
void kf_drawtext(Color c, int x, int y, int size, char *text);
78
+
/* Draw text with a shadow using the default font. */
68
79
void kf_drawtextshadowed(Color c, int x, int y, int size, char *text);
69
80
70
81
+6
-1
include/keraforge/input.h
+6
-1
include/keraforge/input.h
···
6
6
#include <raylib.h>
7
7
8
8
9
+
/* Represents an unknown mouse button. Provided by Keraforge, not by Raylib. */
9
10
#define MOUSE_BUTTON_UNKNOWN ((MouseButton)-1)
11
+
/* Represents an unknown gamepad axis. Provided by Keraforge, not by Raylib. */
10
12
#define GAMEPAD_AXIS_UNKNOWN ((GamepadAxis)-1)
11
13
12
14
#define KF_INPUTBIND_MAX UINT8_MAX
···
17
19
/* Struct-of-Arrays for keybindings. */
18
20
struct _kf_inputbinds
19
21
{
20
-
kf_inputbind_t count; /* must start at 1. 0 is the `none` keybind. */
22
+
/* Amount of input bindings registered.
23
+
Must start at 1. 0 is the `none` keybind. */
24
+
kf_inputbind_t count;
25
+
/* String IDs of each binding. */
21
26
char *id[KF_INPUTBIND_MAX];
22
27
KeyboardKey key[KF_INPUTBIND_MAX];
23
28
KeyboardKey alt[KF_INPUTBIND_MAX];
+1
include/keraforge/inputbinds.h
+1
include/keraforge/inputbinds.h
+8
-2
include/keraforge/log.h
+8
-2
include/keraforge/log.h
···
1
1
#ifndef __kf_log__
2
2
#define __kf_log__
3
3
4
+
4
5
#include <stdio.h> /* fprintf, stderr */
5
6
#include <stdlib.h> /* exit */
6
7
#include <stdarg.h>
7
8
9
+
10
+
/* Log a message. */
8
11
void kf_vlog(char *level, char *fmt, va_list va);
12
+
/* Log a message. */
9
13
void kf_log(char *level, char *fmt, ...);
14
+
/* Log a debug message. */
10
15
void kf_logdbg(char *fmt, ...);
16
+
/* Log an info message. */
11
17
void kf_loginfo(char *fmt, ...);
18
+
/* Log a error message. */
12
19
void kf_logerr(char *fmt, ...);
13
20
14
-
/* Errors */
15
21
16
22
/* Throw a formatted error message without printing a traceback or exiting. */
17
23
#define KF_THROWSOFTER(MSG, ...) \
···
36
42
} \
37
43
while (0)
38
44
39
-
/* Sanity Checking */
40
45
41
46
#ifdef KF_SANITY_CHECKS
42
47
/* Indicate that the given expression should never resolve to false and throw an error if it manages to. */
···
61
66
# define KF_SANITY_CHECK(EXPR, MSG, ...) do { ; } while (0)
62
67
# define KF_UNREACHABLE(MSG, ...) do { ; } while (0)
63
68
#endif
69
+
64
70
65
71
#endif
+3
include/keraforge/sprites.h
+3
include/keraforge/sprites.h
···
10
10
Can be used for animations or texture atlases. */
11
11
struct kf_spritesheet
12
12
{
13
+
/* The texture to pull sprites from. */
13
14
Texture2D texture;
15
+
/* Width and height of each sprite in this sheet. */
14
16
u16 spritewidth, spriteheight;
17
+
/* Number of sprites in this sheet. */
15
18
u32 nsprites;
16
19
};
17
20
+1
-7
include/keraforge/state.h
+1
-7
include/keraforge/state.h
···
8
8
#define KF_NPCPOOL_SIZE 1024
9
9
10
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. */
11
+
/* Stores global variables to be saved alongside the world. Use this for save data. */
13
12
struct kf_state
14
13
{
15
14
/* Do not modify this and do not relocate it. See kf_world for an explanation. */
16
15
u16 revision;
17
-
/* Player data */
18
-
struct {
19
-
struct kf_vec2(f32) pos;
20
-
} player;
21
-
// struct kf_actor npc[KF_NPCPOOL_SIZE];
22
16
};
23
17
24
18
+12
include/keraforge/string.h
+12
include/keraforge/string.h
+3
include/keraforge/time.h
+3
include/keraforge/time.h
+11
-11
include/keraforge/world.h
+11
-11
include/keraforge/world.h
···
8
8
#include <raylib.h>
9
9
10
10
11
+
/* Size of tiles in pixels. */
11
12
#define KF_TILE_SIZE_PX 16
12
13
14
+
/* Number of bits to use for storing tile IDs. See: struct kf_tile. */
13
15
#define KF_TILE_IDWIDTH 10
16
+
/* Number of bits to use for storing tile datum. See: struct kf_tile. */
14
17
#define KF_TILE_DATAWIDTH 4
15
18
16
-
#define KF_TILEID_MAX (1023) /* 2^10-1 */
19
+
/* Number of max tiles. This should be (2^KF_TILE_IDWIDTH-1). */
20
+
#define KF_TILEID_MAX (1023)
17
21
18
22
/* Used to store tile IDs. Stored in 10 bits; max value is 1023! */
19
23
typedef u16 kf_tileid_t;
···
31
35
32
36
33
37
/* Represents a singular tile in the world. */
34
-
// struct kf_tile
35
-
// {
36
-
// kf_tileid_t subid : KF_TILE_IDWIDTH;
37
-
// kf_tileid_t id : KF_TILE_IDWIDTH;
38
-
// kf_tiledatum_t data : KF_TILE_DATAWIDTH;
39
-
// } __attribute__((packed));
40
38
struct kf_tile
41
39
{
42
-
kf_tileid_t subid ;//: KF_TILE_IDWIDTH;
43
-
kf_tileid_t id ;//: KF_TILE_IDWIDTH;
44
-
kf_tiledatum_t data ;//: KF_TILE_DATAWIDTH;
45
-
};// __attribute__((packed));
40
+
kf_tileid_t subid : KF_TILE_IDWIDTH;
41
+
kf_tileid_t id : KF_TILE_IDWIDTH;
42
+
kf_tiledatum_t data : KF_TILE_DATAWIDTH;
43
+
} __attribute__((packed));
46
44
47
45
/* Represents a world (or a subworld, often called "rooms"). */
48
46
struct kf_world
···
93
91
bool transparent;
94
92
};
95
93
94
+
/* Register a tile. */
96
95
kf_tileid_t kf_addtile(struct kf_tile_opts opts);
96
+
/* Register a tile. */
97
97
#define KF_ADDTILE(...) (kf_addtile((struct kf_tile_opts){ __VA_ARGS__ }))
98
98
99
99
/* Create a world using the given width and height.
+1
include/keraforge.h
+1
include/keraforge.h
+23
readme
+23
readme
···
54
54
Develop
55
55
-------
56
56
57
+
Libraries (Debian):
58
+
Raylib:
59
+
libasound2-dev libx11-dev libxrandr-dev libxi-dev libgl1-mesa-dev libglu1-mesa-dev libxcursor-dev libxinerama-dev libwayland-dev libxkbcommon-dev
60
+
Keraforge:
61
+
liblzma-dev
62
+
63
+
Initialise a development environment:
64
+
`sh run.sh init`
65
+
57
66
Build "system" is contained in a folder of shell scripts,
58
67
`scripts`. You can run these with the `run.sh` script to
59
68
run multiple tasks in order. Generally:
60
69
`sh run.sh build run`
61
70
is all you'll need to run while developing.
71
+
72
+
Please note that I will be hesitant to accept PRs to this
73
+
codebase. I am very nitpicky with my code style and if your
74
+
PR does not match it (or if it goes out-of-scope, adds
75
+
useless/redundant functions, further pollute global scope,
76
+
etc), then I will likely decline the PR or request a number
77
+
of changes. Ideally, please communicate with me before
78
+
submitting a PR just for it to get closed. You can find my
79
+
contact information on my website. I don't want you wasting
80
+
your time or effort!
81
+
82
+
Additionally, please read through <etc/style.txt> before
83
+
attempting to contribute. It'll make your life much easier
84
+
if you understand my style *before* attempting a PR.
62
85
63
86
License
64
87
-------
+2
-2
scripts/_config.sh
+2
-2
scripts/_config.sh
···
10
10
export KF_DEBUG_CFLAGS="-g -DKF_SANITY_CHECKS"
11
11
export KF_DEBUG_LFLAGS="-g -rdynamic"
12
12
13
-
export CFLAGS="-Wall -Wextra -Werror -std=c99 -Iinclude/ -c -DKF_GNU $KF_DEBUG_CFLAGS"
14
-
export LFLAGS="-lraylib -lm -lGL -lpthread -ldl -lrt -lX11 -llzma $KF_DEBUG_LFLAGS"
13
+
export CFLAGS="-Wall -Wextra -Werror -std=c99 -Iinclude/ -Iraylib/src/ -c -DKF_GNU $KF_DEBUG_CFLAGS"
14
+
export LFLAGS="raylib/src/libraylib.a -lm -lGL -lpthread -ldl -lrt -lX11 -llzma $KF_DEBUG_LFLAGS"
+20
scripts/init.sh
+20
scripts/init.sh
···
1
+
#!/usr/bin/env sh
2
+
3
+
set -e
4
+
5
+
RAYLIB_VERSION=5.5
6
+
7
+
if [ ! -e "raylib.tar.gz" ]
8
+
then
9
+
curl -Lo raylib.tar.gz https://github.com/raysan5/raylib/archive/refs/tags/$RAYLIB_VERSION.tar.gz
10
+
fi
11
+
12
+
if [ ! -e "raylib/" ]
13
+
then
14
+
tar -xkf raylib.tar.gz && mv -v raylib-$RAYLIB_VERSION raylib
15
+
fi
16
+
17
+
cd raylib/src
18
+
make
19
+
cd ../..
20
+
+23
-17
src/actor.c
+23
-17
src/actor.c
···
28
28
}
29
29
30
30
actor->id = kf_actor_getregistryid(key);
31
-
actor->key = key;
32
31
actor->size.x = 10;
33
32
actor->size.y = 10;
34
33
actor->collide = true;
···
206
205
207
206
int kf_saveactors(void)
208
207
{
209
-
size_t nactors = 0;
210
-
211
208
struct bini_stream *bs = bini_new();
212
209
213
210
/* kf_actor_count includes unserialized actors, so we have to manually count. */
211
+
size_t nactors = 0;
214
212
for (struct kf_actor *actor = kf_actors ; actor != NULL ; actor = actor->next)
215
213
{
216
-
if (!actor->key)
217
-
continue;
218
-
int id = kf_actor_getregistryid(actor->key);
219
-
if (id == -1)
214
+
if (actor->id == -1)
220
215
continue;
221
216
nactors++;
222
217
}
223
218
bini_wlu(bs, nactors);
219
+
kf_logdbg("expecting to save %lu actors", nactors);
224
220
225
221
for (struct kf_actor *actor = kf_actors ; actor != NULL ; actor = actor->next)
226
222
{
227
-
if (!actor->key)
228
-
continue;
229
-
int id = kf_actor_getregistryid(actor->key);
230
-
if (id == -1)
223
+
if (actor->id == -1)
231
224
continue;
232
-
bini_wstr(bs, actor->key);
233
-
kf_actorregistry.serialize[id](actor, bs);
225
+
bini_wstr(bs, kf_actorregistry.key[actor->id]);
226
+
kf_actorregistry.serialize[actor->id](actor, bs);
234
227
}
235
228
236
229
kf_logdbg("serialized %d actors (%lu bytes)", nactors, bs->len);
···
248
241
// char *infile = compress ? _KF_ACTORFILE_TMP : _KF_ACTORFILE;
249
242
char *infile = _KF_ACTORFILE;
250
243
244
+
if (!kf_exists(infile))
245
+
{
246
+
kf_logdbg("actors.bin nonexistent, creating...");
247
+
kf_saveactors();
248
+
return 1;
249
+
}
250
+
251
251
size_t len = 0;
252
252
struct bini_stream bs = {
253
253
.mode = BINI_STREAM,
···
260
260
kf_logdbg("loaded actors into binary stream: len=%lu", len);
261
261
262
262
const size_t nactors = bini_rlu(&bs);
263
+
kf_logdbg("expecting to load %lu actors", nactors);
263
264
264
265
for (size_t i = 0 ; i < nactors ; i++)
265
266
{
266
-
char key[4096] = {0};
267
-
bini_rstr(&bs, key);
268
-
int id = kf_actor_getregistryid(key);
267
+
kf_logdbg("loading actor #%lu", i);
268
+
char key[4096];
269
+
size_t n = bini_rstr(&bs, key);
270
+
key[n] = '\0';
271
+
char *keycpy = kf_strdup(key);
272
+
kf_logdbg(" key: %s", keycpy);
273
+
int id = kf_actor_getregistryid(keycpy);
274
+
kf_logdbg(" id: %d", id);
269
275
if (id == -1)
270
276
continue;
271
-
struct kf_actor *actor = kf_actor_new(key);
277
+
struct kf_actor *actor = kf_actor_new(keycpy);
272
278
kf_actorregistry.deserialize[id](actor, &bs);
273
279
}
274
280
+12
-17
src/graphics.c
+12
-17
src/graphics.c
···
44
44
45
45
struct kf_state *state = NULL;
46
46
int is_new_state = kf_state_load(&state);
47
+
(void)is_new_state;
47
48
kf_window.state = state;
48
49
49
50
struct kf_world *world = NULL;
···
64
65
kf_actorregistry.tick[idplayer2] = kf_player_tick;
65
66
kf_actorregistry.draw[idplayer2] = kf_player_draw;
66
67
67
-
if (is_new_state)
68
+
if (!kf_exists("data/actors.bin"))
68
69
{
69
-
struct kf_actor *player = kf_actors; /* player should always be the first actor. */
70
+
struct kf_actor *player = kf_actor_new("player");
71
+
player->controlled = true;
72
+
player->pos.x = world->width * KF_TILE_SIZE_PX / 2.0f;
73
+
player->pos.y = world->width * KF_TILE_SIZE_PX / 2.0f;
70
74
71
-
state->player.pos.x = world->width * KF_TILE_SIZE_PX / 2.0f;
72
-
state->player.pos.y = world->width * KF_TILE_SIZE_PX / 2.0f;
75
+
struct kf_actor *player2 = kf_actor_new("player2");
76
+
player2->pos.x = world->width * KF_TILE_SIZE_PX / 2.0f;
77
+
player2->pos.y = (world->width * KF_TILE_SIZE_PX / 2.0f) - 32;
73
78
74
79
kf_timeit("save actors", kf_saveactors());
75
80
}
···
78
83
kf_timeit("load actors", kf_loadactors());
79
84
}
80
85
81
-
struct kf_actor *player = kf_actors; /* player should always be the first actor. */
82
-
kf_window.player = player;
83
-
84
-
struct kf_actor *player2 = kf_actor_new("player2");
85
-
player2->size.x = 10;
86
-
player2->size.y = 10;
87
-
player2->collide = false;
88
-
player2->sizeoffset.y = 6;
89
-
player2->pos.x = player->pos.x;
90
-
player2->pos.y = player->pos.y - 24;
86
+
kf_window.player = kf_actors; /* player should always be the first actor. */
91
87
92
-
kf_window.cam.target.x = player->pos.x + (player->size.x / 2);
93
-
kf_window.cam.target.y = player->pos.y + (player->size.y / 2);
88
+
kf_window.cam.target.x = kf_window.player->pos.x + (kf_window.player->size.x / 2);
89
+
kf_window.cam.target.y = kf_window.player->pos.y + (kf_window.player->size.y / 2);
94
90
kf_window.cam.zoom = 2;
95
91
96
92
kf_setmodal(&kf_modal_play);
···
145
141
146
142
kf_saveactors();
147
143
148
-
kf_window.state->player.pos = kf_window.player->pos;
149
144
kf_state_save(kf_window.state);
150
145
151
146
free(kf_window.player);
+1
src/player.c
+1
src/player.c
+13
src/string.c
+13
src/string.c
+13
-2
todo
+13
-2
todo
···
10
10
. Core
11
11
. World
12
12
x Tiles
13
-
. Actors
13
+
/ Actors
14
+
x Rendering
15
+
x Serialization
16
+
. NPC paths (i.e, walking to/from locations. Stardew Valley style)
14
17
x Compression
15
18
. Compress without saving the world binary as an intermediate step.
16
-
All I need to do for this is adapt the compression functions to have an in-memory (`u8 *`) compression equivalent instead of just `FILE *` compression.
19
+
20
+
All I need to do for this is adapt the compression functions to have an
21
+
in-memory (`u8 *`) compression equivalent instead of just `FILE *`
22
+
compression.
23
+
24
+
Another good option would be to implement compression support in Bini,
25
+
i.e, a function that compresses a binary stream's buffer. I would
26
+
also need to mark the stream as read-only until a flush occurs, though.
17
27
. Dialogue
18
28
. Quests
29
+
. UI+layout library
19
30
. Combat
20
31
. Character Stats
21
32
. (De)Buffs