1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
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] - 1;
return -1; // 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);
}
|