Freeciv-3.1
Loading...
Searching...
No Matches
unittools.c
Go to the documentation of this file.
1/***********************************************************************
2 Freeciv - Copyright (C) 1996 - A Kjeldberg, L Gregersen, P Unold
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#include <stdio.h>
19#include <stdlib.h>
20#include <string.h>
21
22/* utility */
23#include "bitvector.h"
24#include "fcintl.h"
25#include "log.h"
26#include "mem.h"
27#include "rand.h"
28#include "shared.h"
29#include "support.h"
30
31/* common */
32#include "base.h"
33#include "city.h"
34#include "combat.h"
35#include "events.h"
36#include "game.h"
37#include "government.h"
38#include "idex.h"
39#include "map.h"
40#include "movement.h"
41#include "packets.h"
42#include "player.h"
43#include "research.h"
44#include "terrain.h"
45#include "unit.h"
46#include "unitlist.h"
47#include "unittype.h"
48
49/* common/scriptcore */
50#include "luascript_signal.h"
51#include "luascript_types.h"
52
53/* aicore */
54#include "path_finding.h"
55#include "pf_tools.h"
56
57/* server/scripting */
58#include "script_server.h"
59
60/* server */
61#include "actiontools.h"
62#include "aiiface.h"
63#include "barbarian.h"
64#include "citytools.h"
65#include "cityturn.h"
66#include "diplhand.h"
67#include "gamehand.h"
68#include "maphand.h"
69#include "notify.h"
70#include "plrhand.h"
71#include "sanitycheck.h"
72#include "sernet.h"
73#include "srv_main.h"
74#include "techtools.h"
75#include "unithand.h"
76
77/* server/advisors */
78#include "advgoto.h"
79#include "autoexplorer.h"
80#include "autosettlers.h"
81
82/* ai */
83#include "handicaps.h"
84
85#include "unittools.h"
86
87
88/* Tools for controlling the client vision of every unit when a unit
89 * moves + script effects. See unit_move(). You can access this data with
90 * punit->server.moving; it may be NULL if the unit is not moving). */
93 struct unit *punit; /* NULL for invalidating. */
94 struct player *powner;
95 bv_player can_see_unit;
96 bv_player can_see_move;
98};
99
100#define SPECLIST_TAG unit_move_data
101#include "speclist.h"
102#define unit_move_data_list_iterate(_plist, _pdata) \
103 TYPED_LIST_ITERATE(struct unit_move_data, _plist, _pdata)
104#define unit_move_data_list_iterate_end LIST_ITERATE_END
105#define unit_move_data_list_iterate_rev(_plist, _pdata) \
106 TYPED_LIST_ITERATE_REV(struct unit_move_data, _plist, _pdata)
107#define unit_move_data_list_iterate_rev_end LIST_ITERATE_REV_END
108
109/* This data structure lets the auto attack code cache each potential
110 * attacker unit's probability of success against the target unit during
111 * the checks if the unit can do autoattack. It is then reused when the
112 * list of potential attackers is sorted by probability of success. */
116};
117
118#define SPECLIST_TAG autoattack_prob
119#define SPECLIST_TYPE struct autoattack_prob
120#include "speclist.h"
121
122#define autoattack_prob_list_iterate_safe(autoattack_prob_list, _aap_, \
123 _unit_) \
124 TYPED_LIST_ITERATE(struct autoattack_prob, autoattack_prob_list, _aap_) \
125 struct unit *_unit_ = game_unit_by_number(_aap_->unit_id); \
126 \
127 if (_unit_ == NULL) { \
128 continue; \
129 }
130
131#define autoattack_prob_list_iterate_safe_end LIST_ITERATE_END
132
133static void unit_restore_hitpoints(struct unit *punit);
134static void unit_restore_movepoints(struct player *pplayer, struct unit *punit);
135static void update_unit_activity(struct unit *punit);
136static bool try_to_save_unit(struct unit *punit, const struct unit_type *pttype,
137 bool helpless, bool teleporting,
138 const struct city *pexclcity);
139static void wakeup_neighbor_sentries(struct unit *punit);
140static void do_upgrade_effects(struct player *pplayer);
141
142static bool maybe_cancel_patrol_due_to_enemy(struct unit *punit);
143
144static bool maybe_become_veteran_real(struct unit *punit, int base_chance,
145 bool settler);
146
147static void unit_transport_load_tp_status(struct unit *punit,
148 struct unit *ptrans,
149 bool force);
150
151static void wipe_unit_full(struct unit *punit, bool transported,
152 enum unit_loss_reason reason,
153 struct player *killer);
154
155static int get_unit_vision_base(struct unit *punit, enum vision_layer vlayer,
156 const int base);
157static int unit_vision_range_modifiers(struct unit *punit,
158 const struct tile *ptile);
159
160/**********************************************************************/
174struct unit_type *find_a_unit_type(enum unit_role_id role,
175 enum unit_role_id role_tech)
176{
177 struct unit_type *which[U_LAST];
178 int i, num = 0;
179
180 if (role_tech != -1) {
181 for (i = 0; i < num_role_units(role_tech); i++) {
182 struct unit_type *iunit = get_role_unit(role_tech, i);
183 const int minplayers = 2;
184 int players = 0;
185
186 /* Note, if there's only one player in the game this check will always
187 * fail. */
188 players_iterate(pplayer) {
189 if (!is_barbarian(pplayer)
190 && can_player_build_unit_direct(pplayer, iunit)) {
191 players++;
192 }
194 if (players > minplayers) {
195 which[num++] = iunit;
196 }
197 }
198 }
199 if (num == 0) {
200 for (i = 0; i < num_role_units(role); i++) {
201 which[num++] = get_role_unit(role, i);
202 }
203 }
204
205 /* Ruleset code should ensure there is at least one unit for each
206 * possibly-required role, or check before calling this function. */
207 fc_assert_exit_msg(0 < num, "No unit types in find_a_unit_type(%d, %d)!",
208 role, role_tech);
209
210 return which[fc_rand(num)];
211}
212
213/**********************************************************************/
217bool maybe_make_veteran(struct unit *punit, int base_chance)
218{
219 return maybe_become_veteran_real(punit, base_chance, FALSE);
220}
221
222/**********************************************************************/
235static bool maybe_become_veteran_real(struct unit *punit, int base_chance,
236 bool settler)
237{
238 const struct veteran_system *vsystem;
239 const struct veteran_level *vlevel;
240 int chance;
241
242 fc_assert_ret_val(punit != NULL, FALSE);
243
245 fc_assert_ret_val(vsystem != NULL, FALSE);
247
248 vlevel = vsystem_veteran_level(vsystem, punit->veteran);
249 fc_assert_ret_val(vlevel != NULL, FALSE);
250
251 if (punit->veteran + 1 >= vsystem->levels
252 || unit_has_type_flag(punit, UTYF_NO_VETERAN)) {
253 return FALSE;
254 } else if (!settler) {
255 int mod = base_chance + get_unit_bonus(punit, EFT_VETERAN_COMBAT);
256
257 /* The modification is tacked on as a multiplier to the base chance.
258 * For example with a base chance of 50% for green units and a modifier
259 * of +50% the end chance is 75%. */
260 chance = vlevel->base_raise_chance * mod / 100;
261 } else if (settler && unit_has_type_flag(punit, UTYF_SETTLERS)) {
262 chance = base_chance * vlevel->work_raise_chance / 100;
263 } else {
264 /* No battle and no work done. */
265 return FALSE;
266 }
267
268 if (fc_rand(100) < chance) {
269 punit->veteran++;
270 return TRUE;
271 }
272
273 return FALSE;
274}
275
276/**********************************************************************/
286bool unit_versus_unit(struct unit *attacker, struct unit *defender,
287 int *att_hp, int *def_hp, int *att_vet, int *def_vet)
288{
289 int attackpower = get_total_attack_power(attacker, defender);
290 int defensepower = get_total_defense_power(attacker, defender);
291 int attack_firepower, defense_firepower;
292 struct player *plr1 = unit_owner(attacker);
293 struct player *plr2 = unit_owner(defender);
294 struct civ_map *nmap = &(wld.map);
295 int max_rounds;
296 int rounds;
297 int att_strength;
298 int def_strength;
299
300 *att_hp = attacker->hp;
301 *def_hp = defender->hp;
302 get_modified_firepower(nmap, attacker, defender,
303 &attack_firepower, &defense_firepower);
304
305 log_verbose("attack:%d, defense:%d, attack firepower:%d, "
306 "defense firepower:%d", attackpower, defensepower,
307 attack_firepower, defense_firepower);
308
311
312 att_strength = attackpower * attacker->hp * attack_firepower;
313 def_strength = defensepower * defender->hp * defense_firepower;
314
315 /* In a combat between equal strength units the values are 50% / 50%.
316 * -> scaling that to 100% by doubling, to match scale of chances
317 * in existing rulesets, and in !combat_odds_scaled_veterancy case. */
318 *att_vet = 100 * def_strength * 2 / (att_strength + def_strength);
319 *def_vet = 100 * att_strength * 2 / (att_strength + def_strength);
320
321 if (attackpower == 0) {
322 *att_hp = 0;
323 } else if (defensepower == 0) {
324 *def_hp = 0;
325 }
326 max_rounds = get_unit_bonus(attacker, EFT_COMBAT_ROUNDS);
327 for (rounds = 0;
328 *att_hp > 0 && *def_hp > 0
329 && (max_rounds <= 0 || max_rounds > rounds);
330 rounds++) {
331 if (fc_rand(attackpower + defensepower) >= defensepower) {
332 *def_hp -= attack_firepower;
333 } else {
334 *att_hp -= defense_firepower;
335 }
336 }
337 if (*att_hp < 0) {
338 *att_hp = 0;
339 }
340 if (*def_hp < 0) {
341 *def_hp = 0;
342 }
343
344 return attackpower <= 0 || defensepower <= 0;
345}
346
347/**********************************************************************/
352void unit_bombs_unit(struct unit *attacker, struct unit *defender,
353 int *att_hp, int *def_hp)
354{
355 int i;
356 int rate = unit_bombard_rate(attacker);
357 int attackpower = get_total_attack_power(attacker, defender);
358 int defensepower = get_total_defense_power(attacker, defender);
359 int attack_firepower, defense_firepower;
360 struct player *plr1 = unit_owner(attacker);
361 struct player *plr2 = unit_owner(defender);
362 struct civ_map *nmap = &(wld.map);
363
364 *att_hp = attacker->hp;
365 *def_hp = defender->hp;
366 get_modified_firepower(nmap, attacker, defender,
367 &attack_firepower, &defense_firepower);
368
369 log_verbose("attack:%d, defense:%d, attack firepower:%d, "
370 "defense firepower:%d", attackpower, defensepower,
371 attack_firepower, defense_firepower);
372
375
376 for (i = 0; i < rate; i++) {
377 if (fc_rand(attackpower + defensepower) >= defensepower) {
378 *def_hp -= attack_firepower;
379 }
380 }
381
382 /* Don't kill the target. */
383 if (*def_hp <= 0) {
384 *def_hp = 1;
385 }
386}
387
388/**********************************************************************/
392void combat_veterans(struct unit *attacker, struct unit *defender,
393 bool powerless, int att_vet, int def_vet)
394{
395 if (!powerless || !game.info.only_real_fight_makes_veteran) {
396 if (attacker->hp <= 0 || defender->hp <= 0
399 att_vet = 100;
400 def_vet = 100;
401 }
402 if (attacker->hp > 0) {
403 maybe_make_veteran(attacker, att_vet);
404 }
405 if (defender->hp > 0) {
406 maybe_make_veteran(defender, def_vet);
407 }
408 }
409 }
410}
411
412/**********************************************************************/
416static void do_upgrade_effects(struct player *pplayer)
417{
418 int upgrades = get_player_bonus(pplayer, EFT_UPGRADE_UNIT);
419 struct unit_list *candidates;
420
421 if (upgrades <= 0) {
422 return;
423 }
424 candidates = unit_list_new();
425
426 unit_list_iterate(pplayer->units, punit) {
427 /* We have to be careful not to strand units at sea, for example by
428 * upgrading a frigate to an ironclad while it was carrying a unit. */
429 if (UU_OK == unit_upgrade_test(&(wld.map), punit, TRUE)) {
430 unit_list_prepend(candidates, punit); /* Potential candidate :) */
431 }
433
434 while (upgrades > 0 && unit_list_size(candidates) > 0) {
435 /* Upgrade one unit. The unit is chosen at random from the list of
436 * available candidates. */
437 int candidate_to_upgrade = fc_rand(unit_list_size(candidates));
438 struct unit *punit = unit_list_get(candidates, candidate_to_upgrade);
439 const struct unit_type *type_from = unit_type_get(punit);
440 const struct unit_type *type_to = can_upgrade_unittype(pplayer, type_from);
441
443 notify_player(pplayer, unit_tile(punit), E_UNIT_UPGRADED, ftc_server,
444 _("%s was upgraded for free to %s."),
445 utype_name_translation(type_from),
447 unit_list_remove(candidates, punit);
448 upgrades--;
449 }
450
451 unit_list_destroy(candidates);
452}
453
454/**********************************************************************/
469void player_restore_units(struct player *pplayer)
470{
471 const struct civ_map *nmap = &(wld.map);
472
473 /* 1) get Leonardo out of the way first: */
474 do_upgrade_effects(pplayer);
475
477
478 /* 2) Modify unit hitpoints. Helicopters can even lose them. */
480
481 /* 3) Check that unit has hitpoints */
482 if (punit->hp <= 0) {
483 /* This should usually only happen for heli units, but if any other
484 * units get 0 hp somehow, catch them too. --dwp */
485 /* if 'game.server.killunhomed' is activated unhomed units are slowly
486 * killed; notify player here */
487 if (!punit->homecity && 0 < game.server.killunhomed) {
488 notify_player(pplayer, unit_tile(punit), E_UNIT_LOST_MISC,
489 ftc_server, _("Your %s has run out of hit points "
490 "because it was not supported by a city."),
492 } else {
493 notify_player(pplayer, unit_tile(punit), E_UNIT_LOST_MISC, ftc_server,
494 _("Your %s has run out of hit points."),
496 }
497
498 wipe_unit(punit, ULR_HP_LOSS, NULL);
499 continue; /* Continue iterating... */
500 }
501
502 /* 4) Rescue planes if needed */
504 /* Shall we emergency return home on the last vapors? */
505
506 /* I think this is strongly against the spirit of client goto.
507 * The problem is (again) that here we know too much. -- Zamar */
508
509 if (punit->fuel <= 1
511 struct unit *carrier;
512
513 carrier = transporter_for_unit(punit);
514 if (carrier) {
516 } else {
517 struct pf_map *pfm;
518 struct pf_parameter parameter;
519 bool alive = TRUE;
520
521 pft_fill_unit_parameter(&parameter, nmap, punit);
522 parameter.omniscience = !has_handicap(pplayer, H_MAP);
523 pfm = pf_map_new(&parameter);
524
525 pf_map_move_costs_iterate(pfm, ptile, move_cost, TRUE) {
526 if (move_cost > punit->moves_left) {
527 /* Too far */
528 break;
529 }
530
531 if (is_refuel_point(ptile, pplayer, punit)) {
532 struct pf_path *path;
533 int id = punit->id;
534
535 /* Client orders may be running for this unit - if so
536 * we free them before engaging goto. */
538
539 path = pf_map_path(pfm, ptile);
540
541 alive = adv_follow_path(punit, path, ptile);
542
543 if (!alive) {
544 log_error("rescue plane: unit %d died enroute!", id);
545 } else if (!same_pos(unit_tile(punit), ptile)) {
546 /* Enemy units probably blocked our route
547 * FIXME: We should try find alternative route around
548 * the enemy unit instead of just giving up and crashing. */
549 log_debug("rescue plane: unit %d could not move to "
550 "refuel point!", punit->id);
551 }
552
553 if (alive) {
554 /* Clear activity. Unit info will be sent in the end of
555 * the function. */
556 unit_activity_handling(punit, ACTIVITY_IDLE);
558 punit->goto_tile = NULL;
559
561 carrier = transporter_for_unit(punit);
562 if (carrier) {
564 }
565 }
566
567 notify_player(pplayer, unit_tile(punit),
568 E_UNIT_ORDERS, ftc_server,
569 _("Your %s has returned to refuel."),
571 }
572 pf_path_destroy(path);
573 break;
574 }
576 pf_map_destroy(pfm);
577
578 if (!alive) {
579 /* Unit died trying to move to refuel point. */
580 return;
581 }
582 }
583 }
584
585 /* 5) Update fuel */
586 punit->fuel--;
587
588 /* 6) Automatically refuel air units in cities, airbases, and
589 * transporters (carriers). */
592 }
593 }
595
596 /* 7) Check if there are air units without fuel */
598 const struct unit_type *utype = unit_type_get(punit);
599
600 if (punit->fuel <= 0 && utype_fuel(utype)) {
601 /* Notifications sent from the lua script when unit wiped. */
602 wipe_unit(punit, ULR_FUEL, NULL);
603 }
605
606 /* Send all updates. */
607 unit_list_iterate(pplayer->units, punit) {
608 send_unit_info(NULL, punit);
610}
611
612/**********************************************************************/
623{
624 bool was_lower;
625 const struct unit_type *utype = unit_type_get(punit);
626
627 was_lower = (punit->hp < utype->hp);
628
630
631 fc_assert(punit->hp >= 0);
632 fc_assert(punit->hp <= utype->hp);
633
634 if (punit->hp == utype->hp) {
635 if (was_lower && punit->activity == ACTIVITY_SENTRY) {
636 set_unit_activity(punit, ACTIVITY_IDLE);
637 }
638 }
639
640 punit->moved = FALSE;
642}
643
644/**********************************************************************/
649static void unit_restore_movepoints(struct player *pplayer, struct unit *punit)
650{
653}
654
655/**********************************************************************/
664
665/**********************************************************************/
668void execute_unit_orders(struct player *pplayer)
669{
671 if (unit_has_orders(punit)) {
673 }
675}
676
677/**********************************************************************/
680void unit_tc_effect_refresh(struct player *pplayer)
681{
682 unit_list_iterate(pplayer->units, punit) {
685}
686
687/**********************************************************************/
691{
692 /* Remember activities only after all knock-on effects of unit activities
693 * on other units have been resolved */
694 unit_list_iterate(pplayer->units, punit) {
698 send_unit_info(NULL, punit);
700}
701
702/**********************************************************************/
706static int total_activity(struct tile *ptile, enum unit_activity act,
707 struct extra_type *tgt)
708{
709 int total = 0;
710 bool tgt_matters = activity_requires_target(act);
711
712 unit_list_iterate(ptile->units, punit) {
713 if (punit->activity == act
714 && (!tgt_matters || punit->activity_target == tgt)) {
715 total += punit->activity_count;
716 }
718
719 return total;
720}
721
722/**********************************************************************/
726static bool total_activity_done(struct tile *ptile, enum unit_activity act,
727 struct extra_type *tgt)
728{
729 return total_activity(ptile, act, tgt) >= tile_activity_time(act, ptile, tgt);
730}
731
732/**********************************************************************/
736{
737 const struct veteran_level *vlevel;
738 const struct veteran_system *vsystem;
739
740 if (!punit) {
741 return;
742 }
743
745 fc_assert_ret(vsystem != NULL);
746 fc_assert_ret(vsystem->levels > punit->veteran);
747
748 vlevel = vsystem_veteran_level(vsystem, punit->veteran);
749 fc_assert_ret(vlevel != NULL);
750
752 E_UNIT_BECAME_VET, ftc_server,
753 /* TRANS: Your <unit> became ... rank of <veteran level>. */
754 _("Your %s became more experienced and achieved the rank "
755 "of %s."),
757}
758
759/**********************************************************************/
762static void unit_convert(struct unit *punit)
763{
764 const struct unit_type *to_type;
765 const struct unit_type *from_type;
766
767 from_type = unit_type_get(punit);
768 to_type = from_type->converted_to;
769
770 if (unit_can_convert(&(wld.map), punit)) {
771 transform_unit(punit, to_type, 0);
773 E_UNIT_UPGRADED, ftc_server,
774 _("%s converted to %s."),
775 utype_name_translation(from_type),
776 utype_name_translation(to_type));
777 } else {
779 E_UNIT_UPGRADED, ftc_server,
780 _("%s cannot be converted."),
781 utype_name_translation(from_type));
782 }
783}
784
785/**********************************************************************/
789{
790 if (unit_has_orders(punit)) {
792 E_UNIT_ORDERS, ftc_server,
793 _("Orders for %s aborted because activity "
794 "is no longer available."),
797 }
798
799 set_unit_activity(punit, ACTIVITY_IDLE);
800 send_unit_info(NULL, punit);
801}
802
803/**********************************************************************/
814
815/**********************************************************************/
826
827/**********************************************************************/
841
842/**********************************************************************/
848static void update_unit_activity(struct unit *punit)
849{
850 struct player *pplayer = unit_owner(punit);
851 bool unit_activity_done = FALSE;
852 enum unit_activity activity = punit->activity;
853 struct tile *ptile = unit_tile(punit);
854 const struct unit_type *act_utype = unit_type_get(punit);
855
856 switch (activity) {
857 case ACTIVITY_IDLE:
858 case ACTIVITY_EXPLORE:
859 case ACTIVITY_FORTIFIED:
860 case ACTIVITY_SENTRY:
861 case ACTIVITY_GOTO:
862 case ACTIVITY_PATROL_UNUSED:
863 case ACTIVITY_UNKNOWN:
864 case ACTIVITY_LAST:
865 /* We don't need the activity_count for the above */
866 break;
867
868 case ACTIVITY_FORTIFYING:
869 case ACTIVITY_CONVERT:
871 break;
872
873 case ACTIVITY_POLLUTION:
874 case ACTIVITY_MINE:
875 case ACTIVITY_IRRIGATE:
876 case ACTIVITY_PILLAGE:
877 case ACTIVITY_CULTIVATE:
878 case ACTIVITY_PLANT:
879 case ACTIVITY_TRANSFORM:
880 case ACTIVITY_FALLOUT:
881 case ACTIVITY_BASE:
882 case ACTIVITY_GEN_ROAD:
884
885 /* settler may become veteran when doing something useful */
888 }
889 break;
890 case ACTIVITY_OLD_ROAD:
891 case ACTIVITY_OLD_RAILROAD:
892 case ACTIVITY_FORTRESS:
893 case ACTIVITY_AIRBASE:
895 break;
896 };
897
899
900 switch (activity) {
901 case ACTIVITY_IDLE:
902 case ACTIVITY_FORTIFIED:
903 case ACTIVITY_SENTRY:
904 case ACTIVITY_GOTO:
905 case ACTIVITY_UNKNOWN:
906 case ACTIVITY_FORTIFYING:
907 case ACTIVITY_CONVERT:
908 case ACTIVITY_PATROL_UNUSED:
909 case ACTIVITY_LAST:
910 /* no default, ensure all handled */
911 break;
912
913 case ACTIVITY_EXPLORE:
915 return;
916
917 case ACTIVITY_PILLAGE:
918 if (total_activity_done(ptile, ACTIVITY_PILLAGE,
921 unit_activity_done = TRUE;
922
924
925 /* Change vision if effects have changed. */
927 }
928 break;
929
930 case ACTIVITY_POLLUTION:
931 /* TODO: Remove this fallback target setting when target always correctly
932 * set */
933 if (punit->activity_target == NULL) {
934 punit->activity_target = prev_extra_in_tile(ptile, ERM_CLEANPOLLUTION,
935 NULL, punit);
936 }
937 if (total_activity_done(ptile, ACTIVITY_POLLUTION, punit->activity_target)) {
939 unit_activity_done = TRUE;
940 }
941 break;
942
943 case ACTIVITY_FALLOUT:
944 /* TODO: Remove this fallback target setting when target always correctly
945 * set */
946 if (punit->activity_target == NULL) {
947 punit->activity_target = prev_extra_in_tile(ptile, ERM_CLEANFALLOUT,
948 NULL, punit);
949 }
950 if (total_activity_done(ptile, ACTIVITY_FALLOUT, punit->activity_target)) {
952 unit_activity_done = TRUE;
953 }
954 break;
955
956 case ACTIVITY_BASE:
957 {
958 if (total_activity(ptile, ACTIVITY_BASE, punit->activity_target)
959 >= tile_activity_time(ACTIVITY_BASE, ptile, punit->activity_target)) {
961 unit_activity_done = TRUE;
962 }
963 }
964 break;
965
966 case ACTIVITY_GEN_ROAD:
967 {
968 if (total_activity(ptile, ACTIVITY_GEN_ROAD, punit->activity_target)
969 >= tile_activity_time(ACTIVITY_GEN_ROAD, ptile, punit->activity_target)) {
971 unit_activity_done = TRUE;
972 }
973 }
974 break;
975
976 case ACTIVITY_IRRIGATE:
977 case ACTIVITY_MINE:
978 case ACTIVITY_CULTIVATE:
979 case ACTIVITY_PLANT:
980 case ACTIVITY_TRANSFORM:
981 if (total_activity_done(ptile, activity, punit->activity_target)) {
982 struct terrain *old = tile_terrain(ptile);
983
984 /* The function below could change the terrain. Therefore, we have to
985 * check the terrain (which will also do a sanity check for the tile). */
986 tile_apply_activity(ptile, activity, punit->activity_target);
987 check_terrain_change(ptile, old);
988 unit_activity_done = TRUE;
989 }
990 break;
991
992 case ACTIVITY_OLD_ROAD:
993 case ACTIVITY_OLD_RAILROAD:
994 case ACTIVITY_FORTRESS:
995 case ACTIVITY_AIRBASE:
997 break;
998 }
999
1000 if (unit_activity_done) {
1001 update_tile_knowledge(ptile);
1002 if (ACTIVITY_CULTIVATE == activity
1003 || ACTIVITY_PLANT == activity
1004 || ACTIVITY_TRANSFORM == activity) {
1005 unit_list_iterate(ptile->units, punit2) {
1006 if (punit2->activity == activity) {
1008
1009 set_unit_activity(punit2, ACTIVITY_IDLE);
1010 }
1012 } else {
1013 struct extra_type *act_tgt = punit->activity_target;
1014
1015 unit_list_iterate(ptile->units, punit2) {
1016 if (punit2->activity == activity
1017 && punit2->activity_target == act_tgt) {
1018 /* This unit was helping with the work just finished.
1019 * Mark it idle (already finished) so its "current"
1020 * activity is not considered illegal
1021 * in tile_change_side_effects() . */
1022 set_unit_activity(punit2, ACTIVITY_IDLE);
1023 }
1025 }
1026
1028 }
1029
1030 if (activity == ACTIVITY_FORTIFYING) {
1032 >= action_id_get_act_time(ACTION_FORTIFY,
1033 punit, ptile, punit->activity_target)) {
1034 set_unit_activity(punit, ACTIVITY_FORTIFIED);
1035 unit_activity_done = TRUE;
1036 }
1037 }
1038
1039 if (activity == ACTIVITY_CONVERT) {
1041 >= action_id_get_act_time(ACTION_CONVERT,
1042 punit, ptile, punit->activity_target)) {
1044 set_unit_activity(punit, ACTIVITY_IDLE);
1045 unit_activity_done = TRUE;
1046 }
1047 }
1048
1049 if (unit_activity_done) {
1050 if (activity == ACTIVITY_PILLAGE) {
1051 /* Casus Belli for when the action is completed. */
1052 /* TODO: is it more logical to put Casus_Belli_Success here, change
1053 * Casus_Belli_Complete to Casus_Belli_Successful_Beginning and
1054 * trigger it when an activity successfully has began? */
1057 act_utype,
1061 }
1062 }
1063}
1064
1065/**********************************************************************/
1070{
1071 punit->changed_from = ACTIVITY_IDLE;
1072}
1073
1074/**********************************************************************/
1078bool unit_activity_needs_target_from_client(enum unit_activity activity)
1079{
1080 switch (activity) {
1081 case ACTIVITY_PILLAGE:
1082 /* Can be set server side. */
1083 return FALSE;
1084 default:
1085 return activity_requires_target(activity);
1086 }
1087}
1088
1089/**********************************************************************/
1099 enum unit_activity *activity,
1100 struct extra_type **target)
1101{
1102 const struct civ_map *nmap = &(wld.map);
1103
1104 if (*activity == ACTIVITY_PILLAGE
1105 && *target == NULL) {
1106 struct tile *ptile = unit_tile(punit);
1107 struct extra_type *tgt;
1108 bv_extras extras = *tile_extras(ptile);
1109
1110 while ((tgt = get_preferred_pillage(extras))) {
1111
1112 BV_CLR(extras, extra_index(tgt));
1113
1114 if (can_unit_do_activity_targeted(nmap, punit, *activity, tgt)) {
1115 *target = tgt;
1116 return;
1117 }
1118 }
1119
1120 /* Nothing we can pillage here. */
1121 *activity = ACTIVITY_IDLE;
1122 }
1123}
1124
1125/**********************************************************************/
1129static bool find_a_good_partisan_spot(struct tile *pcenter,
1130 struct player *powner,
1131 struct unit_type *u_type,
1132 int sq_radius,
1133 struct tile **dst_tile)
1134{
1135 int bestvalue = 0;
1136 struct civ_map *nmap = &(wld.map);
1137
1138 /* coords of best tile in arg pointers */
1139 circle_iterate(nmap, pcenter, sq_radius, ptile) {
1140 int value;
1141
1142 if (!is_native_tile(u_type, ptile)) {
1143 continue;
1144 }
1145
1146 if (NULL != tile_city(ptile)) {
1147 continue;
1148 }
1149
1150 if (0 < unit_list_size(ptile->units)) {
1151 continue;
1152 }
1153
1154 /* City may not have changed hands yet; see place_partisans(). */
1155 value = get_virtual_defense_power(nmap, NULL, u_type, powner,
1156 ptile, FALSE, 0);
1157 value *= 10;
1158
1159 if (tile_continent(ptile) != tile_continent(pcenter)) {
1160 value /= 2;
1161 }
1162
1163 value -= fc_rand(value/3);
1164
1165 if (value > bestvalue) {
1166 *dst_tile = ptile;
1167 bestvalue = value;
1168 }
1170
1171 return bestvalue > 0;
1172}
1173
1174/**********************************************************************/
1177void place_partisans(struct tile *pcenter, struct player *powner,
1178 int count, int sq_radius)
1179{
1180 struct tile *ptile = NULL;
1181 struct unit_type *u_type = get_role_unit(L_PARTISAN, 0);
1182 const struct civ_map *nmap = &(wld.map);
1183
1184 while (count-- > 0
1185 && find_a_good_partisan_spot(pcenter, powner, u_type,
1186 sq_radius, &ptile)) {
1187 struct unit *punit;
1188
1189 punit = unit_virtual_prepare(powner, ptile, u_type, 0, 0, -1, -1);
1190 if (can_unit_do_activity(nmap, punit, ACTIVITY_FORTIFYING)) {
1191 punit->activity = ACTIVITY_FORTIFIED; /* Yes; directly fortified */
1192 }
1193
1194 (void) place_unit(punit, powner, NULL, NULL, FALSE);
1195 }
1196}
1197
1198/**********************************************************************/
1203bool teleport_unit_to_city(struct unit *punit, struct city *pcity,
1204 int move_cost, bool verbose)
1205{
1206 struct tile *src_tile = unit_tile(punit), *dst_tile = pcity->tile;
1207
1208 if (city_owner(pcity) == unit_owner(punit)) {
1209 log_verbose("Teleported %s %s from (%d,%d) to %s",
1211 unit_rule_name(punit), TILE_XY(src_tile), city_name_get(pcity));
1212 if (verbose) {
1214 E_UNIT_RELOCATED, ftc_server,
1215 _("Teleported your %s to %s."),
1217 city_link(pcity));
1218 }
1219
1220 /* Silently free orders since they won't be applicable anymore. */
1222
1223 if (move_cost == -1) {
1224 move_cost = punit->moves_left;
1225 }
1226 unit_move(punit, dst_tile, move_cost,
1227 NULL, FALSE, FALSE, FALSE, FALSE, FALSE);
1228
1229 return TRUE;
1230 }
1231 return FALSE;
1232}
1233
1234/**********************************************************************/
1241void bounce_unit(struct unit *punit, bool verbose)
1242{
1243 struct player *pplayer;
1244 struct tile *punit_tile;
1245 int count = 0;
1246
1247 /* I assume that there are no topologies that have more than
1248 * (2d + 1)^2 tiles in the "square" of "radius" d. */
1249 const int DIST = 2;
1250 struct tile *tiles[(2 * DIST + 1) * (2 * DIST + 1)];
1251
1252 if (!punit) {
1253 return;
1254 }
1255
1256 pplayer = unit_owner(punit);
1257 punit_tile = unit_tile(punit);
1258
1259 square_iterate(&(wld.map), punit_tile, DIST, ptile) {
1260 if (count >= ARRAY_SIZE(tiles)) {
1261 break;
1262 }
1263
1264 if (ptile == punit_tile) {
1265 continue;
1266 }
1267
1268 if (can_unit_survive_at_tile(&(wld.map), punit, ptile)
1269 && !is_non_allied_city_tile(ptile, pplayer)
1270 && !is_non_allied_unit_tile(ptile, pplayer)) {
1271 tiles[count++] = ptile;
1272 }
1274
1275 if (count > 0) {
1276 struct tile *ptile = tiles[fc_rand(count)];
1277
1278 if (verbose) {
1279 notify_player(pplayer, ptile, E_UNIT_RELOCATED, ftc_server,
1280 /* TRANS: A unit is moved to resolve stack conflicts. */
1281 _("Moved your %s."),
1282 unit_link(punit));
1283 }
1284
1285 /* TODO: should a unit be able to bounce to a transport like is done
1286 * below? What if the unit can't legally enter the transport, say
1287 * because the transport is Unreachable and the unit doesn't have it in
1288 * its embarks field or because "Transport Embark" isn't enabled? Kept
1289 * like it was to preserve the old rules for now. -- Sveinung */
1290 unit_move(punit, ptile, 0, NULL, TRUE, FALSE, FALSE, FALSE, FALSE);
1291 return;
1292 }
1293
1294 /* Didn't find a place to bounce the unit, going to disband it.
1295 * Try to bounce transported units. */
1297 struct unit_list *pcargo_units;
1298
1299 pcargo_units = unit_transport_cargo(punit);
1300 unit_list_iterate_safe(pcargo_units, pcargo) {
1301 bounce_unit(pcargo, verbose);
1303 }
1304
1305 if (verbose) {
1306 notify_player(pplayer, punit_tile, E_UNIT_LOST_MISC, ftc_server,
1307 /* TRANS: A unit is disbanded to resolve stack conflicts. */
1308 _("Disbanded your %s."),
1310 }
1311
1312 wipe_unit(punit, ULR_STACK_CONFLICT, NULL);
1313}
1314
1315/**********************************************************************/
1320static void throw_units_from_illegal_cities(struct player *pplayer,
1321 bool verbose)
1322{
1323 struct tile *ptile;
1324 struct city *pcity;
1325 struct unit *ptrans;
1326 struct unit_list *pcargo_units;
1327
1328 /* Unload undesired units from transports, if possible. */
1329 unit_list_iterate(pplayer->units, punit) {
1330 ptile = unit_tile(punit);
1331 pcity = tile_city(ptile);
1332 if (NULL != pcity
1333 && !pplayers_allied(city_owner(pcity), pplayer)
1335 pcargo_units = unit_transport_cargo(punit);
1336 unit_list_iterate(pcargo_units, pcargo) {
1337 if (!pplayers_allied(unit_owner(pcargo), pplayer)) {
1338 if (can_unit_exist_at_tile(&(wld.map), pcargo, ptile)) {
1340 }
1341 }
1343 }
1345
1346 /* Bounce units except transported ones which will be bounced with their
1347 * transport. */
1349 ptile = unit_tile(punit);
1350 pcity = tile_city(ptile);
1351 if (NULL != pcity
1352 && !pplayers_allied(city_owner(pcity), pplayer)) {
1353 ptrans = unit_transport_get(punit);
1354 if (NULL == ptrans || pplayer != unit_owner(ptrans)) {
1355 bounce_unit(punit, verbose);
1356 }
1357 }
1359
1360#ifdef FREECIV_DEBUG
1361 /* Sanity check. */
1362 unit_list_iterate(pplayer->units, punit) {
1363 ptile = unit_tile(punit);
1364 pcity = tile_city(ptile);
1365 fc_assert_msg(NULL == pcity
1366 || pplayers_allied(city_owner(pcity), pplayer),
1367 "Failed to throw %s %d from %s %d (%d, %d)",
1369 punit->id,
1370 city_name_get(pcity),
1371 pcity->id,
1372 TILE_XY(ptile));
1374#endif /* FREECIV_DEBUG */
1375}
1376
1377/**********************************************************************/
1385static void resolve_stack_conflicts(struct player *pplayer,
1386 struct player *aplayer, bool verbose)
1387{
1389 struct tile *ptile = unit_tile(punit);
1390
1391 if (is_non_allied_unit_tile(ptile, pplayer)) {
1392 unit_list_iterate_safe(ptile->units, aunit) {
1393 if (unit_owner(aunit) == pplayer
1394 || unit_owner(aunit) == aplayer
1395 || !can_unit_survive_at_tile(&(wld.map), aunit, ptile)) {
1396 bounce_unit(aunit, verbose);
1397 }
1399 }
1401}
1402
1403/**********************************************************************/
1414void resolve_unit_stacks(struct player *pplayer, struct player *aplayer,
1415 bool verbose)
1416{
1417 throw_units_from_illegal_cities(pplayer, verbose);
1418 throw_units_from_illegal_cities(aplayer, verbose);
1419
1420 resolve_stack_conflicts(pplayer, aplayer, verbose);
1421 resolve_stack_conflicts(aplayer, pplayer, verbose);
1422}
1423
1424/**********************************************************************/
1429struct unit_list *get_units_seen_via_ally(const struct player *pplayer,
1430 const struct player *aplayer)
1431{
1432 struct unit_list *seen_units = unit_list_new();
1433
1434 /* Anybody's units inside ally's cities */
1435 city_list_iterate(aplayer->cities, pcity) {
1436 unit_list_iterate(city_tile(pcity)->units, punit) {
1437 if (can_player_see_unit(pplayer, punit)) {
1438 unit_list_append(seen_units, punit);
1439 }
1442
1443 /* Ally's own units inside transports */
1444 unit_list_iterate(aplayer->units, punit) {
1445 if (unit_transported(punit) && can_player_see_unit(pplayer, punit)) {
1446 unit_list_append(seen_units, punit);
1447 }
1449
1450 /* Make sure the same unit is not added in multiple phases
1451 * (unit within transport in a city) */
1452 unit_list_unique(seen_units);
1453
1454 return seen_units;
1455}
1456
1457/**********************************************************************/
1464void remove_allied_visibility(struct player *pplayer, struct player *aplayer,
1465 const struct unit_list *seen_units)
1466{
1467 unit_list_iterate(seen_units, punit) {
1468 /* We need to hide units previously seen by the client. */
1469 if (!can_player_see_unit(pplayer, punit)) {
1470 unit_goes_out_of_sight(pplayer, punit);
1471 }
1473
1474 city_list_iterate(aplayer->cities, pcity) {
1475 /* The player used to know what units were in these cities. Now that
1476 * they don't, they need to get a new short city packet updating the
1477 * occupied status. */
1478 if (map_is_known_and_seen(pcity->tile, pplayer, V_MAIN)) {
1479 send_city_info(pplayer, pcity);
1480 }
1482}
1483
1484/**********************************************************************/
1488void give_allied_visibility(struct player *pplayer,
1489 struct player *aplayer)
1490{
1491 unit_list_iterate(aplayer->units, punit) {
1492 if (can_player_see_unit(pplayer, punit)) {
1493 send_unit_info(pplayer->connections, punit);
1494 }
1496}
1497
1498/**********************************************************************/
1501static bool is_refuel_tile(const struct tile *ptile,
1502 const struct player *pplayer,
1503 const struct unit *punit)
1504{
1505 const struct unit_type *utype;
1506 const struct unit_class *pclass;
1507
1508 if (is_allied_city_tile(ptile, pplayer)) {
1509 return TRUE;
1510 }
1511
1512 utype = unit_type_get(punit);
1513 if (utype_has_flag(utype, UTYF_COAST) && is_safe_ocean(&(wld.map), ptile)) {
1514 return TRUE;
1515 }
1516
1517 pclass = utype_class(utype);
1518 if (NULL != pclass->cache.refuel_extras) {
1519 const struct player_tile *plrtile = map_get_player_tile(ptile, pplayer);
1520
1522 if (BV_ISSET(plrtile->extras, extra_index(pextra))) {
1523 return TRUE;
1524 }
1526 }
1527
1528 return FALSE;
1529}
1530
1531/**********************************************************************/
1535{
1536 return unit_transported(punit) /* Carrier */
1538}
1539
1540/**********************************************************************/
1543bool is_refuel_point(const struct tile *ptile,
1544 const struct player *pplayer,
1545 const struct unit *punit)
1546{
1547 if (is_non_allied_unit_tile(ptile, pplayer)) {
1548 return FALSE;
1549 }
1550
1551 return is_refuel_tile(ptile, pplayer, punit) || unit_could_load_at(punit, ptile);
1552}
1553
1554/**********************************************************************/
1565void transform_unit(struct unit *punit, const struct unit_type *to_unit,
1566 int vet_loss)
1567{
1568 struct player *pplayer = unit_owner(punit);
1569 const struct unit_type *old_type = punit->utype;
1570 int old_mr = unit_move_rate(punit);
1571 int old_hp = unit_type_get(punit)->hp;
1572 int lvls;
1573
1574 punit->utype = to_unit;
1575
1576 /* New type may not have the same veteran system, and we may want to
1577 * knock some levels off. */
1578 lvls = utype_veteran_system(to_unit)->levels - 1;
1579 punit->veteran = MIN(punit->veteran, lvls);
1580 /* Keeping the old behaviour, so first clip top, then reduce */
1581 punit->veteran = MAX(punit->veteran - vet_loss, 0);
1582
1583 /* Scale HP and MP, rounding down. Be careful with integer arithmetic,
1584 * and don't kill the unit. unit_move_rate() is used to take into account
1585 * global effects like Magellan's Expedition. */
1586 punit->hp = MAX(punit->hp * unit_type_get(punit)->hp / old_hp, 1);
1587 if (old_mr == 0) {
1589 } else {
1591 }
1592
1596 }
1597
1598 /* update unit upkeep */
1600
1602
1604
1605 CALL_PLR_AI_FUNC(unit_transformed, pplayer, punit, old_type);
1607
1608 send_unit_info(NULL, punit);
1610}
1611
1612/**********************************************************************/
1615struct unit *create_unit(struct player *pplayer, struct tile *ptile,
1616 const struct unit_type *type, int veteran_level,
1617 int homecity_id, int moves_left)
1618{
1619 return create_unit_full(pplayer, ptile, type, veteran_level, homecity_id,
1620 moves_left, -1, NULL);
1621}
1622
1623/**********************************************************************/
1627{
1628 if (punit->homecity != 0) {
1629 struct city *home = game_city_by_number(punit->homecity);
1630
1631 if (home != NULL && game.info.goods_selection == GSM_LEAVING) {
1633 }
1634 }
1635}
1636
1637/**********************************************************************/
1642struct unit *create_unit_full(struct player *pplayer, struct tile *ptile,
1643 const struct unit_type *type, int veteran_level,
1644 int homecity_id, int moves_left, int hp_left,
1645 struct unit *ptrans)
1646{
1647 struct unit *punit
1648 = unit_virtual_prepare(pplayer, ptile, type, veteran_level,
1649 homecity_id, moves_left, hp_left);
1650 struct city *pcity = (!homecity_id || utype_has_flag(type, UTYF_NOHOME))
1651 ? NULL : game_city_by_number(homecity_id);
1652 bool could_place;
1653
1654 fc_assert_ret_val(punit, NULL);
1655 could_place = place_unit(punit, pplayer, pcity, ptrans, FALSE);
1656 fc_assert(could_place);
1657 if (!could_place) {
1659 punit = NULL;
1660 }
1661
1662 return punit;
1663}
1664
1665/**********************************************************************/
1675struct unit *unit_virtual_prepare(struct player *pplayer, struct tile *ptile,
1676 const struct unit_type *type,
1677 int veteran_level, int homecity_id,
1678 int moves_left, int hp_left)
1679{
1680 struct unit *punit;
1681
1682 fc_assert_ret_val(ptile != NULL, NULL);
1683 punit = unit_virtual_create(pplayer, NULL, type, veteran_level);
1684 unit_tile_set(punit, ptile);
1685
1686 if (utype_has_flag(type, UTYF_NOHOME)) {
1687 punit->homecity = 0; /* none */
1688 } else {
1689 punit->homecity = homecity_id;
1690 }
1691
1692 if (hp_left >= 0) {
1693 /* Override default full HP */
1694 punit->hp = hp_left;
1695 }
1696
1697 if (moves_left >= 0) {
1698 int mr = unit_move_rate(punit);
1699
1700 /* Override default full MP */
1701 /* FIXME: there are valid situations when a unit have mp
1702 * over its move rate. Here, keeping the old behavior. */
1704 /* Assume that if moves_left < 0 then the unit is "fresh",
1705 * and not moved; else the unit has had something happen
1706 * to it (eg, bribed) which we treat as equivalent to moved.
1707 * (Otherwise could pass moved arg too...) --dwp */
1708 punit->moved = TRUE;
1709 }
1710
1711 return punit;
1712}
1713
1714/**********************************************************************/
1723bool place_unit(struct unit *punit, struct player *pplayer,
1724 struct city *pcity, struct unit *ptrans, bool force)
1725{
1726 struct tile *ptile;
1727
1728 fc_assert_ret_val(pplayer, FALSE);
1730 ptile = punit->tile;
1731 fc_assert_ret_val(ptile, FALSE);
1732
1733 /* Register unit */
1736
1737 if (ptrans) {
1738 /* Set transporter for unit. */
1739 unit_transport_load_tp_status(punit, ptrans, force);
1740 }
1741
1743 || can_unit_exist_at_tile(&(wld.map), punit, ptile),
1744 FALSE);
1745
1746 unit_list_prepend(pplayer->units, punit);
1747 unit_list_prepend(ptile->units, punit);
1749 if (pcity && !unit_has_type_flag(punit, UTYF_NOHOME)) {
1750 fc_assert(punit->homecity == pcity->id);
1751 fc_assert(city_owner(pcity) == pplayer);
1752 unit_list_prepend(pcity->units_supported, punit);
1753 /* update unit upkeep */
1754 city_units_upkeep(pcity);
1755 /* Refresh the unit's homecity. */
1756 city_refresh(pcity);
1757 send_city_info(pplayer, pcity);
1758 }
1759
1760 punit->server.vision = vision_new(pplayer, ptile);
1762
1763 send_unit_info(NULL, punit);
1765
1766 /* The unit may have changed the available tiles in nearby cities. */
1768 sync_cities();
1769
1771
1772 CALL_FUNC_EACH_AI(unit_created, punit);
1773 CALL_PLR_AI_FUNC(unit_got, pplayer, punit);
1774
1775 return TRUE;
1776}
1777
1778/**********************************************************************/
1782 void (*callback)(struct unit *punit))
1783{
1784 /* Tried to overwrite another call back. If this assertion is triggered
1785 * in a case where two call back are needed it may be time to support
1786 * more than one unit removal call back at a time. */
1788
1790}
1791
1792/**********************************************************************/
1796{
1798}
1799
1800/**********************************************************************/
1804static void server_remove_unit_full(struct unit *punit, bool transported,
1805 enum unit_loss_reason reason)
1806{
1807 struct packet_unit_remove packet;
1808 struct tile *ptile = unit_tile(punit);
1809 struct city *pcity = tile_city(ptile);
1810 struct city *phomecity = game_city_by_number(punit->homecity);
1811 struct unit *ptrans;
1812 struct player *pplayer = unit_owner(punit);
1813
1814 /* The unit is doomed. */
1816
1817#if defined(FREECIV_DEBUG) && !defined(FREECIV_NDEBUG)
1818 unit_list_iterate(ptile->units, pcargo) {
1821#endif /* FREECIV_DEBUG */
1822
1823 CALL_PLR_AI_FUNC(unit_lost, pplayer, punit);
1824 CALL_FUNC_EACH_AI(unit_destroyed, punit);
1825
1826 /* Save transporter for updating below. */
1827 ptrans = unit_transport_get(punit);
1828 /* Unload unit. */
1830
1831 /* Since settlers plot in new cities in the minimap before they
1832 are built, so that no two settlers head towards the same city
1833 spot, we need to ensure this reservation is cleared should
1834 the settler disappear on the way. */
1836
1837 /* Clear the vision before sending unit remove. Else, we might duplicate
1838 * the PACKET_UNIT_REMOVE if we lose vision of the unit tile. */
1839 if (punit->server.vision != NULL) {
1842 punit->server.vision = NULL;
1843 }
1844
1845 packet.unit_id32 = punit->id;
1846 packet.unit_id16 = packet.unit_id32;
1847 /* Send to onlookers. */
1848 players_iterate(aplayer) {
1850 transported)) {
1851 lsend_packet_unit_remove(aplayer->connections, &packet);
1852 }
1854 /* Send to global observers. */
1856 if (conn_is_global_observer(pconn)) {
1857 send_packet_unit_remove(pconn, &packet);
1858 }
1860
1861 if (punit->server.moving != NULL) {
1862 /* Do not care of this unit for running moves. */
1863 punit->server.moving->punit = NULL;
1864 }
1865
1866 if (punit->server.removal_callback != NULL) {
1867 /* Run the unit removal call back. */
1869 }
1870
1871 /* check if this unit had UTYF_GAMELOSS flag */
1872 if (unit_has_type_flag(punit, UTYF_GAMELOSS) && unit_owner(punit)->is_alive
1873 && ULR_EDITOR != reason) {
1874 notify_conn(game.est_connections, ptile, E_UNIT_LOST_MISC, ftc_server,
1875 _("Unable to defend %s, %s has lost the game."),
1877 player_name(pplayer));
1878 notify_player(pplayer, ptile, E_GAME_END, ftc_server,
1879 _("Losing %s meant losing the game! "
1880 "Be more careful next time!"),
1881 unit_link(punit));
1882 player_status_add(unit_owner(punit), PSTATUS_DYING);
1883 }
1884
1885 /* Have to pass new ULR_UPKEEP as ULR_DISBAND for compatibility reasons.
1886 * Changes in freeciv-3.2 */
1888 unit_loss_reason_name((reason == ULR_UPKEEP)
1889 ? ULR_DISBANDED
1890 : reason));
1891
1894 punit = NULL;
1895
1896 if (NULL != ptrans) {
1897 /* Update the occupy info. */
1898 send_unit_info(NULL, ptrans);
1899 }
1900
1901 /* This unit may have blocked tiles of adjacent cities. Update them. */
1903 sync_cities();
1904
1905 if (phomecity) {
1906 city_refresh(phomecity);
1907 send_city_info(city_owner(phomecity), phomecity);
1908 }
1909
1910 if (pcity && pcity != phomecity) {
1911 city_refresh(pcity);
1912 send_city_info(city_owner(pcity), pcity);
1913 }
1914
1915 if (pcity && unit_list_size(ptile->units) == 0) {
1916 /* The last unit in the city was killed: update the occupied flag. */
1917 send_city_info(NULL, pcity);
1918 }
1919}
1920
1921/**********************************************************************/
1925static void server_remove_unit(struct unit *punit,
1926 enum unit_loss_reason reason)
1927{
1929}
1930
1931/**********************************************************************/
1934static void unit_lost_with_transport(const struct player *pplayer,
1935 struct unit *pcargo,
1936 const struct unit_type *ptransport,
1937 struct player *killer)
1938{
1939 notify_player(pplayer, unit_tile(pcargo), E_UNIT_LOST_MISC, ftc_server,
1940 _("%s lost when %s was lost."),
1941 unit_tile_link(pcargo),
1942 utype_name_translation(ptransport));
1943 /* Unit is not transported any more at this point, but it has jumped
1944 * off the transport and drowns outside. So it must be removed from
1945 * all clients.
1946 * However, we don't know if given client has received ANY updates
1947 * about the swimming unit, and we can't remove it if it's not there
1948 * in the first place -> we send it once here just to be sure it's
1949 * there. */
1950 send_unit_info(NULL, pcargo);
1951 wipe_unit_full(pcargo, FALSE, ULR_TRANSPORT_LOST, killer);
1952}
1953
1954/**********************************************************************/
1958static void wipe_unit_full(struct unit *punit, bool transported,
1959 enum unit_loss_reason reason,
1960 struct player *killer)
1961{
1962 struct tile *ptile = unit_tile(punit);
1963 struct player *pplayer = unit_owner(punit);
1964 const struct unit_type *putype_save = unit_type_get(punit); /* for notify messages */
1965 struct unit_list *helpless = unit_list_new();
1966 struct unit_list *imperiled = unit_list_new();
1967 struct unit_list *unsaved = unit_list_new();
1968 struct unit *ptrans = unit_transport_get(punit);
1969 struct city *pexclcity;
1970 struct civ_map *nmap = &(wld.map);
1971
1972 if (killer != NULL
1973 && (game.info.gameloss_style & GAMELOSS_STYLE_LOOT)
1974 && unit_has_type_flag(punit, UTYF_GAMELOSS)) {
1975 int ransom = fc_rand(1 + pplayer->economic.gold);
1976 int n;
1977
1978 /* Give map */
1979 if (give_distorted_map(pplayer, killer, 50, TRUE)) {
1980 notify_player(killer, NULL, E_HUT_MAP,
1981 ftc_server,
1982 _("You looted parts of %s map!"),
1984 }
1985
1986 log_debug("victim has money: %d", pplayer->economic.gold);
1987
1988 if (ransom > 0) {
1989 notify_player(killer, NULL, E_HUT_GOLD,
1990 ftc_server,
1991 PL_("You loot %d gold!", "You loot %d gold!", ransom),
1992 ransom);
1993 }
1994 killer->economic.gold += ransom;
1995 pplayer->economic.gold -= ransom;
1996
1997 n = 1 + fc_rand(3);
1998
1999 while (n > 0) {
2000 Tech_type_id ttid;
2001
2002 /* steal_a_tech() handles also notifying of the player */
2003 ttid = steal_a_tech(killer, pplayer, A_UNSET);
2004
2005 if (ttid == A_NONE) {
2006 log_debug("Worthless enemy doesn't have more techs to steal.");
2007 break;
2008 } else {
2009 log_debug("Pressed tech %s from captured enemy",
2011 if (!fc_rand(3)) {
2012 break; /* Out of luck */
2013 }
2014 n--;
2015 }
2016 }
2017
2018 {
2019 /* Try to submit some cities */
2020 int vcsize = city_list_size(pplayer->cities);
2021 int evcsize = vcsize;
2022 int conqsize;
2023
2024 if (evcsize < 3) {
2025 evcsize = 0;
2026 } else {
2027 evcsize -=3;
2028 }
2029
2030 /* About a quarter on average with high numbers less probable */
2031 conqsize = fc_rand(fc_rand(evcsize));
2032
2033 log_debug("conqsize=%d", conqsize);
2034
2035 if (conqsize > 0) {
2036 bool palace = game.server.savepalace;
2037 bool submit = FALSE;
2038
2039 game.server.savepalace = FALSE; /* Moving it around is dumb */
2040
2041 city_list_iterate_safe(pplayer->cities, pcity) {
2042 /* Kindly ask the citizens to submit */
2043 if (fc_rand(vcsize) < conqsize) {
2044 submit = TRUE;
2045 }
2046 vcsize--;
2047 if (submit) {
2048 conqsize--;
2049 /* Transfer city to the victorious player
2050 * kill all its units outside of a radius of 7,
2051 * give verbose messages of every unit transferred,
2052 * and raze buildings according to raze chance
2053 * (also removes palace) */
2054 notify_player(killer, city_tile(pcity), E_UNIT_WIN_ATT,
2055 ftc_server,
2056 /* TRANS: Getting a city as loot */
2057 _("You conquer %s as loot!"),
2058 city_link(pcity));
2059
2060 (void) transfer_city(killer, pcity, 7, TRUE, TRUE, TRUE,
2061 !is_barbarian(killer));
2062 submit = FALSE;
2063 }
2064 if (conqsize <= 0) {
2065 break;
2066 }
2068 game.server.savepalace = palace;
2069 }
2070 }
2071 }
2072
2073 /* The unit is doomed. */
2075
2076 /* If a unit is being lost due to loss of its city, ensure that we don't
2077 * try to teleport any of its cargo to that city (which may not yet
2078 * have changed hands or disappeared). (It is assumed that the unit's
2079 * home city is always the one that is being lost/transferred/etc.) */
2080 if (reason == ULR_CITY_LOST) {
2081 pexclcity = unit_home(punit);
2082 } else {
2083 pexclcity = NULL;
2084 }
2085
2086 /* Remove unit itself from its transport */
2087 if (ptrans != NULL) {
2089 send_unit_info(NULL, ptrans);
2090 }
2091
2092 /* First pull all units off of the transporter. */
2094 /* Use iterate_safe as unloaded units will be removed from the list
2095 * while iterating. */
2097 bool healthy = FALSE;
2098
2099 if (!can_unit_unload(pcargo, punit)) {
2100 unit_list_prepend(helpless, pcargo);
2101 } else {
2102 if (!can_unit_exist_at_tile(nmap, pcargo, ptile)) {
2103 unit_list_prepend(imperiled, pcargo);
2104 } else {
2105 /* These units do not need to be saved. */
2106 healthy = TRUE;
2107 }
2108 }
2109
2110 /* Could use unit_transport_unload_send() here, but that would
2111 * call send_unit_info() for the transporter unnecessarily.
2112 * Note that this means that unit might to get seen briefly
2113 * by clients other than owner's, for example as a result of
2114 * update of homecity common to this cargo and some other
2115 * destroyed unit. */
2116 unit_transport_unload(pcargo);
2117 if (pcargo->activity == ACTIVITY_SENTRY) {
2118 /* Activate sentried units - like planes on a disbanded carrier.
2119 * Note this will activate ground units even if they just change
2120 * transporter. */
2121 set_unit_activity(pcargo, ACTIVITY_IDLE);
2122 }
2123
2124 /* Unit info for unhealthy units will be sent when they are
2125 * assigned new transport or removed. */
2126 if (healthy) {
2127 send_unit_info(NULL, pcargo);
2128 }
2130 }
2131
2132 /* Now remove the unit. */
2133 server_remove_unit_full(punit, transported, reason);
2134
2135 switch (reason) {
2136 case ULR_KILLED:
2137 case ULR_EXECUTED:
2138 case ULR_SDI:
2139 case ULR_NUKE:
2140 case ULR_BRIBED:
2141 case ULR_CAPTURED:
2142 case ULR_CAUGHT:
2143 case ULR_ELIMINATED:
2144 case ULR_TRANSPORT_LOST:
2145 if (killer != NULL) {
2146 killer->score.units_killed++;
2147 }
2148 pplayer->score.units_lost++;
2149 break;
2150 case ULR_BARB_UNLEASH:
2151 case ULR_CITY_LOST:
2152 case ULR_STARVED:
2153 case ULR_UPKEEP:
2154 case ULR_NONNATIVE_TERR:
2155 case ULR_ARMISTICE:
2156 case ULR_HP_LOSS:
2157 case ULR_FUEL:
2158 case ULR_STACK_CONFLICT:
2159 case ULR_SOLD:
2160 pplayer->score.units_lost++;
2161 break;
2162 case ULR_RETIRED:
2163 case ULR_DISBANDED:
2164 case ULR_USED:
2165 case ULR_EDITOR:
2166 case ULR_PLAYER_DIED:
2167 case ULR_DETONATED:
2168 case ULR_MISSILE:
2169 break;
2170 }
2171
2172 /* First, sort out helpless cargo. */
2173 if (unit_list_size(helpless) > 0) {
2174 struct unit_list *remaining = unit_list_new();
2175
2176 /* Grant priority to gameloss units and units with the EvacuateFirst
2177 * unit type flag. */
2178 unit_list_iterate_safe(helpless, pcargo) {
2179 if (unit_has_type_flag(pcargo, UTYF_EVAC_FIRST)
2180 || unit_has_type_flag(pcargo, UTYF_GAMELOSS)) {
2181 if (!try_to_save_unit(pcargo, putype_save, TRUE,
2182 unit_has_type_flag(pcargo,
2183 UTYF_EVAC_FIRST),
2184 pexclcity)) {
2185 unit_list_prepend(unsaved, pcargo);
2186 }
2187 } else {
2188 unit_list_prepend(remaining, pcargo);
2189 }
2191
2192 /* Handle non-priority units. */
2193 unit_list_iterate_safe(remaining, pcargo) {
2194 if (!try_to_save_unit(pcargo, putype_save, TRUE, FALSE, pexclcity)) {
2195 unit_list_prepend(unsaved, pcargo);
2196 }
2198
2199 unit_list_destroy(remaining);
2200 }
2201 unit_list_destroy(helpless);
2202
2203 /* Then, save any imperiled cargo. */
2204 if (unit_list_size(imperiled) > 0) {
2205 struct unit_list *remaining = unit_list_new();
2206
2207 /* Grant priority to gameloss units and units with the EvacuateFirst
2208 * unit type flag. */
2209 unit_list_iterate_safe(imperiled, pcargo) {
2210 if (unit_has_type_flag(pcargo, UTYF_EVAC_FIRST)
2211 || unit_has_type_flag(pcargo, UTYF_GAMELOSS)) {
2212 if (!try_to_save_unit(pcargo, putype_save, FALSE,
2213 unit_has_type_flag(pcargo,
2214 UTYF_EVAC_FIRST),
2215 pexclcity)) {
2216 unit_list_prepend(unsaved, pcargo);
2217 }
2218 } else {
2219 unit_list_prepend(remaining, pcargo);
2220 }
2222
2223 /* Handle non-priority units. */
2224 unit_list_iterate_safe(remaining, pcargo) {
2225 if (!try_to_save_unit(pcargo, putype_save, FALSE, FALSE, pexclcity)) {
2226 unit_list_prepend(unsaved, pcargo);
2227 }
2229
2230 unit_list_destroy(remaining);
2231 }
2232 unit_list_destroy(imperiled);
2233
2234 /* Finally, kill off the unsaved units. */
2235 if (unit_list_size(unsaved) > 0) {
2236 unit_list_iterate_safe(unsaved, dying_unit) {
2237 unit_lost_with_transport(pplayer, dying_unit, putype_save, killer);
2239 }
2240 unit_list_destroy(unsaved);
2241}
2242
2243/**********************************************************************/
2247void wipe_unit(struct unit *punit, enum unit_loss_reason reason,
2248 struct player *killer)
2249{
2250 wipe_unit_full(punit, unit_transported(punit), reason, killer);
2251}
2252
2253/**********************************************************************/
2259static bool try_to_save_unit(struct unit *punit, const struct unit_type *pttype,
2260 bool helpless, bool teleporting,
2261 const struct city *pexclcity)
2262{
2263 struct tile *ptile = unit_tile(punit);
2264 struct player *pplayer = unit_owner(punit);
2265 struct unit *ptransport = transporter_for_unit(punit);
2266
2267 /* Helpless units cannot board a transport in their current state. */
2268 if (!helpless
2269 && ptransport != NULL) {
2271 send_unit_info(NULL, punit);
2272 return TRUE;
2273 } else {
2274 /* Only units that cannot find transport are considered for teleport. */
2275 if (teleporting) {
2276 struct city *pcity = find_closest_city(ptile, pexclcity,
2279 utype_class(pttype));
2280 if (pcity != NULL) {
2281 char tplink[MAX_LEN_LINK]; /* In case unit dies when teleported */
2282
2283 sz_strlcpy(tplink, unit_link(punit));
2284
2285 if (teleport_unit_to_city(punit, pcity, 0, FALSE)) {
2286 notify_player(pplayer, ptile, E_UNIT_RELOCATED, ftc_server,
2287 _("%s escaped the destruction of %s, and fled to %s."),
2288 tplink,
2289 utype_name_translation(pttype),
2290 city_link(pcity));
2291 return TRUE;
2292 }
2293 }
2294 }
2295 }
2296
2297 /* The unit could not use transport on the tile, and could not teleport. */
2298 return FALSE;
2299}
2300
2301/**********************************************************************/
2307struct unit *unit_change_owner(struct unit *punit, struct player *pplayer,
2308 int homecity, enum unit_loss_reason reason)
2309{
2310 struct unit *gained_unit;
2311 int id = 0;
2312
2313#ifndef FREECIV_NDEBUG
2314 bool placed;
2315#endif
2316
2319
2320 /* Convert the unit to your cause. It's supposed that the original unit
2321 * is on a valid tile and is not transported. */
2322 gained_unit = unit_virtual_prepare(pplayer, unit_tile(punit),
2325 fc_assert_action(gained_unit, goto uco_wipe); /* Tile must be valid */
2326
2327 /* Owner changes, nationality not. */
2328 gained_unit->nationality = punit->nationality;
2329
2330 /* Copy some more unit fields */
2331 gained_unit->fuel = punit->fuel;
2332 gained_unit->paradropped = punit->paradropped;
2333 gained_unit->server.birth_turn = punit->server.birth_turn;
2334
2335 /* Fog is lifted in the placing algorithm. */
2336#ifndef FREECIV_NDEBUG
2337 placed =
2338#endif
2339 place_unit(gained_unit, pplayer,
2341 NULL, FALSE);
2342
2343 fc_assert_action(placed, unit_virtual_destroy(gained_unit); goto uco_wipe);
2344
2345 id = gained_unit->id;
2346
2347 /* Update unit upkeep in the new homecity */
2348 if (homecity > 0) {
2350 }
2351
2352 /* Be sure to wipe the converted unit! */
2353 /* Old homecity upkeep is updated in process */
2354#ifndef FREECIV_NDEBUG
2355 uco_wipe:
2356#endif
2357
2358 wipe_unit(punit, reason, NULL);
2359
2360 if (!unit_is_alive(id)) {
2361 /* Destroyed by a script */
2362 return NULL;
2363 }
2364
2365 return gained_unit; /* Returns the replacement. */
2366}
2367
2368/**********************************************************************/
2373void kill_unit(struct unit *pkiller, struct unit *punit, bool vet)
2374{
2375 char pkiller_link[MAX_LEN_LINK], punit_link[MAX_LEN_LINK];
2376 struct player *pvictim = unit_owner(punit);
2377 struct player *pvictor = unit_owner(pkiller);
2378 struct tile *deftile = unit_tile(punit);
2379 int ransom, unitcount = 0;
2380 bool escaped;
2381 bool collect_ransom = FALSE;
2382 const struct civ_map *nmap = &(wld.map);
2383
2384 sz_strlcpy(pkiller_link, unit_link(pkiller));
2385 sz_strlcpy(punit_link, unit_tile_link(punit));
2386
2387 /* The unit is doomed. */
2389
2390 /* barbarian leader ransom hack */
2391 if (is_barbarian(pvictim)
2392 && uclass_has_flag(unit_class_get(pkiller), UCF_COLLECT_RANSOM)) {
2393 collect_ransom = TRUE;
2394
2395 unit_list_iterate(deftile->units, capture) {
2396 if (!unit_has_type_role(capture, L_BARBARIAN_LEADER)) {
2397 /* Cannot get ransom when there are other kind of units in the tile */
2398 collect_ransom = FALSE;
2399 break;
2400 }
2402
2403 if (collect_ransom) {
2404 unitcount = unit_list_size(deftile->units);
2405 ransom = unitcount * game.server.ransom_gold;
2406
2407 if (pvictim->economic.gold < ransom) {
2408 ransom = pvictim->economic.gold;
2409 }
2410
2411 notify_player(pvictor, unit_tile(pkiller), E_UNIT_WIN_ATT, ftc_server,
2412 PL_("%d Barbarian leader captured.",
2413 "%d Barbarian leaders captured.",
2414 unitcount),
2415 unitcount);
2416 notify_player(pvictor, unit_tile(pkiller), E_UNIT_WIN_ATT, ftc_server,
2417 PL_("%d gold ransom paid.",
2418 "%d gold ransom paid.",
2419 ransom),
2420 ransom);
2421 pvictor->economic.gold += ransom;
2422 pvictim->economic.gold -= ransom;
2423 send_player_info_c(pvictor, NULL); /* let me see my new gold :-) */
2424 }
2425 }
2426
2427 if (unitcount == 0) {
2428 unit_list_iterate(deftile->units, vunit) {
2429 if (pplayers_at_war(pvictor, unit_owner(vunit))
2430 && is_unit_reachable_at(vunit, pkiller, deftile)) {
2431 unitcount++;
2432 }
2434 }
2435
2436 if (!is_stack_vulnerable(deftile) || unitcount == 1) {
2437 if (vet) {
2438 notify_unit_experience(pkiller);
2439 }
2440 wipe_unit(punit, ULR_KILLED, pvictor);
2441 } else { /* unitcount > 1 */
2442 int i;
2443 int slots = player_slot_count();
2444 int num_killed[slots];
2445 int num_escaped[slots];
2446 struct unit *other_killed[slots];
2447
2448 fc_assert(unitcount > 1);
2449
2450 /* initialize */
2451 for (i = 0; i < slots; i++) {
2452 num_killed[i] = 0;
2453 other_killed[i] = NULL;
2454 num_escaped[i] = 0;
2455 }
2456
2457 /* count killed units */
2458 unit_list_iterate_safe(deftile->units, vunit) {
2459 struct player *vplayer = unit_owner(vunit);
2460
2461 if (pplayers_at_war(pvictor, vplayer)
2462 && is_unit_reachable_at(vunit, pkiller, deftile)) {
2463 escaped = FALSE;
2464
2465 if (unit_has_type_flag(vunit, UTYF_CANESCAPE)
2466 && !unit_has_type_flag(pkiller, UTYF_CANKILLESCAPING)
2467 && vunit->hp > 0
2468 && vunit->moves_left > pkiller->moves_left
2469 && fc_rand(2)) {
2470 int curr_def_bonus;
2471 int def_bonus = 0;
2472 struct tile *dsttile = NULL;
2473 int move_cost;
2474
2475 fc_assert(vunit->hp > 0);
2476
2477 adjc_iterate(nmap, deftile, ptile2) {
2478 if (can_exist_at_tile(nmap, vunit->utype, ptile2)
2479 && NULL == tile_city(ptile2)) {
2480 move_cost = map_move_cost_unit(nmap, vunit, ptile2);
2481 if (pkiller->moves_left <= vunit->moves_left - move_cost
2482 && (is_allied_unit_tile(ptile2, pvictim)
2483 || unit_list_size(ptile2->units)) == 0) {
2484 curr_def_bonus = tile_extras_defense_bonus(ptile2,
2485 vunit->utype);
2486 if (def_bonus <= curr_def_bonus) {
2487 def_bonus = curr_def_bonus;
2488 dsttile = ptile2;
2489 }
2490 }
2491 }
2493
2494 if (dsttile != NULL) {
2495 escaped = (action_auto_perf_unit_do(AAPC_UNIT_STACK_DEATH,
2496 vunit, tile_owner(dsttile),
2497 NULL, NULL, dsttile,
2498 tile_city(dsttile),
2499 NULL, NULL)
2500 != NULL);
2501
2502 if (escaped) {
2503 num_escaped[player_index(vplayer)]++;
2504 unitcount--;
2505 }
2506 }
2507 }
2508
2509 if (!escaped) {
2510 num_killed[player_index(vplayer)]++;
2511
2512 if (vunit != punit) {
2513 other_killed[player_index(vplayer)] = vunit;
2514 other_killed[player_index(pvictor)] = vunit;
2515 }
2516 }
2517 }
2519
2520 /* Inform the destroyer again if more than one unit was killed */
2521 if (unitcount > 1 && !collect_ransom) {
2522 notify_player(pvictor, unit_tile(pkiller), E_UNIT_WIN_ATT, ftc_server,
2523 /* TRANS: "... Cannon ... the Polish Destroyer ...." */
2524 PL_("Your attacking %s succeeded against the %s %s "
2525 "(and %d other unit)!",
2526 "Your attacking %s succeeded against the %s %s "
2527 "(and %d other units)!", unitcount - 1),
2528 pkiller_link,
2530 punit_link,
2531 unitcount - 1);
2532 }
2533
2534 if (vet) {
2535 notify_unit_experience(pkiller);
2536 }
2537
2538 /* inform the owners: this only tells about owned units that were killed.
2539 * there may have been 20 units who died but if only 2 belonged to the
2540 * particular player they'll only learn about those.
2541 *
2542 * Also if a large number of units die you don't find out what type
2543 * they all are. */
2544 for (i = 0; i < slots; i++) {
2545 if (num_killed[i] == 1) {
2546 if (i == player_index(pvictim)) {
2547 fc_assert(other_killed[i] == NULL);
2548 notify_player(player_by_number(i), deftile,
2549 E_UNIT_LOST_DEF, ftc_server,
2550 /* TRANS: "Cannon ... the Polish Destroyer." */
2551 _("%s lost to an attack by the %s %s."),
2552 punit_link,
2554 pkiller_link);
2555 } else {
2556 fc_assert(other_killed[i] != punit);
2557 notify_player(player_by_number(i), deftile,
2558 E_UNIT_LOST_DEF, ftc_server,
2559 /* TRANS: "Cannon lost when the Polish Destroyer
2560 * attacked the German Musketeers." */
2561 _("%s lost when the %s %s attacked the %s %s."),
2562 unit_link(other_killed[i]),
2564 pkiller_link,
2566 punit_link);
2567 }
2568 } else if (num_killed[i] > 1) {
2569 if (i == player_index(pvictim)) {
2570 int others = num_killed[i] - 1;
2571
2572 if (others == 1) {
2573 notify_player(player_by_number(i), deftile,
2574 E_UNIT_LOST_DEF, ftc_server,
2575 /* TRANS: "Musketeers (and Cannon) lost to an
2576 * attack from the Polish Destroyer." */
2577 _("%s (and %s) lost to an attack from the %s %s."),
2578 punit_link,
2579 unit_link(other_killed[i]),
2581 pkiller_link);
2582 } else {
2583 notify_player(player_by_number(i), deftile,
2584 E_UNIT_LOST_DEF, ftc_server,
2585 /* TRANS: "Musketeers and 3 other units lost to
2586 * an attack from the Polish Destroyer."
2587 * (only happens with at least 2 other units) */
2588 PL_("%s and %d other unit lost to an attack "
2589 "from the %s %s.",
2590 "%s and %d other units lost to an attack "
2591 "from the %s %s.", others),
2592 punit_link,
2593 others,
2595 pkiller_link);
2596 }
2597 } else {
2598 notify_player(player_by_number(i), deftile,
2599 E_UNIT_LOST_DEF, ftc_server,
2600 /* TRANS: "2 units lost when the Polish Destroyer
2601 * attacked the German Musketeers."
2602 * (only happens with at least 2 other units) */
2603 PL_("%d unit lost when the %s %s attacked the %s %s.",
2604 "%d units lost when the %s %s attacked the %s %s.",
2605 num_killed[i]),
2606 num_killed[i],
2608 pkiller_link,
2610 punit_link);
2611 }
2612 }
2613 }
2614
2615 /* Inform the owner of the units that escaped.
2616 * 'deftile' is the original tile they defended at, not where
2617 * they escaped to, as there might be multiple different tiles
2618 * different units escaped to. */
2619 for (i = 0; i < slots; i++) {
2620 if (0 < num_escaped[i]) {
2621 notify_player(player_by_number(i), deftile,
2622 E_UNIT_ESCAPED, ftc_server,
2623 PL_("%d unit escaped from attack by %s %s",
2624 "%d units escaped from attack by %s %s",
2625 num_escaped[i]),
2626 num_escaped[i],
2628 pkiller_link
2629 );
2630 }
2631 }
2632
2633 /* remove the units - note the logic of which units actually die
2634 * must be mimiced exactly in at least one place up above. */
2635 punit = NULL; /* wiped during following iteration so unsafe to use */
2636
2637 unit_list_iterate_safe(deftile->units, punit2) {
2638 if (pplayers_at_war(pvictor, unit_owner(punit2))
2639 && is_unit_reachable_at(punit2, pkiller, deftile)) {
2640 wipe_unit(punit2, ULR_KILLED, pvictor);
2641 }
2643 }
2644}
2645
2646/**********************************************************************/
2650void package_unit(struct unit *punit, struct packet_unit_info *packet)
2651{
2652 packet->id32 = punit->id;
2653 packet->id16 = packet->id32;
2654 packet->owner = player_number(unit_owner(punit));
2656 packet->tile = tile_index(unit_tile(punit));
2657 packet->facing = punit->facing;
2658 packet->homecity32 = punit->homecity;
2659 packet->homecity16 = packet->homecity32;
2661 packet->upkeep[o] = punit->upkeep[o];
2663 packet->veteran = punit->veteran;
2665 packet->movesleft = punit->moves_left;
2666 packet->hp = punit->hp;
2667 packet->activity = punit->activity;
2669
2670 if (punit->activity_target != NULL) {
2672 } else {
2673 packet->activity_tgt = EXTRA_NONE;
2674 }
2675
2676 packet->changed_from = punit->changed_from;
2678
2679 if (punit->changed_from_target != NULL) {
2681 } else {
2682 packet->changed_from_tgt = EXTRA_NONE;
2683 }
2684
2686 packet->fuel = punit->fuel;
2687 packet->goto_tile = (NULL != punit->goto_tile
2688 ? tile_index(punit->goto_tile) : -1);
2689 packet->paradropped = punit->paradropped;
2690 packet->done_moving = punit->done_moving;
2691 packet->stay = punit->stay;
2692 if (!unit_transported(punit)) {
2693 packet->transported = FALSE;
2694 packet->transported_by32 = 0;
2695 packet->transported_by16 = 0;
2696 } else {
2697 packet->transported = TRUE;
2699 packet->transported_by16 = packet->transported_by32;
2700 }
2701 if (punit->carrying != NULL) {
2702 packet->carrying = goods_index(punit->carrying);
2703 } else {
2704 packet->carrying = -1;
2705 }
2706 packet->occupied = (get_transporter_occupancy(punit) > 0);
2707 packet->battlegroup = punit->battlegroup;
2708 packet->has_orders = punit->has_orders;
2709 if (punit->has_orders) {
2710 packet->orders_length = punit->orders.length;
2711 packet->orders_index = punit->orders.index;
2712 packet->orders_repeat = punit->orders.repeat;
2714 memcpy(packet->orders, punit->orders.list,
2715 punit->orders.length * sizeof(struct unit_order));
2716 } else {
2717 packet->orders_length = packet->orders_index = 0;
2718 packet->orders_repeat = packet->orders_vigilant = FALSE;
2719 /* No need to initialize array. */
2720 }
2721
2726}
2727
2728/**********************************************************************/
2734 struct packet_unit_short_info *packet,
2735 enum unit_info_use packet_use, int info_city_id)
2736{
2737 packet->packet_use = packet_use;
2738 packet->info_city_id32 = info_city_id;
2739 packet->info_city_id16 = packet->info_city_id32;
2740
2741 packet->id32 = punit->id;
2742 packet->id16 = packet->id32;
2743 packet->owner = player_number(unit_owner(punit));
2744 packet->tile = tile_index(unit_tile(punit));
2745 packet->facing = punit->facing;
2746 packet->veteran = punit->veteran;
2748 packet->hp = punit->hp;
2749 packet->occupied = (get_transporter_occupancy(punit) > 0);
2750 if (punit->activity == ACTIVITY_EXPLORE
2751 || punit->activity == ACTIVITY_GOTO) {
2752 packet->activity = ACTIVITY_IDLE;
2753 } else {
2754 packet->activity = punit->activity;
2755 }
2756
2757 if (punit->activity_target == NULL) {
2758 packet->activity_tgt = EXTRA_NONE;
2759 } else {
2761 }
2762
2763 /* Transported_by information is sent to the client even for units that
2764 * aren't fully known. Note that for non-allied players, any transported
2765 * unit can't be seen at all. For allied players we have to know if
2766 * transporters have room in them so that we can load units properly. */
2767 if (!unit_transported(punit)) {
2768 packet->transported = FALSE;
2769 packet->transported_by32 = 0;
2770 packet->transported_by16 = 0;
2771 } else {
2772 packet->transported = TRUE;
2774 packet->transported_by16 = packet->transported_by32;
2775 }
2776}
2777
2778/**********************************************************************/
2781void unit_goes_out_of_sight(struct player *pplayer, struct unit *punit)
2782{
2784 if (punit->server.moving != NULL) {
2785 /* Update status of 'pplayer' vision for 'punit'. */
2787 }
2788}
2789
2790/**********************************************************************/
2794void send_unit_info(struct conn_list *dest, struct unit *punit)
2795{
2796 const struct player *powner;
2797 struct packet_unit_info info;
2798 struct packet_unit_short_info sinfo;
2799 struct unit_move_data *pdata;
2800
2801 if (dest == NULL) {
2802 dest = game.est_connections;
2803 }
2804
2806
2808 package_unit(punit, &info);
2810 pdata = punit->server.moving;
2811
2812 conn_list_iterate(dest, pconn) {
2813 struct player *pplayer = conn_get_player(pconn);
2814
2815 /* Be careful to consider all cases where pplayer is NULL... */
2816 if (pplayer == NULL) {
2817 if (pconn->observer) {
2818 send_packet_unit_info(pconn, &info);
2819 }
2820 } else if (pplayer == powner) {
2821 send_packet_unit_info(pconn, &info);
2822 if (pdata != NULL) {
2823 BV_SET(pdata->can_see_unit, player_index(pplayer));
2824 }
2825 } else if (can_player_see_unit(pplayer, punit)) {
2826 send_packet_unit_short_info(pconn, &sinfo, FALSE);
2827 if (pdata != NULL) {
2828 BV_SET(pdata->can_see_unit, player_index(pplayer));
2829 }
2830 }
2832}
2833
2834/**********************************************************************/
2838void send_all_known_units(struct conn_list *dest)
2839{
2840 conn_list_do_buffer(dest);
2841 conn_list_iterate(dest, pconn) {
2842 struct player *pplayer = pconn->playing;
2843
2844 if (NULL == pplayer && !pconn->observer) {
2845 continue;
2846 }
2847
2848 players_iterate(unitowner) {
2849 unit_list_iterate(unitowner->units, punit) {
2850 send_unit_info(dest, punit);
2853 }
2856 flush_packets();
2857}
2858
2859/**********************************************************************/
2866static void do_nuke_tile(struct player *pplayer, struct tile *ptile)
2867{
2868 struct city *pcity = NULL;
2869 int pop_loss;
2870
2871 pcity = tile_city(ptile);
2872
2874
2875 /* unit in a city may survive */
2876 if (pcity && fc_rand(100) < game.info.nuke_defender_survival_chance_pct) {
2877 continue;
2878 }
2879 notify_player(unit_owner(punit), ptile, E_UNIT_LOST_MISC, ftc_server,
2880 _("Your %s was nuked by %s."),
2882 pplayer == unit_owner(punit)
2883 ? _("yourself")
2884 : nation_plural_for_player(pplayer));
2885 if (unit_owner(punit) != pplayer) {
2886 notify_player(pplayer, ptile, E_UNIT_WIN_ATT, ftc_server,
2887 _("The %s %s was nuked."),
2890 }
2891 wipe_unit(punit, ULR_NUKE, pplayer);
2893
2894
2895 if (pcity) {
2896 struct player *owner = city_owner(pcity);
2897 char city_name[MAX_LEN_LINK];
2898
2899 sz_strlcpy(city_name, city_link(pcity));
2900
2901 notify_player(owner, ptile, E_CITY_NUKED, ftc_server,
2902 _("%s was nuked by %s."),
2903 city_name,
2904 pplayer == owner
2905 ? _("yourself")
2906 : nation_plural_for_player(pplayer));
2907
2908 if (owner != pplayer) {
2909 notify_player(pplayer, ptile, E_CITY_NUKED, ftc_server,
2910 _("You nuked %s."),
2911 city_name);
2912 }
2913
2914 pop_loss = round((game.info.nuke_pop_loss_pct * city_size_get(pcity)) / 100.0);
2915 if (city_reduce_size(pcity, pop_loss, pplayer, "nuke")) {
2916 /* Send city size reduction to everyone seeing it */
2917 send_city_info(NULL, pcity);
2918 } else {
2919 /* City was destroyed */
2920 notify_player(owner, ptile, E_CITY_NUKED, ftc_server,
2921 _("%s was destroyed by the nuke."),
2922 city_name);
2923 if (owner != pplayer) {
2924 notify_player(pplayer, ptile, E_CITY_NUKED, ftc_server,
2925 _("Your nuke destroyed %s."),
2926 city_name);
2927 }
2928 }
2929 }
2930
2931 if (fc_rand(2) == 1) {
2932 struct extra_type *pextra;
2933
2934 pextra = rand_extra_for_tile(ptile, EC_FALLOUT, FALSE);
2935 if (pextra != NULL && !tile_has_extra(ptile, pextra)) {
2936 tile_add_extra(ptile, pextra);
2937 update_tile_knowledge(ptile);
2938 }
2939 }
2940}
2941
2942/**********************************************************************/
2946void do_nuclear_explosion(struct player *pplayer, struct tile *ptile)
2947{
2948 square_iterate(&(wld.map), ptile, 1, ptile1) {
2949 do_nuke_tile(pplayer, ptile1);
2951
2952 script_server_signal_emit("nuke_exploded", 2, API_TYPE_TILE, ptile,
2953 API_TYPE_PLAYER, pplayer);
2954 notify_conn(NULL, ptile, E_NUKE, ftc_server,
2955 _("The %s detonated a nuke!"),
2956 nation_plural_for_player(pplayer));
2957}
2958
2959/**********************************************************************/
2963bool do_airline(struct unit *punit, struct city *pdest_city,
2964 const struct action *paction)
2965{
2966 struct city *psrc_city = tile_city(unit_tile(punit));
2967
2969 E_UNIT_RELOCATED, ftc_server,
2970 _("%s transported successfully."),
2971 unit_link(punit));
2972
2973 unit_move(punit, pdest_city->tile, punit->moves_left,
2974 NULL, BV_ISSET(paction->sub_results, ACT_SUB_RES_MAY_EMBARK),
2975 /* Can only airlift to allied and domestic cities */
2976 FALSE, FALSE,
2977 BV_ISSET(paction->sub_results, ACT_SUB_RES_HUT_ENTER),
2978 BV_ISSET(paction->sub_results, ACT_SUB_RES_HUT_FRIGHTEN));
2979
2980 /* Update airlift fields. */
2981 if (!(game.info.airlifting_style & AIRLIFTING_UNLIMITED_SRC)) {
2982 psrc_city->airlift--;
2983 send_city_info(city_owner(psrc_city), psrc_city);
2984 }
2985 if (!(game.info.airlifting_style & AIRLIFTING_UNLIMITED_DEST)) {
2986 pdest_city->airlift--;
2987 send_city_info(city_owner(pdest_city), pdest_city);
2988 }
2989
2990 return TRUE;
2991}
2992
2993/**********************************************************************/
2996void do_explore(struct unit *punit)
2997{
2998 switch (manage_auto_explorer(punit)) {
2999 case MR_DEATH:
3000 /* don't use punit! */
3001 return;
3002 case MR_NOT_ALLOWED:
3003 /* Needed for something else */
3004 return;
3005 case MR_OK:
3006 /* FIXME: manage_auto_explorer() isn't supposed to change the activity,
3007 * but don't count on this. See PR#39792.
3008 */
3009 if (punit->activity == ACTIVITY_EXPLORE) {
3010 break;
3011 }
3012
3014 default:
3015 unit_activity_handling(punit, ACTIVITY_IDLE);
3016
3017 /* FIXME: When the manage_auto_explorer() call changes the activity from
3018 * EXPLORE to IDLE, in unit_activity_handling() ai.control is left
3019 * alone. We reset it here. See PR#12931. */
3020 punit->ssa_controller = SSA_NONE;
3021 break;
3022 }
3023
3024 send_unit_info(NULL, punit); /* probably duplicate */
3025}
3026
3027/**********************************************************************/
3032bool do_paradrop(struct unit *punit, struct tile *ptile,
3033 const struct action *paction)
3034{
3035 struct player *pplayer = unit_owner(punit);
3036 struct player *tgt_player = tile_owner(ptile);
3037 const struct unit_type *act_utype = unit_type_get(punit);
3038 const struct city *pcity;
3039
3040 /* Hard requirements */
3041 /* FIXME: hard requirements belong in common/actions's
3042 * is_action_possible() and the explanation texts belong in
3043 * server/unithand's action not enabled system (expl_act_not_enabl(),
3044 * ane_kind, explain_why_no_action_enabled(), etc)
3045 */
3046 if (!map_is_known_and_seen(ptile, pplayer, V_MAIN)) {
3047 /* Only take in account values from player map. */
3048 const struct player_tile *plrtile = map_get_player_tile(ptile, pplayer);
3049
3050 if (NULL == plrtile->site
3052 &(plrtile->extras))) {
3053 notify_player(pplayer, ptile, E_BAD_COMMAND, ftc_server,
3054 _("This unit cannot paradrop into %s."),
3056 return FALSE;
3057 }
3058
3059 if (NULL != plrtile->site
3060 && plrtile->owner != NULL
3061 && !pplayers_allied(pplayer, plrtile->owner)
3062 && !action_has_result(paction, ACTRES_PARADROP_CONQUER)) {
3063 notify_player(pplayer, ptile, E_BAD_COMMAND, ftc_server,
3064 /* TRANS: Paratroopers ... Paradrop Unit */
3065 _("%s cannot conquer a city with \"%s\"."),
3067 action_name_translation(paction));
3068 return FALSE;
3069 }
3070
3071 if (NULL != plrtile->site
3072 && plrtile->owner != NULL
3073 && (pplayers_non_attack(pplayer, plrtile->owner)
3074 || (player_diplstate_get(pplayer, plrtile->owner)->type
3075 == DS_ALLIANCE)
3076 || (player_diplstate_get(pplayer, plrtile->owner)->type
3077 == DS_TEAM))
3078 && action_has_result(paction, ACTRES_PARADROP_CONQUER)) {
3079 notify_player(pplayer, ptile, E_BAD_COMMAND, ftc_server,
3080 _("Cannot attack unless you declare war first."));
3081 return FALSE;
3082 }
3083 }
3084
3085
3086 /* Kill the unit when the landing goes wrong. */
3087
3088 /* Safe terrain, really? Not transformed since player last saw it. */
3089 if (!can_unit_exist_at_tile(&(wld.map), punit, ptile)
3090 && (!BV_ISSET(paction->sub_results, ACT_SUB_RES_MAY_EMBARK)
3091 || !unit_could_load_at(punit, ptile))) {
3092 map_show_circle(pplayer, ptile, act_utype->vision_radius_sq);
3093 notify_player(pplayer, ptile, E_UNIT_LOST_MISC, ftc_server,
3094 _("Your %s paradropped into the %s and was lost."),
3097 pplayer->score.units_lost++;
3098 server_remove_unit(punit, ULR_NONNATIVE_TERR);
3099 return TRUE;
3100 }
3101
3102 pcity = tile_city(ptile);
3103
3104 if ((pcity != NULL && !pplayers_allied(pplayer, city_owner(pcity))
3105 && !action_has_result(paction, ACTRES_PARADROP_CONQUER))
3106 || is_non_allied_unit_tile(ptile, pplayer)) {
3107 struct player *main_victim = NULL;
3108 struct player *secondary_victim = NULL;
3109 char victim_link[MAX_LEN_LINK];
3110
3111 map_show_circle(pplayer, ptile, act_utype->vision_radius_sq);
3112 maybe_make_contact(ptile, pplayer);
3113 notify_player(pplayer, ptile, E_UNIT_LOST_MISC, ftc_server,
3114 _("Your %s was killed by enemy units at the "
3115 "paradrop destination."),
3117 /* TODO: Should defender score.units_killed get increased too?
3118 * What if there's units of several allied players? Should the
3119 * city owner or owner of the first/random unit get the kill? */
3120 pplayer->score.units_lost++;
3121
3122 if (pcity != NULL) {
3123 struct player *owner = city_owner(pcity);
3124
3125 if (!pplayers_at_war(pplayer, owner)) {
3126 main_victim = owner;
3127 } else {
3128 secondary_victim = owner;
3129 }
3130
3131 sz_strlcpy(victim_link, city_link(pcity));
3132 } else {
3133 sz_strlcpy(victim_link, tile_link(ptile));
3134 }
3135
3136 if (main_victim == NULL) {
3137 unit_list_iterate(ptile->units, tgt) {
3138 struct player *owner = unit_owner(tgt);
3139
3140 if (!pplayers_at_war(pplayer, owner)) {
3141 main_victim = owner;
3142 break;
3143 } else if (secondary_victim == NULL) {
3144 secondary_victim = owner;
3145 }
3147
3148 if (main_victim == NULL) {
3149 /* There's no victim with whom the attacker isn't in war,
3150 * fallback to one with whom there's already a war. */
3151 main_victim = secondary_victim;
3152 }
3153 }
3154
3155 action_consequence_caught(paction, pplayer, act_utype,
3156 main_victim, ptile,
3157 victim_link);
3158
3159 server_remove_unit(punit, ULR_KILLED);
3160 return TRUE;
3161 }
3162
3163 /* All ok */
3165 if (unit_move(punit, ptile,
3166 /* Done by Action_Success_Actor_Move_Cost */
3167 0,
3168 NULL, BV_ISSET(paction->sub_results,
3169 ACT_SUB_RES_MAY_EMBARK),
3170 paction->result == ACTRES_PARADROP_CONQUER,
3171 paction->result == ACTRES_PARADROP_CONQUER,
3172 BV_ISSET(paction->sub_results, ACT_SUB_RES_HUT_ENTER),
3173 BV_ISSET(paction->sub_results, ACT_SUB_RES_HUT_FRIGHTEN))) {
3174 /* Ensure we finished on valid state. */
3177 }
3178
3179 /* May cause an incident */
3180 action_consequence_success(paction, pplayer, act_utype, tgt_player,
3181 ptile, tile_link(ptile));
3182
3183 return TRUE;
3184}
3185
3186/**********************************************************************/
3190static bool hut_get_limited(struct unit *punit)
3191{
3192 bool ok = TRUE;
3193 int hut_chance = fc_rand(12);
3194 struct player *pplayer = unit_owner(punit);
3195 const struct civ_map *nmap = &(wld.map);
3196
3197 /* 1 in 12 to get barbarians */
3198 if (hut_chance != 0) {
3199 int cred = 25;
3200
3201 notify_player(pplayer, unit_tile(punit), E_HUT_GOLD, ftc_server,
3202 PL_("You found %d gold.",
3203 "You found %d gold.", cred), cred);
3204 pplayer->economic.gold += cred;
3206 || unit_has_type_flag(punit, UTYF_GAMELOSS)) {
3207 notify_player(pplayer, unit_tile(punit),
3208 E_HUT_BARB_CITY_NEAR, ftc_server,
3209 _("An abandoned village is here."));
3210 } else {
3211 notify_player(pplayer, unit_tile(punit), E_HUT_BARB_KILLED, ftc_server,
3212 _("Your %s has been killed by barbarians!"),
3214 wipe_unit(punit, ULR_BARB_UNLEASH, NULL);
3215 ok = FALSE;
3216 }
3217
3218 return ok;
3219}
3220
3221/**********************************************************************/
3225static void unit_enter_hut(struct unit *punit, bool frighten_hut)
3226{
3227 struct player *pplayer = unit_owner(punit);
3228 int id = punit->id;
3229 struct tile *ptile = unit_tile(punit);
3230 bool hut = FALSE;
3231 const struct req_context context = {
3232 .player = pplayer,
3233 .tile = ptile,
3234 };
3235
3236 extra_type_by_rmcause_iterate(ERM_ENTER, pextra) {
3237 if (tile_has_extra(ptile, pextra)
3238 && are_reqs_active(&context, tile_owner(ptile), &pextra->rmreqs,
3240 ) {
3241 hut = TRUE;
3242 /* FIXME: are all enter-removes extras worth counting? */
3243 pplayer->server.huts++;
3244
3245 destroy_extra(ptile, pextra);
3247
3248 /* FIXME: enable different classes
3249 * to behave differently with different huts */
3250 if (frighten_hut) {
3251 script_server_signal_emit("hut_frighten", punit,
3252 extra_rule_name(pextra));
3253 } else if (is_ai(pplayer) && has_handicap(pplayer, H_LIMITEDHUTS)) {
3254 /* AI with H_LIMITEDHUTS only gets 25 gold (or barbs if unlucky) */
3255 (void) hut_get_limited(punit);
3256 } else {
3257 script_server_signal_emit("hut_enter", punit, extra_rule_name(pextra));
3258 }
3259
3260 /* We need punit for the callbacks, can't continue if the unit died */
3261 if (!unit_is_alive(id)) {
3262 break;
3263 }
3264 }
3266
3267 if (hut) {
3268 send_player_info_c(pplayer, pplayer->connections); /* eg, gold */
3269 }
3270 return;
3271}
3272
3273/**********************************************************************/
3276void unit_transport_load_send(struct unit *punit, struct unit *ptrans)
3277{
3278 bv_player can_see_unit;
3279
3280 fc_assert_ret(punit != NULL);
3281 fc_assert_ret(ptrans != NULL);
3282
3283 BV_CLR_ALL(can_see_unit);
3284 players_iterate(pplayer) {
3285 if (can_player_see_unit(pplayer, punit)) {
3286 BV_SET(can_see_unit, player_index(pplayer));
3287 }
3289
3291
3292 players_iterate(pplayer) {
3293 if (BV_ISSET(can_see_unit, player_index(pplayer))
3294 && !can_player_see_unit(pplayer, punit)) {
3295 unit_goes_out_of_sight(pplayer, punit);
3296 }
3298
3299 send_unit_info(NULL, punit);
3300 send_unit_info(NULL, ptrans);
3301}
3302
3303/**********************************************************************/
3307 struct unit *ptrans,
3308 bool force)
3309{
3310 bool had_cargo;
3311
3312 fc_assert_ret(punit != NULL);
3313 fc_assert_ret(ptrans != NULL);
3314
3315 had_cargo = get_transporter_occupancy(ptrans) > 0;
3316
3317 unit_transport_load(punit, ptrans, force);
3318
3319 if (!had_cargo) {
3320 /* Transport's loaded status changed */
3321 send_unit_info(NULL, ptrans);
3322 }
3323}
3324
3325/**********************************************************************/
3329{
3330 struct unit *ptrans;
3331
3333
3334 ptrans = unit_transport_get(punit);
3335
3336 fc_assert_ret(ptrans);
3337
3339
3340 send_unit_info(NULL, punit);
3341 send_unit_info(NULL, ptrans);
3342}
3343
3344/**********************************************************************/
3348static void autoattack_prob_free(struct autoattack_prob *prob)
3349{
3350 free(prob);
3351}
3352
3353/**********************************************************************/
3362static int compare_units(const struct autoattack_prob *const *p1,
3363 const struct autoattack_prob *const *q1)
3364{
3365 const struct unit *p1unit = game_unit_by_number((*p1)->unit_id);
3366 const struct unit *q1unit = game_unit_by_number((*q1)->unit_id);
3367
3368 /* Sort by transport depth first. This makes sure that no transport
3369 * attacks before its cargo does -- cargo sorts earlier in the list. */
3370 {
3371 const struct unit *p1trans = p1unit, *q1trans = q1unit;
3372
3373 /* Walk the transport stacks in parallel, so as to bail out as soon as
3374 * one of them is empty (avoid walking deep stacks more often than
3375 * necessary). */
3376 while (p1trans && q1trans) {
3377 p1trans = unit_transport_get(p1trans);
3378 q1trans = unit_transport_get(q1trans);
3379 }
3380 if (!p1trans && q1trans) {
3381 /* q1 is at greater depth (perhaps it's p1's cargo). It should sort
3382 * earlier in the list (p1 > q1). */
3383 return 1;
3384 } else if (p1trans && !q1trans) {
3385 /* p1 is at greater depth, so should sort earlier (p1 < q1). */
3386 return -1;
3387 }
3388 /* else same depth, so move on to checking win chance: */
3389 }
3390
3391 /* Put the units with the highest probability of success first. The up
3392 * side of this is that units with bonuses against the victim attacks
3393 * before other units. The downside is that strong units can be led
3394 * away by sacrificial units. */
3395 return (-1
3396 /* Assume the worst. */
3397 * action_prob_cmp_pessimist((*p1)->prob, (*q1)->prob));
3398}
3399
3400/**********************************************************************/
3405{
3406 struct autoattack_prob_list *autoattack;
3407 int moves = punit->moves_left;
3408 int sanity1 = punit->id;
3409 struct civ_map *nmap = &(wld.map);
3410
3411 if (!game.server.autoattack) {
3412 return TRUE;
3413 }
3414
3415 autoattack = autoattack_prob_list_new_full(autoattack_prob_free);
3416
3417 /* Kludge to prevent attack power from dropping to zero during calc */
3419
3420 adjc_iterate(nmap, unit_tile(punit), ptile) {
3421 /* First add all eligible units to a autoattack list */
3422 unit_list_iterate(ptile->units, penemy) {
3423 struct autoattack_prob *probability = fc_malloc(sizeof(*probability));
3424 struct tile *tgt_tile = unit_tile(punit);
3425
3426 fc_assert_action(tgt_tile, continue);
3427
3428 probability->prob =
3429 action_auto_perf_unit_prob(AAPC_UNIT_MOVED_ADJ,
3430 penemy, unit_owner(punit), NULL, NULL,
3431 tgt_tile, tile_city(tgt_tile),
3432 punit, NULL);
3433
3434 if (action_prob_possible(probability->prob)) {
3435 probability->unit_id = penemy->id;
3436 autoattack_prob_list_prepend(autoattack, probability);
3437 } else {
3438 FC_FREE(probability);
3439 }
3442
3443 /* Sort the potential attackers from highest to lowest success
3444 * probability. */
3445 if (autoattack_prob_list_size(autoattack) >= 2) {
3446 autoattack_prob_list_sort(autoattack, &compare_units);
3447 }
3448
3449 autoattack_prob_list_iterate_safe(autoattack, peprob, penemy) {
3450 int sanity2 = penemy->id;
3451 struct tile *ptile = unit_tile(penemy);
3452 struct unit *enemy_defender = get_defender(nmap, punit, ptile);
3453 double punitwin, penemywin;
3454 double threshold = 0.25;
3455 struct tile *tgt_tile = unit_tile(punit);
3456
3457 fc_assert(tgt_tile);
3458
3459 if (tile_city(ptile) && unit_list_size(ptile->units) == 1) {
3460 /* Don't leave city defenseless */
3461 threshold = 0.90;
3462 }
3463
3464 if (NULL != enemy_defender) {
3465 punitwin = unit_win_chance(nmap, punit, enemy_defender);
3466 } else {
3467 /* 'penemy' can attack 'punit' but it may be not reciproque. */
3468 punitwin = 1.0;
3469 }
3470
3471 /* Previous attacks may have changed the odds. Recalculate. */
3472 peprob->prob =
3473 action_auto_perf_unit_prob(AAPC_UNIT_MOVED_ADJ,
3474 penemy, unit_owner(punit), NULL, NULL,
3475 tgt_tile, tile_city(tgt_tile),
3476 punit, NULL);
3477
3478 if (!action_prob_possible(peprob->prob)) {
3479 /* No longer legal. */
3480 continue;
3481 }
3482
3483 /* Assume the worst. */
3484 penemywin = action_prob_to_0_to_1_pessimist(peprob->prob);
3485
3486 if ((penemywin > 1.0 - punitwin
3487 || unit_has_type_flag(punit, UTYF_PROVOKING))
3488 && penemywin > threshold) {
3489
3490#ifdef REALLY_DEBUG_THIS
3491 log_test("AA %s -> %s (%d,%d) %.2f > %.2f && > %.2f",
3493 TILE_XY(unit_tile(punit)), penemywin,
3494 1.0 - punitwin, threshold);
3495#endif
3496
3497 unit_activity_handling(penemy, ACTIVITY_IDLE);
3498 action_auto_perf_unit_do(AAPC_UNIT_MOVED_ADJ,
3499 penemy, unit_owner(punit), NULL, NULL,
3500 tgt_tile, tile_city(tgt_tile), punit, NULL);
3501 } else {
3502#ifdef REALLY_DEBUG_THIS
3503 log_test("!AA %s -> %s (%d,%d) %.2f > %.2f && > %.2f",
3505 TILE_XY(unit_tile(punit)), penemywin,
3506 1.0 - punitwin, threshold);
3507#endif
3508 continue;
3509 }
3510
3511 if (game_unit_by_number(sanity2)) {
3512 send_unit_info(NULL, penemy);
3513 }
3514 if (game_unit_by_number(sanity1)) {
3515 send_unit_info(NULL, punit);
3516 } else {
3517 autoattack_prob_list_destroy(autoattack);
3518 return FALSE; /* moving unit dead */
3519 }
3521
3522 autoattack_prob_list_destroy(autoattack);
3523 if (game_unit_by_number(sanity1)) {
3524 /* We could have lost movement in combat */
3525 punit->moves_left = MIN(punit->moves_left, moves);
3526 send_unit_info(NULL, punit);
3527 return TRUE;
3528 } else {
3529 return FALSE;
3530 }
3531}
3532
3533/**********************************************************************/
3536static void cancel_orders(struct unit *punit, char *dbg_msg)
3537{
3539 send_unit_info(NULL, punit);
3540 log_debug("%s", dbg_msg);
3541}
3542
3543/**********************************************************************/
3548{
3549 bool alone_in_city;
3550
3551 if (NULL != tile_city(unit_tile(punit))) {
3552 int count = 0;
3553
3555 /* Consider only units not transported. */
3556 if (!unit_transported(aunit)) {
3557 count++;
3558 }
3560
3561 alone_in_city = (1 == count);
3562 } else {
3563 alone_in_city = FALSE;
3564 }
3565
3566 /* There may be sentried units with a sightrange > 3, but we don't
3567 wake them up if the punit is farther away than 3. */
3568 square_iterate(&(wld.map), unit_tile(punit), 3, ptile) {
3569 unit_list_iterate(ptile->units, penemy) {
3570 int distance_sq = sq_map_distance(unit_tile(punit), ptile);
3571 int radius_sq = get_unit_vision_at(penemy, unit_tile(penemy), V_MAIN);
3572
3574 && penemy->activity == ACTIVITY_SENTRY
3575 && radius_sq >= distance_sq
3576 /* If the unit moved on a city, and the unit is alone, consider
3577 * it is visible. */
3578 && (alone_in_city
3580 /* on board transport; don't awaken */
3581 && can_unit_exist_at_tile(&(wld.map), penemy, unit_tile(penemy))) {
3582 set_unit_activity(penemy, ACTIVITY_IDLE);
3583 send_unit_info(NULL, penemy);
3584 }
3587
3588 /* Wakeup patrolling units we bump into.
3589 We do not wakeup units further away than 3 squares... */
3590 square_iterate(&(wld.map), unit_tile(punit), 3, ptile) {
3591 unit_list_iterate(ptile->units, ppatrol) {
3592 if (punit != ppatrol
3593 && unit_has_orders(ppatrol)
3594 && ppatrol->orders.vigilant) {
3595 if (maybe_cancel_patrol_due_to_enemy(ppatrol)) {
3596 cancel_orders(ppatrol, " stopping because of nearby enemy");
3597 notify_player(unit_owner(ppatrol), unit_tile(ppatrol),
3598 E_UNIT_ORDERS, ftc_server,
3599 _("Orders for %s aborted after enemy movement was "
3600 "spotted."),
3601 unit_link(ppatrol));
3602 }
3603 }
3606}
3607
3608/**********************************************************************/
3618 struct tile *src_tile,
3619 struct tile *dst_tile,
3620 bool passenger,
3621 bool conquer_city_allowed)
3622{
3623 struct city *fromcity = tile_city(src_tile);
3624 struct city *tocity = tile_city(dst_tile);
3625 struct city *homecity_start_pos = NULL;
3626 struct city *homecity_end_pos = NULL;
3627 int homecity_id_start_pos = punit->homecity;
3628 int homecity_id_end_pos = punit->homecity;
3629 struct player *pplayer_start_pos = unit_owner(punit);
3630 struct player *pplayer_end_pos = pplayer_start_pos;
3631 const struct unit_type *type_start_pos = unit_type_get(punit);
3632 const struct unit_type *type_end_pos = type_start_pos;
3633 bool refresh_homecity_start_pos = FALSE;
3634 bool refresh_homecity_end_pos = FALSE;
3635 int saved_id = punit->id;
3636 bool alive = TRUE;
3637 const struct civ_map *nmap = &(wld.map);
3638
3639 if (tocity && conquer_city_allowed) {
3640 if (!passenger) {
3641 /* The unit that does the move may conquer. */
3642 unit_conquer_city(punit, tocity);
3643 }
3644
3645 /* Run for passengers too. A passenger may have been killed when its
3646 * transport conquered a city. (unit_conquer_city() can cause Lua code
3647 * to run) */
3648
3649 alive = unit_is_alive(saved_id);
3650 if (alive) {
3651 /* In case script has changed something about unit */
3652 pplayer_end_pos = unit_owner(punit);
3653 type_end_pos = unit_type_get(punit);
3654 homecity_id_end_pos = punit->homecity;
3655 }
3656 }
3657
3658 if (homecity_id_start_pos != 0) {
3659 homecity_start_pos = game_city_by_number(homecity_id_start_pos);
3660 }
3661 if (homecity_id_start_pos != homecity_id_end_pos) {
3662 homecity_end_pos = game_city_by_number(homecity_id_end_pos);
3663 } else {
3664 homecity_end_pos = homecity_start_pos;
3665 }
3666
3667 /* We only do refreshes for non-AI players to now make sure the AI turns
3668 doesn't take too long. Perhaps we should make a special refresh_city
3669 functions that only refreshed happines. */
3670
3671 /* might have changed owners or may be destroyed */
3672 tocity = tile_city(dst_tile);
3673
3674 if (tocity) { /* entering a city */
3675 if (tocity->owner == pplayer_end_pos) {
3676 if (tocity != homecity_end_pos && is_human(pplayer_end_pos)) {
3677 city_refresh(tocity);
3678 send_city_info(pplayer_end_pos, tocity);
3679 }
3680 }
3681 if (homecity_start_pos) {
3682 refresh_homecity_start_pos = TRUE;
3683 }
3684 }
3685
3686 if (fromcity) { /* leaving a city */
3687 if (homecity_start_pos) {
3688 refresh_homecity_start_pos = TRUE;
3689 }
3690 if (fromcity != homecity_start_pos
3691 && fromcity->owner == pplayer_start_pos
3692 && is_human(pplayer_start_pos)) {
3693 city_refresh(fromcity);
3694 send_city_info(pplayer_start_pos, fromcity);
3695 }
3696 }
3697
3698 /* Entering/leaving a fortress or friendly territory */
3699 if (homecity_start_pos || homecity_end_pos) {
3700 if ((game.info.happyborders != HB_DISABLED && tile_owner(src_tile) != tile_owner(dst_tile))
3702 type_end_pos)
3703 && is_friendly_city_near(nmap, pplayer_end_pos, dst_tile))
3705 type_start_pos)
3706 && is_friendly_city_near(nmap, pplayer_start_pos, src_tile))) {
3707 refresh_homecity_start_pos = TRUE;
3708 refresh_homecity_end_pos = TRUE;
3709 }
3710 }
3711
3712 if (refresh_homecity_start_pos && is_human(pplayer_start_pos)) {
3713 city_refresh(homecity_start_pos);
3714 send_city_info(pplayer_start_pos, homecity_start_pos);
3715 }
3716 if (refresh_homecity_end_pos
3717 && (!refresh_homecity_start_pos
3718 || homecity_start_pos != homecity_end_pos)
3719 && is_human(pplayer_end_pos)) {
3720 city_refresh(homecity_end_pos);
3721 send_city_info(pplayer_end_pos, homecity_end_pos);
3722 }
3723
3724 city_map_update_tile_now(dst_tile);
3725 sync_cities();
3726
3727 return alive;
3728}
3729
3730/**********************************************************************/
3734static void check_unit_activity(struct unit *punit)
3735{
3736 switch (punit->activity) {
3737 case ACTIVITY_IDLE:
3738 case ACTIVITY_SENTRY:
3739 case ACTIVITY_EXPLORE:
3740 case ACTIVITY_GOTO:
3741 break;
3742 case ACTIVITY_POLLUTION:
3743 case ACTIVITY_MINE:
3744 case ACTIVITY_IRRIGATE:
3745 case ACTIVITY_CULTIVATE:
3746 case ACTIVITY_PLANT:
3747 case ACTIVITY_FORTIFIED:
3748 case ACTIVITY_FORTRESS:
3749 case ACTIVITY_PILLAGE:
3750 case ACTIVITY_TRANSFORM:
3751 case ACTIVITY_UNKNOWN:
3752 case ACTIVITY_AIRBASE:
3753 case ACTIVITY_FORTIFYING:
3754 case ACTIVITY_FALLOUT:
3755 case ACTIVITY_PATROL_UNUSED:
3756 case ACTIVITY_BASE:
3757 case ACTIVITY_GEN_ROAD:
3758 case ACTIVITY_CONVERT:
3759 case ACTIVITY_OLD_ROAD:
3760 case ACTIVITY_OLD_RAILROAD:
3761 case ACTIVITY_LAST:
3762 set_unit_activity(punit, ACTIVITY_IDLE);
3763 break;
3764 };
3765}
3766
3767/**********************************************************************/
3771 struct tile *psrctile,
3772 struct tile *pdesttile)
3773{
3774 struct unit_move_data *pdata;
3775 struct player *powner = unit_owner(punit);
3776
3777 if (punit->server.moving) {
3778 /* Recursive moving (probably due to a script). */
3779 pdata = punit->server.moving;
3780 pdata->ref_count++;
3781 fc_assert_msg(pdata->punit == punit,
3782 "Unit number %d (%p) was going to die, but "
3783 "server attempts to move it.",
3784 punit->id, punit);
3785 fc_assert_msg(pdata->old_vision == NULL,
3786 "Unit number %d (%p) has done an incomplete move.",
3787 punit->id, punit);
3788 } else {
3789 pdata = fc_malloc(sizeof(*pdata));
3790 pdata->ref_count = 1;
3791 pdata->punit = punit;
3792 punit->server.moving = pdata;
3793 BV_CLR_ALL(pdata->can_see_unit);
3794 }
3795 pdata->powner = powner;
3796 BV_CLR_ALL(pdata->can_see_move);
3797 pdata->old_vision = punit->server.vision;
3798
3799 return pdata;
3800}
3801
3802/**********************************************************************/
3805static void unit_move_by_data(struct unit_move_data *pdata,
3806 struct tile *psrctile, struct tile *pdesttile)
3807{
3808 struct vision *new_vision;
3809 struct unit *punit = pdata->punit;
3810 int mod = unit_vision_range_modifiers(punit, pdesttile);
3811 const v_radius_t radius_sq =
3812 V_RADIUS(get_unit_vision_base(punit, V_MAIN, mod),
3813 get_unit_vision_base(punit, V_INVIS, mod),
3814 get_unit_vision_base(punit, V_SUBSURFACE, mod));
3815
3816 /* Remove unit from the source tile. */
3817 fc_assert(unit_tile(punit) == psrctile);
3818
3819#ifndef FREECIV_NDEBUG
3820 bool success =
3821#endif
3822 unit_list_remove(psrctile->units, punit);
3823 fc_assert(success);
3824
3825 /* Set new tile. */
3826 unit_tile_set(punit, pdesttile);
3827 unit_list_prepend(pdesttile->units, punit);
3828
3829 if (unit_transported(punit)) {
3830 /* Silently free orders since they won't be applicable anymore. */
3832 }
3833
3834 /* Check unit activity. */
3838
3839 /* We first unfog the destination, then send the move,
3840 * and then fog the old territory. This means that the player
3841 * gets a chance to see the newly explored territory while the
3842 * client moves the unit, and both areas are visible during the
3843 * move */
3844
3845 /* Enhance vision if unit steps into a fortress */
3846 new_vision = vision_new(pdata->powner, pdesttile);
3847 punit->server.vision = new_vision;
3848 vision_change_sight(new_vision, radius_sq);
3849 ASSERT_VISION(new_vision);
3850}
3851
3852/**********************************************************************/
3855static void unit_move_data_unref(struct unit_move_data *pdata)
3856{
3857 fc_assert_ret(pdata != NULL);
3858 fc_assert_ret(pdata->ref_count > 0);
3859 fc_assert_msg(pdata->old_vision == NULL,
3860 "Unit number %d (%p) has done an incomplete move.",
3861 pdata->punit != NULL ? pdata->punit->id : -1, pdata->punit);
3862
3863 pdata->ref_count--;
3864 if (pdata->ref_count == 0) {
3865 if (pdata->punit != NULL) {
3866 fc_assert(pdata->punit->server.moving == pdata);
3867 pdata->punit->server.moving = NULL;
3868 }
3869 free(pdata);
3870 }
3871}
3872
3873/**********************************************************************/
3884bool unit_move(struct unit *punit, struct tile *pdesttile, int move_cost,
3885 struct unit *embark_to, bool find_embark_target,
3886 bool conquer_city_allowed, bool conquer_extras_allowed,
3887 bool enter_hut, bool frighten_hut)
3888{
3889 struct player *pplayer;
3890 struct tile *psrctile;
3891 struct city *psrccity;
3892 struct city *pdestcity;
3893 struct unit *ptransporter;
3894 struct packet_unit_info src_info, dest_info;
3895 struct packet_unit_short_info src_sinfo, dest_sinfo;
3896 struct unit_move_data_list *plist =
3897 unit_move_data_list_new_full(unit_move_data_unref);
3898 struct unit_move_data *pdata;
3899 int saved_id;
3900 bool unit_lives;
3901 bool adj;
3902 enum direction8 facing;
3903
3904 /* Some checks. */
3905 fc_assert_ret_val(punit != NULL, FALSE);
3906 fc_assert_ret_val(pdesttile != NULL, FALSE);
3907
3908 pplayer = unit_owner(punit);
3909 saved_id = punit->id;
3910 psrctile = unit_tile(punit);
3911 adj = base_get_direction_for_step(&(wld.map), psrctile, pdesttile, &facing);
3912
3914
3915 /* Unload the unit if on a transport. */
3916 ptransporter = unit_transport_get(punit);
3917 if (ptransporter != NULL) {
3918 /* Unload unit _before_ setting the new tile! */
3920 /* Send updated information to anyone watching that transporter
3921 * was unloading cargo. */
3922 send_unit_info(NULL, ptransporter);
3923 }
3924
3925 /* Wakup units next to us before we move. */
3927
3928 /* Make info packets at 'psrctile'. */
3929 if (adj) {
3930 /* If tiles are adjacent, we will show the move to users able
3931 * to see it. */
3932 package_unit(punit, &src_info);
3934 }
3935
3936 /* Make new data for 'punit'. */
3937 pdata = unit_move_data(punit, psrctile, pdesttile);
3938 unit_move_data_list_prepend(plist, pdata);
3939
3940 /* Set unit orientation */
3941 if (adj) {
3942 /* Only change orientation when moving to adjacent tile */
3943 punit->facing = facing;
3944 }
3945
3946 /* Move magic. */
3947 punit->moved = TRUE;
3948 punit->moves_left = MAX(0, punit->moves_left - move_cost);
3949 if (punit->moves_left == 0 && !unit_has_orders(punit)) {
3950 /* The next order may not require any remaining move fragments. */
3952 }
3953
3954 /* No longer relevant. */
3956 punit->action_decision_want = ACT_DEC_NOTHING;
3957
3958 /* Claim ownership of fortress? */
3959 if (conquer_extras_allowed
3961 /* Yes. We claim *all* bases if there's *any* claimable base(s).
3962 * Even if original unit cannot claim other kind of bases, the
3963 * first claimed base will have influence over other bases,
3964 * or something like that. */
3965 tile_claim_bases(pdesttile, pplayer);
3966 }
3967
3968 /* Move all contained units. */
3969 unit_cargo_iterate(punit, pcargo) {
3970 pdata = unit_move_data(pcargo, psrctile, pdesttile);
3971 unit_move_data_list_append(plist, pdata);
3973
3974 /* Get data for 'punit'. */
3975 pdata = unit_move_data_list_front(plist);
3976
3977 /* Determine the players able to see the move(s), now that the player
3978 * vision has been increased. */
3979 if (adj) {
3980 /* Main unit for adjacent move: the move is visible for every player
3981 * able to see on the matching unit layer. */
3982 enum vision_layer vlayer = unit_type_get(punit)->vlayer;
3983
3984 players_iterate(oplayer) {
3985 if (map_is_known_and_seen(psrctile, oplayer, vlayer)
3986 || map_is_known_and_seen(pdesttile, oplayer, vlayer)) {
3987 BV_SET(pdata->can_see_unit, player_index(oplayer));
3988 BV_SET(pdata->can_see_move, player_index(oplayer));
3989 }
3991 }
3992
3993 unit_move_data_list_iterate(plist, pmove_data) {
3994
3995 unit_move_by_data(pmove_data, psrctile, pdesttile);
3996
3997 if (adj && pmove_data == pdata) {
3998 /* If positions are adjacent, we have already handled 'punit'. See
3999 * above. */
4000 continue;
4001 }
4002
4003 players_iterate(oplayer) {
4004 if ((adj
4005 && can_player_see_unit_at(oplayer, pmove_data->punit, psrctile,
4006 pmove_data != pdata))
4007 || can_player_see_unit_at(oplayer, pmove_data->punit, pdesttile,
4008 pmove_data != pdata)) {
4009 BV_SET(pmove_data->can_see_unit, player_index(oplayer));
4010 BV_SET(pmove_data->can_see_move, player_index(oplayer));
4011 }
4012 if (can_player_see_unit_at(oplayer, pmove_data->punit, psrctile,
4013 pmove_data != pdata)) {
4014 /* The unit was seen with its source tile even if it was
4015 * teleported. */
4016 BV_SET(pmove_data->can_see_unit, player_index(oplayer));
4017 }
4020
4021 /* Check timeout settings. */
4023 bool new_information_for_enemy = FALSE;
4024
4025 phase_players_iterate(penemy) {
4026 /* Increase the timeout if an enemy unit moves and the
4027 * timeoutaddenemymove setting is in use. */
4028 if (penemy->is_connected
4029 && pplayer != penemy
4030 && pplayers_at_war(pplayer, penemy)
4031 && BV_ISSET(pdata->can_see_move, player_index(penemy))) {
4032 new_information_for_enemy = TRUE;
4033 break;
4034 }
4036
4037 if (new_information_for_enemy) {
4039 }
4040 }
4041
4042 if (!adj
4043 && action_tgt_city(punit, pdesttile, FALSE)) {
4044 /* The unit can perform an action to the city at the destination tile.
4045 * A long distance move (like an airlift) doesn't ask what action to
4046 * perform before moving. Ask now. */
4047
4048 punit->action_decision_want = ACT_DEC_PASSIVE;
4049 punit->action_decision_tile = pdesttile;
4050 }
4051
4052 /* Notifications of the move to the clients. */
4053 if (adj) {
4054 /* Special case: 'punit' is moving to adjacent position. Then we show
4055 * 'punit' move to all users able to see 'psrctile' or 'pdesttile'. */
4056
4057 /* Make info packets at 'pdesttile'. */
4058 package_unit(punit, &dest_info);
4060
4062 struct player *aplayer = conn_get_player(pconn);
4063
4064 if (aplayer == NULL) {
4065 if (pconn->observer) {
4066 /* Global observers see all... */
4067 send_packet_unit_info(pconn, &src_info);
4068 send_packet_unit_info(pconn, &dest_info);
4069 }
4070 } else if (BV_ISSET(pdata->can_see_move, player_index(aplayer))) {
4071 if (aplayer == pplayer) {
4072 send_packet_unit_info(pconn, &src_info);
4073 send_packet_unit_info(pconn, &dest_info);
4074 } else {
4075 send_packet_unit_short_info(pconn, &src_sinfo, FALSE);
4076 send_packet_unit_short_info(pconn, &dest_sinfo, FALSE);
4077 }
4078 }
4080 }
4081
4082 /* Other moves. */
4083 unit_move_data_list_iterate(plist, pmove_data) {
4084 if (adj && pmove_data == pdata) {
4085 /* If positions are adjacent, we have already shown 'punit' move.
4086 * See above. */
4087 continue;
4088 }
4089
4090 /* Make info packets at 'pdesttile'. */
4091 package_unit(pmove_data->punit, &dest_info);
4092 package_short_unit(pmove_data->punit, &dest_sinfo,
4094
4096 struct player *aplayer = conn_get_player(pconn);
4097
4098 if (aplayer == NULL) {
4099 if (pconn->observer) {
4100 /* Global observers see all... */
4101 send_packet_unit_info(pconn, &dest_info);
4102 }
4103 } else if (BV_ISSET(pmove_data->can_see_move, player_index(aplayer))) {
4104 if (aplayer == pmove_data->powner) {
4105 send_packet_unit_info(pconn, &dest_info);
4106 } else {
4107 send_packet_unit_short_info(pconn, &dest_sinfo, FALSE);
4108 }
4109 }
4112
4113 /* Clear old vision. */
4114 unit_move_data_list_iterate(plist, pmove_data) {
4115 if (pmove_data->old_vision != NULL) {
4116 vision_clear_sight(pmove_data->old_vision);
4117 vision_free(pmove_data->old_vision);
4118 pmove_data->old_vision = NULL;
4119 }
4121
4122 /* Move consequences. */
4123 unit_move_data_list_iterate(plist, pmove_data) {
4124 struct unit *aunit = pmove_data->punit;
4125
4126 if (aunit != NULL
4127 && unit_owner(aunit) == pmove_data->powner
4128 && unit_tile(aunit) == pdesttile) {
4129 (void) unit_move_consequences(aunit, psrctile, pdesttile,
4130 pdata != pmove_data,
4131 conquer_city_allowed);
4132 }
4134
4135 unit_lives = (pdata->punit == punit);
4136
4137 /* Wakeup units and make contact. */
4138 if (unit_lives) {
4140 }
4141 maybe_make_contact(pdesttile, pplayer);
4142
4143 if (unit_lives) {
4144 /* Special checks for ground units in the ocean. */
4145 if (embark_to || !can_unit_survive_at_tile(&(wld.map), punit, pdesttile)) {
4146 if (embark_to != NULL) {
4147 ptransporter = embark_to;
4148 } else if (find_embark_target) {
4149 /* TODO: Consider to stop supporting find_embark_target and make all
4150 * callers that wants auto loading set embark_to. */
4151 ptransporter = transporter_for_unit(punit);
4152 } else {
4153 ptransporter = NULL;
4154 }
4155 if (ptransporter) {
4157
4158 /* Set activity to sentry if boarding a ship. */
4159 if (is_human(pplayer)
4161 && punit->ssa_controller == SSA_NONE
4162 && !can_unit_exist_at_tile(&(wld.map), punit, pdesttile)) {
4163 set_unit_activity(punit, ACTIVITY_SENTRY);
4164 }
4165
4166 send_unit_info(NULL, punit);
4167 }
4168 }
4169 }
4170
4171 /* Remove units going out of sight. */
4172 unit_move_data_list_iterate_rev(plist, pmove_data) {
4173 struct unit *aunit = pmove_data->punit;
4174
4175 if (aunit == NULL) {
4176 continue; /* Died! */
4177 }
4178
4179 players_iterate(aplayer) {
4180 if (BV_ISSET(pmove_data->can_see_unit, player_index(aplayer))
4181 && !can_player_see_unit(aplayer, aunit)) {
4182 unit_goes_out_of_sight(aplayer, aunit);
4183 }
4186
4187 /* Inform the owner's client about actor unit arrival. Can, depending on
4188 * the client settings, cause the client to start the process that makes
4189 * the action selection dialog pop up. */
4190 pdestcity = tile_city(pdesttile);
4191 if (pdestcity != NULL) {
4192 /* Arrival in a city counts. */
4193
4194 unit_move_data_list_iterate(plist, pmove_data) {
4195 struct unit *ptrans;
4196 bool ok;
4197 struct unit *act_unit;
4198 struct player *act_player;
4199
4200 act_unit = pmove_data->punit;
4201 act_player = unit_owner(act_unit);
4202
4203 if (act_unit == NULL
4204 || !unit_is_alive(act_unit->id)) {
4205 /* The unit died before reaching this point. */
4206 continue;
4207 }
4208
4209 if (unit_tile(act_unit) != pdesttile) {
4210 /* The unit didn't arrive at the destination tile. */
4211 continue;
4212 }
4213
4214 if (!is_human(act_player)) {
4215 /* Only humans need reminders. */
4216 continue;
4217 }
4218
4219 if (!unit_transported(act_unit)) {
4220 /* Don't show the action selection dialog again. Non transported
4221 * units are handled before they move to the tile. */
4222 continue;
4223 }
4224
4225 /* Open action dialog only if 'act_unit' and all its transporters
4226 * (recursively) don't have orders. */
4227 if (unit_has_orders(act_unit)) {
4228 /* The unit it self has orders. */
4229 continue;
4230 }
4231
4232 for (ptrans = unit_transport_get(act_unit);;
4233 ptrans = unit_transport_get(ptrans)) {
4234 if (NULL == ptrans) {
4235 /* No (recursive) transport has orders. */
4236 ok = TRUE;
4237 break;
4238 } else if (unit_has_orders(ptrans)) {
4239 /* A unit transporting the unit has orders */
4240 ok = FALSE;
4241 break;
4242 }
4243 }
4244
4245 if (!ok) {
4246 /* A unit transporting act_unit has orders. */
4247 continue;
4248 }
4249
4250 if (action_tgt_city(act_unit, pdesttile, FALSE)) {
4251 /* There is a valid target. */
4252
4253 act_unit->action_decision_want = ACT_DEC_PASSIVE;
4254 act_unit->action_decision_tile = pdesttile;
4255
4256 /* Let the client know that this unit wants the player to decide
4257 * what to do. */
4258 send_unit_info(player_reply_dest(act_player), act_unit);
4259 }
4261 }
4262
4263 unit_move_data_list_destroy(plist);
4264 /* Check cities at source and destination. */
4265 psrccity = tile_city(psrctile);
4266 if (psrccity != NULL) {
4267 refresh_dumb_city(psrccity);
4268 }
4269 if (pdestcity != NULL) {
4270 refresh_dumb_city(pdestcity);
4271 }
4272
4273 if (unit_lives) {
4274 /* Let the scripts run ... */
4275 script_server_signal_emit("unit_moved", punit, psrctile, pdesttile);
4276 unit_lives = unit_is_alive(saved_id);
4277 }
4278
4279 if (unit_lives) {
4280 /* Autoattack. */
4281 unit_lives = unit_survive_autoattack(punit);
4282 }
4283
4284 if (unit_lives && (enter_hut || frighten_hut)) {
4285 /* Is there a hut? */
4288 unit_lives = unit_is_alive(saved_id);
4289 }
4290
4292
4293 if (unit_lives) {
4294 CALL_FUNC_EACH_AI(unit_move_seen, punit);
4295 }
4296
4297 return unit_lives;
4298}
4299
4300/**********************************************************************/
4304 struct tile *ptile)
4305{
4306 return (is_non_allied_unit_tile(ptile, unit_owner(punit))
4308}
4309
4310/**********************************************************************/
4317{
4318 bool cancel = FALSE;
4319 int radius_sq = get_unit_vision_at(punit, unit_tile(punit), V_MAIN);
4320 struct player *pplayer = unit_owner(punit);
4321
4322 circle_iterate(&(wld.map), unit_tile(punit), radius_sq, ptile) {
4323 struct unit *penemy = tile_non_allied_unit(ptile, pplayer);
4324 struct vision_site *pdcity = map_get_player_site(ptile, pplayer);
4325
4326 if ((penemy && can_player_see_unit(pplayer, penemy))
4327 || (pdcity && !pplayers_allied(pplayer, vision_site_owner(pdcity))
4328 && pdcity->occupied)) {
4329 cancel = TRUE;
4330 break;
4331 }
4333
4334 return cancel;
4335}
4336
4337/**********************************************************************/
4345static inline bool player_is_watching(struct unit *punit, const bool fresh)
4346{
4347 /* The player just sent the orders to the unit. The unit has moves left.
4348 * It is therefore safe to assume that the player already is paying
4349 * attention to the unit. */
4350 return fresh && punit->moves_left > 0;
4351}
4352
4353/**********************************************************************/
4372bool execute_orders(struct unit *punit, const bool fresh)
4373{
4374 struct act_prob prob;
4375 bool performed;
4376 const char *name;
4377 bool res, last_order;
4378 int unitid = punit->id;
4379 struct player *pplayer = unit_owner(punit);
4380 int moves_made = 0;
4381 const struct civ_map *nmap = &(wld.map);
4382
4384
4385 if (punit->activity != ACTIVITY_IDLE) {
4386 /* Unit's in the middle of an activity; wait for it to finish. */
4388 return TRUE;
4389 }
4390
4391 log_debug("Executing orders for %s %d", unit_rule_name(punit), punit->id);
4392
4393 /* Any time the orders are canceled we should give the player a message. */
4394
4395 while (TRUE) {
4396 struct unit_order order;
4397
4398 struct action *oaction;
4399
4400 struct tile *dst_tile;
4401 struct city *tgt_city;
4402 struct unit *tgt_unit;
4403 int tgt_id;
4404 int sub_tgt_id;
4405 struct extra_type *pextra;
4406
4407 if (punit->done_moving) {
4408 log_debug(" stopping because we're done this turn");
4409 return TRUE;
4410 }
4411
4413 /* "Patrol" orders are stopped if an enemy is near. */
4414 cancel_orders(punit, " stopping because of nearby enemy");
4415 notify_player(pplayer, unit_tile(punit), E_UNIT_ORDERS, ftc_server,
4416 _("Orders for %s aborted as there are units nearby."),
4417 unit_link(punit));
4418 return TRUE;
4419 }
4420
4421 if (moves_made == punit->orders.length) {
4422 /* For repeating orders, don't repeat more than once per turn. */
4423 log_debug(" stopping because we ran a round");
4425 send_unit_info(NULL, punit);
4426 return TRUE;
4427 }
4428 moves_made++;
4429
4430 order = punit->orders.list[punit->orders.index];
4431
4432 /* An ORDER_PERFORM_ACTION that doesn't specify an action should not get
4433 * this far. */
4435 || action_id_exists(order.action)),
4436 continue);
4437
4438 switch (order.order) {
4439 case ORDER_MOVE:
4440 case ORDER_ACTION_MOVE:
4441 case ORDER_FULL_MP:
4442 if (0 == punit->moves_left) {
4443 log_debug(" stopping because of no more move points");
4444 return TRUE;
4445 }
4446 break;
4449 log_debug(" stopping. Not enough move points this turn");
4450 return TRUE;
4451 }
4452 break;
4453 case ORDER_ACTIVITY:
4454 case ORDER_LAST:
4455 /* Those actions don't require moves left. */
4456 break;
4457 }
4458
4459 last_order = (!punit->orders.repeat
4460 && punit->orders.index + 1 == punit->orders.length);
4461
4462 if (last_order) {
4463 /* Clear the orders before we engage in the move. That way any
4464 * has_orders checks will yield FALSE and this will be treated as
4465 * a normal move. This is important: for instance a caravan goto
4466 * will popup the caravan dialog on the last move only. */
4468 }
4469
4470 /* Advance the orders one step forward. This is needed because any
4471 * updates sent to the client as a result of the action should include
4472 * the new index value. Note that we have to send_unit_info somewhere
4473 * after this point so that the client is properly updated. */
4474 punit->orders.index++;
4475
4476 switch (order.order) {
4477 case ORDER_FULL_MP:
4479 /* If the unit doesn't have full MP then it just waits until the
4480 * next turn. We assume that the next turn it will have full MP
4481 * (there's no check for that). */
4483 log_debug(" waiting this turn");
4484 send_unit_info(NULL, punit);
4485 }
4486 break;
4487 case ORDER_ACTIVITY:
4488 {
4489 enum unit_activity activity = order.activity;
4490
4491 fc_assert(activity == ACTIVITY_SENTRY);
4492
4493 if (can_unit_do_activity(nmap, punit, activity)) {
4495 set_unit_activity(punit, activity);
4496 send_unit_info(NULL, punit);
4497
4498 break;
4499 }
4500 }
4501
4502 cancel_orders(punit, " orders canceled because of failed activity");
4503 notify_player(pplayer, unit_tile(punit), E_UNIT_ORDERS, ftc_server,
4504 _("Orders for %s aborted since they "
4505 "give an invalid activity."),
4506 unit_link(punit));
4507 return TRUE;
4508 case ORDER_MOVE:
4509 case ORDER_ACTION_MOVE:
4510 /* Move unit */
4511 if (!(dst_tile = mapstep(&(wld.map), unit_tile(punit), order.dir))) {
4512 cancel_orders(punit, " move order sent us to invalid location");
4513 notify_player(pplayer, unit_tile(punit), E_UNIT_ORDERS, ftc_server,
4514 _("Orders for %s aborted since they "
4515 "give an invalid location."),
4516 unit_link(punit));
4517 return TRUE;
4518 }
4519
4520 if (order.order != ORDER_ACTION_MOVE
4521 && maybe_cancel_goto_due_to_enemy(punit, dst_tile)) {
4522 /* Plain move required: no attack, trade route etc. */
4523 cancel_orders(punit, " orders canceled because of enemy");
4524 notify_player(pplayer, unit_tile(punit), E_UNIT_ORDERS, ftc_server,
4525 _("Orders for %s aborted as there "
4526 "are units in the way."),
4527 unit_link(punit));
4528 return TRUE;
4529 }
4530
4531 log_debug(" moving to %d,%d", TILE_XY(dst_tile));
4532 res = unit_move_handling(punit, dst_tile,
4533 order.order != ORDER_ACTION_MOVE);
4534 if (!player_unit_by_number(pplayer, unitid)) {
4535 log_debug(" unit died while moving.");
4536 /* A player notification should already have been sent. */
4537 return FALSE;
4538 }
4539
4540 if (res && !same_pos(dst_tile, unit_tile(punit))) {
4541 /* Movement succeeded but unit didn't move. */
4542 log_debug(" orders resulted in combat.");
4543 send_unit_info(NULL, punit);
4544 return TRUE;
4545 }
4546
4547 if (!res) {
4548 fc_assert(0 <= punit->moves_left);
4549
4550 /* Movement failed (ZOC, etc.) */
4551 cancel_orders(punit, " attempt to move failed.");
4552
4553 if (!player_is_watching(punit, fresh)
4554 /* The final move "failed" because the unit needs to ask the
4555 * player what action it should take.
4556 *
4557 * The action decision request notifies the player. Its
4558 * location at the unit's last order makes it clear to the
4559 * player who the decision is for. ("The Spy I sent to Berlin
4560 * has arrived.")
4561 *
4562 * A notification message is therefore redundant. */
4563 && !(last_order
4564 && punit->action_decision_want == ACT_DEC_ACTIVE
4565 && punit->action_decision_tile == dst_tile)) {
4566 /* The player may have missed this. No one else will announce it
4567 * in a satisfying manner. Inform the player. */
4568 notify_player(pplayer, unit_tile(punit),
4569 E_UNIT_ORDERS, ftc_server,
4570 _("Orders for %s aborted because of failed move."),
4571 unit_link(punit));
4572 }
4573
4574 return TRUE;
4575 }
4576 break;
4578 oaction = action_by_number(order.action);
4579
4580 /* Checked in unit_order_list_is_sane() */
4581 fc_assert_action(oaction != NULL, continue);
4582
4583 log_debug(" orders: doing action %s", action_rule_name(oaction));
4584
4585 dst_tile = index_to_tile(&(wld.map), order.target);
4586
4587 if (dst_tile == NULL) {
4588 /* Could be at the edge of the map while trying to target a tile
4589 * outside of it. */
4590
4591 cancel_orders(punit, " target location doesn't exist");
4592 illegal_action_msg(unit_owner(punit), E_UNIT_ORDERS, punit,
4593 order.action, dst_tile, NULL, NULL);
4594
4595 return TRUE;
4596 }
4597
4598 /* Get the target city from the target tile. */
4599 tgt_city = tile_city(dst_tile);
4600
4601 if (tgt_city == NULL
4602 && action_id_get_target_kind(order.action) == ATK_CITY) {
4603 /* This action targets a city but no city target was found. */
4604
4605 cancel_orders(punit, " perform action vs city with no city");
4606 illegal_action_msg(unit_owner(punit), E_UNIT_ORDERS, punit,
4607 order.action, dst_tile, tgt_city, NULL);
4608
4609 return TRUE;
4610 }
4611
4612 /* Get a target unit at the target tile. */
4613 tgt_unit = action_tgt_unit(punit, dst_tile, TRUE);
4614
4615 if (tgt_unit == NULL
4616 && action_id_get_target_kind(order.action) == ATK_UNIT) {
4617 /* This action targets a unit but no target unit was found. */
4618
4619 cancel_orders(punit, " perform action vs unit with no unit");
4620 illegal_action_msg(unit_owner(punit), E_UNIT_ORDERS, punit,
4621 order.action, dst_tile, tgt_city, tgt_unit);
4622
4623 return TRUE;
4624 }
4625
4626 /* Server side sub target assignment */
4627 if (oaction->target_complexity == ACT_TGT_COMPL_FLEXIBLE
4628 && order.sub_target == NO_TARGET) {
4629 /* Try to find a sub target. */
4630 sub_tgt_id = action_sub_target_id_for_action(oaction, punit);
4631 } else {
4632 /* The client should have specified a sub target if needed */
4633 sub_tgt_id = order.sub_target;
4634 }
4635
4636 /* Get a target extra at the target tile */
4637 pextra = (sub_tgt_id == NO_TARGET ?
4638 NULL :
4639 extra_by_number(sub_tgt_id));
4640
4641 if (action_get_sub_target_kind(oaction) == ASTK_EXTRA_NOT_THERE
4642 && pextra != NULL
4643 && action_creates_extra(oaction, pextra)
4644 && tile_has_extra(dst_tile, pextra)) {
4645 /* Already there. Move on to the next order. */
4646 break;
4647 }
4648
4649 if (action_get_sub_target_kind(oaction) == ASTK_EXTRA
4650 && pextra != NULL
4651 && action_removes_extra(oaction, pextra)
4652 && !tile_has_extra(dst_tile, pextra)) {
4653 /* Already not there. Move on to the next order. */
4654 break;
4655 }
4656
4657 /* No target selected. */
4658 tgt_id = -1;
4659
4660 /* Assume impossible until told otherwise. */
4661 prob = ACTPROB_IMPOSSIBLE;
4662
4663 switch (action_id_get_target_kind(order.action)) {
4664 case ATK_UNITS:
4665 prob = action_prob_vs_units(nmap, punit, order.action,
4666 dst_tile);
4667 tgt_id = dst_tile->index;
4668 break;
4669 case ATK_TILE:
4670 prob = action_prob_vs_tile(nmap, punit, order.action,
4671 dst_tile, pextra);
4672 tgt_id = dst_tile->index;
4673 break;
4674 case ATK_EXTRAS:
4675 prob = action_prob_vs_extras(nmap, punit, order.action,
4676 dst_tile, pextra);
4677 tgt_id = dst_tile->index;
4678 break;
4679 case ATK_CITY:
4680 prob = action_prob_vs_city(nmap, punit, order.action,
4681 tgt_city);
4682 tgt_id = tgt_city->id;
4683 break;
4684 case ATK_UNIT:
4685 prob = action_prob_vs_unit(nmap, punit, order.action,
4686 tgt_unit);
4687
4688 tgt_id = tgt_unit->id;
4689 break;
4690 case ATK_SELF:
4691 prob = action_prob_self(nmap, punit, order.action);
4692
4693 tgt_id = unitid;
4694 break;
4695 case ATK_COUNT:
4696 log_error("Invalid action target kind");
4697
4698 /* The check below will abort and cancel the orders because prob
4699 * was initialized to impossible above this switch statement. */
4700
4701 break;
4702 }
4703
4704 if (!action_prob_possible(prob)) {
4705 /* The player has enough information to know that this action is
4706 * against the rules. Don't risk any punishment by trying to
4707 * perform it. */
4708
4709 cancel_orders(punit, " illegal action");
4710 notify_player(pplayer, unit_tile(punit), E_UNIT_ORDERS, ftc_server,
4711 _("%s could not do %s to %s."),
4714 tile_link(dst_tile));
4715
4716 /* Try to explain what rule made it illegal. */
4717 illegal_action_msg(unit_owner(punit), E_BAD_COMMAND, punit,
4718 order.action, dst_tile, tgt_city, tgt_unit);
4719
4720 return TRUE;
4721 }
4722
4723 if (action_id_has_result_safe(order.action, ACTRES_FOUND_CITY)) {
4724 /* This action needs a name. */
4726 } else {
4727 /* This action doesn't need a name. */
4728 name = "";
4729 }
4730
4731 performed = unit_perform_action(pplayer,
4732 unitid,
4733 tgt_id,
4734 sub_tgt_id,
4735 name,
4736 order.action,
4737 ACT_REQ_PLAYER);
4738
4739 if (!player_unit_by_number(pplayer, unitid)) {
4740 /* The unit "died" while performing the action. */
4741 return FALSE;
4742 }
4743
4744 if (!performed) {
4745 /* The action wasn't performed as ordered. */
4746
4747 cancel_orders(punit, " failed action");
4748 notify_player(pplayer, unit_tile(punit), E_UNIT_ORDERS, ftc_server,
4749 _("Orders for %s aborted because "
4750 "doing %s to %s failed."),
4753 tile_link(dst_tile));
4754
4755 return TRUE;
4756 }
4757
4758 if (action_id_get_act_time(order.action, punit, dst_tile, pextra)
4760 /* Done at turn change. */
4762 send_unit_info(NULL, punit);
4763 break;
4764 }
4765
4766 break;
4767 case ORDER_LAST:
4768 /* Should be caught when loading the unit orders from the savegame or
4769 * when receiving the unit orders from the client. */
4770 fc_assert_msg(order.order != ORDER_LAST, "Invalid order: last.");
4771 cancel_orders(punit, " invalid order!");
4772 notify_player(pplayer, unit_tile(punit), E_UNIT_ORDERS, ftc_server,
4773 _("Your %s has invalid orders."),
4774 unit_link(punit));
4775 return TRUE;
4776 }
4777
4778 if (last_order) {
4780 log_debug(" stopping because orders are complete");
4781 return TRUE;
4782 }
4783
4784 if (punit->orders.index == punit->orders.length) {
4786 /* Start over. */
4787 log_debug(" repeating orders.");
4788 punit->orders.index = 0;
4789 }
4790 } /* end while */
4791}
4792
4793/**********************************************************************/
4800static int get_unit_vision_base(struct unit *punit, enum vision_layer vlayer,
4801 const int base)
4802{
4803 switch (vlayer) {
4804 case V_MAIN:
4805 return MAX(0, base);
4806 case V_INVIS:
4807 case V_SUBSURFACE:
4808 return CLIP(0, base, 2);
4809 case V_COUNT:
4810 break;
4811 }
4812
4813 log_error("Unsupported vision layer variant: %d.", vlayer);
4814
4815 return 0;
4816}
4817
4818/**********************************************************************/
4822 const struct tile *ptile)
4823{
4824 const struct unit_type *utype = unit_type_get(punit);
4825
4826 return (utype->vision_radius_sq
4828 utype, NULL,
4829 EFT_UNIT_VISION_RADIUS_SQ));
4830}
4831
4832/**********************************************************************/
4839int get_unit_vision_at(struct unit *punit, const struct tile *ptile,
4840 enum vision_layer vlayer)
4841{
4844}
4845
4846/**********************************************************************/
4853{
4854 struct vision *uvision = punit->server.vision;
4855 const struct tile *utile = unit_tile(punit);
4856 int mod = unit_vision_range_modifiers(punit, utile);
4857 const v_radius_t radius_sq =
4858 V_RADIUS(get_unit_vision_base(punit, V_MAIN, mod),
4859 get_unit_vision_base(punit, V_INVIS, mod),
4860 get_unit_vision_base(punit, V_SUBSURFACE, mod));
4861
4862 vision_change_sight(uvision, radius_sq);
4863 ASSERT_VISION(uvision);
4864}
4865
4866/**********************************************************************/
4869void unit_list_refresh_vision(struct unit_list *punitlist)
4870{
4871 unit_list_iterate(punitlist, punit) {
4874}
4875
4876/**********************************************************************/
4881{
4882 time_t dt;
4883
4884 if (!punit) {
4885 return FALSE;
4886 }
4887
4888 if (game.server.unitwaittime <= 0) {
4889 return TRUE;
4890 }
4891
4892 if (punit->server.action_turn != game.info.turn - 1) {
4893 return TRUE;
4894 }
4895
4896 dt = time(NULL) - punit->server.action_timestamp;
4897 if (dt < game.server.unitwaittime) {
4898 char buf[64];
4899 format_time_duration(game.server.unitwaittime - dt, buf, sizeof(buf));
4900 notify_player(unit_owner(punit), unit_tile(punit), E_BAD_COMMAND,
4901 ftc_server, _("Your unit may not act for another %s "
4902 "this turn. See /help unitwaittime."), buf);
4903 return FALSE;
4904 }
4905
4906 return TRUE;
4907}
4908
4909/**********************************************************************/
4914{
4915 if (!punit) {
4916 return;
4917 }
4918
4919 punit->server.action_timestamp = time(NULL);
4921}
4922
4923/**********************************************************************/
4929{
4930 /* check if there is enemy nearby */
4931 square_iterate(&(wld.map), unit_tile(punit), 3, ptile) {
4933 || is_enemy_unit_tile(ptile, unit_owner(punit))) {
4934 return FALSE;
4935 }
4936 }
4938
4939 return TRUE;
4940}
bool action_removes_extra(const struct action *paction, const struct extra_type *pextra)
Definition actions.c:2312
const char * action_name_translation(const struct action *action)
Definition actions.c:1890
bool action_mp_full_makes_legal(const struct unit *actor, const action_id act_id)
Definition actions.c:7220
const char * action_id_name_translation(action_id act_id)
Definition actions.c:1910
bool action_prob_possible(const struct act_prob probability)
Definition actions.c:6703
struct act_prob action_prob_vs_tile(const struct civ_map *nmap, const struct unit *actor_unit, const action_id act_id, const struct tile *target_tile, const struct extra_type *target_extra)
Definition actions.c:6224
const char * action_rule_name(const struct action *action)
Definition actions.c:1876
enum action_sub_target_kind action_get_sub_target_kind(const struct action *paction)
Definition actions.c:1751
struct act_prob action_prob_vs_extras(const struct civ_map *nmap, const struct unit *actor_unit, const action_id act_id, const struct tile *target_tile, const struct extra_type *target_extra)
Definition actions.c:6307
struct act_prob action_prob_self(const struct civ_map *nmap, const struct unit *actor_unit, const action_id act_id)
Definition actions.c:6377
struct act_prob action_prob_vs_units(const struct civ_map *nmap, const struct unit *actor_unit, const action_id act_id, const struct tile *target_tile)
Definition actions.c:6141
struct act_prob action_prob_vs_city(const struct civ_map *nmap, const struct unit *actor_unit, const action_id act_id, const struct city *target_city)
Definition actions.c:5870
bool action_id_exists(const action_id act_id)
Definition actions.c:1697
bool action_creates_extra(const struct action *paction, const struct extra_type *pextra)
Definition actions.c:2224
int action_prob_cmp_pessimist(const struct act_prob ap1, const struct act_prob ap2)
Definition actions.c:6763
struct act_prob action_prob_vs_unit(const struct civ_map *nmap, const struct unit *actor_unit, const action_id act_id, const struct unit *target_unit)
Definition actions.c:5953
double action_prob_to_0_to_1_pessimist(const struct act_prob ap)
Definition actions.c:6814
static struct action * action_by_number(action_id act_id)
Definition actions.h:638
#define action_has_result(_act_, _res_)
Definition actions.h:448
#define action_id_get_act_time(act_id, actor_unit, tgt_tile, tgt_extra)
Definition actions.h:683
#define ACTPROB_IMPOSSIBLE
Definition actions.h:939
#define action_id_get_target_kind(act_id)
Definition actions.h:655
#define action_id_has_result_safe(act_id, result)
Definition actions.h:668
void action_consequence_complete(const struct action *paction, struct player *offender, const struct unit_type *offender_utype, struct player *victim_player, const struct tile *victim_tile, const char *victim_link)
void action_consequence_caught(const struct action *paction, struct player *offender, const struct unit_type *offender_utype, struct player *victim_player, const struct tile *victim_tile, const char *victim_link)
struct act_prob action_auto_perf_unit_prob(const enum action_auto_perf_cause cause, struct unit *actor, const struct player *other_player, const struct output_type *eval_output, const struct action *eval_action, const struct tile *target_tile, const struct city *target_city, const struct unit *target_unit, const struct extra_type *target_extra)
const struct action * action_auto_perf_unit_do(const enum action_auto_perf_cause cause, struct unit *actor, const struct player *other_player, const struct output_type *eval_output, const struct action *eval_action, const struct tile *target_tile, const struct city *target_city, const struct unit *target_unit, const struct extra_type *target_extra)
struct unit * action_tgt_unit(struct unit *actor, struct tile *target_tile, bool accept_all_actions)
void action_consequence_success(const struct action *paction, struct player *offender, const struct unit_type *offender_utype, struct player *victim_player, const struct tile *victim_tile, const char *victim_link)
struct city * action_tgt_city(struct unit *actor, struct tile *target_tile, bool accept_all_actions)
int action_sub_target_id_for_action(const struct action *paction, struct unit *actor_unit)
bool adv_follow_path(struct unit *punit, struct pf_path *path, struct tile *ptile)
Definition advgoto.c:47
#define CALL_FUNC_EACH_AI(_func,...)
Definition ai.h:384
#define CALL_PLR_AI_FUNC(_func, _player,...)
Definition ai.h:374
#define n
Definition astring.c:77
enum unit_move_result manage_auto_explorer(struct unit *punit)
void adv_unit_new_task(struct unit *punit, enum adv_unit_task task, struct tile *ptile)
#define BV_CLR_ALL(bv)
Definition bitvector.h:95
#define BV_SET(bv, bit)
Definition bitvector.h:81
#define BV_ISSET(bv, bit)
Definition bitvector.h:78
#define BV_CLR(bv, bit)
Definition bitvector.h:86
const char * city_name_get(const struct city *pcity)
Definition city.c:1115
bool is_friendly_city_near(const struct civ_map *nmap, const struct player *owner, const struct tile *ptile)
Definition city.c:2065
bool city_exists_within_max_city_map(const struct civ_map *nmap, const struct tile *ptile, bool may_be_on_center)
Definition city.c:2084
#define city_list_iterate_safe(citylist, _city)
Definition city.h:502
static bool is_non_allied_city_tile(const struct tile *ptile, const struct player *pplayer)
Definition city.h:748
#define city_list_iterate(citylist, pcity)
Definition city.h:488
#define city_tile(_pcity_)
Definition city.h:544
static bool is_enemy_city_tile(const struct tile *ptile, const struct player *pplayer)
Definition city.h:712
static citizens city_size_get(const struct city *pcity)
Definition city.h:549
static bool is_allied_city_tile(const struct tile *ptile, const struct player *pplayer)
Definition city.h:724
#define output_type_iterate(output)
Definition city.h:821
#define city_owner(_pcity_)
Definition city.h:543
#define city_list_iterate_end
Definition city.h:490
#define city_list_iterate_safe_end
Definition city.h:524
#define output_type_iterate_end
Definition city.h:827
bool city_map_update_tile_now(struct tile *ptile)
Definition citytools.c:3229
const char * city_name_suggestion(struct player *pplayer, struct tile *ptile)
Definition citytools.c:456
void send_city_info(struct player *dest, struct city *pcity)
Definition citytools.c:2327
struct city * find_closest_city(const struct tile *ptile, const struct city *pexclcity, const struct player *pplayer, bool only_ocean, bool only_continent, bool only_known, bool only_player, bool only_enemy, const struct unit_class *pclass)
Definition citytools.c:854
void refresh_dumb_city(struct city *pcity)
Definition citytools.c:2188
void sync_cities(void)
Definition citytools.c:3238
bool unit_conquer_city(struct unit *punit, struct city *pcity)
Definition citytools.c:1963
void city_units_upkeep(const struct city *pcity)
Definition citytools.c:3026
bool transfer_city(struct player *ptaker, struct city *pcity, int kill_outside, bool transfer_unit_verbose, bool resolve_stack, bool raze, bool build_free)
Definition citytools.c:1070
bool city_reduce_size(struct city *pcity, citizens pop_loss, struct player *destroyer, const char *reason)
Definition cityturn.c:808
bool city_refresh(struct city *pcity)
Definition cityturn.c:161
bool is_unit_reachable_at(const struct unit *defender, const struct unit *attacker, const struct tile *location)
Definition combat.c:85
bool is_stack_vulnerable(const struct tile *ptile)
Definition combat.c:930
int get_virtual_defense_power(const struct civ_map *nmap, const struct unit_type *att_type, const struct unit_type *def_type, struct player *def_player, struct tile *ptile, bool fortified, int veteran)
Definition combat.c:659
int unit_bombard_rate(struct unit *punit)
Definition combat.c:961
int get_total_defense_power(const struct unit *attacker, const struct unit *defender)
Definition combat.c:714
int get_total_attack_power(const struct unit *attacker, const struct unit *defender)
Definition combat.c:569
double unit_win_chance(const struct civ_map *nmap, const struct unit *attacker, const struct unit *defender)
Definition combat.c:438
struct unit * get_defender(const struct civ_map *nmap, const struct unit *attacker, const struct tile *ptile)
Definition combat.c:783
void get_modified_firepower(const struct civ_map *nmap, const struct unit *attacker, const struct unit *defender, int *att_fp, int *def_fp)
Definition combat.c:369
struct player * conn_get_player(const struct connection *pconn)
Definition connection.c:760
void conn_list_do_unbuffer(struct conn_list *dest)
Definition connection.c:365
void conn_list_do_buffer(struct conn_list *dest)
Definition connection.c:355
bool conn_is_global_observer(const struct connection *pconn)
Definition connection.c:750
#define conn_list_iterate(connlist, pconn)
Definition connection.h:113
#define conn_list_iterate_end
Definition connection.h:115
static void base(QVariant data1, QVariant data2)
Definition dialogs.cpp:2840
static void enter_hut(QVariant data1, QVariant data2)
Definition dialogs.cpp:2571
static void frighten_hut(QVariant data1, QVariant data2)
Definition dialogs.cpp:2601
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 get_unit_bonus(const struct unit *punit, enum effect_type effect_type)
Definition effects.c:992
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
int get_player_bonus(const struct player *pplayer, enum effect_type effect_type)
Definition effects.c:771
struct extra_type * rand_extra_for_tile(struct tile *ptile, enum extra_cause cause, bool generated)
Definition extras.c:267
struct extra_type * prev_extra_in_tile(const struct tile *ptile, enum extra_rmcause rmcause, const struct player *pplayer, const struct unit *punit)
Definition extras.c:765
struct extra_type * extra_by_number(int id)
Definition extras.c:175
static struct extra_type extras[MAX_EXTRA_TYPES]
Definition extras.c:31
const char * extra_rule_name(const struct extra_type *pextra)
Definition extras.c:195
#define extra_type_list_iterate(extralist, pextra)
Definition extras.h:159
#define extra_type_by_rmcause_iterate_end
Definition extras.h:334
#define extra_index(_e_)
Definition extras.h:177
#define extra_type_by_rmcause_iterate(_rmcause, _extra)
Definition extras.h:329
#define EXTRA_NONE
Definition extras.h:82
#define extra_type_list_iterate_end
Definition extras.h:161
#define NO_TARGET
Definition fc_types.h:324
int Tech_type_id
Definition fc_types.h:347
#define ACT_TIME_INSTANTANEOUS
Definition fc_types.h:319
@ RPT_CERTAIN
Definition fc_types.h:586
@ AUT_NONE
Definition fc_types.h:340
@ HB_DISABLED
Definition fc_types.h:1142
#define IDENTITY_NUMBER_ZERO
Definition fc_types.h:82
#define PL_(String1, String2, n)
Definition fcintl.h:71
#define _(String)
Definition fcintl.h:67
const char * tile_link(const struct tile *ptile)
const struct ft_color ftc_server
const char * city_link(const struct city *pcity)
const char * unit_link(const struct unit *punit)
const char * unit_tile_link(const struct unit *punit)
#define MAX_LEN_LINK
struct civ_game game
Definition game.c:57
int current_turn_timeout(void)
Definition game.c:828
struct world wld
Definition game.c:58
void game_remove_unit(struct world *gworld, struct unit *punit)
Definition game.c:119
struct unit * game_unit_by_number(int id)
Definition game.c:111
struct city * game_city_by_number(int id)
Definition game.c:102
void increase_timeout_because_unit_moved(void)
Definition gamehand.c:1034
struct city * owner
Definition citydlg.c:219
GType type
Definition repodlgs.c:1312
bool has_handicap(const struct player *pplayer, enum handicap_type htype)
Definition handicaps.c:66
@ H_MAP
Definition handicaps.h:28
@ H_LIMITEDHUTS
Definition handicaps.h:20
void idex_register_unit(struct world *iworld, struct unit *punit)
Definition idex.c:81
const char * name
Definition inputfile.c:127
#define fc_assert_msg(condition, message,...)
Definition log.h:181
#define fc_assert_ret(condition)
Definition log.h:191
#define fc_assert_exit_msg(condition, message,...)
Definition log.h:211
#define log_test
Definition log.h:136
#define log_verbose(message,...)
Definition log.h:109
#define fc_assert(condition)
Definition log.h:176
#define fc_assert_ret_val(condition, val)
Definition log.h:194
#define fc_assert_action(condition, action)
Definition log.h:187
#define log_debug(message,...)
Definition log.h:115
#define log_error(message,...)
Definition log.h:103
int sq_map_distance(const struct tile *tile0, const struct tile *tile1)
Definition map.c:639
bool is_safe_ocean(const struct civ_map *nmap, const struct tile *ptile)
Definition map.c:665
struct tile * index_to_tile(const struct civ_map *imap, int mindex)
Definition map.c:454
bool same_pos(const struct tile *tile1, const struct tile *tile2)
Definition map.c:938
struct tile * mapstep(const struct civ_map *nmap, const struct tile *ptile, enum direction8 dir)
Definition map.c:369
bool base_get_direction_for_step(const struct civ_map *nmap, const struct tile *start_tile, const struct tile *end_tile, enum direction8 *dir)
Definition map.c:1326
#define adjc_iterate_end
Definition map.h:427
#define square_iterate(nmap, center_tile, radius, tile_itr)
Definition map.h:385
#define adjc_iterate(nmap, center_tile, itr_tile)
Definition map.h:422
#define square_iterate_end
Definition map.h:388
static int map_move_cost_unit(const struct civ_map *nmap, struct unit *punit, const struct tile *ptile)
Definition map.h:287
#define circle_iterate(nmap, center_tile, sq_radius, tile_itr)
Definition map.h:395
#define circle_iterate_end
Definition map.h:398
void vision_clear_sight(struct vision *vision)
Definition maphand.c:2517
void destroy_extra(struct tile *ptile, struct extra_type *pextra)
Definition maphand.c:2605
void bounce_units_on_terrain_change(struct tile *ptile)
Definition maphand.c:1903
void tile_claim_bases(struct tile *ptile, struct player *powner)
Definition maphand.c:2204
void create_extra(struct tile *ptile, struct extra_type *pextra, struct player *pplayer)
Definition maphand.c:2540
void tile_change_side_effects(struct tile *ptile, bool refresh_city)
Definition maphand.c:2708
bool map_is_known_and_seen(const struct tile *ptile, const struct player *pplayer, enum vision_layer vlayer)
Definition maphand.c:900
void map_show_circle(struct player *pplayer, struct tile *ptile, int radius_sq)
Definition maphand.c:856
void update_tile_knowledge(struct tile *ptile)
Definition maphand.c:1427
void check_terrain_change(struct tile *ptile, struct terrain *oldter)
Definition maphand.c:1979
bool give_distorted_map(struct player *pfrom, struct player *pto, int prob, bool reveal_cities)
Definition maphand.c:2680
struct vision_site * map_get_player_site(const struct tile *ptile, const struct player *pplayer)
Definition maphand.c:1359
struct player_tile * map_get_player_tile(const struct tile *ptile, const struct player *pplayer)
Definition maphand.c:1370
void vision_change_sight(struct vision *vision, const v_radius_t radius_sq)
Definition maphand.c:2505
#define FC_FREE(ptr)
Definition mem.h:41
#define fc_malloc(sz)
Definition mem.h:34
bool can_exist_at_tile(const struct civ_map *nmap, const struct unit_type *utype, const struct tile *ptile)
Definition movement.c:275
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
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
bool is_native_to_class(const struct unit_class *punitclass, const struct terrain *pterrain, const bv_extras *extras)
Definition movement.c:327
bool can_unit_survive_at_tile(const struct civ_map *nmap, const struct unit *punit, const struct tile *ptile)
Definition movement.c:476
@ MR_OK
Definition movement.h:33
@ MR_NOT_ALLOWED
Definition movement.h:50
@ MR_DEATH
Definition movement.h:34
static const char * name_translation_get(const struct name_translation *ptrans)
const char * nation_rule_name(const struct nation_type *pnation)
Definition nation.c:137
struct nation_type * nation_of_unit(const struct unit *punit)
Definition nation.c:462
const char * nation_adjective_for_player(const struct player *pplayer)
Definition nation.c:168
const char * nation_plural_for_player(const struct player *pplayer)
Definition nation.c:177
void notify_player(const struct player *pplayer, const struct tile *ptile, enum event_type event, const struct ft_color color, const char *format,...)
Definition notify.c:291
void notify_conn(struct conn_list *dest, const struct tile *ptile, enum event_type event, const struct ft_color color, const char *format,...)
Definition notify.c:238
unit_info_use
Definition packets.h:81
@ UNIT_INFO_IDENTITY
Definition packets.h:82
int send_packet_unit_remove(struct connection *pc, const struct packet_unit_remove *packet)
void lsend_packet_unit_remove(struct conn_list *dest, const struct packet_unit_remove *packet)
int send_packet_unit_short_info(struct connection *pc, const struct packet_unit_short_info *packet, bool force_to_send)
int send_packet_unit_info(struct connection *pc, const struct packet_unit_info *packet)
void dlsend_packet_unit_remove(struct conn_list *dest, int unit_id16, int unit_id32)
void pf_path_destroy(struct pf_path *path)
struct pf_map * pf_map_new(const struct pf_parameter *parameter)
struct pf_path * pf_map_path(struct pf_map *pfm, struct tile *ptile)
void pf_map_destroy(struct pf_map *pfm)
#define pf_map_move_costs_iterate_end
#define pf_map_move_costs_iterate(ARG_pfm, NAME_tile, NAME_cost, COND_from_start)
void pft_fill_unit_parameter(struct pf_parameter *parameter, const struct civ_map *nmap, const struct unit *punit)
Definition pf_tools.c:840
struct unit * player_unit_by_number(const struct player *pplayer, int unit_id)
Definition player.c:1205
struct player * player_by_number(const int player_id)
Definition player.c:840
bool can_player_see_unit_at(const struct player *pplayer, const struct unit *punit, const struct tile *ptile, bool is_transported)
Definition player.c:1025
int player_slot_count(void)
Definition player.c:411
int player_number(const struct player *pplayer)
Definition player.c:828
const char * player_name(const struct player *pplayer)
Definition player.c:886
bool can_player_see_unit(const struct player *pplayer, const struct unit *punit)
Definition player.c:1084
bool pplayers_at_war(const struct player *pplayer, const struct player *pplayer2)
Definition player.c:1364
int player_index(const struct player *pplayer)
Definition player.c:820
struct player_diplstate * player_diplstate_get(const struct player *plr1, const struct player *plr2)
Definition player.c:317
bool pplayers_allied(const struct player *pplayer, const struct player *pplayer2)
Definition player.c:1381
struct player_slot * slots
Definition player.c:50
bool pplayers_non_attack(const struct player *pplayer, const struct player *pplayer2)
Definition player.c:1435
#define players_iterate_end
Definition player.h:535
#define players_iterate(_pplayer)
Definition player.h:530
static bool is_barbarian(const struct player *pplayer)
Definition player.h:488
#define is_ai(plr)
Definition player.h:234
#define is_human(plr)
Definition player.h:233
void player_update_last_war_action(struct player *pplayer)
Definition plrhand.c:746
void player_status_add(struct player *plr, enum player_status pstatus)
Definition plrhand.c:3042
void maybe_make_contact(struct tile *ptile, struct player *pplayer)
Definition plrhand.c:2191
void send_player_info_c(struct player *src, struct conn_list *dest)
Definition plrhand.c:1000
struct conn_list * player_reply_dest(struct player *pplayer)
Definition plrhand.c:1425
#define phase_players_iterate(pplayer)
Definition plrhand.h:111
#define phase_players_iterate_end
Definition plrhand.h:116
#define fc_rand(_size)
Definition rand.h:34
bool are_reqs_active(const struct req_context *context, const struct player *other_player, const struct requirement_vector *reqs, const enum req_problem_type prob_type)
const char * research_advance_rule_name(const struct research *presearch, Tech_type_id tech)
Definition research.c:238
struct research * research_get(const struct player *pplayer)
Definition research.c:126
void script_server_signal_emit(const char *signal_name,...)
void script_server_remove_exported_object(void *object)
void flush_packets(void)
Definition sernet.c:379
void format_time_duration(time_t t, char *buf, int maxlen)
Definition shared.c:1957
#define CLIP(lower, current, upper)
Definition shared.h:57
#define ARRAY_SIZE(x)
Definition shared.h:85
#define MIN(x, y)
Definition shared.h:55
#define MAX(x, y)
Definition shared.h:54
int identity_number(void)
Definition srv_main.c:1952
enum action_result result
Definition actions.h:382
bv_action_sub_results sub_results
Definition actions.h:383
enum act_tgt_compl target_complexity
Definition actions.h:390
struct act_prob prob
Definition unittools.c:115
Definition city.h:309
int id
Definition city.h:315
struct player * owner
Definition city.h:312
int airlift
Definition city.h:365
struct tile * tile
Definition city.h:311
struct unit_list * units_supported
Definition city.h:391
int unitwaittime
Definition game.h:197
struct civ_game::@30::@34 server
struct conn_list * est_connections
Definition game.h:97
struct packet_game_info info
Definition game.h:89
int autoupgrade_veteran_loss
Definition game.h:131
int killunhomed
Definition game.h:153
bool savepalace
Definition game.h:186
int ransom_gold
Definition game.h:174
bool autoattack
Definition game.h:130
int timeoutaddenemymove
Definition game.h:207
enum gameloss_style gameloss_style
enum goods_selection_method goods_selection
enum happyborders_type happyborders
int nuke_defender_survival_chance_pct
bool only_real_fight_makes_veteran
enum airlifting_style airlifting_style
bool only_killing_makes_veteran
bool combat_odds_scaled_veterancy
int upkeep[O_LAST]
enum action_decision action_decision_want
struct unit_order orders[MAX_LEN_ROUTE]
enum unit_activity activity
Unit_type_id type
enum unit_activity changed_from
enum direction8 facing
enum server_side_agent ssa_controller
enum direction8 facing
enum diplstate_type type
Definition player.h:201
int units_killed
Definition player.h:112
int units_lost
Definition player.h:113
bv_extras extras
Definition maphand.h:36
struct vision_site * site
Definition maphand.h:31
struct terrain * terrain
Definition maphand.h:33
struct player * owner
Definition maphand.h:34
struct city_list * cities
Definition player.h:281
struct unit_list * units
Definition player.h:282
struct conn_list * connections
Definition player.h:298
int huts
Definition player.h:349
bool is_alive
Definition player.h:268
struct player_economic economic
Definition player.h:284
struct player_score score
Definition player.h:283
struct player::@69::@71 server
const struct player * player
Definition tile.h:49
int index
Definition tile.h:50
struct unit_list * units
Definition tile.h:57
struct unit_class::@85 cache
struct extra_type_list * refuel_extras
Definition unittype.h:155
bv_player can_see_unit
Definition unittools.c:95
struct player * powner
Definition unittools.c:94
bv_player can_see_move
Definition unittools.c:96
struct unit * punit
Definition unittools.c:93
struct vision * old_vision
Definition unittools.c:97
enum unit_activity activity
Definition unit.h:94
enum unit_orders order
Definition unit.h:93
int action
Definition unit.h:100
enum direction8 dir
Definition unit.h:102
int target
Definition unit.h:97
int sub_target
Definition unit.h:98
int vision_radius_sq
Definition unittype.h:503
enum vision_layer vlayer
Definition unittype.h:550
const struct unit_type * converted_to
Definition unittype.h:511
Definition unit.h:138
time_t action_timestamp
Definition unit.h:243
int length
Definition unit.h:195
int upkeep[O_LAST]
Definition unit.h:148
bool has_orders
Definition unit.h:193
enum action_decision action_decision_want
Definition unit.h:202
int battlegroup
Definition unit.h:191
enum unit_activity activity
Definition unit.h:157
int moves_left
Definition unit.h:150
int id
Definition unit.h:145
bool moved
Definition unit.h:173
int index
Definition unit.h:195
struct vision * vision
Definition unit.h:242
bool vigilant
Definition unit.h:197
int hp
Definition unit.h:151
struct unit::@79 orders
int fuel
Definition unit.h:153
struct extra_type * changed_from_target
Definition unit.h:170
bool stay
Definition unit.h:205
enum direction8 facing
Definition unit.h:142
struct tile * tile
Definition unit.h:140
struct extra_type * activity_target
Definition unit.h:164
int activity_count
Definition unit.h:162
struct unit_order * list
Definition unit.h:198
enum unit_activity changed_from
Definition unit.h:168
struct player * nationality
Definition unit.h:144
bool repeat
Definition unit.h:196
void(* removal_callback)(struct unit *punit)
Definition unit.h:251
struct unit_move_data * moving
Definition unit.h:245
int action_turn
Definition unit.h:244
struct unit::@80::@83 server
int homecity
Definition unit.h:146
bool paradropped
Definition unit.h:174
bool done_moving
Definition unit.h:181
int birth_turn
Definition unit.h:235
struct goods_type * carrying
Definition unit.h:186
struct tile * goto_tile
Definition unit.h:155
struct tile * action_decision_tile
Definition unit.h:203
const struct unit_type * utype
Definition unit.h:139
int veteran
Definition unit.h:152
int changed_from_count
Definition unit.h:169
bool dying
Definition unit.h:248
enum server_side_agent ssa_controller
Definition unit.h:172
int base_raise_chance
Definition unittype.h:471
struct name_translation name
Definition unittype.h:468
int work_raise_chance
Definition unittype.h:472
bool occupied
Definition vision.h:117
struct civ_map map
#define sz_strlcpy(dest, src)
Definition support.h:167
#define TRUE
Definition support.h:46
#define FALSE
Definition support.h:47
#define fc__fallthrough
Definition support.h:109
#define A_NONE
Definition tech.h:43
#define A_UNSET
Definition tech.h:48
Tech_type_id steal_a_tech(struct player *pplayer, struct player *victim, Tech_type_id preferred)
Definition techtools.c:1208
const char * terrain_name_translation(const struct terrain *pterrain)
Definition terrain.c:226
struct extra_type * get_preferred_pillage(bv_extras extras)
Definition terrain.c:538
void tile_add_extra(struct tile *ptile, const struct extra_type *pextra)
Definition tile.c:940
bool tile_has_not_aggressive_extra_for_unit(const struct tile *ptile, const struct unit_type *punittype)
Definition tile.c:193
bool tile_has_claimable_base(const struct tile *ptile, const struct unit_type *punittype)
Definition tile.c:209
bool tile_apply_activity(struct tile *ptile, Activity_type_id act, struct extra_type *tgt)
Definition tile.c:658
int tile_extras_defense_bonus(const struct tile *ptile, const struct unit_type *punittype)
Definition tile.c:227
int tile_activity_time(enum unit_activity activity, const struct tile *ptile, const struct extra_type *tgt)
Definition tile.c:412
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
#define TILE_XY(ptile)
Definition tile.h:42
static const bv_extras * tile_extras(const struct tile *ptile)
Definition tile.h:119
#define tile_continent(_tile)
Definition tile.h:91
#define tile_has_extra(ptile, pextra)
Definition tile.h:146
#define tile_owner(_tile)
Definition tile.h:95
struct goods_type * goods_from_city_to_unit(struct city *src, struct unit *punit)
Goods_type_id goods_index(const struct goods_type *pgood)
struct unit * tile_non_allied_unit(const struct tile *ptile, const struct player *pplayer)
Definition unit.c:1332
int get_transporter_occupancy(const struct unit *ptrans)
Definition unit.c:1767
void free_unit_orders(struct unit *punit)
Definition unit.c:1753
bool unit_is_alive(int id)
Definition unit.c:2237
int get_activity_rate_this_turn(const struct unit *punit)
Definition unit.c:505
bool unit_transport_load(struct unit *pcargo, struct unit *ptrans, bool force)
Definition unit.c:2354
void set_unit_activity(struct unit *punit, enum unit_activity new_activity)
Definition unit.c:1107
struct player * unit_nationality(const struct unit *punit)
Definition unit.c:1271
struct unit * unit_transport_get(const struct unit *pcargo)
Definition unit.c:2425
bool unit_transport_unload(struct unit *pcargo)
Definition unit.c:2374
int unit_gain_hitpoints(const struct unit *punit)
Definition unit.c:2167
bool can_unit_continue_current_activity(const struct civ_map *nmap, struct unit *punit)
Definition unit.c:845
struct unit * unit_virtual_create(struct player *pplayer, struct city *pcity, const struct unit_type *punittype, int veteran_level)
Definition unit.c:1617
bool can_unit_do_activity(const struct civ_map *nmap, const struct unit *punit, enum unit_activity activity)
Definition unit.c:872
void unit_virtual_destroy(struct unit *punit)
Definition unit.c:1713
void unit_tile_set(struct unit *punit, struct tile *ptile)
Definition unit.c:1281
enum unit_upgrade_result unit_upgrade_test(const struct civ_map *nmap, const struct unit *punit, bool is_free)
Definition unit.c:1972
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
struct unit_list * unit_transport_cargo(const struct unit *ptrans)
Definition unit.c:2435
bool unit_has_orders(const struct unit *punit)
Definition unit.c:204
struct unit * transporter_for_unit(const struct unit *pcargo)
Definition unit.c:1896
bool unit_can_convert(const struct civ_map *nmap, const struct unit *punit)
Definition unit.c:2019
bool activity_requires_target(enum unit_activity activity)
Definition unit.c:541
bool can_unit_do_activity_targeted(const struct civ_map *nmap, const struct unit *punit, enum unit_activity activity, struct extra_type *target)
Definition unit.c:911
#define unit_tile(_pu)
Definition unit.h:395
static bool is_enemy_unit_tile(const struct tile *ptile, const struct player *pplayer)
Definition unit.h:418
#define unit_cargo_iterate_end
Definition unit.h:570
@ ORDER_ACTION_MOVE
Definition unit.h:45
@ ORDER_ACTIVITY
Definition unit.h:41
@ ORDER_FULL_MP
Definition unit.h:43
@ ORDER_MOVE
Definition unit.h:39
@ ORDER_LAST
Definition unit.h:49
@ ORDER_PERFORM_ACTION
Definition unit.h:47
static bool is_allied_unit_tile(const struct tile *ptile, const struct player *pplayer)
Definition unit.h:406
#define unit_cargo_iterate(_ptrans, _pcargo)
Definition unit.h:567
#define CHECK_UNIT(punit)
Definition unit.h:268
#define unit_owner(_pu)
Definition unit.h:394
@ UU_OK
Definition unit.h:61
#define unit_home(_pu_)
Definition unit.h:393
static bool is_non_allied_unit_tile(const struct tile *ptile, const struct player *pplayer)
Definition unit.h:430
void illegal_action_msg(struct player *pplayer, const enum event_type event, struct unit *actor, const action_id stopped_action, const struct tile *target_tile, const struct city *target_city, const struct unit *target_unit)
Definition unithand.c:2352
bool unit_activity_handling(struct unit *punit, enum unit_activity new_activity)
Definition unithand.c:6179
bool unit_perform_action(struct player *pplayer, const int actor_id, const int target_id, const int sub_tgt_id_incoming, const char *name, const action_id action_type, const enum action_requester requester)
Definition unithand.c:3175
bool unit_move_handling(struct unit *punit, struct tile *pdesttile, bool move_do_not_act)
Definition unithand.c:5239
#define unit_list_iterate(unitlist, punit)
Definition unitlist.h:31
#define unit_list_iterate_safe(unitlist, _unit)
Definition unitlist.h:39
#define unit_list_iterate_end
Definition unitlist.h:33
#define unit_list_iterate_safe_end
Definition unitlist.h:61
void unit_did_action(struct unit *punit)
Definition unittools.c:4913
static void autoattack_prob_free(struct autoattack_prob *prob)
Definition unittools.c:3348
bool do_airline(struct unit *punit, struct city *pdest_city, const struct action *paction)
Definition unittools.c:2963
void place_partisans(struct tile *pcenter, struct player *powner, int count, int sq_radius)
Definition unittools.c:1177
static bool try_to_save_unit(struct unit *punit, const struct unit_type *pttype, bool helpless, bool teleporting, const struct city *pexclcity)
Definition unittools.c:2259
static void unit_move_by_data(struct unit_move_data *pdata, struct tile *psrctile, struct tile *pdesttile)
Definition unittools.c:3805
bool execute_orders(struct unit *punit, const bool fresh)
Definition unittools.c:4372
static void unit_convert(struct unit *punit)
Definition unittools.c:762
void update_unit_activities(struct player *pplayer)
Definition unittools.c:658
static void throw_units_from_illegal_cities(struct player *pplayer, bool verbose)
Definition unittools.c:1320
#define unit_move_data_list_iterate_rev_end
Definition unittools.c:107
void transform_unit(struct unit *punit, const struct unit_type *to_unit, int vet_loss)
Definition unittools.c:1565
static void server_remove_unit_full(struct unit *punit, bool transported, enum unit_loss_reason reason)
Definition unittools.c:1804
struct unit_list * get_units_seen_via_ally(const struct player *pplayer, const struct player *aplayer)
Definition unittools.c:1429
static bool is_refuel_tile(const struct tile *ptile, const struct player *pplayer, const struct unit *punit)
Definition unittools.c:1501
static void unit_lost_with_transport(const struct player *pplayer, struct unit *pcargo, const struct unit_type *ptransport, struct player *killer)
Definition unittools.c:1934
void remove_allied_visibility(struct player *pplayer, struct player *aplayer, const struct unit_list *seen_units)
Definition unittools.c:1464
static bool maybe_cancel_goto_due_to_enemy(struct unit *punit, struct tile *ptile)
Definition unittools.c:4303
void combat_veterans(struct unit *attacker, struct unit *defender, bool powerless, int att_vet, int def_vet)
Definition unittools.c:392
static int unit_vision_range_modifiers(struct unit *punit, const struct tile *ptile)
Definition unittools.c:4821
void resolve_unit_stacks(struct player *pplayer, struct player *aplayer, bool verbose)
Definition unittools.c:1414
static void unit_move_data_unref(struct unit_move_data *pdata)
Definition unittools.c:3855
void unit_set_removal_callback(struct unit *punit, void(*callback)(struct unit *punit))
Definition unittools.c:1781
void unit_bombs_unit(struct unit *attacker, struct unit *defender, int *att_hp, int *def_hp)
Definition unittools.c:352
static void unit_enter_hut(struct unit *punit, bool frighten_hut)
Definition unittools.c:3225
void package_unit(struct unit *punit, struct packet_unit_info *packet)
Definition unittools.c:2650
#define unit_move_data_list_iterate_end
Definition unittools.c:104
void unit_goes_out_of_sight(struct player *pplayer, struct unit *punit)
Definition unittools.c:2781
static void unit_restore_movepoints(struct player *pplayer, struct unit *punit)
Definition unittools.c:649
static void wakeup_neighbor_sentries(struct unit *punit)
Definition unittools.c:3547
static int total_activity(struct tile *ptile, enum unit_activity act, struct extra_type *tgt)
Definition unittools.c:706
void unit_activities_cancel_all_illegal_plr(const struct player *pplayer)
Definition unittools.c:806
static void unit_transport_load_tp_status(struct unit *punit, struct unit *ptrans, bool force)
Definition unittools.c:3306
#define autoattack_prob_list_iterate_safe_end
Definition unittools.c:131
static bool unit_survive_autoattack(struct unit *punit)
Definition unittools.c:3404
void finalize_unit_phase_beginning(struct player *pplayer)
Definition unittools.c:690
void execute_unit_orders(struct player *pplayer)
Definition unittools.c:668
static bool find_a_good_partisan_spot(struct tile *pcenter, struct player *powner, struct unit_type *u_type, int sq_radius, struct tile **dst_tile)
Definition unittools.c:1129
void send_unit_info(struct conn_list *dest, struct unit *punit)
Definition unittools.c:2794
static void wipe_unit_full(struct unit *punit, bool transported, enum unit_loss_reason reason, struct player *killer)
Definition unittools.c:1958
static void resolve_stack_conflicts(struct player *pplayer, struct player *aplayer, bool verbose)
Definition unittools.c:1385
static void check_unit_activity(struct unit *punit)
Definition unittools.c:3734
static void unit_restore_hitpoints(struct unit *punit)
Definition unittools.c:622
static void do_upgrade_effects(struct player *pplayer)
Definition unittools.c:416
int get_unit_vision_at(struct unit *punit, const struct tile *ptile, enum vision_layer vlayer)
Definition unittools.c:4839
bool unit_versus_unit(struct unit *attacker, struct unit *defender, int *att_hp, int *def_hp, int *att_vet, int *def_vet)
Definition unittools.c:286
bool place_unit(struct unit *punit, struct player *pplayer, struct city *pcity, struct unit *ptrans, bool force)
Definition unittools.c:1723
void notify_unit_experience(struct unit *punit)
Definition unittools.c:735
void unit_activities_cancel(struct unit *punit)
Definition unittools.c:788
void package_short_unit(struct unit *punit, struct packet_unit_short_info *packet, enum unit_info_use packet_use, int info_city_id)
Definition unittools.c:2733
struct unit * unit_virtual_prepare(struct player *pplayer, struct tile *ptile, const struct unit_type *type, int veteran_level, int homecity_id, int moves_left, int hp_left)
Definition unittools.c:1675
void give_allied_visibility(struct player *pplayer, struct player *aplayer)
Definition unittools.c:1488
void unit_forget_last_activity(struct unit *punit)
Definition unittools.c:1069
#define unit_move_data_list_iterate(_plist, _pdata)
Definition unittools.c:102
struct unit * create_unit_full(struct player *pplayer, struct tile *ptile, const struct unit_type *type, int veteran_level, int homecity_id, int moves_left, int hp_left, struct unit *ptrans)
Definition unittools.c:1642
static void server_remove_unit(struct unit *punit, enum unit_loss_reason reason)
Definition unittools.c:1925
void unit_unset_removal_callback(struct unit *punit)
Definition unittools.c:1795
bool maybe_make_veteran(struct unit *punit, int base_chance)
Definition unittools.c:217
void unit_refresh_vision(struct unit *punit)
Definition unittools.c:4852
struct unit * create_unit(struct player *pplayer, struct tile *ptile, const struct unit_type *type, int veteran_level, int homecity_id, int moves_left)
Definition unittools.c:1615
void do_explore(struct unit *punit)
Definition unittools.c:2996
void unit_transport_load_send(struct unit *punit, struct unit *ptrans)
Definition unittools.c:3276
bool unit_can_do_action_now(const struct unit *punit)
Definition unittools.c:4880
#define autoattack_prob_list_iterate_safe(autoattack_prob_list, _aap_, _unit_)
Definition unittools.c:122
void wipe_unit(struct unit *punit, enum unit_loss_reason reason, struct player *killer)
Definition unittools.c:2247
void unit_tc_effect_refresh(struct player *pplayer)
Definition unittools.c:680
bool do_paradrop(struct unit *punit, struct tile *ptile, const struct action *paction)
Definition unittools.c:3032
static bool player_is_watching(struct unit *punit, const bool fresh)
Definition unittools.c:4345
void player_restore_units(struct player *pplayer)
Definition unittools.c:469
void do_nuclear_explosion(struct player *pplayer, struct tile *ptile)
Definition unittools.c:2946
static void do_nuke_tile(struct player *pplayer, struct tile *ptile)
Definition unittools.c:2866
bool is_refuel_point(const struct tile *ptile, const struct player *pplayer, const struct unit *punit)
Definition unittools.c:1543
static void update_unit_activity(struct unit *punit)
Definition unittools.c:848
#define unit_move_data_list_iterate_rev(_plist, _pdata)
Definition unittools.c:105
void unit_transport_unload_send(struct unit *punit)
Definition unittools.c:3328
bool is_unit_being_refueled(const struct unit *punit)
Definition unittools.c:1534
struct unit_type * find_a_unit_type(enum unit_role_id role, enum unit_role_id role_tech)
Definition unittools.c:174
static void cancel_orders(struct unit *punit, char *dbg_msg)
Definition unittools.c:3536
bool unit_can_be_retired(struct unit *punit)
Definition unittools.c:4928
static bool total_activity_done(struct tile *ptile, enum unit_activity act, struct extra_type *tgt)
Definition unittools.c:726
void unit_activities_cancel_all_illegal_tile(const struct tile *ptile)
Definition unittools.c:818
struct unit * unit_change_owner(struct unit *punit, struct player *pplayer, int homecity, enum unit_loss_reason reason)
Definition unittools.c:2307
bool teleport_unit_to_city(struct unit *punit, struct city *pcity, int move_cost, bool verbose)
Definition unittools.c:1203
static int get_unit_vision_base(struct unit *punit, enum vision_layer vlayer, const int base)
Definition unittools.c:4800
static bool hut_get_limited(struct unit *punit)
Definition unittools.c:3190
void unit_assign_specific_activity_target(struct unit *punit, enum unit_activity *activity, struct extra_type **target)
Definition unittools.c:1098
static int compare_units(const struct autoattack_prob *const *p1, const struct autoattack_prob *const *q1)
Definition unittools.c:3362
void unit_activities_cancel_all_illegal_area(const struct tile *ptile)
Definition unittools.c:833
static bool unit_move_consequences(struct unit *punit, struct tile *src_tile, struct tile *dst_tile, bool passenger, bool conquer_city_allowed)
Definition unittools.c:3617
void unit_get_goods(struct unit *punit)
Definition unittools.c:1626
void send_all_known_units(struct conn_list *dest)
Definition unittools.c:2838
static bool maybe_become_veteran_real(struct unit *punit, int base_chance, bool settler)
Definition unittools.c:235
static bool maybe_cancel_patrol_due_to_enemy(struct unit *punit)
Definition unittools.c:4316
bool unit_move(struct unit *punit, struct tile *pdesttile, int move_cost, struct unit *embark_to, bool find_embark_target, bool conquer_city_allowed, bool conquer_extras_allowed, bool enter_hut, bool frighten_hut)
Definition unittools.c:3884
void unit_list_refresh_vision(struct unit_list *punitlist)
Definition unittools.c:4869
void kill_unit(struct unit *pkiller, struct unit *punit, bool vet)
Definition unittools.c:2373
void bounce_unit(struct unit *punit, bool verbose)
Definition unittools.c:1241
bool unit_activity_needs_target_from_client(enum unit_activity activity)
Definition unittools.c:1078
const struct unit_type * unit_type_get(const struct unit *punit)
Definition unittype.c:123
const char * unit_name_translation(const struct unit *punit)
Definition unittype.c:1621
struct unit_type * get_role_unit(int role, int role_index)
Definition unittype.c:2301
const char * unit_rule_name(const struct unit *punit)
Definition unittype.c:1639
const struct veteran_system * utype_veteran_system(const struct unit_type *punittype)
Definition unittype.c:2616
int num_role_units(int role)
Definition unittype.c:2251
bool utype_player_already_has_this_unique(const struct player *pplayer, const struct unit_type *putype)
Definition unittype.c:1979
const struct unit_type * can_upgrade_unittype(const struct player *pplayer, const struct unit_type *punittype)
Definition unittype.c:1755
bool can_player_build_unit_direct(const struct player *p, const struct unit_type *punittype)
Definition unittype.c:2015
struct unit_class * unit_class_get(const struct unit *punit)
Definition unittype.c:2547
bool unit_has_type_role(const struct unit *punit, enum unit_role_id role)
Definition unittype.c:202
bool unit_has_type_flag(const struct unit *punit, enum unit_type_flag_id flag)
Definition unittype.c:184
const struct veteran_level * vsystem_veteran_level(const struct veteran_system *vsystem, int level)
Definition unittype.c:2633
Unit_type_id utype_number(const struct unit_type *punittype)
Definition unittype.c:100
const char * utype_name_translation(const struct unit_type *punittype)
Definition unittype.c:1612
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 U_LAST
Definition unittype.h:40
struct vision * vision_new(struct player *pplayer, struct tile *ptile)
Definition vision.c:33
void vision_free(struct vision *vision)
Definition vision.c:50
#define ASSERT_VISION(v)
Definition vision.h:98
#define V_RADIUS(main_sq, invis_sq, subs_sq)
Definition vision.h:96
#define vision_site_owner(v)
Definition vision.h:128
short int v_radius_t[V_COUNT]
Definition vision.h:83