summaryrefslogtreecommitdiff
path: root/src/world.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/world.c')
-rw-r--r--src/world.c128
1 files changed, 128 insertions, 0 deletions
diff --git a/src/world.c b/src/world.c
new file mode 100644
index 0000000..a24c7a6
--- /dev/null
+++ b/src/world.c
@@ -0,0 +1,128 @@
+World g_world = {0};
+
+#define expect(X) if (!(X)) { \
+ perr("expect failed: "STR(X)); \
+ if (fp != NULL) fclose(fp); \
+ world_deinit(); \
+ exit(EXIT_FAILURE); \
+}
+
+void
+world_init(const char *path, const char *cell_pattern)
+{
+ assert(path != NULL);
+ assert(cell_pattern != NULL);
+
+ FILE *fp = fopen(path, "rw");
+ expect(fp != NULL);
+
+ int cell_count = 0;
+ fscanf(fp, "%d[^,\n", &cell_count);
+ fscanf(fp, "%*c");
+ expect(cell_count > 0);
+
+ // skip x and y
+ fscanf(fp, "%*d[^,\n]");
+ fscanf(fp, "%*c");
+ fscanf(fp, "%*d[^,\n]");
+ fscanf(fp, "%*c");
+
+ int min_x = INT_MAX, min_y = INT_MAX, max_x = INT_MIN, max_y = INT_MIN;
+ rfor (i, 0, cell_count) {
+ int id = 0, x = 0, y = 0;
+ fscanf(fp, "%d[^,\n]", &id);
+ fscanf(fp, "%*c");
+ fscanf(fp, "%d[^,\n]", &x);
+ fscanf(fp, "%*c");
+ fscanf(fp, "%d[^,\n]", &y);
+ fscanf(fp, "%*c");
+
+ min_x = min(x, min_x);
+ min_y = min(x, min_y);
+ max_x = max(x, max_x);
+ max_y = max(x, max_y);
+
+ Cell *const cell = cell_load(cell_pattern, id, x, y);
+ expect(cell != NULL);
+ cell->next = g_world.root_cell;
+ g_world.root_cell = cell;
+ }
+ expect(g_world.root_cell != NULL);
+
+ fclose(fp);
+ fp = NULL;
+
+ // flatten the cell structure
+ g_world.width = max_x - min_x + 1;
+ g_world.height = max_y - min_y + 1;
+ g_world.cells = alloc(sizeof(Cell*) * g_world.width * g_world.height);
+ expect(g_world.cells != NULL);
+
+ foreach (cell, g_world.root_cell) {
+ const int cell_x = cell->x - min_x;
+ const int cell_y = cell->y - min_y;
+ g_world.cells[cell_x + cell_y * g_world.width] = cell;
+ }
+}
+
+void
+world_deinit(void)
+{
+ if (g_world.cells != NULL) {
+ free(g_world.cells);
+ g_world.cells = NULL;
+ }
+ cell_destroy(g_world.root_cell, true);
+}
+
+void
+world_draw(void)
+{
+ with (cell, g_world.cells[g_world.x + g_world.y * g_world.width])
+ cell_draw(cell, 0, 0);
+}
+
+int
+world_get(int x, int y)
+{
+ int wx = g_world.x;
+ int wy = g_world.y;
+
+ if (x < 0) {
+ x += cfg.tile_width * cfg.cell_width;
+ wx -= 1;
+ } else if (x >= cfg.tile_width * cfg.cell_width) {
+ x -= cfg.tile_width * cfg.cell_width;
+ wx += 1;
+ }
+ if (y < 0) {
+ y += cfg.tile_height * cfg.cell_height;
+ wy -= 1;
+ } else if (y >= cfg.tile_height * cfg.cell_height) {
+ y -= cfg.tile_height * cfg.cell_height;
+ wy += 1;
+ }
+
+ const int i = x / cfg.tile_width + (y / cfg.tile_height) * cfg.cell_width;
+ with (cell, g_world.cells[wx + wy * g_world.width])
+ return cell->data[i] ? (cell->data[i] - 1) : 0;
+ return 0; // oob tile
+}
+
+int2
+world_find(int tile)
+{
+ rfor (y, 0, g_world.height) {
+ rfor (x, 0, g_world.width) {
+ Cell *const cell = g_world.cells[x + y * g_world.width];
+ if (cell == NULL)
+ continue;
+ const int2 spawn = cell_find(cell, tile + 1);
+ if (spawn.x < 0)
+ continue;
+ return I2(x, y);
+ }
+ }
+
+ return I2(-1, -1);
+}