Freeciv-3.1
Loading...
Searching...
No Matches
movement.c
Go to the documentation of this file.
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/* utility */
19#include "bitvector.h"
20#include "fcintl.h"
21#include "log.h"
22#include "shared.h"
23#include "support.h"
24
25/* common */
26#include "astring.h"
27#include "base.h"
28#include "effects.h"
29#include "fc_types.h"
30#include "game.h"
31#include "map.h"
32#include "road.h"
33#include "unit.h"
34#include "unitlist.h"
35#include "unittype.h"
36#include "terrain.h"
37
38#include "movement.h"
39
40/************************************************************************/
47int utype_move_rate(const struct unit_type *utype, const struct tile *ptile,
48 const struct player *pplayer, int veteran_level,
49 int hitpoints)
50{
51 const struct unit_class *uclass;
52 const struct veteran_level *vlevel;
53 int base_move_rate, move_rate;
54 int min_speed;
55
56 fc_assert_ret_val(NULL != utype, 0);
57 fc_assert_ret_val(NULL != pplayer, 0);
58 vlevel = utype_veteran_level(utype, veteran_level);
59 fc_assert_ret_val(NULL != vlevel, 0);
60 uclass = utype_class(utype);
61
62 base_move_rate = utype->move_rate + vlevel->move_bonus;
63 move_rate = base_move_rate;
64
65 if (uclass_has_flag(uclass, UCF_DAMAGE_SLOWS)) {
66 /* Scale the MP based on how many HP the unit has. */
67 move_rate = (move_rate * hitpoints) / utype->hp;
68 }
69
70 /* Add on effects bonus (Magellan's Expedition, Lighthouse,
71 * Nuclear Power). */
72 move_rate += (get_unittype_bonus(pplayer, ptile, utype, NULL,
73 EFT_MOVE_BONUS)
74 * SINGLE_MOVE);
75
76 /* Don't let the move_rate be less than min_speed unless the base_move_rate is
77 * also less than min_speed. */
78 min_speed = MIN(uclass->min_speed, base_move_rate);
79 if (move_rate < min_speed) {
80 move_rate = min_speed;
81 }
82
83 return move_rate;
84}
85
86/************************************************************************/
90int unit_move_rate(const struct unit *punit)
91{
92 fc_assert_ret_val(NULL != punit, 0);
93
96}
97
98/************************************************************************/
105int utype_unknown_move_cost(const struct unit_type *utype)
106{
107 const struct unit_class *uclass = utype_class(utype);
108 int move_cost;
109 int worst_effect_mc;
110
111 if (!uclass_has_flag(uclass, UCF_TERRAIN_SPEED)) {
112 /* Unit is not subject to terrain movement costs. */
113 move_cost = SINGLE_MOVE;
114 } else if (utype_has_flag(utype, UTYF_IGTER)) {
115 /* All terrain movement costs are equal! */
116 move_cost = MOVE_COST_IGTER;
117 } else {
118 /* Unit is subject to terrain movement costs. */
119 move_cost = 1; /* Arbitrary minimum. */
120 terrain_type_iterate(pterrain) {
121 if (is_native_to_class(uclass, pterrain, NULL)
122 && pterrain->movement_cost > move_cost) {
123 /* Exact movement cost matters only if we can enter
124 * the tile. */
125 move_cost = pterrain->movement_cost;
126 }
128 move_cost *= SINGLE_MOVE; /* Real value. */
129 }
130
131 /* Move cost from effects. */
132 worst_effect_mc = 0;
133 action_by_result_iterate(paction, ACTRES_UNIT_MOVE) {
134 struct universal req_pattern[] = {
135 { .kind = VUT_ACTION, .value.action = paction },
136 { .kind = VUT_UTYPE, .value.utype = utype },
137 };
138 int max_effect_mc;
139
140 if (!utype_can_do_action(utype, paction->id)) {
141 /* Not relevant. */
142 continue;
143 }
144
145 max_effect_mc = effect_cumulative_max(EFT_ACTION_SUCCESS_MOVE_COST,
146 req_pattern, ARRAY_SIZE(req_pattern));
147
148 if (max_effect_mc > worst_effect_mc) {
149 worst_effect_mc = max_effect_mc;
150 }
152 move_cost += worst_effect_mc;
153
154 /* Let's see if we can cross over all terrain types, else apply a malus.
155 * We want units that may encounter unsuitable terrain explore less.
156 * N.B.: We don't take in account terrain no unit can enter here. */
157 terrain_type_iterate(pterrain) {
158 if (BV_ISSET_ANY(pterrain->native_to)
159 && !is_native_to_class(uclass, pterrain, NULL)) {
160 /* Units that may encounter unsuitable terrain explore less. */
161 move_cost *= 2;
162 break;
163 }
165
166 return move_cost;
167}
168
169
170/************************************************************************/
175bool unit_can_defend_here(const struct civ_map *nmap, const struct unit *punit)
176{
177 struct unit *ptrans = unit_transport_get(punit);
178
179 if (ptrans == NULL) {
180 /* FIXME: Redundant check; if unit is in the tile without transport
181 * it's known to be able to exist there. */
183 }
184
185 switch (unit_type_get(punit)->tp_defense) {
186 case TDT_BLOCKED:
187 return FALSE;
188 case TDT_ALIGHT:
190 && can_unit_alight_or_be_unloaded(nmap, punit, ptrans);
191 }
192
194
195 return FALSE;
196}
197
198/************************************************************************/
203{
204 return uclass_has_flag(utype_class(utype), UCF_ATTACK_NON_NATIVE)
205 && (utype_can_do_action_result(utype, ACTRES_ATTACK)
206 || utype_can_do_action_result(utype, ACTRES_BOMBARD)
207 || utype_can_do_action_result(utype, ACTRES_NUKE_UNITS))
208 && !utype_has_flag(utype, UTYF_ONLY_NATIVE_ATTACK);
209}
210
211/************************************************************************/
216{
217 return (utype_can_do_action_result_when_ustate(utype, ACTRES_ATTACK,
218 USP_NATIVE_TILE, FALSE)
220 ACTRES_CONQUER_CITY,
221 USP_LIVABLE_TILE,
222 FALSE));
223}
224
225/************************************************************************/
228bool is_city_channel_tile(const struct civ_map *nmap,
229 const struct unit_class *punitclass,
230 const struct tile *ptile,
231 const struct tile *pexclude)
232{
233 struct dbv tile_processed;
234 struct tile_list *process_queue = tile_list_new();
235 bool found = FALSE;
236
237 dbv_init(&tile_processed, map_num_tiles());
238 for (;;) {
239 dbv_set(&tile_processed, tile_index(ptile));
240 adjc_iterate(nmap, ptile, piter) {
241 if (dbv_isset(&tile_processed, tile_index(piter))) {
242 continue;
243 } else if (piter != pexclude
244 && is_native_to_class(punitclass, tile_terrain(piter),
245 tile_extras(piter))) {
246 found = TRUE;
247 break;
248 } else if (piter != pexclude
249 && NULL != tile_city(piter)) {
250 tile_list_append(process_queue, piter);
251 } else {
252 dbv_set(&tile_processed, tile_index(piter));
253 }
255
256 if (found || 0 == tile_list_size(process_queue)) {
257 break; /* No more tile to process. */
258 } else {
259 ptile = tile_list_front(process_queue);
260 tile_list_pop_front(process_queue);
261 }
262 }
263
264 dbv_free(&tile_processed);
265 tile_list_destroy(process_queue);
266
267 return found;
268}
269
270/************************************************************************/
275bool can_exist_at_tile(const struct civ_map *nmap,
276 const struct unit_type *utype,
277 const struct tile *ptile)
278{
279 /* Cities are safe havens except for units in the middle of non-native
280 * terrain. This can happen if adjacent terrain is changed after unit
281 * arrived to city. */
282 if (NULL != tile_city(ptile)
283 && (uclass_has_flag(utype_class(utype), UCF_BUILD_ANYWHERE)
284 || is_native_near_tile(nmap, utype_class(utype), ptile)
285 || (1 == game.info.citymindist
286 && is_city_channel_tile(nmap, utype_class(utype), ptile, NULL)))) {
287 return TRUE;
288 }
289
290 /* UTYF_COAST_STRICT unit cannot exist in an ocean tile without access to land. */
291 if (utype_has_flag(utype, UTYF_COAST_STRICT)
292 && !is_safe_ocean(nmap, ptile)) {
293 return FALSE;
294 }
295
296 return is_native_tile(utype, ptile);
297}
298
299/************************************************************************/
304bool can_unit_exist_at_tile(const struct civ_map *nmap,
305 const struct unit *punit,
306 const struct tile *ptile)
307{
308 return can_exist_at_tile(nmap, unit_type_get(punit), ptile);
309}
310
311/************************************************************************/
316bool is_native_tile(const struct unit_type *punittype,
317 const struct tile *ptile)
318{
319 return is_native_to_class(utype_class(punittype), tile_terrain(ptile),
320 tile_extras(ptile));
321}
322
323/************************************************************************/
327bool is_native_to_class(const struct unit_class *punitclass,
328 const struct terrain *pterrain,
329 const bv_extras *extras)
330{
331 if (!pterrain) {
332 /* Unknown is considered native terrain */
333 return TRUE;
334 }
335
336 if (BV_ISSET(pterrain->native_to, uclass_index(punitclass))) {
337 return TRUE;
338 }
339
340 if (extras != NULL) {
342 if (BV_ISSET(*extras, extra_index(pextra))) {
343 return TRUE;
344 }
346 }
347
348 return FALSE;
349}
350
351
352/************************************************************************/
358bool is_native_move(const struct civ_map *nmap,
359 const struct unit_class *punitclass,
360 const struct tile *src_tile,
361 const struct tile *dst_tile)
362{
363 const struct road_type *proad;
364
365 if (is_native_to_class(punitclass, tile_terrain(dst_tile), NULL)) {
366 /* We aren't using extras to make the destination native. */
367 return TRUE;
368 } else if (!is_native_tile_to_class(punitclass, src_tile)) {
369 /* Disembarking or leaving port, so ignore road connectivity. */
370 return TRUE;
371 } else if (is_native_to_class(punitclass, tile_terrain(src_tile), NULL)) {
372 /* Native source terrain depends entirely on destination tile nativity. */
373 return is_native_tile_to_class(punitclass, dst_tile);
374 }
375
376 /* Check for non-road native extras on the source tile. */
378 if (tile_has_extra(src_tile, pextra)
379 && !is_extra_caused_by(pextra, EC_ROAD)
380 && is_native_tile_to_class(punitclass, dst_tile)) {
381 /* If there is one, and the destination is native, the move is native. */
382 return TRUE;
383 }
385
387 if (!tile_has_extra(dst_tile, pextra)) {
388 continue;
389 } else if (!is_extra_caused_by(pextra, EC_ROAD)) {
390 /* The destination is native because of a non-road extra. */
391 return TRUE;
392 }
393
394 proad = extra_road_get(pextra);
395
396 if (road_has_flag(proad, RF_JUMP_TO)) {
398 if (pextra != jextra
399 && is_extra_caused_by(jextra, EC_ROAD)
400 && tile_has_extra(src_tile, jextra)
401 && road_has_flag(jextra->data.road, RF_JUMP_FROM)) {
402 return TRUE;
403 }
405 }
406
407 extra_type_list_iterate(proad->integrators, iextra) {
408 if (!tile_has_extra(src_tile, iextra)) {
409 continue;
410 }
412 /* move_mode does not matter as all of them accept cardinal move */
413 return TRUE;
414 }
415 switch (extra_road_get(iextra)->move_mode) {
416 case RMM_FAST_ALWAYS:
417 /* Road connects source and destination, so we're fine. */
418 return TRUE;
419 case RMM_CARDINAL:
420 /* Road connects source and destination if cardinal move. */
421 if (is_move_cardinal(nmap, src_tile, dst_tile)) {
422 return TRUE;
423 }
424 break;
425 case RMM_RELAXED:
426 if (is_move_cardinal(nmap, src_tile, dst_tile)) {
427 /* Cardinal moves have no between tiles, so connected. */
428 return TRUE;
429 }
430 cardinal_between_iterate(nmap, src_tile, dst_tile, between) {
431 if (tile_has_extra(between, iextra)
432 || (pextra != iextra && tile_has_extra(between, pextra))) {
433 /* We have a link for the connection.
434 * 'pextra != iextra' is there just to avoid tile_has_extra()
435 * in by far more common case that 'pextra == iextra' */
436 return TRUE;
437 }
439 break;
440 }
443
444 return FALSE;
445}
446
447/************************************************************************/
450bool is_native_near_tile(const struct civ_map *nmap,
451 const struct unit_class *uclass,
452 const struct tile *ptile)
453{
454 if (is_native_tile_to_class(uclass, ptile)) {
455 return TRUE;
456 }
457
458 adjc_iterate(nmap, ptile, ptile2) {
459 if (is_native_tile_to_class(uclass, ptile2)) {
460 return TRUE;
461 }
463
464 return FALSE;
465}
466
467/************************************************************************/
476bool can_unit_survive_at_tile(const struct civ_map *nmap,
477 const struct unit *punit,
478 const struct tile *ptile)
479{
480 const struct unit_type *utype;
481
482 if (!can_unit_exist_at_tile(nmap, punit, ptile)) {
483 return FALSE;
484 }
485
486 if (tile_city(ptile)) {
487 return TRUE;
488 }
489
490 utype = unit_type_get(punit);
491 if (tile_has_refuel_extra(ptile, utype_class(utype))) {
492 /* Unit can always survive at refueling base */
493 return TRUE;
494 }
495
496 if (utype_has_flag(utype, UTYF_COAST) && is_safe_ocean(nmap, ptile)) {
497 /* Refueling coast */
498 return TRUE;
499 }
500
501 if (utype_fuel(utype)) {
502 /* Unit requires fuel and this is not refueling tile */
503 return FALSE;
504 }
505
506 if (is_losing_hp(punit)) {
507 /* Unit is losing HP over time in this tile (no city or native base) */
508 return FALSE;
509 }
510
511 return TRUE;
512}
513
514
515/************************************************************************/
527bool can_step_taken_wrt_to_zoc(const struct unit_type *punittype,
528 const struct player *unit_owner,
529 const struct tile *src_tile,
530 const struct tile *dst_tile,
531 const struct civ_map *zmap)
532{
533 if (unit_type_really_ignores_zoc(punittype)) {
534 return TRUE;
535 }
536 if (is_allied_unit_tile(dst_tile, unit_owner)) {
537 return TRUE;
538 }
539 if (tile_city(src_tile) || tile_city(dst_tile)) {
540 return TRUE;
541 }
542 if (terrain_has_flag(tile_terrain(src_tile), TER_NO_ZOC)
543 || terrain_has_flag(tile_terrain(dst_tile), TER_NO_ZOC)) {
544 return TRUE;
545 }
546
547 return (is_my_zoc(unit_owner, src_tile, zmap)
548 || is_my_zoc(unit_owner, dst_tile, zmap));
549}
550
551/************************************************************************/
557bool unit_can_move_to_tile(const struct civ_map *nmap,
558 const struct unit *punit,
559 const struct tile *dst_tile,
560 bool igzoc,
561 bool enter_transport,
562 bool enter_enemy_city)
563{
564 return (MR_OK == unit_move_to_tile_test(nmap, punit,
566 dst_tile, igzoc,
567 enter_transport, NULL,
568 enter_enemy_city));
569}
570
571/************************************************************************/
596 const struct unit *punit,
597 enum unit_activity activity,
598 const struct tile *src_tile,
599 const struct tile *dst_tile, bool igzoc,
600 bool enter_transport, struct unit *embark_to,
601 bool enter_enemy_city)
602{
603 bool zoc;
604 struct city *pcity;
605 const struct unit_type *punittype = unit_type_get(punit);
606 const struct player *puowner = unit_owner(punit);
607
608 /* 1) */
609 if (activity != ACTIVITY_IDLE
610 && activity != ACTIVITY_GOTO) {
611 /* For other activities the unit must be stationary. */
612 return MR_BAD_ACTIVITY;
613 }
614
615 /* 2) */
616 if (punit->stay) {
617 return MR_UNIT_STAY;
618 }
619
620 /* 3) */
621 if (!is_tiles_adjacent(src_tile, dst_tile)) {
622 /* Of course you can only move to adjacent positions. */
623 return MR_BAD_DESTINATION;
624 }
625
626 /* 4) */
627 if (is_non_allied_unit_tile(dst_tile, puowner)) {
628 /* You can't move onto a tile with non-allied units on it (try
629 * attacking instead). */
631 }
632
633 /* 5) */
634 if (puowner->ai_common.barbarian_type == ANIMAL_BARBARIAN
635 && dst_tile->terrain->animal != punittype) {
637 }
638
639 /* 6) */
640 if (embark_to != NULL) {
641 if (!could_unit_load(punit, embark_to)) {
643 }
644 } else if (!(can_exist_at_tile(nmap, punittype, dst_tile)
645 || (enter_transport
646 && unit_could_load_at(punit, dst_tile)))) {
648 }
649
650 /* 7) */
651 if (is_non_attack_unit_tile(dst_tile, puowner)) {
652 /* You can't move into a non-allied tile.
653 *
654 * FIXME: this should never happen since it should be caught by check
655 * #4. */
656 return MR_NO_WAR;
657 }
658
659 /* 8) */
660 if ((pcity = tile_city(dst_tile))) {
661 if (enter_enemy_city) {
662 if (pplayers_non_attack(city_owner(pcity), puowner)) {
663 /* You can't move into an empty city of a civilization you're at
664 * peace with - you must first either declare war or make an
665 * alliance. */
666 return MR_NO_WAR;
667 }
668 } else {
669 if (!pplayers_allied(city_owner(pcity), puowner)) {
670 /* You can't move into an empty city of a civilization you're not
671 * allied to. Assume that the player tried to attack. */
672 return MR_NO_WAR;
673 }
674 }
675 }
676
677 /* 9) */
678 zoc = igzoc
679 || can_step_taken_wrt_to_zoc(punittype, puowner, src_tile, dst_tile, nmap);
680 if (!zoc) {
681 /* The move is illegal because of zones of control. */
682 return MR_ZOC;
683 }
684
685 /* 10) */
686 if (utype_has_flag(punittype, UTYF_COAST_STRICT)
687 && !pcity && !is_safe_ocean(nmap, dst_tile)) {
688 return MR_TRIREME;
689 }
690
691 /* 11) */
692 if (!utype_has_flag(punittype, UTYF_CIVILIAN)
693 && !player_can_invade_tile(puowner, dst_tile)) {
694 return MR_PEACE;
695 }
696
697 /* 12) */
700 return MR_CANNOT_DISEMBARK;
701 }
702
703 /* 13) */
704 if (!(is_native_move(nmap, utype_class(punittype), src_tile, dst_tile)
705 /* Allow non-native moves into cities or boarding transport. */
706 || pcity
707 || unit_could_load_at(punit, dst_tile))) {
708 return MR_NON_NATIVE_MOVE;
709 }
710
711 return MR_OK;
712}
713
714/************************************************************************/
733 const struct unit *punit,
734 enum unit_activity activity,
735 const struct tile *src_tile,
736 const struct tile *dst_tile,
737 bool enter_transport, struct unit *embark_to,
738 bool enter_enemy_city)
739{
740 struct city *pcity;
741 const struct unit_type *punittype = unit_type_get(punit);
742 const struct player *puowner = unit_owner(punit);
743
744 /* 1) */
745 if (is_non_allied_unit_tile(dst_tile, puowner)) {
746 /* You can't move onto a tile with non-allied units on it (try
747 * attacking instead). */
749 }
750
751 /* 2) */
752 if (puowner->ai_common.barbarian_type == ANIMAL_BARBARIAN
753 && dst_tile->terrain->animal != punittype) {
755 }
756
757 /* 3) */
758 if (embark_to != NULL) {
759 if (!could_unit_load(punit, embark_to)) {
761 }
762 } else if (!(can_exist_at_tile(nmap, punittype, dst_tile)
763 || (enter_transport
764 && unit_could_load_at(punit, dst_tile)))) {
766 }
767
768 /* 4) */
769 if (is_non_attack_unit_tile(dst_tile, puowner)) {
770 /* You can't move into a non-allied tile.
771 *
772 * FIXME: this should never happen since it should be caught by check
773 * #1. */
774 return MR_NO_WAR;
775 }
776
777 /* 5) */
778 if ((pcity = tile_city(dst_tile))) {
779 if (enter_enemy_city) {
780 if (pplayers_non_attack(city_owner(pcity), puowner)) {
781 /* You can't move into an empty city of a civilization you're at
782 * peace with - you must first either declare war or make an
783 * alliance. */
784 return MR_NO_WAR;
785 }
786 } else {
787 if (!pplayers_allied(city_owner(pcity), puowner)) {
788 /* You can't move into an empty city of a civilization you're not
789 * allied to. Assume that the player tried to attack. */
790 return MR_NO_WAR;
791 }
792 }
793 }
794
795 /* 6) */
796 if (utype_has_flag(punittype, UTYF_COAST_STRICT)
797 && !pcity && !is_safe_ocean(nmap, dst_tile)) {
798 return MR_TRIREME;
799 }
800
801 /* 7) */
802 if (!utype_has_flag(punittype, UTYF_CIVILIAN)
803 && !player_can_invade_tile(puowner, dst_tile)) {
804 return MR_PEACE;
805 }
806
807 return MR_OK;
808}
809
810/************************************************************************/
813bool can_unit_transport(const struct unit *transporter,
814 const struct unit *transported)
815{
816 fc_assert_ret_val(transporter != NULL, FALSE);
817 fc_assert_ret_val(transported != NULL, FALSE);
818
819 return can_unit_type_transport(unit_type_get(transporter),
820 unit_class_get(transported));
821}
822
823/************************************************************************/
826bool can_unit_type_transport(const struct unit_type *transporter,
827 const struct unit_class *transported)
828{
829 if (transporter->transport_capacity <= 0) {
830 return FALSE;
831 }
832
833 return BV_ISSET(transporter->cargo, uclass_index(transported));
834}
835
836/************************************************************************/
841bool unit_can_load(const struct unit *punit)
842{
843 if (unit_transported(punit)) {
844 /* In another transport already. Can it unload first? */
846 return FALSE;
847 }
848 }
849
850 unit_list_iterate(unit_tile(punit)->units, ptransport) {
851 /* could_unit_load() instead of can_unit_load() since latter
852 * would check against unit already being transported, and we need
853 * to support unload+load to a new transport. */
854 if (ptransport != punit->transporter) {
855 if (could_unit_load(punit, ptransport)) {
856 return TRUE;
857 }
858 }
860
861 return FALSE;
862}
863
864/************************************************************************/
869bool unit_could_load_at(const struct unit *punit, const struct tile *ptile)
870{
871 unit_list_iterate(ptile->units, ptransport) {
872 if (could_unit_load(punit, ptransport)) {
873 return TRUE;
874 }
876
877 return FALSE;
878}
879
880static int move_points_denomlen = 0;
881
882/************************************************************************/
886{
887 char denomstr[10];
888 /* String length of maximum denominator for fractional representation of
889 * movement points, for padding of text representation */
890 fc_snprintf(denomstr, sizeof(denomstr), "%d", SINGLE_MOVE);
891 move_points_denomlen = strlen(denomstr);
892}
893
894/************************************************************************/
906const char *move_points_text_full(int mp, bool reduce, const char *prefix,
907 const char *none, bool align)
908{
909 static struct astring str = ASTRING_INIT;
910 int pad1, pad2;
911
912 if (align && SINGLE_MOVE > 1) {
913 /* Align to worst-case denominator even if we might be reducing to
914 * lowest terms, as other entries in a table might not reduce */
915 pad1 = move_points_denomlen; /* numerator or denominator */
916 pad2 = move_points_denomlen*2+2; /* everything right of integer part */
917 } else {
918 /* If no possible fractional part, alignment unneeded even if requested */
919 pad1 = pad2 = 0;
920 }
921 if (!prefix) {
922 prefix = "";
923 }
924 astr_clear(&str);
925 if ((mp == 0 && none) || SINGLE_MOVE == 0) {
926 /* No movement points, and we have a special representation to use */
927 /* (Also used when SINGLE_MOVE == 0, to avoid dividing by zero, which is
928 * important for client before ruleset has been received. Doesn't much
929 * matter what we print in this case.) */
930 astr_add(&str, "%s%*s", none ? none : "", pad2, "");
931 } else if ((mp % SINGLE_MOVE) == 0) {
932 /* Integer move points */
933 astr_add(&str, "%s%d%*s", prefix, mp / SINGLE_MOVE, pad2, "");
934 } else {
935 /* Fractional part */
936 int cancel;
937
939 if (reduce) {
940 /* Reduce to lowest terms */
941 int gcd = mp;
942 /* Calculate greatest common divisor with Euclid's algorithm */
943 int b = SINGLE_MOVE;
944
945 while (b != 0) {
946 int t = b;
947 b = gcd % b;
948 gcd = t;
949 }
950 cancel = gcd;
951 } else {
952 /* No cancellation */
953 cancel = 1;
954 }
955 if (mp < SINGLE_MOVE) {
956 /* Fractional move points */
957 astr_add(&str, "%s%*d/%*d", prefix,
958 pad1, (mp % SINGLE_MOVE) / cancel, pad1, SINGLE_MOVE / cancel);
959 } else {
960 /* Integer + fractional move points */
961 astr_add(&str,
962 "%s%d %*d/%*d", prefix, mp / SINGLE_MOVE,
963 pad1, (mp % SINGLE_MOVE) / cancel, pad1, SINGLE_MOVE / cancel);
964 }
965 }
966 return astr_str(&str);
967}
968
969/************************************************************************/
973const char *move_points_text(int mp, bool reduce)
974{
975 return move_points_text_full(mp, reduce, NULL, NULL, FALSE);
976}
#define action_by_result_iterate(_paction_, _result_)
Definition actions.h:488
#define action_by_result_iterate_end
Definition actions.h:492
void astr_clear(struct astring *astr)
Definition astring.c:205
void astr_add(struct astring *astr, const char *format,...)
Definition astring.c:287
#define str
Definition astring.c:76
static const char * astr_str(const struct astring *astr) fc__attribute((nonnull(1)))
Definition astring.h:93
#define ASTRING_INIT
Definition astring.h:44
void dbv_init(struct dbv *pdbv, int bits)
Definition bitvector.c:50
void dbv_set(struct dbv *pdbv, int bit)
Definition bitvector.c:144
bool dbv_isset(const struct dbv *pdbv, int bit)
Definition bitvector.c:120
void dbv_free(struct dbv *pdbv)
Definition bitvector.c:95
#define BV_ISSET(bv, bit)
Definition bitvector.h:78
#define BV_ISSET_ANY(vec)
Definition bitvector.h:109
#define city_owner(_pcity_)
Definition city.h:543
struct unit struct city struct unit struct tile struct extra_type const struct act_prob *act_probs int actor_unit_id struct unit struct unit * punit
Definition dialogs_g.h:73
int effect_cumulative_max(enum effect_type type, struct universal *unis, size_t n_unis)
Definition effects.c:331
int get_unittype_bonus(const struct player *pplayer, const struct tile *ptile, const struct unit_type *punittype, const struct action *paction, enum effect_type effect_type)
Definition effects.c:957
static struct extra_type extras[MAX_EXTRA_TYPES]
Definition extras.c:31
#define extra_type_list_iterate(extralist, pextra)
Definition extras.h:159
#define is_extra_caused_by(e, c)
Definition extras.h:196
#define extra_index(_e_)
Definition extras.h:177
#define extra_type_list_iterate_end
Definition extras.h:161
#define extra_road_get(_e_)
Definition extras.h:185
struct civ_game game
Definition game.c:57
#define fc_assert(condition)
Definition log.h:176
#define fc_assert_ret_val(condition, val)
Definition log.h:194
bool is_move_cardinal(const struct civ_map *nmap, const struct tile *start_tile, const struct tile *end_tile)
Definition map.c:1363
int map_num_tiles(void)
Definition map.c:1012
bool is_tiles_adjacent(const struct tile *tile0, const struct tile *tile1)
Definition map.c:929
bool is_safe_ocean(const struct civ_map *nmap, const struct tile *ptile)
Definition map.c:665
#define adjc_iterate_end
Definition map.h:427
#define cardinal_between_iterate(nmap, tile1, tile2, between)
Definition map.h:471
#define adjc_iterate(nmap, center_tile, itr_tile)
Definition map.h:422
#define ALL_DIRECTIONS_CARDINAL()
Definition map.h:47
#define cardinal_between_iterate_end
Definition map.h:476
const char * move_points_text(int mp, bool reduce)
Definition movement.c:973
const char * move_points_text_full(int mp, bool reduce, const char *prefix, const char *none, bool align)
Definition movement.c:906
bool can_exist_at_tile(const struct civ_map *nmap, const struct unit_type *utype, const struct tile *ptile)
Definition movement.c:275
enum unit_move_result unit_move_to_tile_test(const struct civ_map *nmap, const struct unit *punit, enum unit_activity activity, const struct tile *src_tile, const struct tile *dst_tile, bool igzoc, bool enter_transport, struct unit *embark_to, bool enter_enemy_city)
Definition movement.c:595
bool can_unit_exist_at_tile(const struct civ_map *nmap, const struct unit *punit, const struct tile *ptile)
Definition movement.c:304
bool is_native_tile(const struct unit_type *punittype, const struct tile *ptile)
Definition movement.c:316
bool can_step_taken_wrt_to_zoc(const struct unit_type *punittype, const struct player *unit_owner, const struct tile *src_tile, const struct tile *dst_tile, const struct civ_map *zmap)
Definition movement.c:527
int utype_unknown_move_cost(const struct unit_type *utype)
Definition movement.c:105
bool unit_can_load(const struct unit *punit)
Definition movement.c:841
bool can_unit_transport(const struct unit *transporter, const struct unit *transported)
Definition movement.c:813
int unit_move_rate(const struct unit *punit)
Definition movement.c:90
bool unit_could_load_at(const struct unit *punit, const struct tile *ptile)
Definition movement.c:869
static int move_points_denomlen
Definition movement.c:880
bool can_attack_from_non_native(const struct unit_type *utype)
Definition movement.c:215
enum unit_move_result unit_teleport_to_tile_test(const struct civ_map *nmap, const struct unit *punit, enum unit_activity activity, const struct tile *src_tile, const struct tile *dst_tile, bool enter_transport, struct unit *embark_to, bool enter_enemy_city)
Definition movement.c:732
bool unit_can_defend_here(const struct civ_map *nmap, const struct unit *punit)
Definition movement.c:175
bool is_native_move(const struct civ_map *nmap, const struct unit_class *punitclass, const struct tile *src_tile, const struct tile *dst_tile)
Definition movement.c:358
bool is_native_to_class(const struct unit_class *punitclass, const struct terrain *pterrain, const bv_extras *extras)
Definition movement.c:327
int utype_move_rate(const struct unit_type *utype, const struct tile *ptile, const struct player *pplayer, int veteran_level, int hitpoints)
Definition movement.c:47
bool is_city_channel_tile(const struct civ_map *nmap, const struct unit_class *punitclass, const struct tile *ptile, const struct tile *pexclude)
Definition movement.c:228
bool can_unit_survive_at_tile(const struct civ_map *nmap, const struct unit *punit, const struct tile *ptile)
Definition movement.c:476
bool is_native_near_tile(const struct civ_map *nmap, const struct unit_class *uclass, const struct tile *ptile)
Definition movement.c:450
bool unit_can_move_to_tile(const struct civ_map *nmap, const struct unit *punit, const struct tile *dst_tile, bool igzoc, bool enter_transport, bool enter_enemy_city)
Definition movement.c:557
bool can_unit_type_transport(const struct unit_type *transporter, const struct unit_class *transported)
Definition movement.c:826
void init_move_fragments(void)
Definition movement.c:885
bool can_attack_non_native(const struct unit_type *utype)
Definition movement.c:202
#define SINGLE_MOVE
Definition movement.h:24
static bool is_native_tile_to_class(const struct unit_class *punitclass, const struct tile *ptile)
Definition movement.h:80
unit_move_result
Definition movement.h:32
@ MR_CANNOT_DISEMBARK
Definition movement.h:46
@ MR_OK
Definition movement.h:33
@ MR_DESTINATION_OCCUPIED_BY_NON_ALLIED_UNIT
Definition movement.h:43
@ MR_TRIREME
Definition movement.h:45
@ MR_NON_NATIVE_MOVE
Definition movement.h:47
@ MR_BAD_ACTIVITY
Definition movement.h:39
@ MR_ANIMAL_DISALLOWED
Definition movement.h:48
@ MR_PEACE
Definition movement.h:37
@ MR_ZOC
Definition movement.h:38
@ MR_NO_WAR
Definition movement.h:36
@ MR_BAD_DESTINATION
Definition movement.h:40
@ MR_NO_TRANSPORTER_CAPACITY
Definition movement.h:44
@ MR_UNIT_STAY
Definition movement.h:49
#define MOVE_COST_IGTER
Definition movement.h:25
bool player_can_invade_tile(const struct player *pplayer, const struct tile *ptile)
Definition player.c:264
bool pplayers_allied(const struct player *pplayer, const struct player *pplayer2)
Definition player.c:1381
bool pplayers_non_attack(const struct player *pplayer, const struct player *pplayer2)
Definition player.c:1435
bool road_has_flag(const struct road_type *proad, enum road_flag_id flag)
Definition road.c:410
#define ARRAY_SIZE(x)
Definition shared.h:85
#define MIN(x, y)
Definition shared.h:55
Definition city.h:309
struct packet_game_info info
Definition game.h:89
enum barbarian_type barbarian_type
Definition player.h:128
struct player_ai ai_common
Definition player.h:288
struct unit_list * units
Definition player.h:282
enum road_move_mode move_mode
Definition road.h:79
struct extra_type_list * integrators
Definition road.h:93
bv_unit_classes native_to
Definition terrain.h:243
const struct unit_type * animal
Definition terrain.h:223
Definition tile.h:49
struct unit_list * units
Definition tile.h:57
struct terrain * terrain
Definition tile.h:56
struct unit_class::@85 cache
struct extra_type_list * native_tile_extras
Definition unittype.h:156
int min_speed
Definition unittype.h:141
int transport_capacity
Definition unittype.h:504
bv_unit_classes cargo
Definition unittype.h:539
int move_rate
Definition unittype.h:497
Definition unit.h:138
enum unit_activity activity
Definition unit.h:157
int hp
Definition unit.h:151
bool stay
Definition unit.h:205
struct unit * transporter
Definition unit.h:183
const struct unit_type * utype
Definition unit.h:139
int veteran
Definition unit.h:152
enum universals_n kind
Definition fc_types.h:758
int fc_snprintf(char *str, size_t n, const char *format,...)
Definition support.c:969
#define TRUE
Definition support.h:46
#define FALSE
Definition support.h:47
#define terrain_type_iterate(_p)
Definition terrain.h:358
#define terrain_type_iterate_end
Definition terrain.h:364
#define terrain_has_flag(terr, flag)
Definition terrain.h:269
bool tile_has_refuel_extra(const struct tile *ptile, const struct unit_class *uclass)
Definition tile.c:303
struct city * tile_city(const struct tile *ptile)
Definition tile.c:83
#define tile_index(_pt_)
Definition tile.h:87
#define tile_terrain(_tile)
Definition tile.h:109
static const bv_extras * tile_extras(const struct tile *ptile)
Definition tile.h:119
#define tile_has_extra(ptile, pextra)
Definition tile.h:146
bool unit_type_really_ignores_zoc(const struct unit_type *punittype)
Definition unit.c:1510
bool is_losing_hp(const struct unit *punit)
Definition unit.c:2212
struct unit * unit_transport_get(const struct unit *pcargo)
Definition unit.c:2425
bool could_unit_load(const struct unit *pcargo, const struct unit *ptrans)
Definition unit.c:719
bool unit_transported(const struct unit *pcargo)
Definition unit.c:2409
bool can_unit_unload(const struct unit *pcargo, const struct unit *ptrans)
Definition unit.c:771
bool can_unit_alight_or_be_unloaded(const struct civ_map *nmap, const struct unit *pcargo, const struct unit *ptrans)
Definition unit.c:796
#define unit_tile(_pu)
Definition unit.h:395
static bool is_non_attack_unit_tile(const struct tile *ptile, const struct player *pplayer)
Definition unit.h:455
static bool is_allied_unit_tile(const struct tile *ptile, const struct player *pplayer)
Definition unit.h:406
#define unit_owner(_pu)
Definition unit.h:394
static bool is_non_allied_unit_tile(const struct tile *ptile, const struct player *pplayer)
Definition unit.h:430
static bool is_my_zoc(const struct player *unit_owner, const struct tile *ptile, const struct civ_map *zmap)
Definition unit.h:476
#define unit_list_iterate(unitlist, punit)
Definition unitlist.h:31
#define unit_list_iterate_end
Definition unitlist.h:33
const struct unit_type * unit_type_get(const struct unit *punit)
Definition unittype.c:123
struct unit_class * unit_class_get(const struct unit *punit)
Definition unittype.c:2547
bool utype_can_do_action_result_when_ustate(const struct unit_type *putype, enum action_result result, const enum ustate_prop prop, const bool is_there)
Definition unittype.c:1027
bool utype_can_do_action_result(const struct unit_type *putype, enum action_result result)
Definition unittype.c:459
const struct veteran_level * utype_veteran_level(const struct unit_type *punittype, int level)
Definition unittype.c:2645
bool utype_can_do_action(const struct unit_type *putype, const action_id act_id)
Definition unittype.c:443
static bool uclass_has_flag(const struct unit_class *punitclass, enum unit_class_flag_id flag)
Definition unittype.h:753
#define utype_class(_t_)
Definition unittype.h:736
#define utype_fuel(ptype)
Definition unittype.h:825
static bool utype_has_flag(const struct unit_type *punittype, int flag)
Definition unittype.h:604
#define uclass_index(_c_)
Definition unittype.h:729