Changed printf to error_msg.
[cantaveria.git] / stage.c
blob8e40fe2358e1b94d59c1a297e742ae633c425acb
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 int dummy;
172 stage* s = xmalloc(sizeof(stage));
173 read_short(rd, &s->i);
174 read_short(rd, &s->j);
175 read_byte(rd, &dummy); // flags ?
177 for(i=0; i<4; i++){
178 char* str;
179 read_string(rd, &str);
180 free(str);
183 for(i=0; i<15; i++){
184 for(j=0; j<20; j++){
185 read_byte(rd, (int*)&s->fg[i][j]);
189 return s;
192 /* collision computations */
193 /*FIXME*/
194 int left_side_of(block bl, int top, int bottom){
195 return bl.x;
198 int right_side_of(block bl, int top, int bottom){
199 return bl.x + 16;
202 int top_of(block bl, int left, int right){
203 return bl.y;
206 int bottom_of(block bl, int left, int right){
207 return bl.y + 16;
210 int xhit(int v, block block, int top, int bottom){
211 if(v > 0) return left_side_of(block, top, bottom);
212 if(v < 0) return right_side_of(block, top, bottom);
213 return 0;
216 int yhit(int v, block block, int left, int right){
217 if(v > 0) return top_of(block, left, right);
218 if(v < 0) return bottom_of(block, left, right);
219 return 0;
222 int rect_is_on(block bl, int L, int R, int T, int B){
223 int l = bl.x;
224 int r = bl.x + 16;
225 int t = bl.y;
226 int b = bl.y + 16;
227 return !(r < L || l > R || t > B || b < T);
234 /* blocks */
235 block make_block(int shape, int x, int y, int none){
236 block bl;
237 bl.x = x;
238 bl.y = y;
239 bl.none = none;
240 bl.shape = shape;
241 return bl;
244 block no_block(){
245 return make_block(0, 0, 0, 1);
248 block null_block(){
249 return make_block(SHAPE_NULL, 0, 0, 0);
252 block block_of(int shape, int x, int y){
253 return make_block(shape, x, y, 0);
256 /* get block in s at i j */
257 block block_from_stage(stage* s, int i, int j){
258 zone* z = zone_of_stage(s);
259 int tile = s->fg[i][j];
260 int shape = z->shapes[tile];
261 return block_of(shape, i, j);
264 /* get block at absolute x y if you are in stage home */
265 block get_block(stage* home, int x, int y){
266 zone* z = zone_of_stage(home);
267 int i = x/1024/16 - (home->i + z->i)*20;
268 int j = y/1024/16 - (home->j + z->j)*15;
270 stage* s = find_stage(home, i, j);
271 if(s == NULL)
272 return null_block();
273 else
274 return block_from_stage(s, i, j);
277 /* returns either a block that the rect is intersecting
278 or it returns a block with none set to 1 */
279 block intersecting_block(stage* s, int left, int right, int top, int bottom){
280 int i;
281 for(i=0; i<4; i++){
282 block bl;
283 switch(i){
284 case 0: bl = get_block(s, top, left); break;
285 case 1: bl = get_block(s, top, right); break;
286 case 2: bl = get_block(s, bottom, left); break;
287 case 3: bl = get_block(s, bottom, right); break;
289 if(rect_is_on(bl, left, right, top, bottom)) return bl;
291 return no_block();
299 /* public methods */
300 void stage_init(){
301 zones = empty();
305 int load_zone_gfx(reader* rd){
306 char* filename;
307 read_string(rd, &filename);
308 int id = load_bitmap(filename);
309 free(filename);
310 return id;
314 int load_zone(char* filename){
315 int i, j;
316 int N;
318 reader* rd = data_open("zones/", filename);
319 zone* z = xmalloc(sizeof(zone)); /* load routine */
321 strncpy(z->name, filename, 32);
322 z->id = 0;
323 z->fgtiles = load_zone_gfx(rd);
324 // z->bgtiles = load_zone_gfx(rd);
325 // z->dectiles = load_zone_gfx(rd);;
326 z->bgimage = load_bitmap("background.tga");
328 for(i=0; i<256; i++){
329 read_byte(rd, (int*)&z->shapes[i]);
332 read_short(rd, &z->i);
333 read_short(rd, &z->j);
334 read_short(rd, &z->w);
335 read_short(rd, &z->h);
336 z->stages = xmalloc(z->w * z->h * sizeof(stage*));
338 for(i=0; i < z->w; i++){
339 for(j=0; j < z->h; j++){
340 *(z->stages + i + j*z->w) = NULL;
344 read_short(rd, &N);
345 for(i=0; i<N; i++){
346 stage* s = load_stage(rd);
347 z->stages[s->i + s->j * z->w] = s;
350 push(zones, z);
351 return z->id;
355 void print_zone(int id){
356 zone* z = find_zone_by_id(id);
357 printf("zone: %p\n", z);
361 void stage_bind_camera(location l, int* x, int* y){
362 //for each snap, snap x y
365 void draw_stage_fg(location loc, int cx, int cy){
366 //draw decorations
367 //draw water
370 void draw_stage_bg(location loc, int cx, int cy){
371 //for each visible tile
372 //bg or bg tiles or fg tiles
375 /* returns 1 if a collision will occur, 0 otherwise
376 if 1 is returned, x will be set to the collision point */
377 int stage_xcollide(location loc, int w, int h, int v, int* x){
378 zone* z = find_zone_by_id(loc.z);
379 stage* s = stage_lookup(z, loc.i, loc.j);
380 int X = loc.x + v*10; /* FIXME dt */
381 int right = X + w;
382 int left = X;
383 int top = loc.y;
384 int bottom = loc.y + h;
386 block bl = intersecting_block(s, left, right, top, bottom);
388 if(bl.none) return 0;
389 else{
390 *x = xhit(v, bl, top, bottom);
391 return 1;
395 int stage_ycollide(location loc, int w, int h, int v, int* y){
396 return 0;