1 /*------------------------------------------------------------------.
2 | Copyright 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 #include "system.h"
22 #include "lvl_priv.h"
23 #include "format.h"
24 
25 /* Reverse the walls: Check all neighbour squares if it's allowed to enter
26    the current square from there. */
27 static void
en_reverse_walls(const a_level * lvl,a_dir_mask8 * square_walls_in)28 en_reverse_walls (const a_level *lvl, a_dir_mask8 *square_walls_in)
29 {
30   a_square_index idx;
31 
32   for (idx = 0; idx < lvl->square_count; ++idx) {
33     a_square_coord this_x = SQR_INDEX_TO_COORD_X (lvl, idx);
34     a_square_coord this_y = SQR_INDEX_TO_COORD_Y (lvl, idx);
35     {
36       a_square_coord dest_y = SQR_COORD_UP (lvl, this_y);
37       if (SQR_COORD_Y_VALID (lvl, dest_y)) {
38 	a_square_index dest = SQR_COORDS_TO_INDEX (lvl, dest_y, this_x);
39 	if ((lvl->square_walls_out[dest] & DM_DOWN)
40 	    || ((lvl->square_type[dest] == T_TUNNEL)
41 		&& (lvl->square_direction[dest] == D_DOWN)))
42 	  square_walls_in[idx] |= DM_DOWN;
43       }
44     }
45     {
46       a_square_coord dest_x = SQR_COORD_RIGHT (lvl, this_x);
47       if (SQR_COORD_X_VALID (lvl, dest_x)) {
48 	a_square_index dest = SQR_COORDS_TO_INDEX (lvl, this_y, dest_x);
49 	if ((lvl->square_walls_out[dest] & DM_LEFT)
50 	    || ((lvl->square_type[dest] == T_TUNNEL)
51 		&& (lvl->square_direction[dest] == D_LEFT)))
52 	  square_walls_in[idx] |= DM_LEFT;
53       }
54     }
55     {
56       a_square_coord dest_y = SQR_COORD_DOWN (lvl, this_y);
57       if (SQR_COORD_Y_VALID (lvl, dest_y)) {
58 	a_square_index dest = SQR_COORDS_TO_INDEX (lvl, dest_y, this_x);
59 	if ((lvl->square_walls_out[dest] & DM_UP)
60 	    || ((lvl->square_type[dest] == T_TUNNEL)
61 		&& (lvl->square_direction[dest] == D_UP)))
62 	  square_walls_in[idx] |= DM_UP;
63       }
64     }
65     {
66       a_square_coord dest_x = SQR_COORD_LEFT (lvl, this_x);
67       if (SQR_COORD_X_VALID (lvl, dest_x)) {
68 	a_square_index dest = SQR_COORDS_TO_INDEX (lvl, this_y, dest_x);
69 	if ((lvl->square_walls_out[dest] & DM_RIGHT)
70 	    || ((lvl->square_type[dest] == T_TUNNEL)
71 		&& (lvl->square_direction[dest] == D_RIGHT)))
72 	  square_walls_in[idx] |= DM_RIGHT;
73       }
74     }
75   }
76 }
77 
78 /* Encode the level body into the preallocated buffer data */
79 void
encode_level_body(a_u8 * data,const a_level * lvl)80 encode_level_body (a_u8 *data, const a_level *lvl)
81 {
82   a_tile_index ti;		/* Current tile index. */
83   a_square_index si;		/* Current square index. */
84   a_tile_index tcount;		/* Total tile count to write.  */
85   a_dir_mask8 *square_walls_in;	/* Walls forbiding to *enter* a tile.  */
86 
87   tcount = lvl->tile_count;
88   XCALLOC_ARRAY (square_walls_in, lvl->square_count);
89   /* T_OUTWAY squares cannot be entered from any direction */
90   for (si = 0; si < lvl->square_count; ++si)
91     if (lvl->square_type[si] == T_OUTWAY)
92       square_walls_in[si] = DM_ALL;
93   en_reverse_walls (lvl, square_walls_in);
94 
95   /* Write each tile to buffer. */
96   for (ti = 0; ti < tcount; ++ti, data += LVL_RECORD_SIZE) {
97     a_tile_type tt;		/* Tile type.  */
98 
99     si = TILE_INDEX_TO_SQR_INDEX (lvl, ti);
100 
101     /* Store tile type.  */
102     tt = lvl->private->tile[ti].type;
103     SET_TILE_TYPE (data, tt);
104 
105     /* Store inside walls. */
106     SET_TILE_WALLS (data, 0, square_walls_in[SQR0 (lvl, si)]);
107     SET_TILE_WALLS (data, 1, square_walls_in[SQR1 (lvl, si)]);
108     SET_TILE_WALLS (data, 2, square_walls_in[SQR2 (lvl, si)]);
109     SET_TILE_WALLS (data, 3, square_walls_in[SQR3 (lvl, si)]);
110 
111     /* Store sprites.  */
112     SET_TILE_SPRITE (data, lvl->private->tile[ti].sprite_offset);
113     SET_TILE_OVERLAY (data, lvl->private->tile[ti].sprite_overlay_offset);
114 
115     switch (tt) {
116     case T_TUNNEL:
117       {
118 	int s;
119 	a_dir td;
120 	a_square_index tsi;
121 	a_tile_index dti;
122 
123 	/* find a square that's part of the tunnel */
124 	s = 0;
125 	while (lvl->square_type[SQRX (lvl, si, s)] != T_TUNNEL) ++s;
126 	tsi = SQRX (lvl, si, s);
127 
128 	td = lvl->square_direction[tsi];
129 	dti = SQR_INDEX_TO_TILE_INDEX (lvl, lvl->square_move[td][tsi]);
130 	SET_TUNNEL_OUTPUT (data, dti);
131 	SET_TUNNEL_DIR (data, DIR_TO_DIRMASK (td));
132       }
133       break;
134     case T_ANIM:
135       SET_ANIM_FRAME_COUNT (data, lvl->private->tile[ti].frame_count);
136       SET_ANIM_FRAME_DELAY (data, lvl->private->tile[ti].frame_delay - 1);
137       break;
138     case T_SPEED:
139       {
140 	int x;
141 	for (x = 0; x < 4; ++x)
142 	  if (lvl->square_type[SQRX (lvl, si, x)] != T_NONE)
143 	    SPEED_DIR (data)[x] |=
144 	      DIR_TO_DIRMASK (lvl->square_direction[SQRX (lvl, si, x)]);
145       }
146       goto decode_small_anim;
147     case T_STOP:
148     case T_BOOM:
149     case T_ICE:
150     case T_DUST:
151       {
152 	int x;
153 	/* Set EFFECT_SET=non_zero for all squares that have
154 	   some special effect enabled  */
155 	for (x = 0; x < 4; ++x)
156 	  if (lvl->square_type [SQRX (lvl, si, x)] == T_NONE)
157 	    SET_EFFECT_SET (data, x, 0);
158 	  else
159 	    SET_EFFECT_SET (data, x, 1);
160       }
161       /* Fall through.  */
162     decode_small_anim:
163     case T_OUTWAY:
164     case T_NONE:
165       SET_SANIM_FRAME_COUNT_DELAY (data,
166 				   (lvl->private->tile[ti].frame_count << 4) |
167 				   (lvl->private->tile[ti].frame_delay - 1));
168       break;
169     default:
170       assert (0);
171     }
172   }
173   free (square_walls_in);
174 }
175