Stage loader uses new file format.
[cantaveria.git] / stage.c
blobfa484828e1f02d1b4967cbde755e1604375d1641
1 /*
2 Cantaveria - action adventure platform game
3 Copyright (C) 2009 2010 Evan Rinehart
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License
7 as published by the Free Software Foundation; either version 2
8 of the License, or (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to
18 The Free Software Foundation, Inc.
19 51 Franklin Street, Fifth Floor
20 Boston, MA 02110-1301, USA
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
28 #include <util.h>
29 #include <list.h>
30 #include <loader.h>
31 #include <graphics.h>
33 #include <stage.h>
35 enum cardinal {NORTH, SOUTH, EAST, WEST};
38 enum tile_shape {
39 SHAPE_FREE,
40 SHAPE_SQUARE,
41 SHAPE_NULL,
43 SHAPE_TRI_NE,
44 SHAPE_TRI_NW,
45 SHAPE_TRI_SE,
46 SHAPE_TRI_SW,
48 SHAPE_LTRAP_FLOOR,
49 SHAPE_RTRAP_FLOOR,
50 SHAPE_LSLOPE_FLOOR,
51 SHAPE_RSLOPE_FLOOR,
52 SHAPE_LTRAP_CEIL,
53 SHAPE_RTRAP_CEIL,
54 SHAPE_LSLOPE_CEIL,
55 SHAPE_RSLOPE_CEIL,
57 SHAPE_HALF_FLOOR,
58 SHAPE_HALF_CEIL
61 typedef struct {
62 int tile;
63 int i, j;
64 } decoration;
66 typedef struct {
67 int zone;
68 int i, j;
69 enum cardinal dir;
70 } zoneport;
72 typedef struct {
73 int i, j;
74 int w, h;
75 int flags;
76 } water;
78 typedef struct {
79 int zid;
80 int i, j;
81 char fg[20][15];
82 char bg[20][15];
83 list* decs;
84 list* waters;
85 char snap[4];
86 zoneport* exit;
87 } stage;
89 typedef struct {
90 int id;
91 char name[32];
92 int w, h, i, j;
93 int fgtiles;
94 int bgtiles;
95 int dectiles;
96 int bgimage;
97 enum tile_shape shapes[256];
98 stage** stages; // w by h array
99 } zone;
102 how the above is stored in a binary file
103 string z->name
104 byte[256] z->shapes
105 short[4] z->{i, j, w, h}
106 short [number of stages N]
107 [N of the following
108 short[2] s->{i, j}
109 byte unknown
110 string[4] exits
111 byte[20x15] s->fg
114 new version
115 byte[4] 0x0a 0x0b 0x0c 0x0d
116 int format version (1)
117 int z->id
118 short[4] z->{i, j, w, h}
119 string fgtiles file
120 string bgtiles file
121 string dectiles file
122 string bgimage file
123 byte[256] z->shapes
124 short number of stages N
125 [N of the following
126 short[2] s->{i, j}
127 byte[4] s->snap
128 byte[4] 'exit' or 'none'
129 a zone port is next if previous was 'exit'
130 string zone
131 short[2] i, j
132 byte 'L' 'U' 'D' or 'R'
133 short number of decorations M
134 [M of the following
135 short[2] i, j
136 short tile
138 short number of waters W
139 [W of the following
140 short[4] i, j, w, h
141 int flags
143 byte[20x15] fg
144 byte[20x15] bg
148 typedef struct {
149 int x, y;
150 int shape;
151 int none;
152 } block;
157 /* VVV */
158 list* zones = NULL;
159 /* ^^^ */
163 enum cardinal dir_of(int i, int j){
164 if(i < 0) return WEST;
165 if(j < 0) return NORTH;
166 if(i > 0) return EAST;
167 if(j > 0) return SOUTH;
168 fatal_error("stage.c: (%d,%d) is not a valid direction\n", i, j);
169 return NORTH;
176 /* zones and stages */
177 zone* find_zone_by_id(int id){
178 list* ptr = zones->next;
179 while(ptr){
180 zone* z = ptr->item;
181 if(z->id == id) return z;
182 ptr = ptr->next;
184 return NULL;
187 zone* zone_of_stage(stage* s){
188 return find_zone_by_id(s->zid);
191 stage* stage_lookup(zone* z, int i, int j){
192 if(i < 0 || i >= z->w || j < 0 || j >= z->h){
193 return NULL;
195 return *(z->stages + i + j*z->w);
199 stage* follow_zoneport(zoneport* zp){
200 zone* z = find_zone_by_id(zp->zone);
201 return stage_lookup(z, zp->i, zp->j);
204 stage* find_stage(stage* home, int i, int j){
205 zone* z = zone_of_stage(home);
206 int si = i/20;
207 int sj = j/15;
208 int di = home->i - si;
209 int dj = home->j - sj;
210 if(di==0 && dj==0)
211 return home;
213 else if(home->exit && home->exit->dir == dir_of(di,dj))
214 return follow_zoneport(home->exit);
216 else
217 return stage_lookup(z, si - z->w, sj - z->h);
222 /* collision computations */
223 /*FIXME*/
224 int left_side_of(block bl, int top, int bottom){
225 return bl.x;
228 int right_side_of(block bl, int top, int bottom){
229 return bl.x + 16;
232 int top_of(block bl, int left, int right){
233 return bl.y;
236 int bottom_of(block bl, int left, int right){
237 return bl.y + 16;
240 int xhit(int v, block block, int top, int bottom){
241 if(v > 0) return left_side_of(block, top, bottom);
242 if(v < 0) return right_side_of(block, top, bottom);
243 return 0;
246 int yhit(int v, block block, int left, int right){
247 if(v > 0) return top_of(block, left, right);
248 if(v < 0) return bottom_of(block, left, right);
249 return 0;
252 int rect_is_on(block bl, int L, int R, int T, int B){
253 int l = bl.x;
254 int r = bl.x + 16;
255 int t = bl.y;
256 int b = bl.y + 16;
257 return !(r < L || l > R || t > B || b < T);
264 /* blocks */
265 block make_block(int shape, int x, int y, int none){
266 block bl;
267 bl.x = x;
268 bl.y = y;
269 bl.none = none;
270 bl.shape = shape;
271 return bl;
274 block no_block(){
275 return make_block(0, 0, 0, 1);
278 block null_block(){
279 return make_block(SHAPE_NULL, 0, 0, 0);
282 block block_of(int shape, int x, int y){
283 return make_block(shape, x, y, 0);
286 /* get block in s at i j */
287 block block_from_stage(stage* s, int i, int j){
288 zone* z = zone_of_stage(s);
289 int tile = s->fg[i][j];
290 int shape = z->shapes[tile];
291 return block_of(shape, i, j);
294 /* get block at absolute x y if you are in stage home */
295 block get_block(stage* home, int x, int y){
296 zone* z = zone_of_stage(home);
297 int i = x/1024/16 - (home->i + z->i)*20;
298 int j = y/1024/16 - (home->j + z->j)*15;
300 stage* s = find_stage(home, i, j);
301 if(s == NULL)
302 return null_block();
303 else
304 return block_from_stage(s, i, j);
307 /* returns either a block that the rect is intersecting
308 or it returns a block with none set to 1 */
309 block intersecting_block(stage* s, int left, int right, int top, int bottom){
310 int i;
311 for(i=0; i<4; i++){
312 block bl;
313 switch(i){
314 case 0: bl = get_block(s, top, left); break;
315 case 1: bl = get_block(s, top, right); break;
316 case 2: bl = get_block(s, bottom, left); break;
317 case 3: bl = get_block(s, bottom, right); break;
319 if(rect_is_on(bl, left, right, top, bottom)) return bl;
321 return no_block();
329 /******** stage loading routines ********/
330 static int load_stage_dimensions(stage* s, reader* rd){
331 return
332 read_short(rd, &s->i) ||
333 read_short(rd, &s->j);
336 static int load_stage_snap(stage* s, reader* rd){
337 return read_bytes(rd, (unsigned char*)s->snap, 4);
340 static int load_stage_exit(stage* s, reader* rd){
341 char what[5] = {0,0,0,0,0};
342 if(read_bytes(rd, (unsigned char*)what, 4)) return -1;
344 if(strcmp(what, "none") == 0){
345 return 0;
347 if(strcmp(what, "exit") == 0){
348 /* FIXME */
349 printf("INCOMPLETE load_stage_exit doesnt work yet\n");
350 return -1;
353 error_msg("load_zone: invalid stage header (missing exit)\n");
354 return -1;
357 static int load_stage_decorations(stage* s, reader* rd){
358 int N;
359 if(read_short(rd, &N)) return -1;
361 if(N > 0){
362 /* FIXME */
363 printf("INCOMPLETE load_stage_decorations doesnt work yet\n");
364 return -1;
367 return 0;
370 static int load_stage_waters(stage* s, reader* rd){
371 int N;
372 if(read_short(rd, &N)) return -1;
374 if(N > 0){
375 /* FIXME */
376 printf("INCOMPLETE load_stage_waters doesnt work yet\n");
377 return -1;
380 return 0;
383 static int load_stage_data(stage* s, reader* rd){
384 int i, j;
385 for(i=0; i<15; i++){
386 for(j=0; j<20; j++){
387 if(read_byte(rd, (int*)&s->fg[i][j])) return -1;
390 for(i=0; i<15; i++){
391 for(j=0; j<20; j++){
392 if(read_byte(rd, (int*)&s->bg[i][j])) return -1;
395 return 0;
398 static stage* load_stage(reader* rd){
399 stage* s = xmalloc(sizeof(stage));
400 s->decs = empty();
401 s->exit = NULL;
402 s->snap[NORTH] = 0;
403 s->snap[WEST] = 0;
404 s->snap[EAST] = 0;
405 s->snap[SOUTH] = 0;
408 load_stage_dimensions(s, rd) ||
409 load_stage_snap(s, rd) ||
410 load_stage_exit(s, rd) ||
411 load_stage_decorations(s, rd) ||
412 load_stage_waters(s, rd) ||
413 load_stage_data(s, rd)
416 recycle(s->decs);
417 free(s);
418 return NULL;
420 return s;
423 static int load_zone_bitmap(reader* rd, int* out){
424 char* filename;
425 if(read_string(rd, &filename)){
426 error_msg("load_zone: read error (graphics list)\n");
427 return -1;
429 if(strlen(filename) == 0){
430 *out = -1;
431 return 0;
433 *out = load_bitmap(filename);
434 free(filename);
435 if(*out < 0){
436 error_msg("load_zone: can't load graphics %s\n", filename);
437 return -1;
439 else{
440 return 0;
444 static int load_zone_gfx(zone* z, reader* rd){
445 return
446 load_zone_bitmap(rd, &z->fgtiles) ||
447 load_zone_bitmap(rd, &z->bgtiles) ||
448 load_zone_bitmap(rd, &z->dectiles) ||
449 load_zone_bitmap(rd, &z->bgimage);
452 static int load_zone_shapes(zone* z, reader* rd){
453 int i;
454 for(i=0; i<256; i++){
455 if(read_byte(rd, (int*)&z->shapes[i])){
456 return -1;
459 return 0;
462 static int load_zone_dimensions(zone* z, reader* rd){
463 return
464 read_short(rd, &z->i) ||
465 read_short(rd, &z->j) ||
466 read_short(rd, &z->w) ||
467 read_short(rd, &z->h);
470 static int load_zone_stages(zone* z, reader* rd){
471 int i, j, N;
473 z->stages = xmalloc(z->w * z->h * sizeof(stage*));
475 for(i=0; i < z->w; i++){
476 for(j=0; j < z->h; j++){
477 *(z->stages + i + j*z->w) = NULL;
481 if(read_short(rd, &N)) return -1;
483 printf("number of stages %d\n", N);
484 for(i=0; i<N; i++){
485 stage* s = load_stage(rd);
486 if(s == NULL) return -1;
487 z->stages[s->i + s->j * z->w] = s;
490 return 0;
493 int load_zone_header(zone* z, reader* rd){
494 unsigned char magic1[4];
495 unsigned char magic2[4] = {0x0a, 0x0b, 0x0c, 0x0d};
496 int format;
499 read_bytes(rd, magic1, 4) ||
500 read_int(rd, &format) ||
501 read_int(rd, &z->id)
503 return -1;
505 if(memcmp(magic1, magic2, 4) != 0){
506 error_msg("load_zone: wrong file type (missing magic)\n");
507 return -1;
510 if(format != 1){
511 error_msg("load_zone: wrong format version\n");
512 return -1;
515 return 0;
519 int load_zone(char* filename){
520 reader* rd = data_open("zones/", filename);
521 if(rd == NULL){
522 error_msg("load_zone: error opening \"%s\"\n", filename);
523 return -1;
526 zone* z = xmalloc(sizeof(zone));
527 strncpy(z->name, filename, 32);
528 z->id = 0; /* supposed to be in file */
529 z->fgtiles = -1;
530 z->bgtiles = -1;
531 z->dectiles = -1;
532 z->bgimage = -1;
535 load_zone_header(z, rd) ||
536 load_zone_dimensions(z, rd) ||
537 load_zone_gfx(z, rd) ||
538 load_zone_shapes(z, rd) ||
539 load_zone_stages(z, rd)
541 error_msg("load_zone: error reading \"%s\"\n", filename);
542 free(z);
543 loader_close(rd);
544 return -1;
547 push(zones, z);
548 return z->id;
550 /**************************************/
556 void print_shapes(enum tile_shape shapes[256]){
557 int i, j;
558 for(i=0; i<16; i++){
559 printf(" ");
560 for(j=0; j<16; j++){
561 printf("%02x ", shapes[i*16 + j]);
563 printf("\n");
567 void print_dir(char snap[4], enum cardinal dir, char* c){
568 if(snap[dir]) printf("%s", c);
569 else printf(" ");
572 void print_snaps(char snap[4]){
573 printf(" snap: (");
574 print_dir(snap, WEST, "L");
575 print_dir(snap, NORTH, "U");
576 print_dir(snap, SOUTH, "D");
577 print_dir(snap, EAST, "R");
578 printf(")\n");
581 void print_stages(stage** stages, int w, int h){
582 int i, j;
583 for(j=0; j<h; j++){
584 printf(" ");
585 for(i=0; i<w; i++){
586 stage* s = stages[j*w + i];
587 if(s == NULL){
588 printf(" ");
590 else{
591 printf("O");
594 printf("\n");
597 for(j=0; j<h; j++){
598 for(i=0; i<w; i++){
599 stage* s = stages[j*w + i];
600 if(s == NULL) continue;
602 printf(" stage (%d, %d):\n", i, j);
603 printf(" decs: %d\n", length(s->decs));
604 print_snaps(s->snap);
605 printf(" exit: %p\n", s->exit);
606 printf("\n");
612 void print_zone(int id){
613 zone* z = find_zone_by_id(id);
614 printf("zone: %s\n", z->name);
616 printf(" id: %d\n", z->id);
617 printf(" dimensions: %d x %d\n", z->w, z->h);
618 printf(" position: (%d, %d)\n", z->i, z->j);
619 printf(" fg: %d\n", z->fgtiles);
620 printf(" bg: %d\n", z->bgtiles);
621 printf(" dec: %d\n", z->dectiles);
622 printf(" bgimage: %d\n", z->bgimage);
623 printf(" shapes:\n");
624 print_shapes(z->shapes);
625 printf(" stages:\n");
626 print_stages(z->stages, z->w, z->h);
631 void stage_bind_camera(location l, int* x, int* y){
632 //for each snap, snap x y
635 void draw_stage_fg(location loc, int cx, int cy){
636 //draw decorations
637 //draw water
640 void draw_stage_bg(location loc, int cx, int cy){
641 //for each visible tile
642 //bg or bg tiles or fg tiles
645 /* returns 1 if a collision will occur, 0 otherwise
646 if 1 is returned, x will be set to the collision point */
647 int stage_xcollide(location loc, int w, int h, int v, int* x){
648 zone* z = find_zone_by_id(loc.z);
649 stage* s = stage_lookup(z, loc.i, loc.j);
650 int X = loc.x + v*10; /* FIXME dt */
651 int right = X + w;
652 int left = X;
653 int top = loc.y;
654 int bottom = loc.y + h;
656 block bl = intersecting_block(s, left, right, top, bottom);
658 if(bl.none) return 0;
659 else{
660 *x = xhit(v, bl, top, bottom);
661 return 1;
665 int stage_ycollide(location loc, int w, int h, int v, int* y){
666 return 0;
672 void stage_init(){
673 zones = empty();