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