1 /*------------------------------------------------------------------.
2 | Copyright 2001, 2002  Alexandre Duret-Lutz <duret_g@epita.fr>     |
3 |                                                                   |
4 | This file is part of Heroes.                                      |
5 |                                                                   |
6 | Heroes is free software; you can redistribute it and/or modify it |
7 | under the terms of the GNU General Public License version 2 as    |
8 | published by the Free Software Foundation.                        |
9 |                                                                   |
10 | Heroes is distributed in the hope that it will be useful, but     |
11 | WITHOUT ANY WARRANTY; without even the implied warranty of        |
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU |
13 | General Public License for more details.                          |
14 |                                                                   |
15 | You should have received a copy of the GNU General Public License |
16 | along with this program; if not, write to the Free Software       |
17 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA          |
18 | 02111-1307 USA                                                    |
19 `------------------------------------------------------------------*/
20 
21 #ifndef HEROES__LVL__H
22 #define HEROES__LVL__H
23 
24 /* Tiles are units of 24x20 pixels, squares are units of 12x10 pixels.
25    There is 4 squares per tiles.
26 
27    Functions can use squares or tiles, depending on the resolution
28    with which entities are stored.  For instance the bonuses are
29    stored in a tile-sized array, while the vehicules are stored in an
30    squares-sized array.
31 
32    Those types are defined for better readability.  The a_*_coord
33    types are used to designate a coordinate (either X, or Y), while
34    the a_*_index are used for square numbers (indices in one
35    dimensional arrays: index = y_coord * width + x_coord).  */
36 typedef unsigned int a_square_coord;
37 typedef unsigned int a_square_index;
38 typedef unsigned int a_tile_coord;
39 typedef unsigned int a_tile_index;
40 #define INVALID_INDEX (~0u)
41 
42 typedef struct a_square_corrd_pair a_square_corrd_pair;
43 struct a_square_corrd_pair {
44   a_square_coord y, x;
45 };
46 
47 typedef struct a_tile_coord_pair a_tile_coord_pair;
48 struct a_tile_coord_pair {
49   a_tile_coord y, x;
50 };
51 
52 /* Direction constants.  */
53 typedef enum a_dir a_dir;
54 enum a_dir { D_UP = 0,
55 	     D_RIGHT = 1,
56 	     D_DOWN = 2,
57 	     D_LEFT = 3 };
58 typedef a_u8 a_dir8;		/* Hold the same values, on 8bits. */
59 #define REVERSE_DIR(d) ((d) ^ 2)
60 
61 /* Two direction on one byte (used for trails).
62    Don't change the encoding, this the resulting value is used
63    to lookup sprites to draw the trail.  */
64 typedef a_u8 a_dir8_pair;
65 #define DIR8_TAIL(X) ((X) >> 2)
66 #define DIR8_HEAD(X) ((X) & 0x3)
67 #define DIR8_PAIR(H, T) (((T) << 2) | (H))
68 
69 
70 /* Number of directions,
71    unless Heroes goes 3D this is unlikely to change :) */
72 #define DIR_MAX 4
73 
74 /* Similar constants, but OR-able, to indicate multiple directions.  */
75 typedef enum a_dir_mask a_dir_mask;
76 enum a_dir_mask { DM_UP = 1,
77 		  DM_RIGHT = 2,
78 		  DM_DOWN = 4,
79 		  DM_LEFT = 8 };
80 typedef a_u8 a_dir_mask8;	/* Hold the same values, on 8bits. */
81 #define DM_ALL (DM_UP | DM_RIGHT | DM_DOWN | DM_LEFT)
82 #define DIR_TO_DIRMASK(dir) (1 << (dir))
83 
84 /* Tile type constants.  */
85 typedef enum a_tile_type a_tile_type;
86 enum a_tile_type { T_NONE = 0,
87 		   T_STOP = 1,
88 		   T_SPEED = 2,
89 		   T_TUNNEL = 3,
90 		   T_BOOM = 4,
91 		   T_ANIM = 5,
92 		   T_ICE = 6,
93 		   T_DUST = 7,
94 		   T_OUTWAY = 8,
95 		   T_MAXTYPE	/* Keep this upper bound last in the enum. */};
96 typedef a_u8 a_tile_type8;	/* Hold the same values, on 8bits. */
97 
98 
99 typedef struct a_level a_level;	/* An Heroes level.  */
100 typedef struct a_level_bits a_level_bits; /* Hiden details about levels.  */
101 
102 
103 /* The pointers in the a_level structure should point to constant
104    data.  But from the level loading code the data need to be mutable.
105    So we allow const to be removed by defining LVL_MUTABLE.  */
106 
107 #ifndef LVL_MUTABLE
108 # define LVL_MUTABLE const
109 #endif
110 
111 struct a_level {
112   /*-------------.
113   | Dimensions.  |
114   `-------------*/
115 
116   /* We store the dimensions in those two units, so that they are
117      directly available.  */
118   a_tile_coord tile_height;
119   a_tile_coord tile_width;
120   a_square_coord square_height;
121   a_square_coord square_width;
122 
123   /* Some levels are wrapped: when the vehicle reach the right edge of
124      the level, they continue as if they were entering the level from
125      the left edge, and vice-versa.  Of course this can also be set
126      for the top and bottom.
127 
128      The _wrap members should be ANDed with a coordinate to wrap it.
129      For instance a wrapped level with a width of 32 will have
130      `tile_width_wrap' set to 31.  That way an y coordinate of 35 will
131      be mapped to 3 (== 35 & 31).  Non-wrapped level set this value to
132      `~0u' (== DONT_WRAP) so that ANDing is no-op.  */
133   a_tile_coord tile_height_wrap;
134   a_tile_coord tile_width_wrap;
135   a_square_coord square_height_wrap;
136   a_square_coord square_width_wrap;
137 
138   /* Most maps are allocated as one-dimensional arrays.  So we define
139      to more constants used for the size of the arrays.  */
140   a_tile_index tile_count;	/* == tile_width * tile_height */
141   a_square_index square_count;	/* == square_width * square_height */
142 
143   /*----------------------------------------------------------------.
144   | The following arrays are initialized only if the level body has |
145   | been loaded.  See the load_body argument of lvl_load_file.      |
146   `----------------------------------------------------------------*/
147 
148   /* Type of each square.  */
149   LVL_MUTABLE a_tile_type8 *square_type;
150   /* Set of blocked directions for each square.  If the entry is set
151      to DM_UP|DM_LEFT, it means a vehicle cannot *leave* the square
152      by the top or left edges.  */
153   LVL_MUTABLE a_dir_mask8 *square_walls_out;
154   /* Directions for squares for which it matters (i.e., T_SPEED, and
155      T_TUNNEL).  */
156   LVL_MUTABLE a_dir8 *square_direction;
157   /* square_move[D_UP][SQR] is the square that a vehicle shoud go into
158      when it leave SQR by the top edge.  */
159   LVL_MUTABLE a_square_index *square_move[DIR_MAX];
160 
161   /*-------------------------------------------------------------.
162   | Opaque structure to hide the remaining data.  Use one of the |
163   | following functions to access anything relevant in there.    |
164   `-------------------------------------------------------------*/
165 
166   LVL_MUTABLE a_level_bits *private;
167 };
168 
169 #ifndef DONT_WRAP
170 # define DONT_WRAP (~0u)	/* Used for non wrapping directions.  */
171 #endif
172 
173 /* Load a level from FILENAME to OUT.  Return 0 on success, !0
174    otherwise.  If LOAD_BODY is true, parse the body, and compute the
175    various constant square_* maps declared in a_level.  If LOAD_BODY
176    is false, only the header of the level will be loaded.  */
177 int lvl_load_file (const char *filename, a_level *out, bool load_body);
178 int lvl_save_file (const char *filename, const a_level *out);
179 /* Free any data associated to LVL.  */
180 void lvl_free (a_level *lvl);
181 
182 /* These two functions return a pointer to a string allocated for LVL,
183    and freed by lvl_free().  You should not free them yourself, and
184    you should not use these results after a call to lvl_free().  */
185 const char *lvl_sound_track (const a_level *lvl);
186 const char *lvl_tile_sprite_map_basename (const a_level *lvl);
187 
188 /* Initialize COORD, and DIR, with the starting position for PLAYER.  */
189 void lvl_start_position (const a_level *lvl, unsigned int player,
190 			 a_square_corrd_pair *coord, a_dir *dir);
191 
192 /*--------------------------------------------------------------------.
193 | NOTE: The following function will fail if the body of the level     |
194 | has not been loaded (see the load_body argument of lvl_load_file).  |
195 `--------------------------------------------------------------------*/
196 
197 /* Return the type of tile TILE on level LVL.  */
198 a_tile_type lvl_tile_type (const a_level *lvl, a_tile_index tile);
199 
200 /* Return the output direction of a tunnel on tile TILE.  This function
201    should only be called on tiles of type T_TUNNEL.  */
202 a_dir lvl_tunnel_output_dir (const a_level *lvl, a_tile_index tile);
203 
204 /* Return the offset (to the first pixel) of the sprite used to draw TILE.  */
205 unsigned int lvl_tile_sprite_offset (const a_level *lvl,
206 				     a_tile_index tile);
207 /* Return the offset (to the first pixel) of the overlay sprite to
208    draw on TILE.  */
209 unsigned int lvl_tile_sprite_overlay_offset (const a_level *lvl,
210 					     a_tile_index tile);
211 
212 /* Kind of animation.  */
213 typedef enum an_anim_kind an_anim_kind;
214 enum an_anim_kind { A_NONE, A_LOOP, A_PINGPONG };
215 
216 /* Return information about a possible animation on tile TILE.
217    FRAME_COUNT is the number of frames to display, and DELAY a number
218    of 1/70sec to wait between each frame.  Actually, FRAME_COUNT is
219    the number of sprites to display: FRAME_COUNT sprites starting at
220    the sprite index for the current tile should be displayed.
221 
222    There is no animation if FRAME_COUNT is set to 0.  */
223 void lvl_animation_info (const a_level *lvl, a_tile_index tile,
224 			 unsigned int *frame_count, unsigned int *delay,
225 			 an_anim_kind *kind);
226 
227 /*----------------.
228 | Useful macros.  |
229 `----------------*/
230 
231 /* Moving to neighbor squares.  */
232 #define SQR_COORD_LEFT(lvl_ptr, sqr_x_coord) \
233   (((sqr_x_coord) - 1) & (lvl_ptr)->square_width_wrap)
234 #define SQR_COORD_RIGHT(lvl_ptr, sqr_x_coord) \
235   (((sqr_x_coord) + 1) & (lvl_ptr)->square_width_wrap)
236 #define SQR_COORD_UP(lvl_ptr, sqr_y_coord) \
237   (((sqr_y_coord) - 1) & (lvl_ptr)->square_height_wrap)
238 #define SQR_COORD_DOWN(lvl_ptr, sqr_y_coord) \
239   (((sqr_y_coord) + 1) & (lvl_ptr)->square_height_wrap)
240 
241 /* Checking square coordinates.  */
242 #define SQR_COORD_X_VALID(lvl_ptr, sqr_coord_x) \
243   (((sqr_coord_x) < (lvl_ptr)->square_width))
244 #define SQR_COORD_Y_VALID(lvl_ptr, sqr_coord_y) \
245   (((sqr_coord_y) < (lvl_ptr)->square_height))
246 #define SQR_COORD_VALID(lvl_ptr, sqr_coord_y, sqr_coord_x) \
247   (SQR_COORD_Y_VALID (lvl_ptr, sqr_coord_y) \
248    && SQR_COORD_X_VALID (lvl_ptr, sqr_coord_x))
249 
250 /* Index to coordinate conversions.  */
251 #define SQR_INDEX_TO_COORD_X(lvl_ptr, sqr_index) \
252   ((sqr_index) % (lvl_ptr)->square_width)
253 #define SQR_INDEX_TO_COORD_Y(lvl_ptr, sqr_index) \
254   ((sqr_index) / (lvl_ptr)->square_width)
255 #define SQR_COORDS_TO_INDEX(lvl_ptr, sqr_y, sqr_x) \
256   ((lvl_ptr)->square_width * (sqr_y) + (sqr_x))
257 
258 #define TILE_INDEX_TO_COORD_X(lvl_ptr, tile_index) \
259   ((tile_index) % (lvl_ptr)->tile_width)
260 #define TILE_INDEX_TO_COORD_Y(lvl_ptr, tile_index) \
261   ((tile_index) / (lvl_ptr)->tile_width)
262 #define TILE_COORDS_TO_INDEX(lvl_ptr, tile_y, tile_x) \
263   ((lvl_ptr)->tile_width * (tile_y) + (tile_x))
264 
265 
266 /* Tile indexes to square indexes conversions.  */
267 #define TILE_INDEX_TO_SQR_INDEX(lvl_ptr, tile_index)		\
268   (TILE_INDEX_TO_COORD_Y ((lvl_ptr), (tile_index)) * 2		\
269    * (lvl_ptr)->square_width					\
270    + TILE_INDEX_TO_COORD_X ((lvl_ptr), (tile_index)) * 2)
271 
272 #define SQR_INDEX_TO_TILE_INDEX(lvl_ptr, sqr_index)		\
273   ((SQR_INDEX_TO_COORD_Y ((lvl_ptr), (sqr_index)) / 2)		\
274    * (lvl_ptr)->tile_width					\
275    + (SQR_INDEX_TO_COORD_X ((lvl_ptr), (sqr_index)) / 2))
276 
277 /* Given the index of the top left square of a tile,
278    compute the index for each square in the tile.  */
279 #define SQR0(lvl_ptr, sqr0) (sqr0)
280 #define SQR1(lvl_ptr, sqr0) ((sqr0) + 1)
281 #define SQR2(lvl_ptr, sqr0) ((sqr0) + (lvl_ptr)->square_width)
282 #define SQR3(lvl_ptr, sqr0) ((sqr0) + (lvl_ptr)->square_width + 1)
283 #define SQRX(lvl_ptr, sqr0, x) \
284   ((sqr0) + (((x) & 2) ? (lvl_ptr)->square_width : 0) + ((x) & 1))
285 
286 
287 #endif /* HEROES__LVL__H */
288