Merge branch 'stage'
[cantaveria.git] / stage.c
blobf5b149e42002ce03707a9cd870a2b19804798282
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 zid;
74 int i, j;
75 char fg[20][15];
76 char bg[20][15];
77 list* decs;
78 enum cardinal snap[4];
79 zoneport* exit;
80 } stage;
82 typedef struct {
83 int id;
84 char name[32];
85 int w, h, i, j;
86 int fgtiles;
87 int bgtiles;
88 int dectiles;
89 int bgimage;
90 enum tile_shape shapes[256];
91 stage** stages; // w by h array
92 } zone;
97 typedef struct {
98 int x, y;
99 int shape;
100 int none;
101 } block;
106 /* VVV */
107 list* zones = NULL;
108 /* ^^^ */
112 enum cardinal dir_of(int i, int j){
113 if(i < 0) return WEST;
114 if(j < 0) return NORTH;
115 if(i > 0) return EAST;
116 if(j > 0) return SOUTH;
117 fatal_error("stage.c: (%d,%d) is not a valid direction\n", i, j);
118 return NORTH;
125 /* zones and stages */
126 zone* find_zone_by_id(int id){
127 list* ptr = zones->next;
128 while(ptr){
129 zone* z = ptr->item;
130 if(z->id == id) return z;
131 ptr = ptr->next;
133 return NULL;
136 zone* zone_of_stage(stage* s){
137 return find_zone_by_id(s->zid);
140 stage* stage_lookup(zone* z, int i, int j){
141 if(i < 0 || i >= z->w || j < 0 || j >= z->h){
142 return NULL;
144 return *(z->stages + i + j*z->w);
148 stage* follow_zoneport(zoneport* zp){
149 zone* z = find_zone_by_id(zp->zone);
150 return stage_lookup(z, zp->i, zp->j);
153 stage* find_stage(stage* home, int i, int j){
154 zone* z = zone_of_stage(home);
155 int si = i/20;
156 int sj = j/15;
157 int di = home->i - si;
158 int dj = home->j - sj;
159 if(di==0 && dj==0)
160 return home;
162 else if(home->exit && home->exit->dir == dir_of(di,dj))
163 return follow_zoneport(home->exit);
165 else
166 return stage_lookup(z, si - z->w, sj - z->h);
169 stage* load_stage(reader* rd){
170 int i,j;
171 stage* s = xmalloc(sizeof(stage));
172 s->i = read_short(rd);
173 s->j = read_short(rd);
174 read_byte(rd); // flags ?
176 for(i=0; i<4; i++){
177 char* str = read_string(rd);
178 free(str);
181 for(i=0; i<15; i++){
182 for(j=0; j<20; j++){
183 s->fg[i][j] = read_byte(rd);
187 return s;
190 /* collision computations */
191 /*FIXME*/
192 int left_side_of(block bl, int top, int bottom){
193 return bl.x;
196 int right_side_of(block bl, int top, int bottom){
197 return bl.x + 16;
200 int top_of(block bl, int left, int right){
201 return bl.y;
204 int bottom_of(block bl, int left, int right){
205 return bl.y + 16;
208 int xhit(int v, block block, int top, int bottom){
209 if(v > 0) return left_side_of(block, top, bottom);
210 if(v < 0) return right_side_of(block, top, bottom);
211 return 0;
214 int yhit(int v, block block, int left, int right){
215 if(v > 0) return top_of(block, left, right);
216 if(v < 0) return bottom_of(block, left, right);
217 return 0;
220 int rect_is_on(block bl, int L, int R, int T, int B){
221 int l = bl.x;
222 int r = bl.x + 16;
223 int t = bl.y;
224 int b = bl.y + 16;
225 return !(r < L || l > R || t > B || b < T);
232 /* blocks */
233 block make_block(int shape, int x, int y, int none){
234 block bl;
235 bl.x = x;
236 bl.y = y;
237 bl.none = none;
238 bl.shape = shape;
239 return bl;
242 block no_block(){
243 return make_block(0, 0, 0, 1);
246 block null_block(){
247 return make_block(SHAPE_NULL, 0, 0, 0);
250 block block_of(int shape, int x, int y){
251 return make_block(shape, x, y, 0);
254 /* get block in s at i j */
255 block block_from_stage(stage* s, int i, int j){
256 zone* z = zone_of_stage(s);
257 int tile = s->fg[i][j];
258 int shape = z->shapes[tile];
259 return block_of(shape, i, j);
262 /* get block at absolute x y if you are in stage home */
263 block get_block(stage* home, int x, int y){
264 zone* z = zone_of_stage(home);
265 int i = x/1024/16 - (home->i + z->i)*20;
266 int j = y/1024/16 - (home->j + z->j)*15;
268 stage* s = find_stage(home, i, j);
269 if(s == NULL)
270 return null_block();
271 else
272 return block_from_stage(s, i, j);
275 /* returns either a block that the rect is intersecting
276 or it returns a block with none set to 1 */
277 block intersecting_block(stage* s, int left, int right, int top, int bottom){
278 int i;
279 for(i=0; i<4; i++){
280 block bl;
281 switch(i){
282 case 0: bl = get_block(s, top, left); break;
283 case 1: bl = get_block(s, top, right); break;
284 case 2: bl = get_block(s, bottom, left); break;
285 case 3: bl = get_block(s, bottom, right); break;
287 if(rect_is_on(bl, left, right, top, bottom)) return bl;
289 return no_block();
297 /* public methods */
298 void stage_init(){
299 zones = empty();
303 int load_zone_gfx(reader* rd){
304 char* filename = read_string(rd);
305 int id = load_bitmap(filename);
306 free(filename);
307 return id;
311 int load_zone(char* filename){
312 int i, j;
314 reader* rd = data_open("zones/", filename);
315 zone* z = xmalloc(sizeof(zone)); /* load routine */
317 strncpy(z->name, filename, 32);
318 z->id = 0;
319 z->fgtiles = load_zone_gfx(rd);
320 // z->bgtiles = load_zone_gfx(rd);
321 // z->dectiles = load_zone_gfx(rd);;
322 z->bgimage = load_bitmap("background.tga");
324 for(i=0; i<256; i++){
325 z->shapes[i] = read_byte(rd);
328 z->i = read_short(rd);
329 z->j = read_short(rd);
330 z->w = read_short(rd);
331 z->h = read_short(rd);
332 z->stages = xmalloc(z->w * z->h * sizeof(stage*));
334 for(i=0; i < z->w; i++){
335 for(j=0; j < z->h; j++){
336 *(z->stages + i + j*z->w) = NULL;
340 int N = read_short(rd);
341 for(i=0; i<N; i++){
342 stage* s = load_stage(rd);
343 z->stages[s->i + s->j * z->w] = s;
346 push(zones, z);
347 return z->id;
351 void print_zone(int id){
352 zone* z = find_zone_by_id(id);
353 printf("zone: %p\n", z);
357 void stage_bind_camera(location l, int* x, int* y){
358 //for each snap, snap x y
361 void draw_stage_fg(location loc, int cx, int cy){
362 //draw decorations
363 //draw water
366 void draw_stage_bg(location loc, int cx, int cy){
367 //for each visible tile
368 //bg or bg tiles or fg tiles
371 /* returns 1 if a collision will occur, 0 otherwise
372 if 1 is returned, x will be set to the collision point */
373 int stage_xcollide(location loc, int w, int h, int v, int* x){
374 zone* z = find_zone_by_id(loc.z);
375 stage* s = stage_lookup(z, loc.i, loc.j);
376 int X = loc.x + v*10; /* FIXME dt */
377 int right = X + w;
378 int left = X;
379 int top = loc.y;
380 int bottom = loc.y + h;
382 block bl = intersecting_block(s, left, right, top, bottom);
384 if(bl.none) return 0;
385 else{
386 *x = xhit(v, bl, top, bottom);
387 return 1;
391 int stage_ycollide(location loc, int w, int h, int v, int* y){
392 return 0;