1 #include "empire.h"
2
3 #include "building/menu.h"
4 #include "city/military.h"
5 #include "city/warning.h"
6 #include "core/image_group.h"
7 #include "empire/city.h"
8 #include "empire/empire.h"
9 #include "empire/object.h"
10 #include "empire/trade_route.h"
11 #include "empire/type.h"
12 #include "game/tutorial.h"
13 #include "graphics/generic_button.h"
14 #include "graphics/graphics.h"
15 #include "graphics/image.h"
16 #include "graphics/image_button.h"
17 #include "graphics/lang_text.h"
18 #include "graphics/screen.h"
19 #include "graphics/text.h"
20 #include "graphics/window.h"
21 #include "input/input.h"
22 #include "input/scroll.h"
23 #include "scenario/empire.h"
24 #include "scenario/invasion.h"
25 #include "window/advisors.h"
26 #include "window/city.h"
27 #include "window/message_dialog.h"
28 #include "window/popup_dialog.h"
29 #include "window/resource_settings.h"
30 #include "window/trade_opened.h"
31
32 #define MAX_WIDTH 2032
33 #define MAX_HEIGHT 1136
34
35 static void button_help(int param1, int param2);
36 static void button_return_to_city(int param1, int param2);
37 static void button_advisor(int advisor, int param2);
38 static void button_open_trade(int param1, int param2);
39 static void button_show_resource_window(int resource, int param2);
40
41 static image_button image_button_help[] = {
42 {0, 0, 27, 27, IB_NORMAL, GROUP_CONTEXT_ICONS, 0, button_help, button_none, 0, 0, 1}
43 };
44 static image_button image_button_return_to_city[] = {
45 {0, 0, 24, 24, IB_NORMAL, GROUP_CONTEXT_ICONS, 4, button_return_to_city, button_none, 0, 0, 1}
46 };
47 static image_button image_button_advisor[] = {
48 {-4, 0, 24, 24, IB_NORMAL, GROUP_MESSAGE_ADVISOR_BUTTONS, 12, button_advisor, button_none, ADVISOR_TRADE, 0, 1}
49 };
50 static generic_button generic_button_trade_resource[] = {
51 {0, 0, 101, 27, button_show_resource_window, button_none, RESOURCE_WHEAT, 0},
52 {0, 0, 101, 27, button_show_resource_window, button_none, RESOURCE_VEGETABLES , 0},
53 {0, 0, 101, 27, button_show_resource_window, button_none, RESOURCE_FRUIT , 0},
54 {0, 0, 101, 27, button_show_resource_window, button_none, RESOURCE_OLIVES , 0},
55 {0, 0, 101, 27, button_show_resource_window, button_none, RESOURCE_VINES , 0},
56 {0, 0, 101, 27, button_show_resource_window, button_none, RESOURCE_MEAT, 0},
57 {0, 0, 101, 27, button_show_resource_window, button_none, RESOURCE_WINE , 0},
58 {0, 0, 101, 27, button_show_resource_window, button_none, RESOURCE_OIL , 0},
59 {0, 0, 101, 27, button_show_resource_window, button_none, RESOURCE_IRON , 0},
60 {0, 0, 101, 27, button_show_resource_window, button_none, RESOURCE_TIMBER, 0},
61 {0, 0, 101, 27, button_show_resource_window, button_none, RESOURCE_CLAY, 0},
62 {0, 0, 101, 27, button_show_resource_window, button_none, RESOURCE_MARBLE, 0},
63 {0, 0, 101, 27, button_show_resource_window, button_none, RESOURCE_WEAPONS, 0},
64 {0, 0, 101, 27, button_show_resource_window, button_none, RESOURCE_FURNITURE, 0},
65 {0, 0, 101, 27, button_show_resource_window, button_none, RESOURCE_POTTERY, 0}
66 };
67 static generic_button generic_button_open_trade[] = {
68 {30, 56, 440, 26, button_open_trade, button_none, 0, 0}
69 };
70
71 static struct {
72 int selected_button;
73 int selected_city;
74 int x_min, x_max, y_min, y_max;
75 int x_draw_offset, y_draw_offset;
76 int focus_button_id;
77 int is_scrolling;
78 int finished_scroll;
79 int focus_resource;
80 } data = { 0, 1 };
81
init(void)82 static void init(void)
83 {
84 data.selected_button = 0;
85 int selected_object = empire_selected_object();
86 if (selected_object) {
87 data.selected_city = empire_city_get_for_object(selected_object - 1);
88 } else {
89 data.selected_city = 0;
90 }
91 data.focus_button_id = 0;
92 }
93
draw_paneling(void)94 static void draw_paneling(void)
95 {
96 int image_base = image_group(GROUP_EMPIRE_PANELS);
97 // bottom panel background
98 graphics_set_clip_rectangle(data.x_min, data.y_min, data.x_max - data.x_min, data.y_max - data.y_min);
99 for (int x = data.x_min; x < data.x_max; x += 70) {
100 image_draw(image_base + 3, x, data.y_max - 120);
101 image_draw(image_base + 3, x, data.y_max - 80);
102 image_draw(image_base + 3, x, data.y_max - 40);
103 }
104
105 // horizontal bar borders
106 for (int x = data.x_min; x < data.x_max; x += 86) {
107 image_draw(image_base + 1, x, data.y_min);
108 image_draw(image_base + 1, x, data.y_max - 120);
109 image_draw(image_base + 1, x, data.y_max - 16);
110 }
111
112 // vertical bar borders
113 for (int y = data.y_min + 16; y < data.y_max; y += 86) {
114 image_draw(image_base, data.x_min, y);
115 image_draw(image_base, data.x_max - 16, y);
116 }
117
118 // crossbars
119 image_draw(image_base + 2, data.x_min, data.y_min);
120 image_draw(image_base + 2, data.x_min, data.y_max - 120);
121 image_draw(image_base + 2, data.x_min, data.y_max - 16);
122 image_draw(image_base + 2, data.x_max - 16, data.y_min);
123 image_draw(image_base + 2, data.x_max - 16, data.y_max - 120);
124 image_draw(image_base + 2, data.x_max - 16, data.y_max - 16);
125
126 graphics_reset_clip_rectangle();
127 }
128
draw_trade_resource(resource_type resource,int trade_max,int x_offset,int y_offset)129 static void draw_trade_resource(resource_type resource, int trade_max, int x_offset, int y_offset)
130 {
131 graphics_draw_inset_rect(x_offset, y_offset, 26, 26);
132
133 int image_id = resource + image_group(GROUP_EMPIRE_RESOURCES);
134 int resource_offset = resource_image_offset(resource, RESOURCE_IMAGE_ICON);
135 image_draw(image_id + resource_offset, x_offset + 1, y_offset + 1);
136
137 if (data.focus_resource == resource) {
138 button_border_draw(x_offset - 2, y_offset - 2, 101 + 4, 30, 1);
139 }
140
141 switch (trade_max) {
142 case 15:
143 image_draw(image_group(GROUP_TRADE_AMOUNT), x_offset + 21, y_offset - 1);
144 break;
145 case 25:
146 image_draw(image_group(GROUP_TRADE_AMOUNT) + 1, x_offset + 17, y_offset - 1);
147 break;
148 case 40:
149 image_draw(image_group(GROUP_TRADE_AMOUNT) + 2, x_offset + 13, y_offset - 1);
150 break;
151 }
152 }
153
draw_trade_city_info(const empire_object * object,const empire_city * city)154 static void draw_trade_city_info(const empire_object *object, const empire_city *city)
155 {
156 int x_offset = (data.x_min + data.x_max - 500) / 2;
157 int y_offset = data.y_max - 113;
158 if (city->is_open) {
159 // city sells
160 lang_text_draw(47, 10, x_offset + 44, y_offset + 40, FONT_NORMAL_GREEN);
161 int index = 0;
162 for (int resource = RESOURCE_MIN; resource < RESOURCE_MAX; resource++) {
163 if (!city->sells_resource[resource]) {
164 continue;
165 }
166 int trade_max = trade_route_limit(city->route_id, resource);
167 draw_trade_resource(resource, trade_max, x_offset + 104 * index + 120, y_offset + 31);
168 int trade_now = trade_route_traded(city->route_id, resource);
169 if (trade_now > trade_max) {
170 trade_max = trade_now;
171 }
172 int text_width = text_draw_number(trade_now, '@', "",
173 x_offset + 104 * index + 150, y_offset + 40, FONT_NORMAL_GREEN, 0);
174 text_width += lang_text_draw(47, 11,
175 x_offset + 104 * index + 148 + text_width, y_offset + 40, FONT_NORMAL_GREEN);
176 text_draw_number(trade_max, '@', "",
177 x_offset + 104 * index + 138 + text_width, y_offset + 40, FONT_NORMAL_GREEN, 0);
178 index++;
179 }
180 // city buys
181 lang_text_draw(47, 9, x_offset + 44, y_offset + 71, FONT_NORMAL_GREEN);
182 index = 0;
183 for (int resource = RESOURCE_MIN; resource < RESOURCE_MAX; resource++) {
184 if (!city->buys_resource[resource]) {
185 continue;
186 }
187 int trade_max = trade_route_limit(city->route_id, resource);
188 draw_trade_resource(resource, trade_max, x_offset + 104 * index + 120, y_offset + 62);
189 int trade_now = trade_route_traded(city->route_id, resource);
190 if (trade_now > trade_max) {
191 trade_max = trade_now;
192 }
193 int text_width = text_draw_number(trade_now, '@', "",
194 x_offset + 104 * index + 150, y_offset + 71, FONT_NORMAL_GREEN, 0);
195 text_width += lang_text_draw(47, 11,
196 x_offset + 104 * index + 148 + text_width, y_offset + 71, FONT_NORMAL_GREEN);
197 text_draw_number(trade_max, '@', "",
198 x_offset + 104 * index + 138 + text_width, y_offset + 71, FONT_NORMAL_GREEN, 0);
199 index++;
200 }
201 } else { // trade is closed
202 int index = lang_text_draw(47, 5, x_offset + 50, y_offset + 42, FONT_NORMAL_GREEN);
203 for (int resource = RESOURCE_MIN; resource < RESOURCE_MAX; resource++) {
204 if (!city->sells_resource[resource]) {
205 continue;
206 }
207 int trade_max = trade_route_limit(city->route_id, resource);
208 draw_trade_resource(resource, trade_max, x_offset + index + 60, y_offset + 33);
209 index += 32;
210 }
211 index += lang_text_draw(47, 4, x_offset + index + 100, y_offset + 42, FONT_NORMAL_GREEN);
212 for (int resource = RESOURCE_MIN; resource < RESOURCE_MAX; resource++) {
213 if (!city->buys_resource[resource]) {
214 continue;
215 }
216 int trade_max = trade_route_limit(city->route_id, resource);
217 draw_trade_resource(resource, trade_max, x_offset + index + 110, y_offset + 33);
218 index += 32;
219 }
220 index = lang_text_draw_amount(8, 0, city->cost_to_open,
221 x_offset + 40, y_offset + 73, FONT_NORMAL_GREEN);
222 lang_text_draw(47, 6, x_offset + index + 40, y_offset + 73, FONT_NORMAL_GREEN);
223 int image_id = image_group(GROUP_EMPIRE_TRADE_ROUTE_TYPE) + 1 - city->is_sea_trade;
224 image_draw(image_id, x_offset + 430, y_offset + 65 + 2 * city->is_sea_trade);
225 }
226 }
227
draw_city_info(const empire_object * object)228 static void draw_city_info(const empire_object *object)
229 {
230 int x_offset = (data.x_min + data.x_max - 240) / 2;
231 int y_offset = data.y_max - 88;
232
233 const empire_city *city = empire_city_get(data.selected_city);
234 switch (city->type) {
235 case EMPIRE_CITY_DISTANT_ROMAN:
236 lang_text_draw_centered(47, 12, x_offset, y_offset + 42, 240, FONT_NORMAL_GREEN);
237 break;
238 case EMPIRE_CITY_VULNERABLE_ROMAN:
239 if (city_military_distant_battle_city_is_roman()) {
240 lang_text_draw_centered(47, 12, x_offset, y_offset + 42, 240, FONT_NORMAL_GREEN);
241 } else {
242 lang_text_draw_centered(47, 13, x_offset, y_offset + 42, 240, FONT_NORMAL_GREEN);
243 }
244 break;
245 case EMPIRE_CITY_FUTURE_TRADE:
246 case EMPIRE_CITY_DISTANT_FOREIGN:
247 case EMPIRE_CITY_FUTURE_ROMAN:
248 lang_text_draw_centered(47, 0, x_offset, y_offset + 42, 240, FONT_NORMAL_GREEN);
249 break;
250 case EMPIRE_CITY_OURS:
251 lang_text_draw_centered(47, 1, x_offset, y_offset + 42, 240, FONT_NORMAL_GREEN);
252 break;
253 case EMPIRE_CITY_TRADE:
254 draw_trade_city_info(object, city);
255 break;
256 }
257 }
258
draw_roman_army_info(const empire_object * object)259 static void draw_roman_army_info(const empire_object *object)
260 {
261 if (city_military_distant_battle_roman_army_is_traveling()) {
262 if (city_military_distant_battle_roman_months_traveled() == object->distant_battle_travel_months) {
263 int x_offset = (data.x_min + data.x_max - 240) / 2;
264 int y_offset = data.y_max - 68;
265 int text_id;
266 if (city_military_distant_battle_roman_army_is_traveling_forth()) {
267 text_id = 15;
268 } else {
269 text_id = 16;
270 }
271 lang_text_draw_multiline(47, text_id, x_offset, y_offset, 240, FONT_NORMAL_GREEN);
272 }
273 }
274 }
275
draw_enemy_army_info(const empire_object * object)276 static void draw_enemy_army_info(const empire_object *object)
277 {
278 if (city_military_months_until_distant_battle() > 0) {
279 if (city_military_distant_battle_enemy_months_traveled() == object->distant_battle_travel_months) {
280 lang_text_draw_multiline(47, 14,
281 (data.x_min + data.x_max - 240) / 2,
282 data.y_max - 68,
283 240, FONT_NORMAL_GREEN);
284 }
285 }
286 }
287
draw_object_info(void)288 static void draw_object_info(void)
289 {
290 int selected_object = empire_selected_object();
291 if (selected_object) {
292 const empire_object *object = empire_object_get(selected_object - 1);
293 switch (object->type) {
294 case EMPIRE_OBJECT_CITY:
295 draw_city_info(object);
296 break;
297 case EMPIRE_OBJECT_ROMAN_ARMY:
298 draw_roman_army_info(object);
299 break;
300 case EMPIRE_OBJECT_ENEMY_ARMY:
301 draw_enemy_army_info(object);
302 break;
303 }
304 } else {
305 lang_text_draw_centered(47, 8, data.x_min, data.y_max - 48, data.x_max - data.x_min, FONT_NORMAL_GREEN);
306 }
307 }
308
draw_background(void)309 static void draw_background(void)
310 {
311 int s_width = screen_width();
312 int s_height = screen_height();
313 data.x_min = s_width <= MAX_WIDTH ? 0 : (s_width - MAX_WIDTH) / 2;
314 data.x_max = s_width <= MAX_WIDTH ? s_width : data.x_min + MAX_WIDTH;
315 data.y_min = s_height <= MAX_HEIGHT ? 0 : (s_height - MAX_HEIGHT) / 2;
316 data.y_max = s_height <= MAX_HEIGHT ? s_height : data.y_min + MAX_HEIGHT;
317
318 if (data.x_min || data.y_min) {
319 graphics_clear_screens();
320 }
321 }
322
draw_empire_object(const empire_object * obj)323 static void draw_empire_object(const empire_object *obj)
324 {
325 if (obj->type == EMPIRE_OBJECT_LAND_TRADE_ROUTE || obj->type == EMPIRE_OBJECT_SEA_TRADE_ROUTE) {
326 if (!empire_city_is_trade_route_open(obj->trade_route_id)) {
327 return;
328 }
329 }
330 int x, y, image_id;
331 if (scenario_empire_is_expanded()) {
332 x = obj->expanded.x;
333 y = obj->expanded.y;
334 image_id = obj->expanded.image_id;
335 } else {
336 x = obj->x;
337 y = obj->y;
338 image_id = obj->image_id;
339 }
340
341 if (obj->type == EMPIRE_OBJECT_CITY) {
342 const empire_city *city = empire_city_get(empire_city_get_for_object(obj->id));
343 if (city->type == EMPIRE_CITY_DISTANT_FOREIGN ||
344 city->type == EMPIRE_CITY_FUTURE_ROMAN) {
345 image_id = image_group(GROUP_EMPIRE_FOREIGN_CITY);
346 } else if (city->type == EMPIRE_CITY_TRADE) {
347 // Fix cases where empire map still gives a blue flag for new trade cities
348 // (e.g. Massilia in campaign Lugdunum)
349 image_id = image_group(GROUP_EMPIRE_CITY_TRADE);
350 }
351 }
352 if (obj->type == EMPIRE_OBJECT_BATTLE_ICON) {
353 // handled later
354 return;
355 }
356 if (obj->type == EMPIRE_OBJECT_ENEMY_ARMY) {
357 if (city_military_months_until_distant_battle() <= 0) {
358 return;
359 }
360 if (city_military_distant_battle_enemy_months_traveled() != obj->distant_battle_travel_months) {
361 return;
362 }
363 }
364 if (obj->type == EMPIRE_OBJECT_ROMAN_ARMY) {
365 if (!city_military_distant_battle_roman_army_is_traveling()) {
366 return;
367 }
368 if (city_military_distant_battle_roman_months_traveled() != obj->distant_battle_travel_months) {
369 return;
370 }
371 }
372 image_draw(image_id, data.x_draw_offset + x, data.y_draw_offset + y);
373 const image *img = image_get(image_id);
374 if (img->animation_speed_id) {
375 int new_animation = empire_object_update_animation(obj, image_id);
376 image_draw(image_id + new_animation,
377 data.x_draw_offset + x + img->sprite_offset_x,
378 data.y_draw_offset + y + img->sprite_offset_y);
379 }
380 }
381
draw_invasion_warning(int x,int y,int image_id)382 static void draw_invasion_warning(int x, int y, int image_id)
383 {
384 image_draw(image_id, data.x_draw_offset + x, data.y_draw_offset + y);
385 }
386
draw_map(void)387 static void draw_map(void)
388 {
389 graphics_set_clip_rectangle(data.x_min + 16, data.y_min + 16,
390 data.x_max - data.x_min - 32, data.y_max - data.y_min - 136);
391
392 empire_set_viewport(data.x_max - data.x_min - 32, data.y_max - data.y_min - 136);
393
394 data.x_draw_offset = data.x_min + 16;
395 data.y_draw_offset = data.y_min + 16;
396 empire_adjust_scroll(&data.x_draw_offset, &data.y_draw_offset);
397 image_draw(image_group(GROUP_EMPIRE_MAP), data.x_draw_offset, data.y_draw_offset);
398
399 empire_object_foreach(draw_empire_object);
400
401 scenario_invasion_foreach_warning(draw_invasion_warning);
402
403 graphics_reset_clip_rectangle();
404 }
405
draw_city_name(const empire_city * city)406 static void draw_city_name(const empire_city *city)
407 {
408 int image_base = image_group(GROUP_EMPIRE_PANELS);
409 image_draw(image_base + 6, data.x_min + 2, data.y_max - 199);
410 image_draw(image_base + 7, data.x_max - 84, data.y_max - 199);
411 image_draw(image_base + 8, (data.x_min + data.x_max - 332) / 2, data.y_max - 181);
412 if (city) {
413 lang_text_draw_centered(21, city->name_id,
414 (data.x_min + data.x_max - 332) / 2 + 64, data.y_max - 118, 268, FONT_LARGE_BLACK);
415 }
416 }
417
draw_panel_buttons(const empire_city * city)418 static void draw_panel_buttons(const empire_city *city)
419 {
420 image_buttons_draw(data.x_min + 20, data.y_max - 44, image_button_help, 1);
421 image_buttons_draw(data.x_max - 44, data.y_max - 44, image_button_return_to_city, 1);
422 image_buttons_draw(data.x_max - 44, data.y_max - 100, image_button_advisor, 1);
423 if (city) {
424 if (city->type == EMPIRE_CITY_TRADE && !city->is_open) {
425 button_border_draw((data.x_min + data.x_max - 500) / 2 + 30, data.y_max - 49, 440,
426 26, data.selected_button);
427 }
428 }
429 }
430
draw_foreground(void)431 static void draw_foreground(void)
432 {
433 draw_map();
434
435 const empire_city *city = 0;
436 int selected_object = empire_selected_object();
437 if (selected_object) {
438 const empire_object *object = empire_object_get(selected_object - 1);
439 if (object->type == EMPIRE_OBJECT_CITY) {
440 data.selected_city = empire_city_get_for_object(object->id);
441 city = empire_city_get(data.selected_city);
442 }
443 }
444 draw_paneling();
445 draw_city_name(city);
446 draw_panel_buttons(city);
447 draw_object_info();
448 }
449
is_outside_map(int x,int y)450 static int is_outside_map(int x, int y)
451 {
452 return (x < data.x_min + 16 || x >= data.x_max - 16 ||
453 y < data.y_min + 16 || y >= data.y_max - 120);
454 }
455
determine_selected_object(const mouse * m)456 static void determine_selected_object(const mouse *m)
457 {
458 if (!m->left.went_up || data.finished_scroll || is_outside_map(m->x, m->y)) {
459 data.finished_scroll = 0;
460 return;
461 }
462 empire_select_object(m->x - data.x_min - 16, m->y - data.y_min - 16);
463 window_invalidate();
464 }
465
handle_input(const mouse * m,const hotkeys * h)466 static void handle_input(const mouse *m, const hotkeys *h)
467 {
468 pixel_offset position;
469 if (scroll_get_delta(m, &position, SCROLL_TYPE_EMPIRE)) {
470 empire_scroll_map(position.x, position.y);
471 }
472 if (m->is_touch) {
473 const touch *t = touch_get_earliest();
474 if (!is_outside_map(t->current_point.x, t->current_point.y)) {
475 if (t->has_started) {
476 data.is_scrolling = 1;
477 scroll_drag_start(1);
478 }
479 }
480 if (t->has_ended) {
481 data.is_scrolling = 0;
482 data.finished_scroll = !touch_was_click(t);
483 scroll_drag_end();
484 }
485 }
486 data.focus_button_id = 0;
487 data.focus_resource = 0;
488 int button_id;
489 image_buttons_handle_mouse(m, data.x_min + 20, data.y_max - 44, image_button_help, 1, &button_id);
490 if (button_id) {
491 data.focus_button_id = 1;
492 }
493 image_buttons_handle_mouse(m, data.x_max - 44, data.y_max - 44, image_button_return_to_city, 1, &button_id);
494 if (button_id) {
495 data.focus_button_id = 2;
496 }
497 image_buttons_handle_mouse(m, data.x_max - 44, data.y_max - 100, image_button_advisor, 1, &button_id);
498 if (button_id) {
499 data.focus_button_id = 3;
500 }
501 determine_selected_object(m);
502 int selected_object = empire_selected_object();
503 if (selected_object) {
504 const empire_object *obj = empire_object_get(selected_object - 1);
505 if (obj->type == EMPIRE_OBJECT_CITY) {
506 data.selected_city = empire_city_get_for_object(selected_object - 1);
507 const empire_city *city = empire_city_get(data.selected_city);
508 if (city->type == EMPIRE_CITY_TRADE) {
509 if (city->is_open) {
510 int x_offset = (data.x_min + data.x_max - 500) / 2;
511 int y_offset = data.y_max - 113;
512 int index_sell = 0;
513 int index_buy = 0;
514
515 // we only want to handle resource buttons that the selected city trades
516 for (int resource = RESOURCE_MIN; resource < RESOURCE_MAX; resource++) {
517 if (empire_object_city_sells_resource(obj->id, resource)) {
518 generic_buttons_handle_mouse(m, x_offset + 120 + 104 * index_sell, y_offset + 31,
519 generic_button_trade_resource + resource - 1, 1, &button_id);
520 index_sell++;
521 } else if (empire_object_city_buys_resource(obj->id, resource)) {
522 generic_buttons_handle_mouse(m, x_offset + 120 + 104 * index_buy, y_offset + 62,
523 generic_button_trade_resource + resource - 1, 1, &button_id);
524 index_buy++;
525 }
526
527 if (button_id) {
528 data.focus_resource = resource;
529 // if we're focusing any button we can skip further checks
530 break;
531 }
532 }
533 } else {
534 generic_buttons_handle_mouse(
535 m, (data.x_min + data.x_max - 500) / 2, data.y_max - 105,
536 generic_button_open_trade, 1, &data.selected_button);
537 }
538 }
539 }
540 if (input_go_back_requested(m, h)) {
541 empire_clear_selected_object();
542 window_invalidate();
543 }
544 } else {
545 if (input_go_back_requested(m, h)) {
546 window_city_show();
547 }
548 }
549 }
550
is_mouse_hit(tooltip_context * c,int x,int y,int size)551 static int is_mouse_hit(tooltip_context *c, int x, int y, int size)
552 {
553 int mx = c->mouse_x;
554 int my = c->mouse_y;
555 return x <= mx && mx < x + size && y <= my && my < y + size;
556 }
557
get_tooltip_resource(tooltip_context * c)558 static int get_tooltip_resource(tooltip_context *c)
559 {
560 const empire_city *city = empire_city_get(data.selected_city);
561 // we only want to check tooltips on our own closed cities.
562 // open city resource tooltips are handled by their respective buttons directly
563 if (city->type != EMPIRE_CITY_TRADE || city->is_open) {
564 return 0;
565 }
566 int object_id = empire_selected_object() - 1;
567 int x_offset = (data.x_min + data.x_max - 500) / 2;
568 int y_offset = data.y_max - 113;
569
570 int item_offset = lang_text_get_width(47, 5, FONT_NORMAL_GREEN);
571 for (int r = RESOURCE_MIN; r < RESOURCE_MAX; r++) {
572 if (empire_object_city_sells_resource(object_id, r)) {
573 if (is_mouse_hit(c, x_offset + 60 + item_offset, y_offset + 33, 26)) {
574 return r;
575 }
576 item_offset += 32;
577 }
578 }
579 item_offset += lang_text_get_width(47, 4, FONT_NORMAL_GREEN);
580 for (int r = RESOURCE_MIN; r <= RESOURCE_MAX; r++) {
581 if (empire_object_city_buys_resource(object_id, r)) {
582 if (is_mouse_hit(c, x_offset + 110 + item_offset, y_offset + 33, 26)) {
583 return r;
584 }
585 item_offset += 32;
586 }
587 }
588
589 return 0;
590 }
591
get_tooltip_trade_route_type(tooltip_context * c)592 static void get_tooltip_trade_route_type(tooltip_context *c)
593 {
594 int selected_object = empire_selected_object();
595 if (!selected_object || empire_object_get(selected_object - 1)->type != EMPIRE_OBJECT_CITY) {
596 return;
597 }
598
599 data.selected_city = empire_city_get_for_object(selected_object - 1);
600 const empire_city *city = empire_city_get(data.selected_city);
601 if (city->type != EMPIRE_CITY_TRADE || city->is_open) {
602 return;
603 }
604
605 int x_offset = (data.x_min + data.x_max + 355) / 2;
606 int y_offset = data.y_max - 41;
607 int y_offset_max = y_offset + 22 - 2 * city->is_sea_trade;
608 if (c->mouse_x >= x_offset && c->mouse_x < x_offset + 32 &&
609 c->mouse_y >= y_offset && c->mouse_y < y_offset_max) {
610 c->type = TOOLTIP_BUTTON;
611 c->text_group = 44;
612 c->text_id = 28 + city->is_sea_trade;
613 }
614 }
615
get_tooltip(tooltip_context * c)616 static void get_tooltip(tooltip_context *c)
617 {
618 int resource = data.focus_resource ? data.focus_resource : get_tooltip_resource(c);
619 if (resource) {
620 c->type = TOOLTIP_BUTTON;
621 c->text_id = 131 + resource;
622 } else if (data.focus_button_id) {
623 c->type = TOOLTIP_BUTTON;
624 switch (data.focus_button_id) {
625 case 1: c->text_id = 1; break;
626 case 2: c->text_id = 2; break;
627 case 3: c->text_id = 69; break;
628 }
629 } else {
630 get_tooltip_trade_route_type(c);
631 }
632 }
633
button_help(int param1,int param2)634 static void button_help(int param1, int param2)
635 {
636 window_message_dialog_show(MESSAGE_DIALOG_EMPIRE_MAP, 0);
637 }
638
button_return_to_city(int param1,int param2)639 static void button_return_to_city(int param1, int param2)
640 {
641 window_city_show();
642 }
643
button_advisor(int advisor,int param2)644 static void button_advisor(int advisor, int param2)
645 {
646 window_advisors_show_advisor(advisor);
647 }
648
button_show_resource_window(int resource,int param2)649 static void button_show_resource_window(int resource, int param2)
650 {
651 window_resource_settings_show(resource);
652 }
653
confirmed_open_trade(int accepted,int checked)654 static void confirmed_open_trade(int accepted, int checked)
655 {
656 if (accepted) {
657 empire_city_open_trade(data.selected_city);
658 building_menu_update();
659 window_trade_opened_show(data.selected_city);
660 }
661 }
662
button_open_trade(int param1,int param2)663 static void button_open_trade(int param1, int param2)
664 {
665 window_popup_dialog_show(POPUP_DIALOG_OPEN_TRADE, confirmed_open_trade, 2);
666 }
667
window_empire_show(void)668 void window_empire_show(void)
669 {
670 window_type window = {
671 WINDOW_EMPIRE,
672 draw_background,
673 draw_foreground,
674 handle_input,
675 get_tooltip
676 };
677 init();
678 window_show(&window);
679 }
680
window_empire_show_checked(void)681 void window_empire_show_checked(void)
682 {
683 tutorial_availability avail = tutorial_advisor_empire_availability();
684 if (avail == AVAILABLE) {
685 window_empire_show();
686 } else {
687 city_warning_show(avail == NOT_AVAILABLE ? WARNING_NOT_AVAILABLE : WARNING_NOT_AVAILABLE_YET);
688 }
689 }
690