1 /****************************************************************************
2 Freeciv - Copyright (C) 2004 - The Freeciv Team
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License as published by
5 the Free Software Foundation; either version 2, or (at your option)
6 any later version.
7
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
12 ****************************************************************************/
13
14 #ifdef HAVE_CONFIG_H
15 #include <fc_config.h>
16 #endif
17
18 /* common */
19 #include "extras.h"
20 #include "fc_types.h"
21 #include "game.h"
22 #include "map.h"
23 #include "movement.h"
24 #include "name_translation.h"
25 #include "unittype.h"
26
27 #include "road.h"
28
29 /**************************************************************************
30 Return the road id.
31 **************************************************************************/
road_number(const struct road_type * proad)32 Road_type_id road_number(const struct road_type *proad)
33 {
34 fc_assert_ret_val(NULL != proad, -1);
35
36 return proad->id;
37 }
38
39 /**************************************************************************
40 Return the road index.
41
42 Currently same as road_number(), paired with road_count()
43 indicates use as an array index.
44 **************************************************************************/
road_index(const struct road_type * proad)45 Road_type_id road_index(const struct road_type *proad)
46 {
47 fc_assert_ret_val(NULL != proad, -1);
48
49 /* FIXME: */
50 /* return proad - roads; */
51 return road_number(proad);
52 }
53
54 /**************************************************************************
55 Return extra that road is.
56 **************************************************************************/
road_extra_get(const struct road_type * proad)57 struct extra_type *road_extra_get(const struct road_type *proad)
58 {
59 return proad->self;
60 }
61
62 /**************************************************************************
63 Return the number of road_types.
64 **************************************************************************/
road_count(void)65 Road_type_id road_count(void)
66 {
67 return game.control.num_road_types;
68 }
69
70 /****************************************************************************
71 Return road type of given id.
72 ****************************************************************************/
road_by_number(Road_type_id id)73 struct road_type *road_by_number(Road_type_id id)
74 {
75 struct extra_type_list *roads;
76
77 roads = extra_type_list_by_cause(EC_ROAD);
78
79 if (roads == NULL || id < 0 || id >= extra_type_list_size(roads)) {
80 return NULL;
81 }
82
83 return extra_road_get(extra_type_list_get(roads, id));
84 }
85
86 /****************************************************************************
87 This function is passed to road_type_list_sort() to sort a list of roads
88 in ascending move_cost (faster roads first).
89 ****************************************************************************/
compare_road_move_cost(const struct extra_type * const * p,const struct extra_type * const * q)90 int compare_road_move_cost(const struct extra_type *const *p,
91 const struct extra_type *const *q)
92 {
93 const struct road_type *proad = extra_road_get(*p);
94 const struct road_type *qroad = extra_road_get(*q);
95
96 if (proad->move_cost > qroad->move_cost) {
97 return -1; /* q is faster */
98 } else if (proad->move_cost == qroad->move_cost) {
99 return 0;
100 } else {
101 return 1; /* p is faster */
102 }
103 }
104
105 /****************************************************************************
106 Initialize road_type structures.
107 ****************************************************************************/
road_type_init(struct extra_type * pextra,int idx)108 void road_type_init(struct extra_type *pextra, int idx)
109 {
110 struct road_type *proad;
111
112 proad = fc_malloc(sizeof(*proad));
113
114 pextra->data.road = proad;
115
116 requirement_vector_init(&proad->first_reqs);
117
118 proad->id = idx;
119 proad->integrators = NULL;
120 proad->self = pextra;
121 }
122
123
124 /****************************************************************************
125 Initialize the road integrators cache
126 ****************************************************************************/
road_integrators_cache_init(void)127 void road_integrators_cache_init(void)
128 {
129 extra_type_by_cause_iterate(EC_ROAD, pextra) {
130 struct road_type *proad = extra_road_get(pextra);
131
132 proad->integrators = extra_type_list_new();
133 /* Roads always integrate with themselves. */
134 extra_type_list_append(proad->integrators, pextra);
135 extra_type_by_cause_iterate(EC_ROAD, oextra) {
136 struct road_type *oroad = extra_road_get(oextra);
137 if (BV_ISSET(proad->integrates, road_index(oroad))) {
138 extra_type_list_append(proad->integrators, oextra);
139 }
140 } extra_type_by_cause_iterate_end;
141 extra_type_list_unique(proad->integrators);
142 extra_type_list_sort(proad->integrators, &compare_road_move_cost);
143 } extra_type_by_cause_iterate_end;
144 }
145
146 /****************************************************************************
147 Free the memory associated with road types
148 ****************************************************************************/
road_types_free(void)149 void road_types_free(void)
150 {
151 extra_type_by_cause_iterate(EC_ROAD, pextra) {
152 struct road_type *proad = extra_road_get(pextra);
153
154 requirement_vector_free(&proad->first_reqs);
155
156 if (proad->integrators != NULL) {
157 extra_type_list_destroy(proad->integrators);
158 proad->integrators = NULL;
159 }
160 } extra_type_by_cause_iterate_end;
161 }
162
163 /****************************************************************************
164 Return tile special that used to represent this road type.
165 ****************************************************************************/
road_compat_special(const struct road_type * proad)166 enum road_compat road_compat_special(const struct road_type *proad)
167 {
168 return proad->compat;
169 }
170
171 /****************************************************************************
172 Return road type represented by given compatibility special, or NULL if
173 special does not represent road type at all.
174 ****************************************************************************/
road_by_compat_special(enum road_compat compat)175 struct road_type *road_by_compat_special(enum road_compat compat)
176 {
177 if (compat == ROCO_NONE) {
178 return NULL;
179 }
180
181 extra_type_by_cause_iterate(EC_ROAD, pextra) {
182 struct road_type *proad = extra_road_get(pextra);
183 if (road_compat_special(proad) == compat) {
184 return proad;
185 }
186 } extra_type_by_cause_iterate_end;
187
188 return NULL;
189 }
190
191 /****************************************************************************
192 Tells if road can build to tile if all other requirements are met.
193 ****************************************************************************/
road_can_be_built(const struct road_type * proad,const struct tile * ptile)194 bool road_can_be_built(const struct road_type *proad, const struct tile *ptile)
195 {
196
197 if (!(road_extra_get(proad)->buildable)) {
198 /* Road type not buildable. */
199 return FALSE;
200 }
201
202 if (tile_has_road(ptile, proad)) {
203 /* Road exist already */
204 return FALSE;
205 }
206
207 if (tile_terrain(ptile)->road_time == 0) {
208 return FALSE;
209 }
210
211 return TRUE;
212 }
213
214 /****************************************************************************
215 Tells if player can build road to tile with suitable unit.
216 ****************************************************************************/
can_build_road_base(const struct road_type * proad,const struct player * pplayer,const struct tile * ptile)217 bool can_build_road_base(const struct road_type *proad,
218 const struct player *pplayer,
219 const struct tile *ptile)
220 {
221 if (!road_can_be_built(proad, ptile)) {
222 return FALSE;
223 }
224
225 if (road_has_flag(proad, RF_REQUIRES_BRIDGE)
226 && !player_knows_techs_with_flag(pplayer, TF_BRIDGE)) {
227 /* TODO: Cache list of road types with RF_PREVENTS_OTHER_ROADS
228 * after ruleset loading and use that list here instead
229 * of always iterating through all road types. */
230 extra_type_by_cause_iterate(EC_ROAD, poextra) {
231 struct road_type *old = extra_road_get(poextra);
232
233 if (road_has_flag(old, RF_PREVENTS_OTHER_ROADS)
234 && tile_has_extra(ptile, poextra)) {
235 return FALSE;
236 }
237 } extra_type_by_cause_iterate_end;
238 }
239
240 return TRUE;
241 }
242
243 /****************************************************************************
244 Tells if player and optionally unit have road building requirements
245 fulfilled.
246 ****************************************************************************/
are_road_reqs_fulfilled(const struct road_type * proad,const struct player * pplayer,const struct unit * punit,const struct tile * ptile)247 static bool are_road_reqs_fulfilled(const struct road_type *proad,
248 const struct player *pplayer,
249 const struct unit *punit,
250 const struct tile *ptile)
251 {
252 struct extra_type *pextra = road_extra_get(proad);
253 const struct unit_type *utype;
254
255 if (punit == NULL) {
256 utype = NULL;
257 } else {
258 utype = unit_type_get(punit);
259 }
260
261 if (requirement_vector_size(&proad->first_reqs) > 0) {
262 bool beginning = TRUE;
263
264 extra_type_list_iterate(proad->integrators, iroad) {
265 /* FIXME: mixing cardinal and non-cardinal roads as integrators is
266 * probably not a good idea. */
267 if (is_cardinal_only_road(iroad)) {
268 cardinal_adjc_iterate(ptile, adjc_tile) {
269 if (tile_has_extra(adjc_tile, iroad)) {
270 beginning = FALSE;
271 break;
272 }
273 } cardinal_adjc_iterate_end;
274 } else {
275 adjc_iterate(ptile, adjc_tile) {
276 if (tile_has_extra(adjc_tile, iroad)) {
277 beginning = FALSE;
278 break;
279 }
280 } adjc_iterate_end;
281 }
282
283 if (!beginning) {
284 break;
285 }
286 } extra_type_list_iterate_end;
287
288 if (beginning) {
289 if (!are_reqs_active(pplayer, tile_owner(ptile), NULL, NULL, ptile,
290 punit, utype, NULL, NULL,
291 &proad->first_reqs, RPT_POSSIBLE)) {
292 return FALSE;
293 }
294 }
295 }
296
297 return are_reqs_active(pplayer, tile_owner(ptile), NULL, NULL, ptile,
298 punit, utype, NULL, NULL, &pextra->reqs,
299 RPT_POSSIBLE);
300 }
301
302 /****************************************************************************
303 Tells if player can build road to tile with suitable unit.
304 ****************************************************************************/
player_can_build_road(const struct road_type * proad,const struct player * pplayer,const struct tile * ptile)305 bool player_can_build_road(const struct road_type *proad,
306 const struct player *pplayer,
307 const struct tile *ptile)
308 {
309 if (!can_build_road_base(proad, pplayer, ptile)) {
310 return FALSE;
311 }
312
313 return are_road_reqs_fulfilled(proad, pplayer, NULL, ptile);
314 }
315
316 /****************************************************************************
317 Tells if unit can build road on tile.
318 ****************************************************************************/
can_build_road(struct road_type * proad,const struct unit * punit,const struct tile * ptile)319 bool can_build_road(struct road_type *proad,
320 const struct unit *punit,
321 const struct tile *ptile)
322 {
323 struct player *pplayer = unit_owner(punit);
324
325 if (!can_build_road_base(proad, pplayer, ptile)) {
326 return FALSE;
327 }
328
329 return are_road_reqs_fulfilled(proad, pplayer, punit, ptile);
330 }
331
332 /****************************************************************************
333 Count tiles with specified road near the tile. Can be called with NULL
334 road.
335 ****************************************************************************/
count_road_near_tile(const struct tile * ptile,const struct road_type * proad)336 int count_road_near_tile(const struct tile *ptile, const struct road_type *proad)
337 {
338 int count = 0;
339
340 if (proad == NULL) {
341 return 0;
342 }
343
344 adjc_iterate(ptile, adjc_tile) {
345 if (tile_has_road(adjc_tile, proad)) {
346 count++;
347 }
348 } adjc_iterate_end;
349
350 return count;
351 }
352
353 /****************************************************************************
354 Count tiles with any river near the tile.
355 ****************************************************************************/
count_river_near_tile(const struct tile * ptile,const struct extra_type * priver)356 int count_river_near_tile(const struct tile *ptile,
357 const struct extra_type *priver)
358 {
359 int count = 0;
360
361 cardinal_adjc_iterate(ptile, adjc_tile) {
362 if (priver == NULL && tile_has_river(adjc_tile)) {
363 /* Some river */
364 count++;
365 } else if (priver != NULL && tile_has_extra(adjc_tile, priver)) {
366 /* Specific river */
367 count++;
368 }
369 } cardinal_adjc_iterate_end;
370
371 return count;
372 }
373
374 /****************************************************************************
375 Count tiles with river of specific type cardinally adjacent to the tile.
376 ****************************************************************************/
count_river_type_tile_card(const struct tile * ptile,const struct extra_type * priver,bool percentage)377 int count_river_type_tile_card(const struct tile *ptile,
378 const struct extra_type *priver,
379 bool percentage)
380 {
381 int count = 0;
382 int total = 0;
383
384 fc_assert(priver != NULL);
385
386 cardinal_adjc_iterate(ptile, adjc_tile) {
387 if (tile_has_extra(adjc_tile, priver)) {
388 count++;
389 }
390 total++;
391 } cardinal_adjc_iterate_end;
392
393 if (percentage) {
394 count = count * 100 / total;
395 }
396 return count;
397 }
398
399 /****************************************************************************
400 Count tiles with river of specific type near the tile.
401 ****************************************************************************/
count_river_type_near_tile(const struct tile * ptile,const struct extra_type * priver,bool percentage)402 int count_river_type_near_tile(const struct tile *ptile,
403 const struct extra_type *priver,
404 bool percentage)
405 {
406 int count = 0;
407 int total = 0;
408
409 fc_assert(priver != NULL);
410
411 adjc_iterate(ptile, adjc_tile) {
412 if (tile_has_extra(adjc_tile, priver)) {
413 count++;
414 }
415 total++;
416 } adjc_iterate_end;
417
418 if (percentage) {
419 count = count * 100 / total;
420 }
421 return count;
422 }
423
424 /****************************************************************************
425 Check if road provides effect
426 ****************************************************************************/
road_has_flag(const struct road_type * proad,enum road_flag_id flag)427 bool road_has_flag(const struct road_type *proad, enum road_flag_id flag)
428 {
429 return BV_ISSET(proad->flags, flag);
430 }
431
432 /****************************************************************************
433 Returns TRUE iff any cardinally adjacent tile contains a road with
434 the given flag (does not check ptile itself).
435 ****************************************************************************/
is_road_flag_card_near(const struct tile * ptile,enum road_flag_id flag)436 bool is_road_flag_card_near(const struct tile *ptile, enum road_flag_id flag)
437 {
438 extra_type_by_cause_iterate(EC_ROAD, pextra) {
439 if (road_has_flag(extra_road_get(pextra), flag)) {
440 cardinal_adjc_iterate(ptile, adjc_tile) {
441 if (tile_has_extra(adjc_tile, pextra)) {
442 return TRUE;
443 }
444 } cardinal_adjc_iterate_end;
445 }
446 } extra_type_by_cause_iterate_end;
447
448 return FALSE;
449 }
450
451 /****************************************************************************
452 Returns TRUE iff any adjacent tile contains a road with the given flag
453 (does not check ptile itself).
454 ****************************************************************************/
is_road_flag_near_tile(const struct tile * ptile,enum road_flag_id flag)455 bool is_road_flag_near_tile(const struct tile *ptile, enum road_flag_id flag)
456 {
457 extra_type_by_cause_iterate(EC_ROAD, pextra) {
458 if (road_has_flag(extra_road_get(pextra), flag)) {
459 adjc_iterate(ptile, adjc_tile) {
460 if (tile_has_extra(adjc_tile, pextra)) {
461 return TRUE;
462 }
463 } adjc_iterate_end;
464 }
465 } extra_type_by_cause_iterate_end;
466
467 return FALSE;
468 }
469
470 /****************************************************************************
471 Is tile native to road?
472 ****************************************************************************/
is_native_tile_to_road(const struct road_type * proad,const struct tile * ptile)473 bool is_native_tile_to_road(const struct road_type *proad,
474 const struct tile *ptile)
475 {
476 struct extra_type *pextra;
477
478 if (road_has_flag(proad, RF_RIVER)) {
479 if (!terrain_has_flag(tile_terrain(ptile), TER_CAN_HAVE_RIVER)) {
480 return FALSE;
481 }
482 } else if (tile_terrain(ptile)->road_time == 0) {
483 return FALSE;
484 }
485
486 pextra = road_extra_get(proad);
487
488 return are_reqs_active(NULL, NULL, NULL, NULL, ptile,
489 NULL, NULL, NULL, NULL,
490 &pextra->reqs, RPT_POSSIBLE);
491 }
492
493 /****************************************************************************
494 Is extra cardinal only road.
495 ****************************************************************************/
is_cardinal_only_road(const struct extra_type * pextra)496 bool is_cardinal_only_road(const struct extra_type *pextra)
497 {
498 const struct road_type *proad;
499
500 if (!is_extra_caused_by(pextra, EC_ROAD)) {
501 return FALSE;
502 }
503
504 proad = extra_road_get(pextra);
505
506 return proad->move_mode == RMM_CARDINAL || proad->move_mode == RMM_RELAXED;
507 }
508
509 /****************************************************************************
510 Does road type provide move bonus
511 ****************************************************************************/
road_provides_move_bonus(const struct road_type * proad)512 bool road_provides_move_bonus(const struct road_type *proad)
513 {
514 return proad->move_cost >= 0;
515 }
516