d74d52f3cdcedccb7aead388328ccb57b2790b64
[gbajam22] / src / level.c
1 #include "util.h"
2 #include "debug.h"
3 #include "level.h"
4 #include "player.h"
5 #include "xgl.h"
6
7 struct level *init_level(const char *descstr)
8 {
9         const char *str, *line;
10         int i, j, x, ncols = 0, nrows = 0;
11         struct level *lvl;
12         struct cell *cell;
13
14         str = line = descstr;
15
16         while(*str) {
17                 if(*str == '\n') {
18                         if(ncols > 0 && str > line && str - line != ncols) {
19                                 panic(get_pc(), "init_level: inconsistent ncols (%d != %d)\n", str - line, ncols);
20                         }
21                         ncols = str - line;
22                         nrows++;
23                         while(*++str == '\n');
24                         line = str;
25                 } else {
26                         str++;
27                 }
28         }
29
30         if(!ispow2(ncols)) {
31                 panic(get_pc(), "init_level: width is not pow2 (%d)\n", ncols);
32         }
33
34         lvl = malloc_nf(sizeof *lvl);
35         lvl->width = ncols;
36         lvl->xmask = ncols - 1;
37         lvl->height = nrows;
38         lvl->orgx = lvl->width >> 1;
39         lvl->orgy = lvl->height >> 1;
40         lvl->cells = calloc_nf(ncols * nrows, sizeof *lvl->cells);
41         lvl->mobs = 0;
42         lvl->items = 0;
43
44         lvl->xshift = 0;
45         x = ncols - 1;
46         while(x) {
47                 x >>= 1;
48                 lvl->xshift++;
49         }
50
51         str = descstr;
52         cell = lvl->cells;
53
54         for(i=0; i<nrows; i++) {
55                 for(j=0; j<ncols; j++) {
56                         cell->x = j;
57                         cell->y = i;
58                         if(*str == '#') {
59                                 cell->type = CELL_SOLID;
60                         } else {
61                                 cell->type = CELL_WALK;
62                                 switch(*str) {
63                                 case 's':
64                                         lvl->orgx = j;
65                                         lvl->orgy = i;
66                                         break;
67                                 }
68                         }
69                         cell++;
70                         while(*++str == '\n') str++;
71                 }
72         }
73
74         return lvl;
75 }
76
77 void free_level(struct level *lvl)
78 {
79         void *tmp;
80
81         free(lvl->cells);
82
83         while(lvl->mobs) {
84                 tmp = lvl->mobs;
85                 lvl->mobs = lvl->mobs->next;
86                 free(tmp);
87         }
88         while(lvl->items) {
89                 tmp = lvl->items;
90                 lvl->items = lvl->items->next;
91                 free(tmp);
92         }
93 }
94
95 struct cell *level_cell(struct level *lvl, int cx, int cy)
96 {
97         return lvl->cells + (cy << lvl->xshift) + cx;
98 }
99
100 /* generated with tools/vistab */
101 struct {int dx, dy;} visoffs[8][32] = {
102         /* dir 0 */
103         {{-4,-4}, {4,-4}, {-3,-4}, {3,-4}, {-2,-4}, {2,-4}, {-3,-3}, {3,-3}, {-1,-4},
104          {1,-4}, {0,-4}, {-2,-3}, {2,-3}, {-1,-3}, {1,-3}, {0,-3}, {-2,-2}, {2,-2},
105          {-1,-2}, {1,-2}, {0,-2}, {-1,-1}, {1,-1}, {0,-1}, {0,0}},
106         /* dir 1 */
107         {{4,-4}, {3,-4}, {4,-3}, {2,-4}, {4,-2}, {3,-3}, {1,-4}, {4,-1}, {0,-4},
108          {4,0}, {2,-3}, {3,-2}, {1,-3}, {3,-1}, {0,-3}, {3,0}, {2,-2}, {1,-2},
109          {2,-1}, {0,-2}, {2,0}, {1,-1}, {0,-1}, {1,0}, {0,0}},
110         /* dir 2 */
111         {{4,-4}, {4,4}, {4,-3}, {4,3}, {4,-2}, {4,2}, {3,-3}, {3,3}, {4,-1}, {4,1},
112          {4,0}, {3,-2}, {3,2}, {3,-1}, {3,1}, {3,0}, {2,-2}, {2,2}, {2,-1}, {2,1},
113          {2,0}, {1,-1}, {1,1}, {1,0}, {0,0}},
114         /* dir 3 */
115         {{4,4}, {4,3}, {3,4}, {4,2}, {2,4}, {3,3}, {4,1}, {1,4}, {4,0}, {0,4},
116          {3,2}, {2,3}, {3,1}, {1,3}, {3,0}, {0,3}, {2,2}, {2,1}, {1,2}, {2,0},
117          {0,2}, {1,1}, {1,0}, {0,1}, {0,0}},
118         /* dir 4 */
119         {{-4,4}, {4,4}, {-3,4}, {3,4}, {-2,4}, {2,4}, {-3,3}, {3,3}, {-1,4}, {1,4},
120          {0,4}, {-2,3}, {2,3}, {-1,3}, {1,3}, {0,3}, {-2,2}, {2,2}, {-1,2}, {1,2},
121          {0,2}, {-1,1}, {1,1}, {0,1}, {0,0}},
122         /* dir 5 */
123         {{-4,4}, {-4,3}, {-3,4}, {-4,2}, {-2,4}, {-3,3}, {-4,1}, {-1,4}, {-4,0},
124          {0,4}, {-3,2}, {-2,3}, {-3,1}, {-1,3}, {-3,0}, {0,3}, {-2,2}, {-2,1},
125          {-1,2}, {-2,0}, {0,2}, {-1,1}, {-1,0}, {0,1}, {0,0}},
126         /* dir 6 */
127         {{-4,-4}, {-4,4}, {-4,-3}, {-4,3}, {-4,-2}, {-4,2}, {-3,-3}, {-3,3}, {-4,-1},
128          {-4,1}, {-4,0}, {-3,-2}, {-3,2}, {-3,-1}, {-3,1}, {-3,0}, {-2,-2}, {-2,2},
129          {-2,-1}, {-2,1}, {-2,0}, {-1,-1}, {-1,1}, {-1,0}, {0,0}},
130         /* dir 7 */
131         {{-4,-4}, {-3,-4}, {-4,-3}, {-2,-4}, {-4,-2}, {-3,-3}, {-1,-4}, {-4,-1},
132          {0,-4}, {-4,0}, {-2,-3}, {-3,-2}, {-1,-3}, {-3,-1}, {0,-3}, {-3,0}, {-2,-2},
133          {-1,-2}, {-2,-1}, {0,-2}, {-2,0}, {-1,-1}, {0,-1}, {-1,0}, {0,0}}
134 };
135
136 void upd_vis(struct level *lvl, struct player *p)
137 {
138         int dir, idx;
139         int x, y;
140         struct cell *cptr;
141         int32_t theta;
142
143         pos_to_cell(lvl, p->x, p->y, &p->cx, &p->cy);
144
145         lvl->numvis = 0;
146         idx = -1;
147         theta = X_2PI - p->theta + X_2PI / 16;
148         if(theta >= X_2PI) theta -= X_2PI;
149         dir = (theta << 3) / X_2PI;     /* p->theta is always [0, 2pi) */
150         if(dir < 0 || dir >= 8) {
151                 panic(get_pc(), "dir: %d\ntheta: %d.%d (%d)\n", dir, p->theta >> 16,
152                                 p->theta & 0xffff, p->theta);
153         }
154         do {
155                 idx++;
156                 x = p->cx + visoffs[dir][idx].dx;
157                 y = p->cy + visoffs[dir][idx].dy;
158                 cptr = lvl->cells + y * lvl->width + x;
159                 if(cptr->type != CELL_SOLID) {
160                         lvl->vis[lvl->numvis++] = cptr;
161                 }
162         } while(visoffs[dir][idx].dx | visoffs[dir][idx].dy);
163 }
164
165 void cell_to_pos(struct level *lvl, int cx, int cy, int32_t *px, int32_t *py)
166 {
167         *px = (cx - lvl->orgx) * CELL_SIZE;
168         *py = (cy - lvl->orgy) * CELL_SIZE;
169 }
170
171 void pos_to_cell(struct level *lvl, int32_t px, int32_t py, int *cx, int *cy)
172 {
173         *cx = (px + (CELL_SIZE >> 1)) / CELL_SIZE + lvl->orgx;
174         *cy = (py + (CELL_SIZE >> 1)) / CELL_SIZE + lvl->orgy;
175 }