Imported kball_final_src_16dec2004.tar.gz
[kball.git] / src / tmap.cpp
blob2508e8768eb5e0fe2ce4dd81714b30ba6a16b14c
1 // ------------------------------------------------------------------
2 // tmap.cpp
3 // ------------------------------------------------------------------
4 // This handles the tile map for the ball game
5 // ------------------------------------------------------------------
6 // By Kronoman - In loving memory of my father
7 // Copyright (c) 2003, Kronoman
8 // ------------------------------------------------------------------
9 // ** VERY IMPORTANT NOTICE **
11 // SINCE THE WALLS ARE 3D RENDERED, ALL DRAW ROUTINES *NEED*
12 // A 3D Allegro's create_scene(int nedge, int npoly); BEFORE CALLING THEM!
13 // ------------------------------------------------------------------
14 #include "tmap.h"
16 // NOTE: instead of printf, strcmp, etc, I use the Allegro's UNICODE equivalents
18 // ============================================================================
19 // ============================================================================
20 // CTileClass class
21 // ============================================================================
22 // ============================================================================
24 // ----------------------------------------------------------------------------
25 // Constructor
26 // ----------------------------------------------------------------------------
27 CTileClass::CTileClass()
29 adx = ady = adz = 0.0;
30 mdx = mdy = mdz = 1.0;
31 bounce_factor = 0.9;
32 exit_level = false;
33 solid = false;
34 spr = NULL;
35 sound = NULL;
37 // relative to prize layer
38 score = 0;
39 indispensable = false;
40 is_a_prize = false;
42 usprintf(spr_name,"NULL");
43 usprintf(sound_name,"NULL");
46 // ----------------------------------------------------------------------------
47 // Destructor
48 // ----------------------------------------------------------------------------
49 CTileClass::~CTileClass()
51 // nothing to be done here yet
54 // ----------------------------------------------------------------------------
55 // This saves parameters to a previously set config *FILE* (not memory pointer)
56 // nt is the tile number ID
57 // ----------------------------------------------------------------------------
59 void CTileClass::save_to_config(int nt)
61 char str1[2048];
63 usprintf(str1,"TILE_%d", nt); // section to read
65 set_config_float(str1, "bounce_factor", bounce_factor);
67 set_config_float(str1, "adx", adx);
68 set_config_float(str1, "ady", ady);
69 set_config_float(str1, "adz", adz);
71 set_config_float(str1, "mdx", mdx);
72 set_config_float(str1, "mdy", mdy);
73 set_config_float(str1, "mdz", mdz);
75 set_config_int(str1, "exit_level", (int)exit_level);
76 set_config_int(str1, "solid", (int)solid);
78 set_config_string(str1, "spr", spr_name);
79 set_config_string(str1, "sound", sound_name);
81 set_config_int(str1, "score", score);
82 set_config_int(str1, "is_a_prize", is_a_prize);
83 set_config_int(str1, "indispensable", (int)indispensable);
87 // ----------------------------------------------------------------------------
88 // This loads the tile 'nt' (1..255) from a *previously* set config
89 // is mean to be called ONLY by CTMap::load_tile_set_from_file()
90 // ----------------------------------------------------------------------------
91 void CTileClass::load_from_config(int nt, CWDatafile *data)
93 char str1[2048];
95 usprintf(str1,"TILE_%d", nt); // section to read
97 // parameters
98 bounce_factor = get_config_float(str1, "bounce_factor", 0.9);
99 adx = get_config_float(str1, "adx", 0.0);
100 ady = get_config_float(str1, "ady", 0.0);
101 adz = get_config_float(str1, "adz", 0.0);
103 mdx = get_config_float(str1, "mdx", 1.0);
104 mdy = get_config_float(str1, "mdy", 1.0);
105 mdz = get_config_float(str1, "mdz", 1.0);
107 exit_level = (bool)get_config_int(str1, "exit_level", 0);
108 solid = (bool)get_config_int(str1, "solid", 0);
110 indispensable = (bool)get_config_int(str1,"indispensable",0);
111 score = get_config_int(str1, "score", 0);
112 is_a_prize = (bool)get_config_int(str1, "is_a_prize", 0);
114 if (indispensable)
115 is_a_prize = true; // if is indispensable, it must has the prize flag set
117 // sprite
118 spr = NULL; // default value for sprite
120 usprintf(spr_name, "%s", get_config_string(str1, "spr", "null")); // I'm interested in keep the sprite name for future saving of tile set to disk
122 // if spr_name != "null", then the sprite is defined, so fint it or die trying :P
123 if (ustricmp(spr_name, "null") != 0)
125 spr = (BITMAP *)data->get_resource_dat(spr_name);
128 // sound
129 sound = NULL;
131 usprintf(sound_name, "%s", get_config_string(str1, "sound", "null")); // I'm interested in keep the sound name for future saving of tile set to disk
133 if (ustricmp(sound_name, "null") != 0)
135 sound = (SAMPLE *)data->get_resource_dat(sound_name);
138 // done
141 // ----------------------------------------------------------------------------
142 // Draws the tile on bmp at x,y (pixel coordinates)
143 // draw_grid is of use for the map editor, will signal bad sprites
144 // layer is used to determine highness of the thing.
145 // * Note: prizes aren't scaled *
146 // ----------------------------------------------------------------------------
148 void CTileClass::draw(BITMAP *bmp, int x, int y, bool draw_grid, int layer)
150 V3D_f *v_xyz_p[4]; // this is needed to pass the array pointer to software renderer
151 V3D_f pc_v[8]; // the 8 vertex of the quad are precalculated and stored here
153 int poltype = POLYTYPE_ATEX_MASK; // type of polygon to render, usually POLYTYPE_ATEX_MASK
155 float dx, dy; // displacement to give '3D look'
156 float scale_top = 5; // how much to add to the size of top block (pixels) (this is the height of the walls also)
158 if (is_a_prize)
159 scale_top = 0; // is a prize? don't scale
162 if (spr == NULL)
164 if (draw_grid)
166 line(bmp,x,y,x+TMAPS_W, y+TMAPS_H, makecol(255,0,0));
167 line(bmp,x+TMAPS_W, y, x, y+TMAPS_H, makecol(255,0,0));
169 return;
172 // maximun displacement of top of wall's box
173 #define max_displacement 32.0
174 dx = ((x+spr->w/2) - (bmp->w/2)) * (max_displacement) / (float)(bmp->w/2.0);
175 dy = ((y+spr->h/2) - (bmp->h/2)) * (max_displacement) / (float)(bmp->h/2.0);
177 #undef max_displacement
180 // 3D rendered (by software render, no OpenGL)
182 // precalculate the 8 vertex, 4 first are 'on ground'
183 // REMEMBER to set 'u' and 'v' parameters for texture for each face!!!
184 // 0-->1
185 // 3<--2
187 // 4 last are 'on roof'
188 // 4-->5
189 // 7<--6
190 pc_v[0].x=x;
191 pc_v[0].y=y;
193 pc_v[1].x=x+spr->w;
194 pc_v[1].y=y;
196 pc_v[2].x=x+spr->w;
197 pc_v[2].y=y+spr->h;
199 pc_v[3].x=x;
200 pc_v[3].y=y+spr->h;
202 pc_v[0].z=pc_v[1].z=pc_v[2].z=pc_v[3].z=1;
204 pc_v[4].x=x + dx - scale_top;
205 pc_v[4].y=y + dy - scale_top;
207 pc_v[5].x=x + dx + spr->w + scale_top;
208 pc_v[5].y=y + dy - scale_top;
210 pc_v[6].x=x + spr->w + dx + scale_top;
211 pc_v[6].y=y + spr->h + dy + scale_top;
213 pc_v[7].x=x + dx - scale_top ;
214 pc_v[7].y=y + dy + spr->h + scale_top;
216 pc_v[4].z=pc_v[5].z=pc_v[6].z=pc_v[7].z=0.1;
218 // is a floor, or wall?
219 if (solid)
222 // wall box
224 // top face (roof)
225 v_xyz_p[0] = &pc_v[4];
226 v_xyz_p[1] = &pc_v[5];
227 v_xyz_p[2] = &pc_v[6];
228 v_xyz_p[3] = &pc_v[7];
230 pc_v[4].u = 0;
231 pc_v[4].v = 0;
232 pc_v[5].u = spr->w;
233 pc_v[5].v = 0;
234 pc_v[6].u = spr->w;
235 pc_v[6].v = spr->h;
236 pc_v[7].u = 0;
237 pc_v[7].v = spr->h;
239 scene_polygon3d_f(poltype, spr, 4, v_xyz_p); // top polygon
241 // upper face
242 v_xyz_p[0] = &pc_v[4];
243 v_xyz_p[1] = &pc_v[5];
244 v_xyz_p[2] = &pc_v[1];
245 v_xyz_p[3] = &pc_v[0];
247 pc_v[4].u = 0;
248 pc_v[4].v = 0;
249 pc_v[5].u = spr->w;
250 pc_v[5].v = 0;
251 pc_v[1].u = spr->w;
252 pc_v[1].v = spr->h;
253 pc_v[0].u = 0;
254 pc_v[0].v = spr->h;
256 scene_polygon3d_f(poltype, spr, 4, v_xyz_p);
258 // bottom face
259 v_xyz_p[0] = &pc_v[3];
260 v_xyz_p[1] = &pc_v[2];
261 v_xyz_p[2] = &pc_v[6];
262 v_xyz_p[3] = &pc_v[7];
264 pc_v[3].u = 0;
265 pc_v[3].v = 0;
266 pc_v[2].u = spr->w;
267 pc_v[2].v = 0;
268 pc_v[6].u = spr->w;
269 pc_v[6].v = spr->h;
270 pc_v[7].u = 0;
271 pc_v[7].v = spr->h;
273 scene_polygon3d_f(poltype, spr, 4, v_xyz_p);
275 // left face
276 v_xyz_p[0] = &pc_v[0];
277 v_xyz_p[1] = &pc_v[4];
278 v_xyz_p[2] = &pc_v[7];
279 v_xyz_p[3] = &pc_v[3];
281 pc_v[0].u = 0;
282 pc_v[0].v = 0;
283 pc_v[4].u = spr->w;
284 pc_v[4].v = 0;
285 pc_v[7].u = spr->w;
286 pc_v[7].v = spr->h;
287 pc_v[3].u = 0;
288 pc_v[3].v = spr->h;
290 scene_polygon3d_f(poltype, spr, 4, v_xyz_p);
292 // right face
293 v_xyz_p[0] = &pc_v[1];
294 v_xyz_p[1] = &pc_v[5];
295 v_xyz_p[2] = &pc_v[6];
296 v_xyz_p[3] = &pc_v[2];
298 pc_v[1].u = 0;
299 pc_v[1].v = 0;
300 pc_v[5].u = spr->w;
301 pc_v[5].v = 0;
302 pc_v[6].u = spr->w;
303 pc_v[6].v = spr->h;
304 pc_v[2].u = 0;
305 pc_v[2].v = spr->h;
307 scene_polygon3d_f(poltype, spr, 4, v_xyz_p);
311 else
314 // flat surface
315 if (layer == 0 || is_a_prize)
317 v_xyz_p[0] = &pc_v[0];
318 v_xyz_p[1] = &pc_v[1];
319 v_xyz_p[2] = &pc_v[2];
320 v_xyz_p[3] = &pc_v[3];
322 pc_v[0].u = 0;
323 pc_v[0].v = 0;
324 pc_v[1].u = spr->w;
325 pc_v[1].v = 0;
326 pc_v[2].u = spr->w;
327 pc_v[2].v = spr->h;
328 pc_v[3].u = 0;
329 pc_v[3].v = spr->h;
331 pc_v[0].z=pc_v[1].z=pc_v[2].z=pc_v[3].z= (is_a_prize) ? 0.15 : 1;
333 else
335 v_xyz_p[0] = &pc_v[4];
336 v_xyz_p[1] = &pc_v[5];
337 v_xyz_p[2] = &pc_v[6];
338 v_xyz_p[3] = &pc_v[7];
340 pc_v[4].u = 0;
341 pc_v[4].v = 0;
342 pc_v[5].u = spr->w;
343 pc_v[5].v = 0;
344 pc_v[6].u = spr->w;
345 pc_v[6].v = spr->h;
346 pc_v[7].u = 0;
347 pc_v[7].v = spr->h;
349 pc_v[4].z=pc_v[5].z=pc_v[6].z=pc_v[7].z=0.1;
352 scene_polygon3d_f(poltype, spr, 4, v_xyz_p); // render polygon to scene
356 // ============================================================================
357 // ============================================================================
358 // CTMap class
359 // ============================================================================
360 // ============================================================================
362 // ----------------------------------------------------------------------------
363 // Constructor
364 // ----------------------------------------------------------------------------
366 CTMap::CTMap()
368 empty_the_map(); // reset the map
370 timer_tick_rate = 30; // set this to measure timer tick rate, otherwise, the time will run wild (ex: if update logic is called 30 times by second, then set this to 30)
373 // ----------------------------------------------------------------------------
374 // Destructor - NUNCA DEBE SER LLAMADO AUTOMATICAMENTE POR C++
375 // PORQUE GENERA SEG FAULT, YA QUE ALLEGRO MUERE *ANTES* QUE ESTO
376 // Y LA LIBERACION DE MEMORIA *NO* ANDA
377 // ----------------------------------------------------------------------------
379 CTMap::~CTMap()
381 free_memory();
384 // ----------------------------------------------------------------------------
385 // This free the memory used by the map and the tile set
386 // ----------------------------------------------------------------------------
387 void CTMap::free_memory()
389 tile_set_data.nuke_datafile();
392 // ----------------------------------------------------------------------------
393 // Resets all map to 0s
394 // ----------------------------------------------------------------------------
395 void CTMap::empty_the_map()
397 for (int l =0; l < MAP_LAYERS; l++)
398 for (int x = 0; x < TMAP_SIZE; x++)
399 for (int y = 0; y < TMAP_SIZE; y++)
400 tile_map[x][y][l] = 0; // empty the map
402 // reset start position too (centered)
403 sxp = TMAP_SIZE / 2;
404 syp = TMAP_SIZE / 2;
406 // reset other stuff
407 prize_map_indispensable = 0;
408 time_m = 60;
409 time_s = 0;
410 background_index = 0;
411 music_index = 0;
413 curr_tick = -1; // special flag, means 'start recounting'
416 // ----------------------------------------------------------------------------
417 // This returns if a tile is walkable only
418 // Is useful to see if the ball can move or not in some particular direction
419 // Is not useful for check if the ball must fall (for that purpose,
420 // use get_tile_type and check against < 1 (empty))
422 // This serves for validation purposes (for the ball), will return true
423 // if the tile is walkable, false otherwise (outside map counts as non walkable)
424 // ----------------------------------------------------------------------------
426 bool CTMap::get_tile_walkable(int x, int y, int layer)
428 if (x < 0 || y < 0 || x > TMAP_SIZE-1 || y > TMAP_SIZE-1 || layer < 0 || layer > MAP_LAYERS-1)
429 return false; // outside map!
431 if (tile_set[tile_map[x][y][layer]].solid)
432 return false; // the place is solid
434 // if the tile is empty, or solid = false; then he can walk
435 return true;
438 // ----------------------------------------------------------------------------
439 // This returns the tile type (1..255), or -1 if outside map, or 0 if empty
440 // if empty, or outside map, ball should fall free to death
441 // ----------------------------------------------------------------------------
442 int CTMap::get_tile_type(int x, int y, int layer)
444 if (x < 0 || y < 0 || x > TMAP_SIZE-1 || y > TMAP_SIZE-1 || layer < 0 || layer > MAP_LAYERS-1)
445 return -1; // outside map!
447 return tile_map[x][y][layer];
450 // ----------------------------------------------------------------------------
451 // this sets the tile type at x,y (0..255) x,y are coordinates of the matrix
452 // ----------------------------------------------------------------------------
453 void CTMap::set_tile_type(int x, int y, int layer, int value)
455 if (x < 0 || y < 0 || x > TMAP_SIZE-1 || y > TMAP_SIZE-1 || layer < 0 || layer > MAP_LAYERS-1)
456 return; // outside map!
457 tile_map[x][y][layer] = value;
460 // ----------------------------------------------------------------------------
461 // Loads a tile map from a file, return true if FAILS, false otherwise
462 // NOTICE: FOR THIS TO COUNT PROPERLY THE PRIZE, THE TILE SET SHOULD BE *ALREADY* LOADED
463 // NOTICE: the header of the file is '6''6''6''M''A''P' (6 chars = "666MAP"
464 // ----------------------------------------------------------------------------
465 bool CTMap::load_map_from_file(const char *filename)
467 prize_map_indispensable = 0; //reset prize count
469 // All file I/O in maps is done using Allegro's packfiles, that way I use compression :D
470 PACKFILE *fp = NULL;
472 fp = pack_fopen(filename, F_READ);
474 if (fp == NULL)
475 return true; // error d00d! :(
477 // check header
478 if (pack_getc(fp) != '6')
479 return true; // error
480 if (pack_getc(fp) != '6')
481 return true; // error
482 if (pack_getc(fp) != '6')
483 return true; // error
484 if (pack_getc(fp) != 'M')
485 return true; // error
486 if (pack_getc(fp) != 'A')
487 return true; // error
488 if (pack_getc(fp) != 'P')
489 return true; // error
491 // start reading data
493 // start pos of the player
494 sxp = pack_getc(fp);
495 syp = pack_getc(fp);
497 // time of the map
498 time_m = pack_getc(fp);
499 time_s = pack_getc(fp);
501 // now, get the rest of the map
502 for (int l = 0; l < MAP_LAYERS; l ++)
504 for (int x = 0; x < TMAP_SIZE; x++)
506 for (int y = 0; y < TMAP_SIZE; y++)
508 // if we reach eof before ending the loop, a error occurs, I need all the map !
509 if (pack_feof(fp))
511 pack_fclose(fp);
512 return true; // error!
514 tile_map[x][y][l] = pack_getc(fp);
516 // check if it is a indispensable prize, count it ;
517 // DEBUG: this only counts the indispensable intems if the layer == 1,
518 // otherwise they are on the floor and can't be pick up
519 if (tile_set[tile_map[x][y][l]].indispensable && l == 1)
521 prize_map_indispensable++;
527 // get background ID
528 background_index = pack_getc(fp);
530 // get music index ID
531 music_index = pack_getc(fp);
533 pack_fclose(fp); // ready
535 return false; // all OK
538 // ----------------------------------------------------------------------------
539 // Save tile map to filename, return true if FAILS, false otherwise
540 // NOTICE: the header of the file is '6''6''6''M''A''P' (6 chars = "666MAP"
541 // ----------------------------------------------------------------------------
543 bool CTMap::save_map_to_file(const char *filename)
545 PACKFILE *fp = NULL;
547 fp = pack_fopen(filename, F_WRITE); // DEBUG - deberia ser PACKED, pero PIERDE 2 bytes (BUG de Allegro?)
549 if (fp == NULL)
550 return true; // error d00d! :(
552 // Put file's header '666MAP'
553 pack_putc('6', fp);
554 pack_putc('6', fp);
555 pack_putc('6', fp);
556 pack_putc('M', fp);
557 pack_putc('A', fp);
558 pack_putc('P', fp);
561 // put 2 bytes, start pos of the player
562 pack_putc((char)sxp, fp);
563 pack_putc((char)syp, fp);
565 // time of the map
566 pack_putc((char)time_m, fp);
567 pack_putc((char)time_s, fp);
569 // now, set the rest of the map
570 for (int l = 0; l < MAP_LAYERS; l ++)
571 for (int x = 0; x < TMAP_SIZE; x++)
572 for (int y = 0; y < TMAP_SIZE; y++)
573 pack_putc((char)tile_map[x][y][l], fp);
575 // set background ID
576 pack_putc((char)background_index, fp);
578 // set music ID
579 pack_putc((char)music_index, fp);
581 // DEBUG:: pad with extra bytes, this was used to fix a _PACK bug, but is no more needed, anyways let it here
582 for (int pad=0; pad<916; pad++)
583 pack_putc(rand()%128+64, fp);
585 pack_fclose(fp); // ready
586 return false;
589 // ----------------------------------------------------------------------------
590 // loads a tile set from a DATAFILE (filename is the name of the datafile),
591 // return true if FAILS, false otherwise
592 // ----------------------------------------------------------------------------
593 bool CTMap::load_tile_set_from_file(char *filename)
595 this->free_memory(); // free used memory first
597 if (tile_set_data.load_datafile(filename))
598 return true; // failed :P
600 // now, cache all tile set sprites and all the stuff
602 // first, I need the tile set configuration, text object named "TILE_SET_CFG_TXT"
603 if (tile_set_data.get_resource_dat("TILE_SET_CFG_TXT") == NULL)
604 return true; // error, can't load tile sets without the configuration thing :(
606 push_config_state(); // to later restore config settings
607 // set the config to the data
608 set_config_data((char *)tile_set_data.get_resource_dat("TILE_SET_CFG_TXT"), tile_set_data.get_resource("TILE_SET_CFG_TXT")->size);
610 // get all the tile set
611 for (int i = 1; i < 256; i++)
612 tile_set[i].load_from_config(i, &tile_set_data);
614 pop_config_state(); // restore config settings
616 return false; // done
619 // ----------------------------------------------------------------------------
620 // saves the tile set configuration to a text file (no saves the bitmaps!)
621 // return true if FAILS, false otherwise
622 // ----------------------------------------------------------------------------
624 bool CTMap::save_tile_set_config_to_file(char *filename)
626 push_config_state();
628 // set file
629 set_config_file(filename);
631 // save all data
632 for (int i = 1; i < 256; i++)
633 tile_set[i].save_to_config(i);
635 pop_config_state();
636 return false; // done OK
640 // ----------------------------------------------------------------------------
641 // Draws a zone of a layer of the map, coordinates are in pixels
643 // ix, iy = top left coordinate of map area to draw
644 // iw, ih = width, height of map area to draw
645 // draw_grid = draws the grid on top, only useful for the mapeditor
647 // NOTE: this has 3D software code embedded from Allegro, it *needs*
648 // a create_scene(), clear_scene() call somewhere before using this, and a
649 // ----------------------------------------------------------------------------
651 void CTMap::draw_map(BITMAP *bmp, int ix, int iy, int iw, int ih, int layer, bool draw_grid)
653 // I want the integer remainder, so I can scroll
654 // this returns the remainder of a/b
655 #define remainder(a,b) (a-((a/b)*b))
657 int ret,xof,yof;
659 if (layer < 0 || layer > MAP_LAYERS-1)
660 return;
662 xof = remainder(ix, TMAPS_W);
663 yof = remainder(iy, TMAPS_H);
665 for (int y = iy; y < iy + ih + TMAPS_H; y += TMAPS_H)
667 for (int x = ix; x < ix + iw + TMAPS_W; x += TMAPS_W)
669 ret = get_tile_type( (x / TMAPS_W), (y / TMAPS_H), layer );
670 if (ret > 0)
671 tile_set[ret].draw(bmp, x-ix-xof, y-iy-yof, draw_grid,layer);
673 if (x > TMAP_SIZE*TMAPS_W)
674 break; // outside bounds, no need to do it
676 // draw the 'start' of the player, and the grid (only useful for the map editor)
677 if (draw_grid)
679 rect(bmp, x-ix-xof, y-iy-yof, x-ix-xof+TMAPS_W,y-iy-yof+TMAPS_H, makecol(128,128,128));
680 if (x / TMAPS_W == sxp && y / TMAPS_H == syp)
682 circle(bmp, x-ix-xof+TMAPS_W/2, y-iy-yof+TMAPS_H/2, TMAPS_W/2, makecol(0,0,255));
683 circle(bmp, x-ix-xof+TMAPS_W/2, y-iy-yof+TMAPS_H/2, TMAPS_W/3, makecol(255,0,0));
684 circle(bmp, x-ix-xof+TMAPS_W/2, y-iy-yof+TMAPS_H/2, TMAPS_W/4, makecol(0,255,0));
688 if (y > TMAP_SIZE*TMAPS_H)
689 break; // outside bounds, no need to do it
697 // ----------------------------------------------------------------------------
698 // updates the logic of the map (animations, time remaining, etc)
699 // ----------------------------------------------------------------------------
701 void CTMap::update_logic()
703 curr_tick--;
704 if (curr_tick < 0)
706 curr_tick = timer_tick_rate;
708 time_s--;
709 if (time_s < 0)
711 time_m--;
712 if (time_m < 0)
714 time_m = 0; // your time is OVER d00d! HA HA HA HA die bastard die!
715 time_s = 0;
717 else
719 time_s = 59;