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