1 #include "city_figure.h"
2 
3 #include "city/view.h"
4 #include "figure/formation.h"
5 #include "figure/image.h"
6 #include "figuretype/editor.h"
7 #include "graphics/image.h"
8 #include "graphics/text.h"
9 
draw_figure_with_cart(const figure * f,int x,int y)10 static void draw_figure_with_cart(const figure *f, int x, int y)
11 {
12     if (f->y_offset_cart >= 0) {
13         image_draw(f->image_id, x, y);
14         image_draw(f->cart_image_id, x + f->x_offset_cart, y + f->y_offset_cart);
15     } else {
16         image_draw(f->cart_image_id, x + f->x_offset_cart, y + f->y_offset_cart);
17         image_draw(f->image_id, x, y);
18     }
19 }
20 
draw_hippodrome_horse(const figure * f,int x,int y)21 static void draw_hippodrome_horse(const figure *f, int x, int y)
22 {
23     int val = f->wait_ticks_missile;
24     switch (city_view_orientation()) {
25         case DIR_0_TOP:
26             x += 10;
27             if (val <= 10) {
28                 y -= 2;
29             } else if (val <= 11) {
30                 y -= 10;
31             } else if (val <= 12) {
32                 y -= 18;
33             } else if (val <= 13) {
34                 y -= 16;
35             } else if (val <= 20) {
36                 y -= 14;
37             } else if (val <= 21) {
38                 y -= 10;
39             } else {
40                 y -= 2;
41             }
42             break;
43         case DIR_2_RIGHT:
44             x -= 10;
45             if (val <= 9) {
46                 y -= 12;
47             } else if (val <= 10) {
48                 y += 4;
49             } else if (val <= 11) {
50                 x -= 5;
51                 y += 2;
52             } else if (val <= 13) {
53                 x -= 5;
54             } else if (val <= 20) {
55                 y -= 2;
56             } else if (val <= 21) {
57                 y -= 6;
58             } else {
59                 y -= 12;
60             }
61         case DIR_4_BOTTOM:
62             x += 20;
63             if (val <= 9) {
64                 y += 4;
65             } else if (val <= 10) {
66                 x += 10;
67                 y += 4;
68             } else if (val <= 11) {
69                 x += 10;
70                 y -= 4;
71             } else if (val <= 13) {
72                 y -= 6;
73             } else if (val <= 20) {
74                 y -= 12;
75             } else if (val <= 21) {
76                 y -= 10;
77             } else {
78                 y -= 2;
79             }
80             break;
81         case DIR_6_LEFT:
82             x -= 10;
83             if (val <= 9) {
84                 y -= 12;
85             } else if (val <= 10) {
86                 y += 4;
87             } else if (val <= 11) {
88                 y += 2;
89             } else if (val <= 13) {
90                 // no change
91             } else if (val <= 20) {
92                 y -= 2;
93             } else if (val <= 21) {
94                 y -= 6;
95             } else {
96                 y -= 12;
97             }
98             break;
99     }
100     draw_figure_with_cart(f, x, y);
101 }
102 
draw_fort_standard(const figure * f,int x,int y)103 static void draw_fort_standard(const figure *f, int x, int y)
104 {
105     if (!formation_get(f->formation_id)->in_distant_battle) {
106         // base
107         image_draw(f->image_id, x, y);
108         // flag
109         int flag_height = image_get(f->cart_image_id)->height;
110         image_draw(f->cart_image_id, x, y - flag_height);
111         // top icon
112         int icon_image_id = image_group(GROUP_FIGURE_FORT_STANDARD_ICONS) + f->formation_id - 1;
113         image_draw(icon_image_id, x, y - image_get(icon_image_id)->height - flag_height);
114     }
115 }
116 
draw_map_flag(const figure * f,int x,int y)117 static void draw_map_flag(const figure *f, int x, int y)
118 {
119     // base
120     image_draw(f->image_id, x, y);
121     // flag
122     image_draw(f->cart_image_id, x, y - image_get(f->cart_image_id)->height);
123     // flag number
124     int number = 0;
125     int id = f->resource_id;
126     if (id >= MAP_FLAG_INVASION_MIN && id < MAP_FLAG_INVASION_MAX) {
127         number = id - MAP_FLAG_INVASION_MIN + 1;
128     } else if (id >= MAP_FLAG_FISHING_MIN && id < MAP_FLAG_FISHING_MAX) {
129         number = id - MAP_FLAG_FISHING_MIN + 1;
130     } else if (id >= MAP_FLAG_HERD_MIN && id < MAP_FLAG_HERD_MAX) {
131         number = id - MAP_FLAG_HERD_MIN + 1;
132     }
133     if (number > 0) {
134         text_draw_number_colored(number, '@', " ", x + 6, y + 7, FONT_NORMAL_PLAIN, COLOR_WHITE);
135     }
136 }
137 
tile_cross_country_offset_to_pixel_offset(int cross_country_x,int cross_country_y,int * pixel_x,int * pixel_y)138 static void tile_cross_country_offset_to_pixel_offset(int cross_country_x, int cross_country_y,
139                                                       int *pixel_x, int *pixel_y)
140 {
141     int dir = city_view_orientation();
142     if (dir == DIR_0_TOP || dir == DIR_4_BOTTOM) {
143         int base_pixel_x = 2 * cross_country_x - 2 * cross_country_y;
144         int base_pixel_y = cross_country_x + cross_country_y;
145         *pixel_x = dir == DIR_0_TOP ? base_pixel_x : -base_pixel_x;
146         *pixel_y = dir == DIR_0_TOP ? base_pixel_y : -base_pixel_y;
147     } else {
148         int base_pixel_x = 2 * cross_country_x + 2 * cross_country_y;
149         int base_pixel_y = cross_country_x - cross_country_y;
150         *pixel_x = dir == DIR_2_RIGHT ? base_pixel_x : -base_pixel_x;
151         *pixel_y = dir == DIR_6_LEFT ? base_pixel_y : -base_pixel_y;
152     }
153 }
154 
tile_progress_to_pixel_offset_x(int direction,int progress)155 static int tile_progress_to_pixel_offset_x(int direction, int progress)
156 {
157     if (progress >= 15) {
158         return 0;
159     }
160     switch (direction) {
161         case DIR_0_TOP:
162         case DIR_2_RIGHT:
163             return 2 * progress - 28;
164         case DIR_1_TOP_RIGHT:
165             return 4 * progress - 56;
166         case DIR_4_BOTTOM:
167         case DIR_6_LEFT:
168             return 28 - 2 * progress;
169         case DIR_5_BOTTOM_LEFT:
170             return 56 - 4 * progress;
171         default:
172             return 0;
173     }
174 }
175 
tile_progress_to_pixel_offset_y(int direction,int progress)176 static int tile_progress_to_pixel_offset_y(int direction, int progress)
177 {
178     if (progress >= 15) {
179         return 0;
180     }
181     switch (direction) {
182         case DIR_0_TOP:
183         case DIR_6_LEFT:
184             return 14 - progress;
185         case DIR_2_RIGHT:
186         case DIR_4_BOTTOM:
187             return progress - 14;
188         case DIR_3_BOTTOM_RIGHT:
189             return 2 * progress - 28;
190         case DIR_7_TOP_LEFT:
191             return 28 - 2 * progress;
192         default:
193             return 0;
194     }
195 }
196 
tile_progress_to_pixel_offset(int direction,int progress,int * pixel_x,int * pixel_y)197 static void tile_progress_to_pixel_offset(int direction, int progress, int *pixel_x, int *pixel_y)
198 {
199     *pixel_x = tile_progress_to_pixel_offset_x(direction, progress);
200     *pixel_y = tile_progress_to_pixel_offset_y(direction, progress);
201 }
202 
adjust_pixel_offset(const figure * f,int * pixel_x,int * pixel_y)203 static void adjust_pixel_offset(const figure *f, int *pixel_x, int *pixel_y)
204 {
205     // determining x/y offset on tile
206     int x_offset = 0;
207     int y_offset = 0;
208     if (f->use_cross_country) {
209         tile_cross_country_offset_to_pixel_offset(
210             f->cross_country_x % 15, f->cross_country_y % 15, &x_offset, &y_offset);
211         y_offset -= f->missile_damage;
212     } else {
213         int direction = figure_image_normalize_direction(f->direction);
214         tile_progress_to_pixel_offset(direction, f->progress_on_tile, &x_offset, &y_offset);
215         y_offset -= f->current_height;
216         if (f->figures_on_same_tile_index && f->type != FIGURE_BALLISTA) {
217             // an attempt to not let people walk through each other
218             static const int BUSY_ROAD_X_OFFSETS[] = {
219                 0, 8, 8, -8, -8, 0, 16, 0, -16, 8, -8, 16, -16, 16, -16, 8, -8, 0, 24, 0, -24, 0, 0, 0
220             };
221             static const int BUSY_ROAD_Y_OFFSETS[] = {
222                 0, 0, 8, 8, -8, -16, 0, 16, 0, -16, 16, 8, -8, -8, 8, 16, -16, -24, 0, 24, 0, 0, 0, 0
223             };
224             x_offset += BUSY_ROAD_X_OFFSETS[f->figures_on_same_tile_index];
225             y_offset += BUSY_ROAD_Y_OFFSETS[f->figures_on_same_tile_index];
226         }
227     }
228 
229     x_offset += 29;
230     y_offset += 15;
231 
232     const image *img = f->is_enemy_image ? image_get_enemy(f->image_id) : image_get(f->image_id);
233     *pixel_x += x_offset - img->sprite_offset_x;
234     *pixel_y += y_offset - img->sprite_offset_y;
235 }
236 
draw_figure(const figure * f,int x,int y,int highlight)237 static void draw_figure(const figure *f, int x, int y, int highlight)
238 {
239     if (f->cart_image_id) {
240         switch (f->type) {
241             case FIGURE_CART_PUSHER:
242             case FIGURE_WAREHOUSEMAN:
243             case FIGURE_LION_TAMER:
244             case FIGURE_DOCKER:
245             case FIGURE_NATIVE_TRADER:
246             case FIGURE_IMMIGRANT:
247             case FIGURE_EMIGRANT:
248                 draw_figure_with_cart(f, x, y);
249                 break;
250             case FIGURE_HIPPODROME_HORSES:
251                 draw_hippodrome_horse(f, x, y);
252                 break;
253             case FIGURE_FORT_STANDARD:
254                 draw_fort_standard(f, x, y);
255                 break;
256             case FIGURE_MAP_FLAG:
257                 draw_map_flag(f, x, y);
258                 break;
259             default:
260                 image_draw(f->image_id, x, y);
261                 break;
262         }
263     } else {
264         if (f->is_enemy_image) {
265             image_draw_enemy(f->image_id, x, y);
266         } else {
267             image_draw(f->image_id, x, y);
268             if (highlight) {
269                 image_draw_blend_alpha(f->image_id, x, y, COLOR_MASK_LEGION_HIGHLIGHT);
270             }
271         }
272     }
273 }
274 
city_draw_figure(const figure * f,int x,int y,int highlight)275 void city_draw_figure(const figure *f, int x, int y, int highlight)
276 {
277     adjust_pixel_offset(f, &x, &y);
278     draw_figure(f, x, y, highlight);
279 }
280 
city_draw_selected_figure(const figure * f,int x,int y,pixel_coordinate * coord)281 void city_draw_selected_figure(const figure *f, int x, int y, pixel_coordinate *coord)
282 {
283     adjust_pixel_offset(f, &x, &y);
284     draw_figure(f, x, y, 0);
285     coord->x = x;
286     coord->y = y;
287 }
288