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