1 // ------------------------------------------------------------------
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 // ------------------------------------------------------------------
16 // NOTE: instead of printf, strcmp, etc, I use the Allegro's UNICODE equivalents
18 // ============================================================================
19 // ============================================================================
21 // ============================================================================
22 // ============================================================================
24 // ----------------------------------------------------------------------------
26 // ----------------------------------------------------------------------------
27 CTileClass::CTileClass()
29 adx
= ady
= adz
= 0.0;
30 mdx
= mdy
= mdz
= 1.0;
37 // relative to prize layer
39 indispensable
= false;
42 usprintf(spr_name
,"NULL");
43 usprintf(sound_name
,"NULL");
46 // ----------------------------------------------------------------------------
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
)
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
)
95 usprintf(str1
,"TILE_%d", nt
); // section to read
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);
115 is_a_prize
= true; // if is indispensable, it must has the prize flag set
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
);
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
);
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)
159 scale_top
= 0; // is a prize? don't scale
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));
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!!!
187 // 4 last are 'on roof'
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?
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];
239 scene_polygon3d_f(poltype
, spr
, 4, v_xyz_p
); // top polygon
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];
256 scene_polygon3d_f(poltype
, spr
, 4, v_xyz_p
);
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];
273 scene_polygon3d_f(poltype
, spr
, 4, v_xyz_p
);
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];
290 scene_polygon3d_f(poltype
, spr
, 4, v_xyz_p
);
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];
307 scene_polygon3d_f(poltype
, spr
, 4, v_xyz_p
);
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];
331 pc_v
[0].z
=pc_v
[1].z
=pc_v
[2].z
=pc_v
[3].z
= (is_a_prize
) ? 0.15 : 1;
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];
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 // ============================================================================
359 // ============================================================================
360 // ============================================================================
362 // ----------------------------------------------------------------------------
364 // ----------------------------------------------------------------------------
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 // ----------------------------------------------------------------------------
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)
407 prize_map_indispensable
= 0;
410 background_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
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
472 fp
= pack_fopen(filename
, F_READ
);
475 return true; // error d00d! :(
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
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 !
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
++;
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
)
547 fp
= pack_fopen(filename
, F_WRITE
); // DEBUG - deberia ser PACKED, pero PIERDE 2 bytes (BUG de Allegro?)
550 return true; // error d00d! :(
552 // Put file's header '666MAP'
561 // put 2 bytes, start pos of the player
562 pack_putc((char)sxp
, fp
);
563 pack_putc((char)syp
, fp
);
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
);
576 pack_putc((char)background_index
, fp
);
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
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
)
629 set_config_file(filename
);
632 for (int i
= 1; i
< 256; i
++)
633 tile_set
[i
].save_to_config(i
);
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))
659 if (layer
< 0 || layer
> MAP_LAYERS
-1)
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
);
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)
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()
706 curr_tick
= timer_tick_rate
;
714 time_m
= 0; // your time is OVER d00d! HA HA HA HA die bastard die!