Added algorithm to detect collision with stage.
[cantaveria.git] / stage.c
blobcdcdaba5ebc951efdc27c95b0fa674a9fc303c11
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
25 stage module is responsible for modelling the static world.
26 it has three main functions
27 * load zone files into world
28 * draw world background and foreground layers
29 * calculate if a moving rectangle will collide with world
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <string.h>
37 #include <ctype.h>
39 #include <util.h>
40 #include <list.h>
41 #include <loader.h>
42 #include <graphics.h>
43 #include <video.h>
45 #include <stage.h>
49 enum tile_shape {
50 SHAPE_FREE = '0', /* 'air' */
51 SHAPE_SQUARE = 'M',
53 SHAPE_TRI_NE = 'a',
54 SHAPE_TRI_NW = 'b',
55 SHAPE_TRI_SE = 'c',
56 SHAPE_TRI_SW = 'd',
58 SHAPE_LTRAP_FLOOR = '1', /* trapezoid */
59 SHAPE_RTRAP_FLOOR = '2',
60 SHAPE_LSLOPE_FLOOR = '3',
61 SHAPE_RSLOPE_FLOOR = '4',
62 SHAPE_LTRAP_CEIL = '5',
63 SHAPE_RTRAP_CEIL = '6',
64 SHAPE_LSLOPE_CEIL = '7',
65 SHAPE_RSLOPE_CEIL = '8',
67 SHAPE_HALF_FLOOR = 'm',
68 SHAPE_HALF_CEIL = 'w'
71 typedef struct {
72 unsigned char bg;
73 unsigned char fg;
74 unsigned char shape;
75 } tile;
77 typedef struct stage stage;
78 struct stage {
79 char id[256];
80 int w, h;
81 tile* tiles;
82 int bgimage;
83 int bgtiles;
84 int fgtiles;
85 int ox, oy;
86 stage* next;
89 char zone_name[256] = "NO ZONE";
90 stage* stages = NULL;
91 stage* this_stage = NULL;
93 /***/
97 STAGE MODULE
99 DEADLINES AND MILESTONES
101 load zones / stages from new format - May 15
102 display loaded stages - May 22
103 collision algorithm - May 29
109 /*** collision stuff ***/
111 #define UUU(x) (1024*(x))
112 #define DDD(x) ((x)/1024)
113 /* is the rectangle with corner x y overlapping shape
114 xp yp determine which quadrant the rectangle is in.
115 can be used for sides of a rect rather than the corner */
116 static int corner_overlap(int x, int y, int xp, int yp, char shape){
117 const int L = UUU(16);
118 switch(shape){
119 case SHAPE_FREE: return 0;
120 case SHAPE_SQUARE: return 1;
122 case SHAPE_TRI_NE:
123 if(xp<0 && yp>0) return y<x;
124 else return 1;
125 case SHAPE_TRI_NW:
126 if(xp>0 && yp>0) return y<L-x;
127 else return 1;
128 case SHAPE_TRI_SE:
129 if(xp<0 && yp<0) return y>L-x;
130 else return 1;
131 case SHAPE_TRI_SW:
132 if(xp>0 && yp<0) return y>x;
133 else return 1;
135 case SHAPE_LTRAP_FLOOR:
136 if(xp>0 && yp<0) return y>(x/2);
137 else return 1;
138 case SHAPE_RTRAP_FLOOR:
139 if(xp<0 && yp<0) return y>(L/2-x/2);
140 else return 1;
141 case SHAPE_LSLOPE_FLOOR:
142 if(xp>0 && yp<0) return y>(L/2+x/2);
143 else if(xp<0 && yp<0) return y>L/2;
144 else return 1;
145 case SHAPE_RSLOPE_FLOOR:
146 if(xp<0 && yp<0) return y>(L-x/2);
147 else if(xp>0 && yp<0) return y>L/2;
148 else return 1;
149 case SHAPE_LTRAP_CEIL:
150 if(xp>0 && yp>0) return y<(L-x/2);
151 else return 1;
152 case SHAPE_RTRAP_CEIL:
153 if(xp<0 && yp>0) return y<(L/2+x/2);
154 else return 1;
155 case SHAPE_LSLOPE_CEIL:
156 if(xp>0 && yp>0) return y<(L/2-x/2);
157 else if(xp<0 && yp>0) return y<L/2;
158 else return 1;
159 case SHAPE_RSLOPE_CEIL:
160 if(xp<0 && yp>0) return y<(x/2);
161 else if(xp>0 && yp>0) return y<L/2;
162 else return 1;
164 case SHAPE_HALF_FLOOR: return yp > 0 || y > L/2;
165 case SHAPE_HALF_CEIL: return yp < 0 || y < L/2;
166 default: return 0;
170 static int x_trace(int y, int v, int shape){
171 const int L = UUU(16);
172 switch(shape){
173 case SHAPE_FREE: return 0; /* should not happen */
174 case SHAPE_SQUARE:
175 case SHAPE_HALF_FLOOR:
176 case SHAPE_HALF_CEIL: return v>0 ? 0 : L;
177 case SHAPE_TRI_NE: return v>0 ? y : L;
178 case SHAPE_TRI_NW: return v>0 ? 0 : L-y;
179 case SHAPE_TRI_SE: return v>0 ? L-y : L;
180 case SHAPE_TRI_SW: return v>0 ? 0 : y;
181 case SHAPE_LTRAP_FLOOR: return v>0 ? 0 : 2*y;
182 case SHAPE_RTRAP_FLOOR: return v>0 ? L - 2*y : 0;
183 case SHAPE_LSLOPE_FLOOR: return v>0 ? 0 : 2*y - L;
184 case SHAPE_RSLOPE_FLOOR: return v>0 ? 2*L -2*y : L;
185 case SHAPE_LTRAP_CEIL: return v<0 ? 2*L - 2*y : L;
186 case SHAPE_RTRAP_CEIL: return v>0 ? 2*y - L : L;
187 case SHAPE_LSLOPE_CEIL: return v>0 ? 0 : L - 2*y;
188 case SHAPE_RSLOPE_CEIL: return v>0 ? 2*y : L;
189 default: return 0;
193 static int y_trace(int x, int v, int shape){
194 const int L = UUU(16);
195 switch(shape){
196 case SHAPE_FREE: return 0; /* should not happen */
197 case SHAPE_SQUARE: return v>0 ? 0 : L;
198 case SHAPE_HALF_FLOOR: return v>0 ? L/2 : L;
199 case SHAPE_HALF_CEIL: return v>0 ? 0 : L/2;
200 case SHAPE_TRI_NE: return v>0 ? 0 : x;
201 case SHAPE_TRI_NW: return v>0 ? 0 : L-x;
202 case SHAPE_TRI_SE: return v>0 ? L-x : 0;
203 case SHAPE_TRI_SW: return v>0 ? x : 0;
204 case SHAPE_LTRAP_FLOOR: return v>0 ? x/2 : L;
205 case SHAPE_RTRAP_FLOOR: return v>0 ? L/2 - x/2 : L;
206 case SHAPE_LSLOPE_FLOOR: return v>0 ? L/2 + x/2 : L;
207 case SHAPE_RSLOPE_FLOOR: return v>0 ? L - x/2 : L;
208 case SHAPE_LTRAP_CEIL: return v>0 ? 0 : L - x/2;
209 case SHAPE_RTRAP_CEIL: return v>0 ? 0 : L/2 + x/2;
210 case SHAPE_LSLOPE_CEIL: return v>0 ? 0 : L/2 - x/2;
211 case SHAPE_RSLOPE_CEIL: return v>0 ? 0 : x/2;
212 default: return 0;
216 static int y_polarity(int y_0, int y_1, int shape){
217 switch(shape){
218 case SHAPE_FREE: return y_0;
219 case SHAPE_SQUARE: return y_0;
220 case SHAPE_TRI_NE: return y_0;
221 case SHAPE_TRI_NW: return y_0;
222 case SHAPE_TRI_SE: return y_1;
223 case SHAPE_TRI_SW: return y_1;
224 case SHAPE_LTRAP_FLOOR: return y_1;
225 case SHAPE_RTRAP_FLOOR: return y_1;
226 case SHAPE_LSLOPE_FLOOR: return y_1;
227 case SHAPE_RSLOPE_FLOOR: return y_1;
228 case SHAPE_LTRAP_CEIL: return y_0;
229 case SHAPE_RTRAP_CEIL: return y_0;
230 case SHAPE_LSLOPE_CEIL: return y_0;
231 case SHAPE_RSLOPE_CEIL: return y_0;
232 case SHAPE_HALF_FLOOR: return y_0;
233 case SHAPE_HALF_CEIL: return y_0;
234 default: return y_0;
238 static int x_polarity(int x_0, int x_1, int shape){
239 switch(shape){
240 case SHAPE_FREE: return x_0;
241 case SHAPE_SQUARE: return x_0;
242 case SHAPE_TRI_NE: return x_1;
243 case SHAPE_TRI_NW: return x_0;
244 case SHAPE_TRI_SE: return x_1;
245 case SHAPE_TRI_SW: return x_0;
246 case SHAPE_LTRAP_FLOOR: return x_0;
247 case SHAPE_RTRAP_FLOOR: return x_1;
248 case SHAPE_LSLOPE_FLOOR: return x_0;
249 case SHAPE_RSLOPE_FLOOR: return x_1;
250 case SHAPE_LTRAP_CEIL: return x_0;
251 case SHAPE_RTRAP_CEIL: return x_1;
252 case SHAPE_LSLOPE_CEIL: return x_0;
253 case SHAPE_RSLOPE_CEIL: return x_1;
254 case SHAPE_HALF_FLOOR: return x_0;
255 case SHAPE_HALF_CEIL: return x_0;
256 default: return x_0;
260 static int calc_corners(int x, int y, int w, int h, int id[4]){
261 int W = this_stage->w;
263 int x1 = DDD(x)/16;
264 int x2 = DDD(x+w)/16;
265 int y1 = DDD(y)/16;
266 int y2 = DDD(y+h)/16;
268 id[0] = x1+y1*W;
269 id[1] = x2+y1*W;
270 id[2] = x1+y2*W;
271 id[3] = x2+y2*W;
273 /* single tile test */
274 if(id[0] == id[1] && id[0] == id[2] &&
275 id[0] == id[2] && id[0] == id[3]) return 0;
277 /* line of tile tests */
278 if(id[0] == id[1]) return 2;
279 if(id[1] == id[3]) return 3;
281 /* at least 4 tile tests */
282 return 1;
285 int stage_xcollide(int x, int y, int w, int h, int v, int* xx){
286 int corners[4];
287 int type = calc_corners(x+v,y,w,h,corners);
288 // int x_min = INT_MAX;
289 // int x_max = INT_MIN;
290 int L = UUU(16);
291 int xbase = (x+v) / L * L;
292 int x_ = (x+v) % L;
293 int y_ = y % L;
294 int yz;
295 tile* t = NULL;
297 if(v == 0) return 0;
299 if(type==0){
300 t = this_stage->tiles + corners[0];
301 if(corner_overlap(x_,y_,1,1,t->shape) &&
302 corner_overlap(x_+w,y_,-1,1,t->shape) &&
303 corner_overlap(x_,y_+h,1,-1,t->shape) &&
304 corner_overlap(x_+w,y_+h,-1,-1,t->shape))
306 yz = y_polarity(y_,y_+h,t->shape);
307 *xx = xbase+x_trace(yz,v,t->shape);
308 return 1;
310 else{
311 return 0;
314 else if(type==2){
315 t = this_stage->tiles + corners[0]; /* and 1 */
316 if(corner_overlap(x_,y_,1,1,t->shape) &&
317 corner_overlap(x_+w,y_,-1,1,t->shape))
319 yz = y_polarity(y_,L,t->shape);
320 *xx = xbase+x_trace(yz,v,t->shape);
321 return 1;
324 y_ = (y+h) % L;
325 t = this_stage->tiles + corners[2]; /* and 3 */
326 if(corner_overlap(x_,y_,1,-1,t->shape) &&
327 corner_overlap(x_+w,y_,-1,-1,t->shape))
329 yz = y_polarity(0,y_,t->shape);
330 *xx = xbase+x_trace(yz,v,t->shape);
331 return 1;
334 /* also check middle edge */
336 return 0;
338 else if(type==3){
339 t = this_stage->tiles + corners[0]; /* and 2 */
340 if(corner_overlap(x_,y_,1,1,t->shape) &&
341 corner_overlap(x_,y_+h,1,-1,t->shape))
343 yz = y_polarity(y_,y_+h,t->shape);
344 *xx = xbase+x_trace(yz,v,t->shape);
345 return 1;
348 xbase = (x+v+w) / L * L;
349 x_ = (x+v+w) % L;
350 t = this_stage->tiles + corners[1]; /* and 3 */
351 if(corner_overlap(x_,y_,-1,1,t->shape) &&
352 corner_overlap(x_,y_+h,-1,-1,t->shape))
354 yz = y_polarity(y_,y_+h,t->shape);
355 *xx = xbase+x_trace(yz,v,t->shape);
356 return 1;
359 /* also check middle edge */
361 return 0;
363 else if(type==1){
364 t = this_stage->tiles + corners[0];
365 if(corner_overlap(x_,y_,1,1,t->shape)){
366 yz = y_polarity(y_,L,t->shape);
367 *xx = xbase+x_trace(yz,v,t->shape);
368 return 1;
371 y_ = (y+h)%L;
372 t = this_stage->tiles + corners[2];
373 if(corner_overlap(x_,y_,1,-1,t->shape)){
374 yz = y_polarity(0,y_,t->shape);
375 *xx = xbase+x_trace(yz,v,t->shape);
376 return 1;
379 xbase = (x+v+w) / L * L;
380 x_ = (x+v+w) % L;
381 y_ = y % L;
382 t = this_stage->tiles + corners[1];
383 if(corner_overlap(x_,y_,-1,1,t->shape)){
384 yz = y_polarity(y_,L,t->shape);
385 *xx = xbase+x_trace(yz,v,t->shape);
386 return 1;
389 y_ = (y+h)%L;
390 t = this_stage->tiles + corners[3];
391 if(corner_overlap(x_,y_,-1,-1,t->shape)){
392 yz = y_polarity(0,y_,t->shape);
393 *xx = xbase+x_trace(yz,v,t->shape);
394 return 1;
396 /* check all edges and inside */
398 return 0;
400 else{
401 return 0;
405 int stage_ycollide(int x, int y, int w, int h, int v, int* yy){
406 int corners[4];
407 int type = calc_corners(x,y+v,w,h,corners);
408 // int x_min = INT_MAX;
409 // int x_max = INT_MIN;
410 int L = UUU(16);
411 int ybase = (y+v) / L * L;
412 int y_ = (y+v) % L;
413 int x_ = x % L;
414 int xz;
415 tile* t = NULL;
417 if(v == 0) return 0;
419 if(type==0){
420 t = this_stage->tiles + corners[0];
421 if(corner_overlap(x_,y_,1,1,t->shape) &&
422 corner_overlap(x_+w,y_,-1,1,t->shape) &&
423 corner_overlap(x_,y_+h,1,-1,t->shape) &&
424 corner_overlap(x_+w,y_+h,-1,-1,t->shape))
426 xz = x_polarity(x_,x_+w,t->shape);
427 *yy = ybase+y_trace(xz,v,t->shape);
428 return 1;
430 else{
431 return 0;
434 else if(type==2){
435 t = this_stage->tiles + corners[0]; /* and 1 */
436 if(corner_overlap(x_,y_,1,1,t->shape) &&
437 corner_overlap(x_+w,y_,-1,1,t->shape))
439 xz = x_polarity(x_,x_+w,t->shape);
440 *yy = ybase+y_trace(xz,v,t->shape);
441 return 1;
444 ybase = (y+v+h) / L * L;
445 y_ = (y+v+h) % L;
446 t = this_stage->tiles + corners[2]; /* and 3 */
447 if(corner_overlap(x_,y_,1,-1,t->shape) &&
448 corner_overlap(x_+w,y_,-1,-1,t->shape))
450 xz = x_polarity(x_,x_+w,t->shape);
451 *yy = ybase+y_trace(xz,v,t->shape);
452 return 1;
455 /* also check middle edge */
457 return 0;
459 else if(type==3){
460 t = this_stage->tiles + corners[0]; /* and 2 */
461 if(corner_overlap(x_,y_,1,1,t->shape) &&
462 corner_overlap(x_,y_+h,1,-1,t->shape))
464 xz = x_polarity(x_,L,t->shape);
465 *yy = ybase+y_trace(xz,v,t->shape);
466 return 1;
469 x_ = (x+w) % L;
470 t = this_stage->tiles + corners[1]; /* and 3 */
471 if(corner_overlap(x_,y_,-1,1,t->shape) &&
472 corner_overlap(x_,y_+h,-1,-1,t->shape))
474 xz = x_polarity(0,x_,t->shape);
475 *yy = ybase+y_trace(xz,v,t->shape);
476 return 1;
479 /* also check middle edge */
481 return 0;
483 else if(type==1){
484 t = this_stage->tiles + corners[0];
485 if(corner_overlap(x_,y_,1,1,t->shape)){
486 xz = x_polarity(x_,L,t->shape);
487 *yy = ybase+y_trace(xz,v,t->shape);
488 return 1;
491 x_ = (x+w)%L;
492 t = this_stage->tiles + corners[1];
493 if(corner_overlap(x_,y_,-1,1,t->shape)){
494 xz = x_polarity(0,x_,t->shape);
495 *yy = ybase+y_trace(xz,v,t->shape);
496 return 1;
499 ybase = (y+v+h) / L * L;
500 y_ = (y+v+h) % L;
501 x_ = x % L;
502 t = this_stage->tiles + corners[2];
503 if(corner_overlap(x_,y_,1,-1,t->shape)){
504 xz = x_polarity(x_,L,t->shape);
505 *yy = ybase+y_trace(xz,v,t->shape);
506 return 1;
509 x_ = (x+w)%L;
510 t = this_stage->tiles + corners[3];
511 if(corner_overlap(x_,y_,-1,-1,t->shape)){
512 xz = x_polarity(0,x_,t->shape);
513 *yy = ybase+y_trace(xz,v,t->shape);
514 return 1;
517 /* check all edges and inside */
519 return 0;
521 else{
522 return 0;
529 /*** end collision stuff ***/
534 static void initialize_tiles(int n, tile* tiles){
535 int i;
536 for(i=0; i<n; i++){
537 tiles[i].shape = SHAPE_FREE;
538 tiles[i].fg = 0;
539 tiles[i].bg = 0;
544 static int load_stage(char* gfxpath, char* stagepath){
546 [stage file]
547 width height
548 bgimage
549 dectiles
550 bgtiles
551 fgtiles
552 x y fg bg shape
553 x y fg bg shape
557 reader* f = loader_open(stagepath);
558 char* filename = path_ending(stagepath);
559 char buf[256];
560 char gfx[256];
561 tile* tptr;
562 stage* s = malloc(sizeof(stage));
563 int w = 20;
564 int h = 15;
565 int x, y, ox, oy, fg, bg, shape;
567 loader_scanline(f, "%d %d %d %d", &w, &h, &ox, &oy);
569 loader_scanline(f, "%s", buf);
570 strcpy(gfx, gfxpath);
571 strcat(gfx, buf);
572 s->bgimage = load_bitmap(gfx);
574 loader_scanline(f, "%s", buf);
575 strcpy(gfx, gfxpath);
576 strcat(gfx, buf);
577 s->bgtiles = load_bitmap(gfx);
579 loader_scanline(f, "%s", buf);
580 strcpy(gfx, gfxpath);
581 strcat(gfx, buf);
582 s->fgtiles = load_bitmap(gfx);
584 s->tiles = malloc(w*h*sizeof(tile));
585 initialize_tiles(w*h, s->tiles);
586 s->w = w;
587 s->h = h;
588 s->ox = ox;
589 s->oy = oy;
590 strncpy(s->id, filename, 256);
591 s->id[255] = '\0';
593 while(!loader_feof(f)){
594 loader_scanline(f, "%d %d %d %d %c", &x, &y, &fg, &bg, &shape);
595 tptr = s->tiles + (x+ox) + (s->w * (y+oy));
596 tptr->fg = fg;
597 tptr->bg = bg;
598 tptr->shape = shape;
601 s->next = stages;
602 stages = s;
604 loader_close(f);
605 return 0;
608 /***/
611 int load_zone(string name){
613 loading a zone from a file
614 a zone consists of one or more stages
615 each stage has its own tileset graphics and background
616 it also has a large array of tiles
618 the stage files are in zones/zonename/
619 the name of the file will be used as the id
622 list* dirs;
623 list* ptr;
624 char stagesdir[256] = "";
625 char gfxpath[256] = "";
626 char* stagepath;
628 strcat(stagesdir, "zones/");
629 strcat(stagesdir, name);
630 strcat(stagesdir, "/stages/");
632 strcat(gfxpath, "zones/");
633 strcat(gfxpath, name);
634 strcat(gfxpath, "/gfx/");
636 strncpy(zone_name, name, 256);
637 zone_name[255] = '\0';
639 dirs = loader_readdir((string)stagesdir);
640 if(dirs == NULL){
641 printf("ERROR cant read dirs\n");
642 return -1;
645 ptr = dirs->next;
646 while(ptr){
647 stagepath = ptr->item;
648 if(load_stage(gfxpath, stagepath) < 0){
649 printf("ERROR cant load stage\n");
650 loader_freedirlist(dirs);
651 return -1;
653 ptr = ptr->next;
656 loader_freedirlist(dirs);
657 return 0;
660 void unload_zone(){
661 stage* ptr = stages;
662 stage* prev;
663 while(ptr){
664 free(ptr->tiles);
665 prev = ptr;
666 ptr = ptr->next;
667 free(prev);
670 strcpy(zone_name, "NO ZONE");
673 void switch_stage(string id){
674 stage* ptr = stages;
675 while(ptr){
676 if(strcmp(id, ptr->id) == 0){
677 this_stage = ptr;
678 return;
680 ptr = ptr->next;
683 printf("ERROR stage not found\n");
687 static void draw_tiles(int gfx, char layer, int cx, int cy){
688 tile* tbase = this_stage->tiles;
689 tile* t;
690 int tw = this_stage->w;
691 int th = this_stage->h;
692 int id;
693 int gx, gy;
695 int i;
696 int j;
697 int io = cx/16;
698 int jo = cy/16;
699 int i_ = io + 20;
700 int j_ = jo + 15;
702 int extra_x = 0;
703 int extra_y = 0;
704 int W, H;
705 screen_dimensions(&W, &H);
706 if(W>320){
707 extra_x = (W - 320)/16/2 + 2;
709 if(H>240){
710 extra_y = (H - 240)/16/2 + 2;
713 io -= extra_x;
714 jo -= extra_y;
715 i_ += extra_x;
716 j_ += extra_y+1;
718 if(io > tw-1) return;
719 if(jo > th-1) return;
721 if(io < 0) io = 0;
722 if(jo < 0) jo = 0;
723 if(i_ > tw) i_ = tw;
724 if(j_ > th) j_ = th;
726 for(j=jo; j<j_; j++){
727 for(i=io; i<i_; i++){
728 t = tbase + i + tw*j;
729 if(layer=='b') id = t->bg;
730 else if(layer=='f') id = t->fg;
731 else id = 0;
732 gx = 16*(id%16);
733 gy = 16*(id/16);
734 draw_gfx(gfx, i*16-cx, j*16-cy, gx, gy, 16, 16);
740 cx, cy is the camera position
741 x, y i think is the offset from 0,0 you should shift
742 w, h i think is the width and height of the screen
744 void stage_draw_bg(int cx, int cy){
745 int i;
746 int bw, bh, screen_w, screen_h;
747 int bgimage;
748 int bgshift;
749 int parallax = 2;
751 if(this_stage == NULL) return;
753 /* draw background vertically centered
754 tile horizontally at fraction of camera x */
755 bgimage = this_stage->bgimage;
756 gfx_dimensions(bgimage, &bw, &bh);
757 screen_dimensions(&screen_w, &screen_h);
758 bgshift = cx/parallax/bw;
759 for(i=-1; i<(screen_w/bw)+2; i++){
760 draw_gfx_raw(
761 bgimage,
762 (i+bgshift)*bw-cx/parallax,
763 (screen_h-bh)/2,
764 0, 0, bw, bh
768 draw_tiles(this_stage->bgtiles, 'b', cx, cy);
771 void stage_draw_fg(int cx, int cy){
772 draw_tiles(this_stage->bgtiles, 'f', cx, cy);
778 void stage_init(){
779 /* does nothing */
786 /*** debug ***/
788 void stage_debug(){
789 stage* ptr = stages;
790 int i, j;
791 char c;
793 struct stage {
794 char id[32];
795 int w, h;
796 tile* tiles;
797 int bgimage;
798 int bgtiles;
799 int fgtiles;
800 stage* next;
801 };*/
802 printf("stage debug:\n\n");
803 printf("zone: %s\n\n", zone_name);
805 while(ptr){
806 printf("stage: %s\n", ptr->id);
807 printf("size: %dx%d\n", ptr->w, ptr->h);
808 printf("origin: (%d, %d)\n", ptr->ox, ptr->oy);
809 printf("bgimage: %d\n", ptr->bgimage);
810 printf("bgtiles: %d\n", ptr->bgtiles);
811 printf("fgtiles: %d\n", ptr->fgtiles);
812 printf("tiles:\n");
814 for(j=0; j<ptr->h; j++){
815 for(i=0; i<ptr->w; i++){
816 c = (ptr->tiles + i + ptr->w*j)->fg;
818 if(isprint(c)) printf("%d", c);
819 else printf("?");*/
820 printf("[%02x]", c);
822 printf("\n");
826 printf("\n");
827 ptr = ptr->next;