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
50 SHAPE_FREE
= '0', /* 'air' */
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',
77 typedef struct stage stage
;
89 char zone_name
[256] = "NO ZONE";
91 stage
* this_stage
= NULL
;
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);
119 case SHAPE_FREE
: return 0;
120 case SHAPE_SQUARE
: return 1;
123 if(xp
<0 && yp
>0) return y
<x
;
126 if(xp
>0 && yp
>0) return y
<L
-x
;
129 if(xp
<0 && yp
<0) return y
>L
-x
;
132 if(xp
>0 && yp
<0) return y
>x
;
135 case SHAPE_LTRAP_FLOOR
:
136 if(xp
>0 && yp
<0) return y
>(x
/2);
138 case SHAPE_RTRAP_FLOOR
:
139 if(xp
<0 && yp
<0) return y
>(L
/2-x
/2);
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;
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;
149 case SHAPE_LTRAP_CEIL
:
150 if(xp
>0 && yp
>0) return y
<(L
-x
/2);
152 case SHAPE_RTRAP_CEIL
:
153 if(xp
<0 && yp
>0) return y
<(L
/2+x
/2);
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;
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;
164 case SHAPE_HALF_FLOOR
: return yp
> 0 || y
> L
/2;
165 case SHAPE_HALF_CEIL
: return yp
< 0 || y
< L
/2;
170 static int x_trace(int y
, int v
, int shape
){
171 const int L
= UUU(16);
173 case SHAPE_FREE
: return 0; /* should not happen */
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
;
193 static int y_trace(int x
, int v
, int shape
){
194 const int L
= UUU(16);
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;
216 static int y_polarity(int y_0
, int y_1
, int 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
;
238 static int x_polarity(int x_0
, int x_1
, int 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
;
260 static int calc_corners(int x
, int y
, int w
, int h
, int id
[4]){
261 int W
= this_stage
->w
;
264 int x2
= DDD(x
+w
)/16;
266 int y2
= DDD(y
+h
)/16;
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 */
285 int stage_xcollide(int x
, int y
, int w
, int h
, int v
, int* xx
){
287 int type
= calc_corners(x
+v
,y
,w
,h
,corners
);
288 // int x_min = INT_MAX;
289 // int x_max = INT_MIN;
291 int xbase
= (x
+v
) / L
* L
;
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
);
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
);
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
);
334 /* also check middle edge */
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
);
348 xbase
= (x
+v
+w
) / L
* 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
);
359 /* also check middle edge */
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
);
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
);
379 xbase
= (x
+v
+w
) / L
* 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
);
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
);
396 /* check all edges and inside */
405 int stage_ycollide(int x
, int y
, int w
, int h
, int v
, int* yy
){
407 int type
= calc_corners(x
,y
+v
,w
,h
,corners
);
408 // int x_min = INT_MAX;
409 // int x_max = INT_MIN;
411 int ybase
= (y
+v
) / L
* L
;
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
);
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
);
444 ybase
= (y
+v
+h
) / L
* 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
);
455 /* also check middle edge */
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
);
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
);
479 /* also check middle edge */
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
);
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
);
499 ybase
= (y
+v
+h
) / L
* 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
);
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
);
517 /* check all edges and inside */
529 /*** end collision stuff ***/
534 static void initialize_tiles(int n
, tile
* tiles
){
537 tiles
[i
].shape
= SHAPE_FREE
;
544 static int load_stage(char* gfxpath
, char* stagepath
){
557 reader
* f
= loader_open(stagepath
);
558 char* filename
= path_ending(stagepath
);
562 stage
* s
= malloc(sizeof(stage
));
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
);
572 s
->bgimage
= load_bitmap(gfx
);
574 loader_scanline(f
, "%s", buf
);
575 strcpy(gfx
, gfxpath
);
577 s
->bgtiles
= load_bitmap(gfx
);
579 loader_scanline(f
, "%s", buf
);
580 strcpy(gfx
, gfxpath
);
582 s
->fgtiles
= load_bitmap(gfx
);
584 s
->tiles
= malloc(w
*h
*sizeof(tile
));
585 initialize_tiles(w
*h
, s
->tiles
);
590 strncpy(s
->id
, filename
, 256);
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
));
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
624 char stagesdir
[256] = "";
625 char gfxpath
[256] = "";
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
);
641 printf("ERROR cant read dirs\n");
647 stagepath
= ptr
->item
;
648 if(load_stage(gfxpath
, stagepath
) < 0){
649 printf("ERROR cant load stage\n");
650 loader_freedirlist(dirs
);
656 loader_freedirlist(dirs
);
670 strcpy(zone_name
, "NO ZONE");
673 void switch_stage(string id
){
676 if(strcmp(id
, ptr
->id
) == 0){
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
;
690 int tw
= this_stage
->w
;
691 int th
= this_stage
->h
;
705 screen_dimensions(&W
, &H
);
707 extra_x
= (W
- 320)/16/2 + 2;
710 extra_y
= (H
- 240)/16/2 + 2;
718 if(io
> tw
-1) return;
719 if(jo
> th
-1) return;
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
;
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
){
746 int bw
, bh
, screen_w
, screen_h
;
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
++){
762 (i
+bgshift
)*bw
-cx
/parallax
,
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
);
802 printf("stage debug:\n\n");
803 printf("zone: %s\n\n", zone_name
);
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
);
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);