1 #include "building_tiles.h"
2 
3 #include "building/building.h"
4 #include "building/industry.h"
5 #include "city/view.h"
6 #include "core/direction.h"
7 #include "core/image.h"
8 #include "map/aqueduct.h"
9 #include "map/bridge.h"
10 #include "map/building.h"
11 #include "map/figure.h"
12 #include "map/grid.h"
13 #include "map/image.h"
14 #include "map/property.h"
15 #include "map/random.h"
16 #include "map/sprite.h"
17 #include "map/terrain.h"
18 #include "map/tiles.h"
19 
map_building_tiles_add(int building_id,int x,int y,int size,int image_id,int terrain)20 void map_building_tiles_add(int building_id, int x, int y, int size, int image_id, int terrain)
21 {
22     if (!map_grid_is_inside(x, y, size)) {
23         return;
24     }
25     int x_leftmost, y_leftmost;
26     switch (city_view_orientation()) {
27         case DIR_0_TOP:
28             x_leftmost = 0;
29             y_leftmost = size - 1;
30             break;
31         case DIR_2_RIGHT:
32             x_leftmost = y_leftmost = 0;
33             break;
34         case DIR_4_BOTTOM:
35             x_leftmost = size - 1;
36             y_leftmost = 0;
37             break;
38         case DIR_6_LEFT:
39             x_leftmost = y_leftmost = size - 1;
40             break;
41         default:
42             return;
43     }
44     for (int dy = 0; dy < size; dy++) {
45         for (int dx = 0; dx < size; dx++) {
46             int grid_offset = map_grid_offset(x + dx, y + dy);
47             map_terrain_remove(grid_offset, TERRAIN_CLEARABLE);
48             map_terrain_add(grid_offset, terrain);
49             map_building_set(grid_offset, building_id);
50             map_property_clear_constructing(grid_offset);
51             map_property_set_multi_tile_size(grid_offset, size);
52             map_image_set(grid_offset, image_id);
53             map_property_set_multi_tile_xy(grid_offset, dx, dy,
54                 dx == x_leftmost && dy == y_leftmost);
55         }
56     }
57 }
58 
set_crop_tile(int building_id,int x,int y,int dx,int dy,int crop_image_id,int growth)59 static void set_crop_tile(int building_id, int x, int y, int dx, int dy, int crop_image_id, int growth)
60 {
61     int grid_offset = map_grid_offset(x + dx, y + dy);
62     map_terrain_remove(grid_offset, TERRAIN_CLEARABLE);
63     map_terrain_add(grid_offset, TERRAIN_BUILDING);
64     map_building_set(grid_offset, building_id);
65     map_property_clear_constructing(grid_offset);
66     map_property_set_multi_tile_xy(grid_offset, dx, dy, 1);
67     map_image_set(grid_offset, crop_image_id + (growth < 4 ? growth : 4));
68 }
69 
map_building_tiles_add_farm(int building_id,int x,int y,int crop_image_id,int progress)70 void map_building_tiles_add_farm(int building_id, int x, int y, int crop_image_id, int progress)
71 {
72     if (!map_grid_is_inside(x, y, 3)) {
73         return;
74     }
75     // farmhouse
76     int x_leftmost, y_leftmost;
77     switch (city_view_orientation()) {
78         case DIR_0_TOP:
79             x_leftmost = 0;
80             y_leftmost = 1;
81             break;
82         case DIR_2_RIGHT:
83             x_leftmost = 0;
84             y_leftmost = 0;
85             break;
86         case DIR_4_BOTTOM:
87             x_leftmost = 1;
88             y_leftmost = 0;
89             break;
90         case DIR_6_LEFT:
91             x_leftmost = 1;
92             y_leftmost = 1;
93             break;
94         default:
95             return;
96     }
97     for (int dy = 0; dy < 2; dy++) {
98         for (int dx = 0; dx < 2; dx++) {
99             int grid_offset = map_grid_offset(x + dx, y + dy);
100             map_terrain_remove(grid_offset, TERRAIN_CLEARABLE);
101             map_terrain_add(grid_offset, TERRAIN_BUILDING);
102             map_building_set(grid_offset, building_id);
103             map_property_clear_constructing(grid_offset);
104             map_property_set_multi_tile_size(grid_offset, 2);
105             map_image_set(grid_offset, image_group(GROUP_BUILDING_FARM_HOUSE));
106             map_property_set_multi_tile_xy(grid_offset, dx, dy,
107                 dx == x_leftmost && dy == y_leftmost);
108         }
109     }
110     // crop tile 1
111     int growth = progress / 10;
112     set_crop_tile(building_id, x, y, 0, 2, crop_image_id, growth);
113 
114     // crop tile 2
115     growth -= 4;
116     if (growth < 0) {
117         growth = 0;
118     }
119     set_crop_tile(building_id, x, y, 1, 2, crop_image_id, growth);
120 
121     // crop tile 3
122     growth -= 4;
123     if (growth < 0) {
124         growth = 0;
125     }
126     set_crop_tile(building_id, x, y, 2, 2, crop_image_id, growth);
127 
128     // crop tile 4
129     growth -= 4;
130     if (growth < 0) {
131         growth = 0;
132     }
133     set_crop_tile(building_id, x, y, 2, 1, crop_image_id, growth);
134 
135     // crop tile 5
136     growth -= 4;
137     if (growth < 0) {
138         growth = 0;
139     }
140     set_crop_tile(building_id, x, y, 2, 0, crop_image_id, growth);
141 }
142 
map_building_tiles_add_aqueduct(int x,int y)143 int map_building_tiles_add_aqueduct(int x, int y)
144 {
145     int grid_offset = map_grid_offset(x,y);
146     map_terrain_add(grid_offset, TERRAIN_AQUEDUCT);
147     map_property_clear_constructing(grid_offset);
148     return 1;
149 }
150 
north_tile_grid_offset(int x,int y,int * size)151 static int north_tile_grid_offset(int x, int y, int *size)
152 {
153     int grid_offset = map_grid_offset(x, y);
154     *size = map_property_multi_tile_size(grid_offset);
155     for (int i = 0; i < *size && map_property_multi_tile_x(grid_offset); i++) {
156         grid_offset += map_grid_delta(-1, 0);
157     }
158     for (int i = 0; i < *size && map_property_multi_tile_y(grid_offset); i++) {
159         grid_offset += map_grid_delta(0, -1);
160     }
161     return grid_offset;
162 }
163 
map_building_tiles_remove(int building_id,int x,int y)164 void map_building_tiles_remove(int building_id, int x, int y)
165 {
166     if (!map_grid_is_inside(x, y, 1)) {
167         return;
168     }
169     int size;
170     int base_grid_offset = north_tile_grid_offset(x, y, &size);
171     x = map_grid_offset_to_x(base_grid_offset);
172     y = map_grid_offset_to_y(base_grid_offset);
173     if (map_terrain_get(base_grid_offset) == TERRAIN_ROCK) {
174         return;
175     }
176     building *b = building_get(building_id);
177     if (building_id && building_is_farm(b->type)) {
178         size = 3;
179     }
180     for (int dy = 0; dy < size; dy++) {
181         for (int dx = 0; dx < size; dx++) {
182             int grid_offset = map_grid_offset(x + dx, y + dy);
183             if (building_id && map_building_at(grid_offset) != building_id) {
184                 continue;
185             }
186             if (building_id && b->type != BUILDING_BURNING_RUIN) {
187                 map_set_rubble_building_type(grid_offset, b->type);
188             }
189             map_property_clear_constructing(grid_offset);
190             map_property_set_multi_tile_size(grid_offset, 1);
191             map_property_clear_multi_tile_xy(grid_offset);
192             map_property_mark_draw_tile(grid_offset);
193             map_aqueduct_set(grid_offset, 0);
194             map_building_set(grid_offset, 0);
195             map_building_damage_clear(grid_offset);
196             map_sprite_clear_tile(grid_offset);
197             if (map_terrain_is(grid_offset, TERRAIN_WATER)) {
198                 map_terrain_set(grid_offset, TERRAIN_WATER); // clear other flags
199                 map_tiles_set_water(x + dx, y + dy);
200             } else {
201                 map_image_set(grid_offset,
202                     image_group(GROUP_TERRAIN_UGLY_GRASS) +
203                     (map_random_get(grid_offset) & 7));
204                 map_terrain_remove(grid_offset, TERRAIN_CLEARABLE);
205             }
206         }
207     }
208     map_tiles_update_region_empty_land(x, y, x + size, y + size);
209     map_tiles_update_region_meadow(x, y, x + size, y + size);
210     map_tiles_update_region_rubble(x, y, x + size, y + size);
211 }
212 
map_building_tiles_set_rubble(int building_id,int x,int y,int size)213 void map_building_tiles_set_rubble(int building_id, int x, int y, int size)
214 {
215     if (!map_grid_is_inside(x, y, size)) {
216         return;
217     }
218     building *b = building_get(building_id);
219     for (int dy = 0; dy < size; dy++) {
220         for (int dx = 0; dx < size; dx++) {
221             int grid_offset = map_grid_offset(x + dx, y + dy);
222             if (map_building_at(grid_offset) != building_id) {
223                 continue;
224             }
225             if (building_id && building_get(map_building_at(grid_offset))->type != BUILDING_BURNING_RUIN) {
226                 map_set_rubble_building_type(grid_offset, b->type);
227             } else if (!building_id && map_terrain_get(grid_offset) & TERRAIN_WALL) {
228                 map_set_rubble_building_type(grid_offset, BUILDING_WALL);
229             }
230             map_property_clear_constructing(grid_offset);
231             map_property_set_multi_tile_size(grid_offset, 1);
232             map_aqueduct_set(grid_offset, 0);
233             map_building_set(grid_offset, 0);
234             map_building_damage_clear(grid_offset);
235             map_sprite_clear_tile(grid_offset);
236             map_property_set_multi_tile_xy(grid_offset, 0, 0, 1);
237             if (map_terrain_is(grid_offset, TERRAIN_WATER)) {
238                 map_terrain_set(grid_offset, TERRAIN_WATER); // clear other flags
239                 map_tiles_set_water(x + dx, y + dy);
240             } else {
241                 map_terrain_remove(grid_offset, TERRAIN_CLEARABLE);
242                 map_terrain_add(grid_offset, TERRAIN_RUBBLE);
243                 map_image_set(grid_offset, image_group(GROUP_TERRAIN_RUBBLE) + (map_random_get(grid_offset) & 7));
244             }
245         }
246     }
247 }
248 
adjust_to_absolute_xy(int * x,int * y,int size)249 static void adjust_to_absolute_xy(int *x, int *y, int size)
250 {
251     switch (city_view_orientation()) {
252         case DIR_2_RIGHT:
253             *x = *x - size + 1;
254             break;
255         case DIR_4_BOTTOM:
256             *x = *x - size + 1;
257             // fall-through
258         case DIR_6_LEFT:
259             *y = *y - size + 1;
260             break;
261     }
262 }
263 
map_building_tiles_mark_construction(int x,int y,int size,int terrain,int absolute_xy)264 int map_building_tiles_mark_construction(int x, int y, int size, int terrain, int absolute_xy)
265 {
266     if (!absolute_xy) {
267         adjust_to_absolute_xy(&x, &y, size);
268     }
269     if (!map_grid_is_inside(x, y, size)) {
270         return 0;
271     }
272     for (int dy = 0; dy < size; dy++) {
273         for (int dx = 0; dx < size; dx++) {
274             int grid_offset = map_grid_offset(x + dx, y + dy);
275             if (map_terrain_is(grid_offset, terrain & TERRAIN_NOT_CLEAR) || map_has_figure_at(grid_offset)) {
276                 return 0;
277             }
278         }
279     }
280     // mark as being constructed
281     for (int dy = 0; dy < size; dy++) {
282         for (int dx = 0; dx < size; dx++) {
283             int grid_offset = map_grid_offset(x + dx, y + dy);
284             map_property_mark_constructing(grid_offset);
285         }
286     }
287     return 1;
288 }
289 
map_building_tiles_mark_deleting(int grid_offset)290 void map_building_tiles_mark_deleting(int grid_offset)
291 {
292     int building_id = map_building_at(grid_offset);
293     if (!building_id) {
294         map_bridge_remove(grid_offset, 1);
295     } else {
296         grid_offset = building_main(building_get(building_id))->grid_offset;
297     }
298     map_property_mark_deleted(grid_offset);
299 }
300 
map_building_tiles_are_clear(int x,int y,int size,int terrain)301 int map_building_tiles_are_clear(int x, int y, int size, int terrain)
302 {
303     adjust_to_absolute_xy(&x, &y, size);
304     if (!map_grid_is_inside(x, y, size)) {
305         return 0;
306     }
307     for (int dy = 0; dy < size; dy++) {
308         for (int dx = 0; dx < size; dx++) {
309             int grid_offset = map_grid_offset(x + dx, y + dy);
310             if (map_terrain_is(grid_offset, terrain & TERRAIN_NOT_CLEAR)) {
311                 return 0;
312             }
313         }
314     }
315     return 1;
316 }
317