1 #include "empire.h"
2 
3 #include "building/count.h"
4 #include "city/constants.h"
5 #include "city/population.h"
6 #include "city/resource.h"
7 #include "core/calc.h"
8 #include "core/config.h"
9 #include "core/log.h"
10 #include "core/io.h"
11 #include "empire/city.h"
12 #include "empire/object.h"
13 #include "empire/trade_route.h"
14 
15 #include <string.h>
16 
17 enum {
18     EMPIRE_WIDTH = 2000,
19     EMPIRE_HEIGHT = 1000,
20     EMPIRE_HEADER_SIZE = 1280,
21     EMPIRE_DATA_SIZE = 12800
22 };
23 
24 static struct {
25     int initial_scroll_x;
26     int initial_scroll_y;
27     int scroll_x;
28     int scroll_y;
29     int selected_object;
30     int viewport_width;
31     int viewport_height;
32 } data;
33 
empire_load(int is_custom_scenario,int empire_id)34 void empire_load(int is_custom_scenario, int empire_id)
35 {
36     char raw_data[EMPIRE_DATA_SIZE];
37     const char *filename = is_custom_scenario ? "c32.emp" : "c3.emp";
38 
39     // read header with scroll positions
40     if (!io_read_file_part_into_buffer(filename, NOT_LOCALIZED, raw_data, 4, 32 * empire_id)) {
41         memset(raw_data, 0, 4);
42     }
43     buffer buf;
44     buffer_init(&buf, raw_data, 4);
45     data.initial_scroll_x = buffer_read_i16(&buf);
46     data.initial_scroll_y = buffer_read_i16(&buf);
47 
48     // read data section with objects
49     int offset = EMPIRE_HEADER_SIZE + EMPIRE_DATA_SIZE * empire_id;
50     int read_size = io_read_file_part_into_buffer(filename, NOT_LOCALIZED, raw_data, EMPIRE_DATA_SIZE, offset);
51     if (read_size != EMPIRE_DATA_SIZE) {
52         // load empty empire when loading fails
53         log_error("Unable to load empire data from file", filename, 0);
54         memset(raw_data, 0, EMPIRE_DATA_SIZE);
55     }
56     buffer_init(&buf, raw_data, EMPIRE_DATA_SIZE);
57     empire_object_load(&buf);
58 }
59 
check_scroll_boundaries(void)60 static void check_scroll_boundaries(void)
61 {
62     int max_x = EMPIRE_WIDTH - data.viewport_width;
63     int max_y = EMPIRE_HEIGHT - data.viewport_height;
64 
65     data.scroll_x = calc_bound(data.scroll_x, 0, max_x);
66     data.scroll_y = calc_bound(data.scroll_y, 0, max_y);
67 }
68 
empire_load_editor(int empire_id,int viewport_width,int viewport_height)69 void empire_load_editor(int empire_id, int viewport_width, int viewport_height)
70 {
71     empire_load(1, empire_id);
72     empire_object_init_cities();
73 
74     const empire_object *our_city = empire_object_get_our_city();
75 
76     data.viewport_width = viewport_width;
77     data.viewport_height = viewport_height;
78     if (our_city) {
79         data.scroll_x = our_city->x - data.viewport_width / 2;
80         data.scroll_y = our_city->y - data.viewport_height / 2;
81     } else {
82         data.scroll_x = data.initial_scroll_x;
83         data.scroll_y = data.initial_scroll_y;
84     }
85     check_scroll_boundaries();
86 }
87 
empire_init_scenario(void)88 void empire_init_scenario(void)
89 {
90     data.scroll_x = data.initial_scroll_x;
91     data.scroll_y = data.initial_scroll_y;
92     data.viewport_width = EMPIRE_WIDTH;
93     data.viewport_height = EMPIRE_HEIGHT;
94 
95     empire_object_init_cities();
96 }
97 
empire_set_viewport(int width,int height)98 void empire_set_viewport(int width, int height)
99 {
100     data.viewport_width = width;
101     data.viewport_height = height;
102     check_scroll_boundaries();
103 }
104 
empire_adjust_scroll(int * x_offset,int * y_offset)105 void empire_adjust_scroll(int *x_offset, int *y_offset)
106 {
107     *x_offset = *x_offset - data.scroll_x;
108     *y_offset = *y_offset - data.scroll_y;
109 }
110 
empire_scroll_map(int x,int y)111 void empire_scroll_map(int x, int y)
112 {
113     data.scroll_x += x;
114     data.scroll_y += y;
115     check_scroll_boundaries();
116 }
117 
empire_selected_object(void)118 int empire_selected_object(void)
119 {
120     return data.selected_object;
121 }
122 
empire_clear_selected_object(void)123 void empire_clear_selected_object(void)
124 {
125     data.selected_object = 0;
126 }
127 
empire_select_object(int x,int y)128 void empire_select_object(int x, int y)
129 {
130     int map_x = x + data.scroll_x;
131     int map_y = y + data.scroll_y;
132 
133     data.selected_object = empire_object_get_closest(map_x, map_y);
134 }
135 
empire_can_export_resource_to_city(int city_id,int resource)136 int empire_can_export_resource_to_city(int city_id, int resource)
137 {
138     empire_city *city = empire_city_get(city_id);
139     if (city_id && trade_route_limit_reached(city->route_id, resource)) {
140         // quota reached
141         return 0;
142     }
143     int in_stock = city_resource_count(resource);
144     if (resource_is_food(resource) && config_get(CONFIG_GP_CH_ALLOW_EXPORTING_FROM_GRANARIES)) {
145         in_stock += city_resource_count_food_on_granaries(resource) / RESOURCE_GRANARY_ONE_LOAD;
146     }
147 
148     if (in_stock <= city_resource_export_over(resource)) {
149         // stocks too low
150         return 0;
151     }
152     if (city_id == 0 || city->buys_resource[resource]) {
153         return (city_resource_trade_status(resource) & TRADE_STATUS_EXPORT) == TRADE_STATUS_EXPORT;
154     } else {
155         return 0;
156     }
157 }
158 
159 /**static int get_max_stock_for_population(void)
160 {
161     int population = city_population();
162     if (population < 2000) {
163         return 10;
164     } else if (population < 4000) {
165         return 20;
166     } else if (population < 6000) {
167         return 30;
168     } else {
169         return 40;
170     }
171 }**/
172 
empire_can_import_resource_from_city(int city_id,int resource)173 int empire_can_import_resource_from_city(int city_id, int resource)
174 {
175     empire_city *city = empire_city_get(city_id);
176     if (!city->sells_resource[resource]) {
177         return 0;
178     }
179     if (!(city_resource_trade_status(resource) & TRADE_STATUS_IMPORT)) {
180         return 0;
181     }
182     if (trade_route_limit_reached(city->route_id, resource)) {
183         return 0;
184     }
185 
186     int in_stock = city_resource_count(resource);
187     if (resource_is_food(resource)) {
188         in_stock += city_resource_count_food_on_granaries(resource) / RESOURCE_GRANARY_ONE_LOAD;
189     }
190     int max_in_stock = 0;
191     /* NOTE: don't forget to uncomment function get_max_stock_for_population
192 
193     int finished_good = RESOURCE_NONE;
194     switch (resource) {
195         // food and finished materials
196         case RESOURCE_WHEAT:
197         case RESOURCE_VEGETABLES:
198         case RESOURCE_FRUIT:
199         case RESOURCE_MEAT:
200         case RESOURCE_POTTERY:
201         case RESOURCE_FURNITURE:
202         case RESOURCE_OIL:
203         case RESOURCE_WINE:
204             max_in_stock = get_max_stock_for_population();
205             break;
206 
207         case RESOURCE_MARBLE:
208         case RESOURCE_WEAPONS:
209             max_in_stock = 10;
210             break;
211 
212         case RESOURCE_CLAY:
213             finished_good = RESOURCE_POTTERY;
214             break;
215         case RESOURCE_TIMBER:
216             finished_good = RESOURCE_FURNITURE;
217             break;
218         case RESOURCE_OLIVES:
219             finished_good = RESOURCE_OIL;
220             break;
221         case RESOURCE_VINES:
222             finished_good = RESOURCE_WINE;
223             break;
224         case RESOURCE_IRON:
225             finished_good = RESOURCE_WEAPONS;
226             break;
227     }
228     if (finished_good) {
229         max_in_stock = 2 + 2 * building_count_industry_active(finished_good);
230     }*/
231     max_in_stock = city_resource_import_over(resource);
232     return (max_in_stock == 0 || in_stock < max_in_stock) ? 1 : 0;
233 }
234 
empire_save_state(buffer * buf)235 void empire_save_state(buffer *buf)
236 {
237     buffer_write_i32(buf, data.scroll_x);
238     buffer_write_i32(buf, data.scroll_y);
239     buffer_write_i32(buf, data.selected_object);
240 }
241 
empire_load_state(buffer * buf)242 void empire_load_state(buffer *buf)
243 {
244     data.scroll_x = buffer_read_i32(buf);
245     data.scroll_y = buffer_read_i32(buf);
246     data.selected_object = buffer_read_i32(buf);
247 }
248