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 MAP_TILE_CONN_TO_BY(nmap, ptile, piter,
234 piter != pexclude
235 && is_native_to_class(punitclass, tile_terrain(piter),
236 tile_extras(piter)),
237 piter != pexclude && NULL != tile_city(piter));
238
239 return NULL != ptile;
240}
241
242/************************************************************************/
245bool may_be_city_channel_tile(const struct civ_map *nmap,
246 const struct unit_class *punitclass,
247 const struct tile *ptile,
248 const struct player *pov_player)
249{
250 MAP_TILE_CONN_TO_BY(nmap, ptile, piter,
251 !tile_is_seen(piter, pov_player)
252 || is_native_to_class(punitclass, tile_terrain(piter),
253 tile_extras(piter)),
254 NULL != tile_city(piter));
255
256 return NULL != ptile;
257}
258
259/************************************************************************/
264bool can_exist_at_tile(const struct civ_map *nmap,
265 const struct unit_type *utype,
266 const struct tile *ptile)
267{
268 /* Cities are safe havens except for units in the middle of non-native
269 * terrain. This can happen if adjacent terrain is changed after unit
270 * arrived to city. */
271 if (NULL != tile_city(ptile)
272 && (uclass_has_flag(utype_class(utype), UCF_BUILD_ANYWHERE)
273 || is_native_near_tile(nmap, utype_class(utype), ptile)
274 || (1 == game.info.citymindist
275 && is_city_channel_tile(nmap, utype_class(utype), ptile, NULL)))) {
276 return TRUE;
277 }
278
279 /* UTYF_COAST_STRICT unit cannot exist in an ocean tile without access to land. */
280 if (utype_has_flag(utype, UTYF_COAST_STRICT)
281 && !is_safe_ocean(nmap, ptile)) {
282 return FALSE;
283 }
284
285 return is_native_tile(utype, ptile);
286}
287
288/************************************************************************/
295bool could_exist_in_city(const struct civ_map *nmap,
296 const struct player *pov_player,
297 const struct unit_type *utype,
298 const struct city *pcity)
299{
300 struct unit_class *uclass;
301 struct tile *ctile;
302
303 fc_assert_ret_val(NULL != pcity && NULL != utype, FALSE);
304
305 ctile = city_tile(pcity);
306 uclass = utype_class(utype);
307
308 if (uclass_has_flag(uclass, UCF_BUILD_ANYWHERE)) {
309 /* If the city stands, it can exist there */
310 return TRUE;
311 }
312 adjc_iterate(nmap, ctile, ptile) {
313 if (!tile_is_seen(ptile, pov_player)
314 || is_native_tile_to_class(uclass, ptile)) {
315 /* Could be native. This ignores a rare case when we don't see
316 * only the city center and any native terrain is NoCities */
317 return TRUE;
318 }
320
321 if (1 == game.info.citymindist
322 && may_be_city_channel_tile(nmap, uclass, ctile, pov_player)) {
323 /* Channeled. */
324 return TRUE;
325 }
326
327 /* It definitely can't exist there */
328 return FALSE;
329}
330
331/************************************************************************/
336bool can_unit_exist_at_tile(const struct civ_map *nmap,
337 const struct unit *punit,
338 const struct tile *ptile)
339{
340 return can_exist_at_tile(nmap, unit_type_get(punit), ptile);
341}
342
343/************************************************************************/
348bool is_native_tile(const struct unit_type *punittype,
349 const struct tile *ptile)
350{
351 return is_native_to_class(utype_class(punittype), tile_terrain(ptile),
352 tile_extras(ptile));
353}
354
355/************************************************************************/
359bool is_native_to_class(const struct unit_class *punitclass,
360 const struct terrain *pterrain,
361 const bv_extras *extras)
362{
363 if (!pterrain) {
364 /* Unknown is considered native terrain */
365 return TRUE;
366 }
367
368 if (BV_ISSET(pterrain->native_to, uclass_index(punitclass))) {
369 return TRUE;
370 }
371
372 if (extras != NULL) {
374 if (BV_ISSET(*extras, extra_index(pextra))) {
375 return TRUE;
376 }
378 }
379
380 return FALSE;
381}
382
383
384/************************************************************************/
390bool is_native_move(const struct civ_map *nmap,
391 const struct unit_class *punitclass,
392 const struct tile *src_tile,
393 const struct tile *dst_tile)
394{
395 const struct road_type *proad;
396
397 if (is_native_to_class(punitclass, tile_terrain(dst_tile), NULL)) {
398 /* We aren't using extras to make the destination native. */
399 return TRUE;
400 } else if (!is_native_tile_to_class(punitclass, src_tile)) {
401 /* Disembarking or leaving port, so ignore road connectivity. */
402 return TRUE;
403 } else if (is_native_to_class(punitclass, tile_terrain(src_tile), NULL)) {
404 /* Native source terrain depends entirely on destination tile nativity. */
405 return is_native_tile_to_class(punitclass, dst_tile);
406 }
407
408 /* Check for non-road native extras on the source tile. */
410 if (tile_has_extra(src_tile, pextra)
411 && !is_extra_caused_by(pextra, EC_ROAD)
412 && is_native_tile_to_class(punitclass, dst_tile)) {
413 /* If there is one, and the destination is native, the move is native. */
414 return TRUE;
415 }
417
419 if (!tile_has_extra(dst_tile, pextra)) {
420 continue;
421 } else if (!is_extra_caused_by(pextra, EC_ROAD)) {
422 /* The destination is native because of a non-road extra. */
423 return TRUE;
424 }
425
426 proad = extra_road_get(pextra);
427
428 if (road_has_flag(proad, RF_JUMP_TO)) {
430 if (pextra != jextra
431 && is_extra_caused_by(jextra, EC_ROAD)
432 && tile_has_extra(src_tile, jextra)
433 && road_has_flag(jextra->data.road, RF_JUMP_FROM)) {
434 return TRUE;
435 }
437 }
438
439 extra_type_list_iterate(proad->integrators, iextra) {
440 if (!tile_has_extra(src_tile, iextra)) {
441 continue;
442 }
444 /* move_mode does not matter as all of them accept cardinal move */
445 return TRUE;
446 }
447 switch (extra_road_get(iextra)->move_mode) {
448 case RMM_FAST_ALWAYS:
449 /* Road connects source and destination, so we're fine. */
450 return TRUE;
451 case RMM_CARDINAL:
452 /* Road connects source and destination if cardinal move. */
453 if (is_move_cardinal(nmap, src_tile, dst_tile)) {
454 return TRUE;
455 }
456 break;
457 case RMM_RELAXED:
458 if (is_move_cardinal(nmap, src_tile, dst_tile)) {
459 /* Cardinal moves have no between tiles, so connected. */
460 return TRUE;
461 }
462 cardinal_between_iterate(nmap, src_tile, dst_tile, between) {
463 if (tile_has_extra(between, iextra)
464 || (pextra != iextra && tile_has_extra(between, pextra))) {
465 /* We have a link for the connection.
466 * 'pextra != iextra' is there just to avoid tile_has_extra()
467 * in by far more common case that 'pextra == iextra' */
468 return TRUE;
469 }
471 break;
472 }
475
476 return FALSE;
477}
478
479/************************************************************************/
482bool is_native_near_tile(const struct civ_map *nmap,
483 const struct unit_class *uclass,
484 const struct tile *ptile)
485{
486 if (is_native_tile_to_class(uclass, ptile)) {
487 return TRUE;
488 }
489
490 adjc_iterate(nmap, ptile, ptile2) {
491 if (is_native_tile_to_class(uclass, ptile2)) {
492 return TRUE;
493 }
495
496 return FALSE;
497}
498
499/************************************************************************/
508bool can_unit_survive_at_tile(const struct civ_map *nmap,
509 const struct unit *punit,
510 const struct tile *ptile)
511{
512 const struct unit_type *utype;
513
514 if (!can_unit_exist_at_tile(nmap, punit, ptile)) {
515 return FALSE;
516 }
517
518 if (tile_city(ptile)) {
519 return TRUE;
520 }
521
522 utype = unit_type_get(punit);
523 if (tile_has_refuel_extra(ptile, utype_class(utype))) {
524 /* Unit can always survive at refueling base */
525 return TRUE;
526 }
527
528 if (utype_has_flag(utype, UTYF_COAST) && is_safe_ocean(nmap, ptile)) {
529 /* Refueling coast */
530 return TRUE;
531 }
532
533 if (utype_fuel(utype)) {
534 /* Unit requires fuel and this is not refueling tile */
535 return FALSE;
536 }
537
538 if (is_losing_hp(punit)) {
539 /* Unit is losing HP over time in this tile (no city or native base) */
540 return FALSE;
541 }
542
543 return TRUE;
544}
545
546
547/************************************************************************/
559bool can_step_taken_wrt_to_zoc(const struct unit_type *punittype,
560 const struct player *unit_owner,
561 const struct tile *src_tile,
562 const struct tile *dst_tile,
563 const struct civ_map *zmap)
564{
565 if (unit_type_really_ignores_zoc(punittype)) {
566 return TRUE;
567 }
568 if (is_allied_unit_tile(dst_tile, unit_owner)) {
569 return TRUE;
570 }
571 if (tile_city(src_tile) || tile_city(dst_tile)) {
572 return TRUE;
573 }
574 if (terrain_has_flag(tile_terrain(src_tile), TER_NO_ZOC)
575 || terrain_has_flag(tile_terrain(dst_tile), TER_NO_ZOC)) {
576 return TRUE;
577 }
578
579 return (is_my_zoc(unit_owner, src_tile, zmap)
580 || is_my_zoc(unit_owner, dst_tile, zmap));
581}
582
583/************************************************************************/
589bool unit_can_move_to_tile(const struct civ_map *nmap,
590 const struct unit *punit,
591 const struct tile *dst_tile,
592 bool igzoc,
593 bool enter_transport,
594 bool enter_enemy_city)
595{
596 return (MR_OK == unit_move_to_tile_test(nmap, punit,
598 dst_tile, igzoc,
599 enter_transport, NULL,
600 enter_enemy_city));
601}
602
603/************************************************************************/
628 const struct unit *punit,
629 enum unit_activity activity,
630 const struct tile *src_tile,
631 const struct tile *dst_tile, bool igzoc,
632 bool enter_transport, struct unit *embark_to,
633 bool enter_enemy_city)
634{
635 bool zoc;
636 struct city *pcity;
637 const struct unit_type *punittype = unit_type_get(punit);
638 const struct player *puowner = unit_owner(punit);
639
640 /* 1) */
641 if (activity != ACTIVITY_IDLE
642 && activity != ACTIVITY_GOTO) {
643 /* For other activities the unit must be stationary. */
644 return MR_BAD_ACTIVITY;
645 }
646
647 /* 2) */
648 if (punit->stay) {
649 return MR_UNIT_STAY;
650 }
651
652 /* 3) */
653 if (!is_tiles_adjacent(src_tile, dst_tile)) {
654 /* Of course you can only move to adjacent positions. */
655 return MR_BAD_DESTINATION;
656 }
657
658 /* 4) */
659 if (is_non_allied_unit_tile(dst_tile, puowner)) {
660 /* You can't move onto a tile with non-allied units on it (try
661 * attacking instead). */
663 }
664
665 /* 5) */
666 if (puowner->ai_common.barbarian_type == ANIMAL_BARBARIAN
667 && dst_tile->terrain->animal != punittype) {
669 }
670
671 /* 6) */
672 if (embark_to != NULL) {
673 if (!could_unit_load(punit, embark_to)) {
675 }
676 } else if (!(can_exist_at_tile(nmap, punittype, dst_tile)
677 || (enter_transport
678 && unit_could_load_at(punit, dst_tile)))) {
680 }
681
682 /* 7) */
683 if (is_non_attack_unit_tile(dst_tile, puowner)) {
684 /* You can't move into a non-allied tile.
685 *
686 * FIXME: this should never happen since it should be caught by check
687 * #4. */
688 return MR_NO_WAR;
689 }
690
691 /* 8) */
692 if ((pcity = tile_city(dst_tile))) {
693 if (enter_enemy_city) {
694 if (pplayers_non_attack(city_owner(pcity), puowner)) {
695 /* You can't move into an empty city of a civilization you're at
696 * peace with - you must first either declare war or make an
697 * alliance. */
698 return MR_NO_WAR;
699 }
700 } else {
701 if (!pplayers_allied(city_owner(pcity), puowner)) {
702 /* You can't move into an empty city of a civilization you're not
703 * allied to. Assume that the player tried to attack. */
704 return MR_NO_WAR;
705 }
706 }
707 }
708
709 /* 9) */
710 zoc = igzoc
711 || can_step_taken_wrt_to_zoc(punittype, puowner, src_tile, dst_tile, nmap);
712 if (!zoc) {
713 /* The move is illegal because of zones of control. */
714 return MR_ZOC;
715 }
716
717 /* 10) */
718 if (utype_has_flag(punittype, UTYF_COAST_STRICT)
719 && !pcity && !is_safe_ocean(nmap, dst_tile)) {
720 return MR_TRIREME;
721 }
722
723 /* 11) */
724 if (!utype_has_flag(punittype, UTYF_CIVILIAN)
725 && !player_can_invade_tile(puowner, dst_tile)) {
726 return MR_PEACE;
727 }
728
729 /* 12) */
732 return MR_CANNOT_DISEMBARK;
733 }
734
735 /* 13) */
736 if (!(is_native_move(nmap, utype_class(punittype), src_tile, dst_tile)
737 /* Allow non-native moves into cities or boarding transport. */
738 || pcity
739 || unit_could_load_at(punit, dst_tile))) {
740 return MR_NON_NATIVE_MOVE;
741 }
742
743 return MR_OK;
744}
745
746/************************************************************************/
765 const struct unit *punit,
766 enum unit_activity activity,
767 const struct tile *src_tile,
768 const struct tile *dst_tile,
769 bool enter_transport, struct unit *embark_to,
770 bool enter_enemy_city)
771{
772 struct city *pcity;
773 const struct unit_type *punittype = unit_type_get(punit);
774 const struct player *puowner = unit_owner(punit);
775
776 /* 1) */
777 if (is_non_allied_unit_tile(dst_tile, puowner)) {
778 /* You can't move onto a tile with non-allied units on it (try
779 * attacking instead). */
781 }
782
783 /* 2) */
784 if (puowner->ai_common.barbarian_type == ANIMAL_BARBARIAN
785 && dst_tile->terrain->animal != punittype) {
787 }
788
789 /* 3) */
790 if (embark_to != NULL) {
791 if (!could_unit_load(punit, embark_to)) {
793 }
794 } else if (!(can_exist_at_tile(nmap, punittype, dst_tile)
795 || (enter_transport
796 && unit_could_load_at(punit, dst_tile)))) {
798 }
799
800 /* 4) */
801 if (is_non_attack_unit_tile(dst_tile, puowner)) {
802 /* You can't move into a non-allied tile.
803 *
804 * FIXME: this should never happen since it should be caught by check
805 * #1. */
806 return MR_NO_WAR;
807 }
808
809 /* 5) */
810 if ((pcity = tile_city(dst_tile))) {
811 if (enter_enemy_city) {
812 if (pplayers_non_attack(city_owner(pcity), puowner)) {
813 /* You can't move into an empty city of a civilization you're at
814 * peace with - you must first either declare war or make an
815 * alliance. */
816 return MR_NO_WAR;
817 }
818 } else {
819 if (!pplayers_allied(city_owner(pcity), puowner)) {
820 /* You can't move into an empty city of a civilization you're not
821 * allied to. Assume that the player tried to attack. */
822 return MR_NO_WAR;
823 }
824 }
825 }
826
827 /* 6) */
828 if (utype_has_flag(punittype, UTYF_COAST_STRICT)
829 && !pcity && !is_safe_ocean(nmap, dst_tile)) {
830 return MR_TRIREME;
831 }
832
833 /* 7) */
834 if (!utype_has_flag(punittype, UTYF_CIVILIAN)
835 && !player_can_invade_tile(puowner, dst_tile)) {
836 return MR_PEACE;
837 }
838
839 return MR_OK;
840}
841
842/************************************************************************/
845bool can_unit_transport(const struct unit *transporter,
846 const struct unit *transported)
847{
848 fc_assert_ret_val(transporter != NULL, FALSE);
849 fc_assert_ret_val(transported != NULL, FALSE);
850
851 return can_unit_type_transport(unit_type_get(transporter),
852 unit_class_get(transported));
853}
854
855/************************************************************************/
858bool can_unit_type_transport(const struct unit_type *transporter,
859 const struct unit_class *transported)
860{
861 if (transporter->transport_capacity <= 0) {
862 return FALSE;
863 }
864
865 return BV_ISSET(transporter->cargo, uclass_index(transported));
866}
867
868/************************************************************************/
873bool unit_can_load(const struct unit *punit)
874{
875 if (unit_transported(punit)) {
876 /* In another transport already. Can it unload first? */
878 return FALSE;
879 }
880 }
881
882 unit_list_iterate(unit_tile(punit)->units, ptransport) {
883 /* could_unit_load() instead of can_unit_load() since latter
884 * would check against unit already being transported, and we need
885 * to support unload+load to a new transport. */
886 if (ptransport != punit->transporter) {
887 if (could_unit_load(punit, ptransport)) {
888 return TRUE;
889 }
890 }
892
893 return FALSE;
894}
895
896/************************************************************************/
901bool unit_could_load_at(const struct unit *punit, const struct tile *ptile)
902{
903 unit_list_iterate(ptile->units, ptransport) {
904 if (could_unit_load(punit, ptransport)) {
905 return TRUE;
906 }
908
909 return FALSE;
910}
911
912static int move_points_denomlen = 0;
913
914/************************************************************************/
918{
919 char denomstr[10];
920 /* String length of maximum denominator for fractional representation of
921 * movement points, for padding of text representation */
922 fc_snprintf(denomstr, sizeof(denomstr), "%d", SINGLE_MOVE);
923 move_points_denomlen = strlen(denomstr);
924}
925
926/************************************************************************/
938const char *move_points_text_full(int mp, bool reduce, const char *prefix,
939 const char *none, bool align)
940{
941 static struct astring str = ASTRING_INIT;
942 int pad1, pad2;
943
944 if (align && SINGLE_MOVE > 1) {
945 /* Align to worst-case denominator even if we might be reducing to
946 * lowest terms, as other entries in a table might not reduce */
947 pad1 = move_points_denomlen; /* numerator or denominator */
948 pad2 = move_points_denomlen*2+2; /* everything right of integer part */
949 } else {
950 /* If no possible fractional part, alignment unneeded even if requested */
951 pad1 = pad2 = 0;
952 }
953 if (!prefix) {
954 prefix = "";
955 }
956 astr_clear(&str);
957 if ((mp == 0 && none) || SINGLE_MOVE == 0) {
958 /* No movement points, and we have a special representation to use */
959 /* (Also used when SINGLE_MOVE == 0, to avoid dividing by zero, which is
960 * important for client before ruleset has been received. Doesn't much
961 * matter what we print in this case.) */
962 astr_add(&str, "%s%*s", none ? none : "", pad2, "");
963 } else if ((mp % SINGLE_MOVE) == 0) {
964 /* Integer move points */
965 astr_add(&str, "%s%d%*s", prefix, mp / SINGLE_MOVE, pad2, "");
966 } else {
967 /* Fractional part */
968 int cancel;
969
971 if (reduce) {
972 /* Reduce to lowest terms */
973 int gcd = mp;
974 /* Calculate greatest common divisor with Euclid's algorithm */
975 int b = SINGLE_MOVE;
976
977 while (b != 0) {
978 int t = b;
979 b = gcd % b;
980 gcd = t;
981 }
982 cancel = gcd;
983 } else {
984 /* No cancellation */
985 cancel = 1;
986 }
987 if (mp < SINGLE_MOVE) {
988 /* Fractional move points */
989 astr_add(&str, "%s%*d/%*d", prefix,
990 pad1, (mp % SINGLE_MOVE) / cancel, pad1, SINGLE_MOVE / cancel);
991 } else {
992 /* Integer + fractional move points */
993 astr_add(&str,
994 "%s%d %*d/%*d", prefix, mp / SINGLE_MOVE,
995 pad1, (mp % SINGLE_MOVE) / cancel, pad1, SINGLE_MOVE / cancel);
996 }
997 }
998 return astr_str(&str);
999}
1000
1001/************************************************************************/
1005const char *move_points_text(int mp, bool reduce)
1006{
1007 return move_points_text_full(mp, reduce, NULL, NULL, FALSE);
1008}
#define action_by_result_iterate(_paction_, _result_)
Definition actions.h:490
#define action_by_result_iterate_end
Definition actions.h:494
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
#define BV_ISSET(bv, bit)
Definition bitvector.h:78
#define BV_ISSET_ANY(vec)
Definition bitvector.h:109
#define city_tile(_pcity_)
Definition city.h:544
#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
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:1005
const char * move_points_text_full(int mp, bool reduce, const char *prefix, const char *none, bool align)
Definition movement.c:938
bool can_exist_at_tile(const struct civ_map *nmap, const struct unit_type *utype, const struct tile *ptile)
Definition movement.c:264
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:627
bool can_unit_exist_at_tile(const struct civ_map *nmap, const struct unit *punit, const struct tile *ptile)
Definition movement.c:336
bool is_native_tile(const struct unit_type *punittype, const struct tile *ptile)
Definition movement.c:348
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:559
bool could_exist_in_city(const struct civ_map *nmap, const struct player *pov_player, const struct unit_type *utype, const struct city *pcity)
Definition movement.c:295
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:873
bool can_unit_transport(const struct unit *transporter, const struct unit *transported)
Definition movement.c:845
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:901
static int move_points_denomlen
Definition movement.c:912
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:764
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:390
bool may_be_city_channel_tile(const struct civ_map *nmap, const struct unit_class *punitclass, const struct tile *ptile, const struct player *pov_player)
Definition movement.c:245
bool is_native_to_class(const struct unit_class *punitclass, const struct terrain *pterrain, const bv_extras *extras)
Definition movement.c:359
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:508
bool is_native_near_tile(const struct civ_map *nmap, const struct unit_class *uclass, const struct tile *ptile)
Definition movement.c:482
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:589
bool can_unit_type_transport(const struct unit_type *transporter, const struct unit_class *transported)
Definition movement.c:858
void init_move_fragments(void)
Definition movement.c:917
bool can_attack_non_native(const struct unit_type *utype)
Definition movement.c:202
#define MAP_TILE_CONN_TO_BY(_map_, _tile_, _piter_, _found_, _conn_)
Definition movement.h:154
#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:84
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
bool tile_is_seen(const struct tile *target_tile, const struct player *pow_player)
Definition tile.c:401
struct city * tile_city(const struct tile *ptile)
Definition tile.c:83
#define tile_terrain(_tile)
Definition tile.h:113
static const bv_extras * tile_extras(const struct tile *ptile)
Definition tile.h:123
#define tile_has_extra(ptile, pextra)
Definition tile.h:150
bool unit_type_really_ignores_zoc(const struct unit_type *punittype)
Definition unit.c:1518
bool is_losing_hp(const struct unit *punit)
Definition unit.c:2220
struct unit * unit_transport_get(const struct unit *pcargo)
Definition unit.c:2433
bool could_unit_load(const struct unit *pcargo, const struct unit *ptrans)
Definition unit.c:727
bool unit_transported(const struct unit *pcargo)
Definition unit.c:2417
bool can_unit_unload(const struct unit *pcargo, const struct unit *ptrans)
Definition unit.c:779
bool can_unit_alight_or_be_unloaded(const struct civ_map *nmap, const struct unit *pcargo, const struct unit *ptrans)
Definition unit.c:804
#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