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/**********************************************************************/
353void unit_bombs_unit(struct unit *attacker, struct unit *defender,
354 int *att_hp, int *def_hp)
355{
356 int i;
357 int rate = unit_bombard_rate(attacker);
358 int attackpower = get_total_attack_power(attacker, defender);
359 int defensepower = get_total_defense_power(attacker, defender);
360 int attack_firepower, defense_firepower;
361 struct player *plr1 = unit_owner(attacker);
362 struct player *plr2 = unit_owner(defender);
363 struct civ_map *nmap = &(wld.map);
364
365 *att_hp = attacker->hp;
366 *def_hp = defender->hp;
367 get_modified_firepower(nmap, attacker, defender,
368 &attack_firepower, &defense_firepower);
369
370 log_verbose("attack:%d, defense:%d, attack firepower:%d, "
371 "defense firepower:%d", attackpower, defensepower,
372 attack_firepower, defense_firepower);
373
376
377 for (i = 0; i < rate; i++) {
378 if (fc_rand(attackpower + defensepower) >= defensepower) {
379 *def_hp -= attack_firepower;
380 }
381 }
382
383 /* Don't kill the target. */
384 if (*def_hp <= 0) {
385 *def_hp = 1;
386 }
387}
388
389/**********************************************************************/
393void combat_veterans(struct unit *attacker, struct unit *defender,
394 bool powerless, int att_vet, int def_vet)
395{
396 if (!powerless || !game.info.only_real_fight_makes_veteran) {
397 if (attacker->hp <= 0 || defender->hp <= 0
400 att_vet = 100;
401 def_vet = 100;
402 }
403 if (attacker->hp > 0) {
404 maybe_make_veteran(attacker, att_vet);
405 }
406 if (defender->hp > 0) {
407 maybe_make_veteran(defender, def_vet);
408 }
409 }
410 }
411}
412
413/**********************************************************************/
417static void do_upgrade_effects(struct player *pplayer)
418{
419 int upgrades = get_player_bonus(pplayer, EFT_UPGRADE_UNIT);
420 struct unit_list *candidates;
421
422 if (upgrades <= 0) {
423 return;
424 }
425 candidates = unit_list_new();
426
427 unit_list_iterate(pplayer->units, punit) {
428 /* We have to be careful not to strand units at sea, for example by
429 * upgrading a frigate to an ironclad while it was carrying a unit. */
430 if (UU_OK == unit_upgrade_test(&(wld.map), punit, TRUE)) {
431 unit_list_prepend(candidates, punit); /* Potential candidate :) */
432 }
434
435 while (upgrades > 0 && unit_list_size(candidates) > 0) {
436 /* Upgrade one unit. The unit is chosen at random from the list of
437 * available candidates. */
438 int candidate_to_upgrade = fc_rand(unit_list_size(candidates));
439 struct unit *punit = unit_list_get(candidates, candidate_to_upgrade);
440 const struct unit_type *type_from = unit_type_get(punit);
441 const struct unit_type *type_to = can_upgrade_unittype(pplayer, type_from);
442
444 notify_player(pplayer, unit_tile(punit), E_UNIT_UPGRADED, ftc_server,
445 _("%s was upgraded for free to %s."),
446 utype_name_translation(type_from),
448 unit_list_remove(candidates, punit);
449 upgrades--;
450 }
451
452 unit_list_destroy(candidates);
453}
454
455/**********************************************************************/
470void player_restore_units(struct player *pplayer)
471{
472 const struct civ_map *nmap = &(wld.map);
473
474 /* 1) get Leonardo out of the way first: */
475 do_upgrade_effects(pplayer);
476
478
479 /* 2) Modify unit hitpoints. Helicopters can even lose them. */
481
482 /* 3) Check that unit has hitpoints */
483 if (punit->hp <= 0) {
484 /* This should usually only happen for heli units, but if any other
485 * units get 0 hp somehow, catch them too. --dwp */
486 /* if 'game.server.killunhomed' is activated unhomed units are slowly
487 * killed; notify player here */
488 if (!punit->homecity && 0 < game.server.killunhomed) {
489 notify_player(pplayer, unit_tile(punit), E_UNIT_LOST_MISC,
490 ftc_server, _("Your %s has run out of hit points "
491 "because it was not supported by a city."),
493 } else {
494 notify_player(pplayer, unit_tile(punit), E_UNIT_LOST_MISC, ftc_server,
495 _("Your %s has run out of hit points."),
497 }
498
499 wipe_unit(punit, ULR_HP_LOSS, NULL);
500 continue; /* Continue iterating... */
501 }
502
503 /* 4) Rescue planes if needed */
505 /* Shall we emergency return home on the last vapors? */
506
507 /* I think this is strongly against the spirit of client goto.
508 * The problem is (again) that here we know too much. -- Zamar */
509
510 if (punit->fuel <= 1
512 struct unit *carrier;
513
514 carrier = transporter_for_unit(punit);
515 if (carrier) {
517 } else {
518 struct pf_map *pfm;
519 struct pf_parameter parameter;
520 bool alive = TRUE;
521
522 pft_fill_unit_parameter(&parameter, nmap, punit);
523 parameter.omniscience = !has_handicap(pplayer, H_MAP);
524 pfm = pf_map_new(&parameter);
525
526 pf_map_move_costs_iterate(pfm, ptile, move_cost, TRUE) {
527 if (move_cost > punit->moves_left) {
528 /* Too far */
529 break;
530 }
531
532 if (is_refuel_point(ptile, pplayer, punit)) {
533 struct pf_path *path;
534 int id = punit->id;
535
536 /* Client orders may be running for this unit - if so
537 * we free them before engaging goto. */
539
540 path = pf_map_path(pfm, ptile);
541
542 alive = adv_follow_path(punit, path, ptile);
543
544 if (!alive) {
545 log_error("rescue plane: unit %d died enroute!", id);
546 } else if (!same_pos(unit_tile(punit), ptile)) {
547 /* Enemy units probably blocked our route
548 * FIXME: We should try find alternative route around
549 * the enemy unit instead of just giving up and crashing. */
550 log_debug("rescue plane: unit %d could not move to "
551 "refuel point!", punit->id);
552 }
553
554 if (alive) {
555 /* Clear activity. Unit info will be sent in the end of
556 * the function. */
557 unit_activity_handling(punit, ACTIVITY_IDLE);
559 punit->goto_tile = NULL;
560
562 carrier = transporter_for_unit(punit);
563 if (carrier) {
565 }
566 }
567
568 notify_player(pplayer, unit_tile(punit),
569 E_UNIT_ORDERS, ftc_server,
570 _("Your %s has returned to refuel."),
572 }
573 pf_path_destroy(path);
574 break;
575 }
577 pf_map_destroy(pfm);
578
579 if (!alive) {
580 /* Unit died trying to move to refuel point. */
581 return;
582 }
583 }
584 }
585
586 /* 5) Update fuel */
587 punit->fuel--;
588
589 /* 6) Automatically refuel air units in cities, airbases, and
590 * transporters (carriers). */
593 }
594 }
596
597 /* 7) Check if there are air units without fuel */
599 const struct unit_type *utype = unit_type_get(punit);
600
601 if (punit->fuel <= 0 && utype_fuel(utype)) {
602 /* Notifications sent from the lua script when unit wiped. */
603 wipe_unit(punit, ULR_FUEL, NULL);
604 }
606
607 /* Send all updates. */
608 unit_list_iterate(pplayer->units, punit) {
609 send_unit_info(NULL, punit);
611}
612
613/**********************************************************************/
624{
625 bool was_lower;
626 const struct unit_type *utype = unit_type_get(punit);
627
628 was_lower = (punit->hp < utype->hp);
629
631
632 fc_assert(punit->hp >= 0);
633 fc_assert(punit->hp <= utype->hp);
634
635 if (punit->hp == utype->hp) {
636 if (was_lower && punit->activity == ACTIVITY_SENTRY) {
637 set_unit_activity(punit, ACTIVITY_IDLE);
638 }
639 }
640
641 punit->moved = FALSE;
643}
644
645/**********************************************************************/
650static void unit_restore_movepoints(struct player *pplayer, struct unit *punit)
651{
654}
655
656/**********************************************************************/
665
666/**********************************************************************/
669void execute_unit_orders(struct player *pplayer)
670{
672 if (unit_has_orders(punit)) {
674 }
676}
677
678/**********************************************************************/
681void unit_tc_effect_refresh(struct player *pplayer)
682{
683 unit_list_iterate(pplayer->units, punit) {
686}
687
688/**********************************************************************/
692{
693 /* Remember activities only after all knock-on effects of unit activities
694 * on other units have been resolved */
695 unit_list_iterate(pplayer->units, punit) {
699 send_unit_info(NULL, punit);
701}
702
703/**********************************************************************/
707static int total_activity(struct tile *ptile, enum unit_activity act,
708 struct extra_type *tgt)
709{
710 int total = 0;
711 bool tgt_matters = activity_requires_target(act);
712
713 unit_list_iterate(ptile->units, punit) {
714 if (punit->activity == act
715 && (!tgt_matters || punit->activity_target == tgt)) {
716 total += punit->activity_count;
717 }
719
720 return total;
721}
722
723/**********************************************************************/
727static bool total_activity_done(struct tile *ptile, enum unit_activity act,
728 struct extra_type *tgt)
729{
730 return total_activity(ptile, act, tgt) >= tile_activity_time(act, ptile, tgt);
731}
732
733/**********************************************************************/
737{
738 const struct veteran_level *vlevel;
739 const struct veteran_system *vsystem;
740
741 if (!punit) {
742 return;
743 }
744
746 fc_assert_ret(vsystem != NULL);
747 fc_assert_ret(vsystem->levels > punit->veteran);
748
749 vlevel = vsystem_veteran_level(vsystem, punit->veteran);
750 fc_assert_ret(vlevel != NULL);
751
753 E_UNIT_BECAME_VET, ftc_server,
754 /* TRANS: Your <unit> became ... rank of <veteran level>. */
755 _("Your %s became more experienced and achieved the rank "
756 "of %s."),
758}
759
760/**********************************************************************/
763static void unit_convert(struct unit *punit)
764{
765 const struct unit_type *to_type;
766 const struct unit_type *from_type;
767
768 from_type = unit_type_get(punit);
769 to_type = from_type->converted_to;
770
771 if (unit_can_convert(&(wld.map), punit)) {
772 transform_unit(punit, to_type, 0);
774 E_UNIT_UPGRADED, ftc_server,
775 _("%s converted to %s."),
776 utype_name_translation(from_type),
777 utype_name_translation(to_type));
778 } else {
780 E_UNIT_UPGRADED, ftc_server,
781 _("%s cannot be converted."),
782 utype_name_translation(from_type));
783 }
784}
785
786/**********************************************************************/
790{
791 if (unit_has_orders(punit)) {
793 E_UNIT_ORDERS, ftc_server,
794 _("Orders for %s aborted because activity "
795 "is no longer available."),
798 }
799
800 set_unit_activity(punit, ACTIVITY_IDLE);
801 send_unit_info(NULL, punit);
802}
803
804/**********************************************************************/
815
816/**********************************************************************/
827
828/**********************************************************************/
842
843/**********************************************************************/
849static void update_unit_activity(struct unit *punit)
850{
851 struct player *pplayer = unit_owner(punit);
852 bool unit_activity_done = FALSE;
853 enum unit_activity activity = punit->activity;
854 struct tile *ptile = unit_tile(punit);
855 const struct unit_type *act_utype = unit_type_get(punit);
856
857 switch (activity) {
858 case ACTIVITY_IDLE:
859 case ACTIVITY_EXPLORE:
860 case ACTIVITY_FORTIFIED:
861 case ACTIVITY_SENTRY:
862 case ACTIVITY_GOTO:
863 case ACTIVITY_PATROL_UNUSED:
864 case ACTIVITY_UNKNOWN:
865 case ACTIVITY_LAST:
866 /* We don't need the activity_count for the above */
867 break;
868
869 case ACTIVITY_FORTIFYING:
870 case ACTIVITY_CONVERT:
872 break;
873
874 case ACTIVITY_POLLUTION:
875 case ACTIVITY_MINE:
876 case ACTIVITY_IRRIGATE:
877 case ACTIVITY_PILLAGE:
878 case ACTIVITY_CULTIVATE:
879 case ACTIVITY_PLANT:
880 case ACTIVITY_TRANSFORM:
881 case ACTIVITY_FALLOUT:
882 case ACTIVITY_BASE:
883 case ACTIVITY_GEN_ROAD:
885
886 /* settler may become veteran when doing something useful */
889 }
890 break;
891 case ACTIVITY_OLD_ROAD:
892 case ACTIVITY_OLD_RAILROAD:
893 case ACTIVITY_FORTRESS:
894 case ACTIVITY_AIRBASE:
896 break;
897 };
898
900
901 switch (activity) {
902 case ACTIVITY_IDLE:
903 case ACTIVITY_FORTIFIED:
904 case ACTIVITY_SENTRY:
905 case ACTIVITY_GOTO:
906 case ACTIVITY_UNKNOWN:
907 case ACTIVITY_FORTIFYING:
908 case ACTIVITY_CONVERT:
909 case ACTIVITY_PATROL_UNUSED:
910 case ACTIVITY_LAST:
911 /* no default, ensure all handled */
912 break;
913
914 case ACTIVITY_EXPLORE:
916 return;
917
918 case ACTIVITY_PILLAGE:
919 if (total_activity_done(ptile, ACTIVITY_PILLAGE,
922 unit_activity_done = TRUE;
923
925
926 /* Change vision if effects have changed. */
928 }
929 break;
930
931 case ACTIVITY_POLLUTION:
932 /* TODO: Remove this fallback target setting when target always correctly
933 * set */
934 if (punit->activity_target == NULL) {
935 punit->activity_target = prev_extra_in_tile(ptile, ERM_CLEANPOLLUTION,
936 NULL, punit);
937 }
938 if (total_activity_done(ptile, ACTIVITY_POLLUTION, punit->activity_target)) {
940 unit_activity_done = TRUE;
941 }
942 break;
943
944 case ACTIVITY_FALLOUT:
945 /* TODO: Remove this fallback target setting when target always correctly
946 * set */
947 if (punit->activity_target == NULL) {
948 punit->activity_target = prev_extra_in_tile(ptile, ERM_CLEANFALLOUT,
949 NULL, punit);
950 }
951 if (total_activity_done(ptile, ACTIVITY_FALLOUT, punit->activity_target)) {
953 unit_activity_done = TRUE;
954 }
955 break;
956
957 case ACTIVITY_BASE:
958 {
959 if (total_activity(ptile, ACTIVITY_BASE, punit->activity_target)
960 >= tile_activity_time(ACTIVITY_BASE, ptile, punit->activity_target)) {
962 unit_activity_done = TRUE;
963 }
964 }
965 break;
966
967 case ACTIVITY_GEN_ROAD:
968 {
969 if (total_activity(ptile, ACTIVITY_GEN_ROAD, punit->activity_target)
970 >= tile_activity_time(ACTIVITY_GEN_ROAD, ptile, punit->activity_target)) {
972 unit_activity_done = TRUE;
973 }
974 }
975 break;
976
977 case ACTIVITY_IRRIGATE:
978 case ACTIVITY_MINE:
979 case ACTIVITY_CULTIVATE:
980 case ACTIVITY_PLANT:
981 case ACTIVITY_TRANSFORM:
982 if (total_activity_done(ptile, activity, punit->activity_target)) {
983 struct terrain *old = tile_terrain(ptile);
984
985 /* The function below could change the terrain. Therefore, we have to
986 * check the terrain (which will also do a sanity check for the tile). */
987 tile_apply_activity(ptile, activity, punit->activity_target);
988 check_terrain_change(ptile, old);
989 unit_activity_done = TRUE;
990 }
991 break;
992
993 case ACTIVITY_OLD_ROAD:
994 case ACTIVITY_OLD_RAILROAD:
995 case ACTIVITY_FORTRESS:
996 case ACTIVITY_AIRBASE:
998 break;
999 }
1000
1001 if (unit_activity_done) {
1002 update_tile_knowledge(ptile);
1003 if (ACTIVITY_CULTIVATE == activity
1004 || ACTIVITY_PLANT == activity
1005 || ACTIVITY_TRANSFORM == activity) {
1006 unit_list_iterate(ptile->units, punit2) {
1007 if (punit2->activity == activity) {
1009
1010 set_unit_activity(punit2, ACTIVITY_IDLE);
1011 }
1013 } else {
1014 struct extra_type *act_tgt = punit->activity_target;
1015
1016 unit_list_iterate(ptile->units, punit2) {
1017 if (punit2->activity == activity
1018 && punit2->activity_target == act_tgt) {
1019 /* This unit was helping with the work just finished.
1020 * Mark it idle (already finished) so its "current"
1021 * activity is not considered illegal
1022 * in tile_change_side_effects() . */
1023 set_unit_activity(punit2, ACTIVITY_IDLE);
1024 }
1026 }
1027
1029 }
1030
1031 if (activity == ACTIVITY_FORTIFYING) {
1033 >= action_id_get_act_time(ACTION_FORTIFY,
1034 punit, ptile, punit->activity_target)) {
1035 set_unit_activity(punit, ACTIVITY_FORTIFIED);
1036 unit_activity_done = TRUE;
1037 }
1038 }
1039
1040 if (activity == ACTIVITY_CONVERT) {
1042 >= action_id_get_act_time(ACTION_CONVERT,
1043 punit, ptile, punit->activity_target)) {
1045 set_unit_activity(punit, ACTIVITY_IDLE);
1046 unit_activity_done = TRUE;
1047 }
1048 }
1049
1050 if (unit_activity_done) {
1051 if (activity == ACTIVITY_PILLAGE) {
1052 /* Casus Belli for when the action is completed. */
1053 /* TODO: is it more logical to put Casus_Belli_Success here, change
1054 * Casus_Belli_Complete to Casus_Belli_Successful_Beginning and
1055 * trigger it when an activity successfully has began? */
1058 act_utype,
1062 }
1063 }
1064}
1065
1066/**********************************************************************/
1071{
1072 punit->changed_from = ACTIVITY_IDLE;
1073}
1074
1075/**********************************************************************/
1079bool unit_activity_needs_target_from_client(enum unit_activity activity)
1080{
1081 switch (activity) {
1082 case ACTIVITY_PILLAGE:
1083 /* Can be set server side. */
1084 return FALSE;
1085 default:
1086 return activity_requires_target(activity);
1087 }
1088}
1089
1090/**********************************************************************/
1100 enum unit_activity *activity,
1101 struct extra_type **target)
1102{
1103 const struct civ_map *nmap = &(wld.map);
1104
1105 if (*activity == ACTIVITY_PILLAGE
1106 && *target == NULL) {
1107 struct tile *ptile = unit_tile(punit);
1108 struct extra_type *tgt;
1109 bv_extras extras = *tile_extras(ptile);
1110
1111 while ((tgt = get_preferred_pillage(extras))) {
1112
1113 BV_CLR(extras, extra_index(tgt));
1114
1115 if (can_unit_do_activity_targeted(nmap, punit, *activity, tgt)) {
1116 *target = tgt;
1117 return;
1118 }
1119 }
1120
1121 /* Nothing we can pillage here. */
1122 *activity = ACTIVITY_IDLE;
1123 }
1124}
1125
1126/**********************************************************************/
1130static bool find_a_good_partisan_spot(struct tile *pcenter,
1131 struct player *powner,
1132 struct unit_type *u_type,
1133 int sq_radius,
1134 struct tile **dst_tile)
1135{
1136 int bestvalue = 0;
1137 struct civ_map *nmap = &(wld.map);
1138
1139 /* coords of best tile in arg pointers */
1140 circle_iterate(nmap, pcenter, sq_radius, ptile) {
1141 int value;
1142
1143 if (!is_native_tile(u_type, ptile)) {
1144 continue;
1145 }
1146
1147 if (NULL != tile_city(ptile)) {
1148 continue;
1149 }
1150
1151 if (0 < unit_list_size(ptile->units)) {
1152 continue;
1153 }
1154
1155 /* City may not have changed hands yet; see place_partisans(). */
1156 value = get_virtual_defense_power(nmap, NULL, u_type, powner,
1157 ptile, FALSE, 0);
1158 value *= 10;
1159
1160 if (tile_continent(ptile) != tile_continent(pcenter)) {
1161 value /= 2;
1162 }
1163
1164 value -= fc_rand(value/3);
1165
1166 if (value > bestvalue) {
1167 *dst_tile = ptile;
1168 bestvalue = value;
1169 }
1171
1172 return bestvalue > 0;
1173}
1174
1175/**********************************************************************/
1178void place_partisans(struct tile *pcenter, struct player *powner,
1179 int count, int sq_radius)
1180{
1181 struct tile *ptile = NULL;
1182 struct unit_type *u_type = get_role_unit(L_PARTISAN, 0);
1183 const struct civ_map *nmap = &(wld.map);
1184
1185 while (count-- > 0
1186 && find_a_good_partisan_spot(pcenter, powner, u_type,
1187 sq_radius, &ptile)) {
1188 struct unit *punit;
1189
1190 punit = unit_virtual_prepare(powner, ptile, u_type, 0, 0, -1, -1);
1191 if (can_unit_do_activity(nmap, punit, ACTIVITY_FORTIFYING)) {
1192 punit->activity = ACTIVITY_FORTIFIED; /* Yes; directly fortified */
1193 }
1194
1195 (void) place_unit(punit, powner, NULL, NULL, FALSE);
1196 }
1197}
1198
1199/**********************************************************************/
1204bool teleport_unit_to_city(struct unit *punit, struct city *pcity,
1205 int move_cost, bool verbose)
1206{
1207 struct tile *src_tile = unit_tile(punit), *dst_tile = pcity->tile;
1208
1209 if (city_owner(pcity) == unit_owner(punit)) {
1210 log_verbose("Teleported %s %s from (%d,%d) to %s",
1212 unit_rule_name(punit), TILE_XY(src_tile), city_name_get(pcity));
1213 if (verbose) {
1215 E_UNIT_RELOCATED, ftc_server,
1216 _("Teleported your %s to %s."),
1218 city_link(pcity));
1219 }
1220
1221 /* Silently free orders since they won't be applicable anymore. */
1223
1224 if (move_cost == -1) {
1225 move_cost = punit->moves_left;
1226 }
1227 unit_move(punit, dst_tile, move_cost,
1228 NULL, FALSE, FALSE, FALSE, FALSE, FALSE);
1229
1230 return TRUE;
1231 }
1232 return FALSE;
1233}
1234
1235/**********************************************************************/
1242void bounce_unit(struct unit *punit, bool verbose)
1243{
1244 struct player *pplayer;
1245 struct tile *punit_tile;
1246 int count = 0;
1247
1248 /* I assume that there are no topologies that have more than
1249 * (2d + 1)^2 tiles in the "square" of "radius" d. */
1250 const int DIST = 2;
1251 struct tile *tiles[(2 * DIST + 1) * (2 * DIST + 1)];
1252
1253 if (!punit) {
1254 return;
1255 }
1256
1257 pplayer = unit_owner(punit);
1258 punit_tile = unit_tile(punit);
1259
1260 square_iterate(&(wld.map), punit_tile, DIST, ptile) {
1261 if (count >= ARRAY_SIZE(tiles)) {
1262 break;
1263 }
1264
1265 if (ptile == punit_tile) {
1266 continue;
1267 }
1268
1269 if (can_unit_survive_at_tile(&(wld.map), punit, ptile)
1270 && !is_non_allied_city_tile(ptile, pplayer)
1271 && !is_non_allied_unit_tile(ptile, pplayer)) {
1272 tiles[count++] = ptile;
1273 }
1275
1276 if (count > 0) {
1277 struct tile *ptile = tiles[fc_rand(count)];
1278
1279 if (verbose) {
1280 notify_player(pplayer, ptile, E_UNIT_RELOCATED, ftc_server,
1281 /* TRANS: A unit is moved to resolve stack conflicts. */
1282 _("Moved your %s."),
1283 unit_link(punit));
1284 }
1285
1286 /* TODO: should a unit be able to bounce to a transport like is done
1287 * below? What if the unit can't legally enter the transport, say
1288 * because the transport is Unreachable and the unit doesn't have it in
1289 * its embarks field or because "Transport Embark" isn't enabled? Kept
1290 * like it was to preserve the old rules for now. -- Sveinung */
1291 unit_move(punit, ptile, 0, NULL, TRUE, FALSE, FALSE, FALSE, FALSE);
1292 return;
1293 }
1294
1295 /* Didn't find a place to bounce the unit, going to disband it.
1296 * Try to bounce transported units. */
1298 struct unit_list *pcargo_units;
1299
1300 pcargo_units = unit_transport_cargo(punit);
1301 unit_list_iterate_safe(pcargo_units, pcargo) {
1302 bounce_unit(pcargo, verbose);
1304 }
1305
1306 if (verbose) {
1307 notify_player(pplayer, punit_tile, E_UNIT_LOST_MISC, ftc_server,
1308 /* TRANS: A unit is disbanded to resolve stack conflicts. */
1309 _("Disbanded your %s."),
1311 }
1312
1313 wipe_unit(punit, ULR_STACK_CONFLICT, NULL);
1314}
1315
1316/**********************************************************************/
1321static void throw_units_from_illegal_cities(struct player *pplayer,
1322 bool verbose)
1323{
1324 struct tile *ptile;
1325 struct city *pcity;
1326 struct unit *ptrans;
1327 struct unit_list *pcargo_units;
1328
1329 /* Unload undesired units from transports, if possible. */
1330 unit_list_iterate(pplayer->units, punit) {
1331 ptile = unit_tile(punit);
1332 pcity = tile_city(ptile);
1333 if (NULL != pcity
1334 && !pplayers_allied(city_owner(pcity), pplayer)
1336 pcargo_units = unit_transport_cargo(punit);
1337 unit_list_iterate(pcargo_units, pcargo) {
1338 if (!pplayers_allied(unit_owner(pcargo), pplayer)) {
1339 if (can_unit_exist_at_tile(&(wld.map), pcargo, ptile)) {
1341 }
1342 }
1344 }
1346
1347 /* Bounce units except transported ones which will be bounced with their
1348 * transport. */
1350 ptile = unit_tile(punit);
1351 pcity = tile_city(ptile);
1352 if (NULL != pcity
1353 && !pplayers_allied(city_owner(pcity), pplayer)) {
1354 ptrans = unit_transport_get(punit);
1355 if (NULL == ptrans || pplayer != unit_owner(ptrans)) {
1356 bounce_unit(punit, verbose);
1357 }
1358 }
1360
1361#ifdef FREECIV_DEBUG
1362 /* Sanity check. */
1363 unit_list_iterate(pplayer->units, punit) {
1364 ptile = unit_tile(punit);
1365 pcity = tile_city(ptile);
1366 fc_assert_msg(NULL == pcity
1367 || pplayers_allied(city_owner(pcity), pplayer),
1368 "Failed to throw %s %d from %s %d (%d, %d)",
1370 punit->id,
1371 city_name_get(pcity),
1372 pcity->id,
1373 TILE_XY(ptile));
1375#endif /* FREECIV_DEBUG */
1376}
1377
1378/**********************************************************************/
1386static void resolve_stack_conflicts(struct player *pplayer,
1387 struct player *aplayer, bool verbose)
1388{
1390 struct tile *ptile = unit_tile(punit);
1391
1392 if (is_non_allied_unit_tile(ptile, pplayer)) {
1393 unit_list_iterate_safe(ptile->units, aunit) {
1394 if (unit_owner(aunit) == pplayer
1395 || unit_owner(aunit) == aplayer
1396 || !can_unit_survive_at_tile(&(wld.map), aunit, ptile)) {
1397 bounce_unit(aunit, verbose);
1398 }
1400 }
1402}
1403
1404/**********************************************************************/
1415void resolve_unit_stacks(struct player *pplayer, struct player *aplayer,
1416 bool verbose)
1417{
1418 throw_units_from_illegal_cities(pplayer, verbose);
1419 throw_units_from_illegal_cities(aplayer, verbose);
1420
1421 resolve_stack_conflicts(pplayer, aplayer, verbose);
1422 resolve_stack_conflicts(aplayer, pplayer, verbose);
1423}
1424
1425/**********************************************************************/
1430struct unit_list *get_units_seen_via_ally(const struct player *pplayer,
1431 const struct player *aplayer)
1432{
1433 struct unit_list *seen_units = unit_list_new();
1434
1435 /* Anybody's units inside ally's cities */
1436 city_list_iterate(aplayer->cities, pcity) {
1437 unit_list_iterate(city_tile(pcity)->units, punit) {
1438 if (can_player_see_unit(pplayer, punit)) {
1439 unit_list_append(seen_units, punit);
1440 }
1443
1444 /* Ally's own units inside transports */
1445 unit_list_iterate(aplayer->units, punit) {
1446 if (unit_transported(punit) && can_player_see_unit(pplayer, punit)) {
1447 unit_list_append(seen_units, punit);
1448 }
1450
1451 /* Make sure the same unit is not added in multiple phases
1452 * (unit within transport in a city) */
1453 unit_list_unique(seen_units);
1454
1455 return seen_units;
1456}
1457
1458/**********************************************************************/
1465void remove_allied_visibility(struct player *pplayer, struct player *aplayer,
1466 const struct unit_list *seen_units)
1467{
1468 unit_list_iterate(seen_units, punit) {
1469 /* We need to hide units previously seen by the client. */
1470 if (!can_player_see_unit(pplayer, punit)) {
1471 unit_goes_out_of_sight(pplayer, punit);
1472 }
1474
1475 city_list_iterate(aplayer->cities, pcity) {
1476 /* The player used to know what units were in these cities. Now that
1477 * they don't, they need to get a new short city packet updating the
1478 * occupied status. */
1479 if (map_is_known_and_seen(pcity->tile, pplayer, V_MAIN)) {
1480 send_city_info(pplayer, pcity);
1481 }
1483}
1484
1485/**********************************************************************/
1489void give_allied_visibility(struct player *pplayer,
1490 struct player *aplayer)
1491{
1492 unit_list_iterate(aplayer->units, punit) {
1493 if (can_player_see_unit(pplayer, punit)) {
1494 send_unit_info(pplayer->connections, punit);
1495 }
1497}
1498
1499/**********************************************************************/
1502static bool is_refuel_tile(const struct tile *ptile,
1503 const struct player *pplayer,
1504 const struct unit *punit)
1505{
1506 const struct unit_type *utype;
1507 const struct unit_class *pclass;
1508
1509 if (is_allied_city_tile(ptile, pplayer)) {
1510 return TRUE;
1511 }
1512
1513 utype = unit_type_get(punit);
1514 if (utype_has_flag(utype, UTYF_COAST) && is_safe_ocean(&(wld.map), ptile)) {
1515 return TRUE;
1516 }
1517
1518 pclass = utype_class(utype);
1519 if (NULL != pclass->cache.refuel_extras) {
1520 const struct player_tile *plrtile = map_get_player_tile(ptile, pplayer);
1521
1523 if (BV_ISSET(plrtile->extras, extra_index(pextra))) {
1524 return TRUE;
1525 }
1527 }
1528
1529 return FALSE;
1530}
1531
1532/**********************************************************************/
1536{
1537 return unit_transported(punit) /* Carrier */
1539}
1540
1541/**********************************************************************/
1544bool is_refuel_point(const struct tile *ptile,
1545 const struct player *pplayer,
1546 const struct unit *punit)
1547{
1548 if (is_non_allied_unit_tile(ptile, pplayer)) {
1549 return FALSE;
1550 }
1551
1552 return is_refuel_tile(ptile, pplayer, punit) || unit_could_load_at(punit, ptile);
1553}
1554
1555/**********************************************************************/
1566void transform_unit(struct unit *punit, const struct unit_type *to_unit,
1567 int vet_loss)
1568{
1569 struct player *pplayer = unit_owner(punit);
1570 const struct unit_type *old_type = punit->utype;
1571 int old_mr = unit_move_rate(punit);
1572 int old_hp = unit_type_get(punit)->hp;
1573 int lvls;
1574
1575 punit->utype = to_unit;
1576
1577 /* New type may not have the same veteran system, and we may want to
1578 * knock some levels off. */
1579 lvls = utype_veteran_system(to_unit)->levels - 1;
1580 punit->veteran = MIN(punit->veteran, lvls);
1581 /* Keeping the old behaviour, so first clip top, then reduce */
1582 punit->veteran = MAX(punit->veteran - vet_loss, 0);
1583
1584 /* Scale HP and MP, rounding down. Be careful with integer arithmetic,
1585 * and don't kill the unit. unit_move_rate() is used to take into account
1586 * global effects like Magellan's Expedition. */
1587 punit->hp = MAX(punit->hp * unit_type_get(punit)->hp / old_hp, 1);
1588 if (old_mr == 0) {
1590 } else {
1592 }
1593
1597 }
1598
1599 /* update unit upkeep */
1601
1603
1605
1606 CALL_PLR_AI_FUNC(unit_transformed, pplayer, punit, old_type);
1608
1609 send_unit_info(NULL, punit);
1611}
1612
1613/**********************************************************************/
1616struct unit *create_unit(struct player *pplayer, struct tile *ptile,
1617 const struct unit_type *type, int veteran_level,
1618 int homecity_id, int moves_left)
1619{
1620 return create_unit_full(pplayer, ptile, type, veteran_level, homecity_id,
1621 moves_left, -1, NULL);
1622}
1623
1624/**********************************************************************/
1628{
1629 if (punit->homecity != 0) {
1630 struct city *home = game_city_by_number(punit->homecity);
1631
1632 if (home != NULL && game.info.goods_selection == GSM_LEAVING) {
1634 }
1635 }
1636}
1637
1638/**********************************************************************/
1643struct unit *create_unit_full(struct player *pplayer, struct tile *ptile,
1644 const struct unit_type *type, int veteran_level,
1645 int homecity_id, int moves_left, int hp_left,
1646 struct unit *ptrans)
1647{
1648 struct unit *punit
1649 = unit_virtual_prepare(pplayer, ptile, type, veteran_level,
1650 homecity_id, moves_left, hp_left);
1651 struct city *pcity = (!homecity_id || utype_has_flag(type, UTYF_NOHOME))
1652 ? NULL : game_city_by_number(homecity_id);
1653 bool could_place;
1654
1655 fc_assert_ret_val(punit, NULL);
1656 could_place = place_unit(punit, pplayer, pcity, ptrans, FALSE);
1657 fc_assert(could_place);
1658 if (!could_place) {
1660 punit = NULL;
1661 }
1662
1663 return punit;
1664}
1665
1666/**********************************************************************/
1676struct unit *unit_virtual_prepare(struct player *pplayer, struct tile *ptile,
1677 const struct unit_type *type,
1678 int veteran_level, int homecity_id,
1679 int moves_left, int hp_left)
1680{
1681 struct unit *punit;
1682
1683 fc_assert_ret_val(ptile != NULL, NULL);
1684 punit = unit_virtual_create(pplayer, NULL, type, veteran_level);
1685 unit_tile_set(punit, ptile);
1686
1687 if (utype_has_flag(type, UTYF_NOHOME)) {
1688 punit->homecity = 0; /* none */
1689 } else {
1690 punit->homecity = homecity_id;
1691 }
1692
1693 if (hp_left >= 0) {
1694 /* Override default full HP */
1695 punit->hp = hp_left;
1696 }
1697
1698 if (moves_left >= 0) {
1699 int mr = unit_move_rate(punit);
1700
1701 /* Override default full MP */
1702 /* FIXME: there are valid situations when a unit have mp
1703 * over its move rate. Here, keeping the old behavior. */
1705 /* Assume that if moves_left < 0 then the unit is "fresh",
1706 * and not moved; else the unit has had something happen
1707 * to it (eg, bribed) which we treat as equivalent to moved.
1708 * (Otherwise could pass moved arg too...) --dwp */
1709 punit->moved = TRUE;
1710 }
1711
1712 return punit;
1713}
1714
1715/**********************************************************************/
1724bool place_unit(struct unit *punit, struct player *pplayer,
1725 struct city *pcity, struct unit *ptrans, bool force)
1726{
1727 struct tile *ptile;
1728
1729 fc_assert_ret_val(pplayer, FALSE);
1731 ptile = punit->tile;
1732 fc_assert_ret_val(ptile, FALSE);
1733
1734 /* Register unit */
1737
1738 if (ptrans) {
1739 /* Set transporter for unit. */
1740 unit_transport_load_tp_status(punit, ptrans, force);
1741 }
1742
1744 || can_unit_exist_at_tile(&(wld.map), punit, ptile),
1745 FALSE);
1746
1747 unit_list_prepend(pplayer->units, punit);
1748 unit_list_prepend(ptile->units, punit);
1750 if (pcity && !unit_has_type_flag(punit, UTYF_NOHOME)) {
1751 fc_assert(punit->homecity == pcity->id);
1752 fc_assert(city_owner(pcity) == pplayer);
1753 unit_list_prepend(pcity->units_supported, punit);
1754 /* update unit upkeep */
1755 city_units_upkeep(pcity);
1756 /* Refresh the unit's homecity. */
1757 city_refresh(pcity);
1758 send_city_info(pplayer, pcity);
1759 }
1760
1761 punit->server.vision = vision_new(pplayer, ptile);
1763
1765
1766 send_unit_info(NULL, punit);
1768
1769 /* The unit may have changed the available tiles in nearby cities. */
1771 sync_cities();
1772
1773 CALL_FUNC_EACH_AI(unit_created, punit);
1774 CALL_PLR_AI_FUNC(unit_got, pplayer, punit);
1775
1776 return TRUE;
1777}
1778
1779/**********************************************************************/
1783 void (*callback)(struct unit *punit))
1784{
1785 /* Tried to overwrite another call back. If this assertion is triggered
1786 * in a case where two call back are needed it may be time to support
1787 * more than one unit removal call back at a time. */
1789
1791}
1792
1793/**********************************************************************/
1797{
1799}
1800
1801/**********************************************************************/
1805static void server_remove_unit_full(struct unit *punit, bool transported,
1806 enum unit_loss_reason reason)
1807{
1808 struct packet_unit_remove packet;
1809 struct tile *ptile = unit_tile(punit);
1810 struct city *pcity = tile_city(ptile);
1811 struct city *phomecity = game_city_by_number(punit->homecity);
1812 struct unit *ptrans;
1813 struct player *pplayer = unit_owner(punit);
1814
1815 /* The unit is doomed. */
1817
1818#if defined(FREECIV_DEBUG) && !defined(FREECIV_NDEBUG)
1819 unit_list_iterate(ptile->units, pcargo) {
1822#endif /* FREECIV_DEBUG */
1823
1824 CALL_PLR_AI_FUNC(unit_lost, pplayer, punit);
1825 CALL_FUNC_EACH_AI(unit_destroyed, punit);
1826
1827 /* Save transporter for updating below. */
1828 ptrans = unit_transport_get(punit);
1829 /* Unload unit. */
1831
1832 /* Since settlers plot in new cities in the minimap before they
1833 are built, so that no two settlers head towards the same city
1834 spot, we need to ensure this reservation is cleared should
1835 the settler disappear on the way. */
1837
1838 /* Clear the vision before sending unit remove. Else, we might duplicate
1839 * the PACKET_UNIT_REMOVE if we lose vision of the unit tile. */
1840 if (punit->server.vision != NULL) {
1843 punit->server.vision = NULL;
1844 }
1845
1846 packet.unit_id32 = punit->id;
1847 packet.unit_id16 = packet.unit_id32;
1848 /* Send to onlookers. */
1849 players_iterate(aplayer) {
1851 transported)) {
1852 lsend_packet_unit_remove(aplayer->connections, &packet);
1853 }
1855 /* Send to global observers. */
1857 if (conn_is_global_observer(pconn)) {
1858 send_packet_unit_remove(pconn, &packet);
1859 }
1861
1862 if (punit->server.moving != NULL) {
1863 /* Do not care of this unit for running moves. */
1864 punit->server.moving->punit = NULL;
1865 }
1866
1867 if (punit->server.removal_callback != NULL) {
1868 /* Run the unit removal call back. */
1870 }
1871
1872 /* check if this unit had UTYF_GAMELOSS flag */
1873 if (unit_has_type_flag(punit, UTYF_GAMELOSS) && unit_owner(punit)->is_alive
1874 && ULR_EDITOR != reason) {
1875 notify_conn(game.est_connections, ptile, E_UNIT_LOST_MISC, ftc_server,
1876 _("Unable to defend %s, %s has lost the game."),
1878 player_name(pplayer));
1879 notify_player(pplayer, ptile, E_GAME_END, ftc_server,
1880 _("Losing %s meant losing the game! "
1881 "Be more careful next time!"),
1882 unit_link(punit));
1883 player_status_add(unit_owner(punit), PSTATUS_DYING);
1884 }
1885
1886 /* Have to pass new ULR_UPKEEP as ULR_DISBAND for compatibility reasons.
1887 * Changes in freeciv-3.2 */
1889 unit_loss_reason_name((reason == ULR_UPKEEP)
1890 ? ULR_DISBANDED
1891 : reason));
1892
1895 punit = NULL;
1896
1897 if (NULL != ptrans) {
1898 /* Update the occupy info. */
1899 send_unit_info(NULL, ptrans);
1900 }
1901
1902 /* This unit may have blocked tiles of adjacent cities. Update them. */
1904 sync_cities();
1905
1906 if (phomecity) {
1907 city_refresh(phomecity);
1908 send_city_info(city_owner(phomecity), phomecity);
1909 }
1910
1911 if (pcity && pcity != phomecity) {
1912 city_refresh(pcity);
1913 send_city_info(city_owner(pcity), pcity);
1914 }
1915
1916 if (pcity && unit_list_size(ptile->units) == 0) {
1917 /* The last unit in the city was killed: update the occupied flag. */
1918 send_city_info(NULL, pcity);
1919 }
1920}
1921
1922/**********************************************************************/
1926static void server_remove_unit(struct unit *punit,
1927 enum unit_loss_reason reason)
1928{
1930}
1931
1932/**********************************************************************/
1935static void unit_lost_with_transport(const struct player *pplayer,
1936 struct unit *pcargo,
1937 const struct unit_type *ptransport,
1938 struct player *killer)
1939{
1940 notify_player(pplayer, unit_tile(pcargo), E_UNIT_LOST_MISC, ftc_server,
1941 _("%s lost when %s was lost."),
1942 unit_tile_link(pcargo),
1943 utype_name_translation(ptransport));
1944 /* Unit is not transported any more at this point, but it has jumped
1945 * off the transport and drowns outside. So it must be removed from
1946 * all clients.
1947 * However, we don't know if given client has received ANY updates
1948 * about the swimming unit, and we can't remove it if it's not there
1949 * in the first place -> we send it once here just to be sure it's
1950 * there. */
1951 send_unit_info(NULL, pcargo);
1952 wipe_unit_full(pcargo, FALSE, ULR_TRANSPORT_LOST, killer);
1953}
1954
1955/**********************************************************************/
1959static void wipe_unit_full(struct unit *punit, bool transported,
1960 enum unit_loss_reason reason,
1961 struct player *killer)
1962{
1963 struct tile *ptile = unit_tile(punit);
1964 struct player *pplayer = unit_owner(punit);
1965 const struct unit_type *putype_save = unit_type_get(punit); /* for notify messages */
1966 struct unit_list *helpless = unit_list_new();
1967 struct unit_list *imperiled = unit_list_new();
1968 struct unit_list *unsaved = unit_list_new();
1969 struct unit *ptrans = unit_transport_get(punit);
1970 struct city *pexclcity;
1971 struct civ_map *nmap = &(wld.map);
1972
1973 if (killer != NULL
1974 && (game.info.gameloss_style & GAMELOSS_STYLE_LOOT)
1975 && unit_has_type_flag(punit, UTYF_GAMELOSS)) {
1976 int ransom = fc_rand(1 + pplayer->economic.gold);
1977 int n;
1978
1979 /* Give map */
1980 if (give_distorted_map(pplayer, killer, 50, TRUE)) {
1981 notify_player(killer, NULL, E_HUT_MAP,
1982 ftc_server,
1983 _("You looted parts of %s map!"),
1985 }
1986
1987 log_debug("victim has money: %d", pplayer->economic.gold);
1988
1989 if (ransom > 0) {
1990 notify_player(killer, NULL, E_HUT_GOLD,
1991 ftc_server,
1992 PL_("You loot %d gold!", "You loot %d gold!", ransom),
1993 ransom);
1994 }
1995 killer->economic.gold += ransom;
1996 pplayer->economic.gold -= ransom;
1997
1998 n = 1 + fc_rand(3);
1999
2000 while (n > 0) {
2001 Tech_type_id ttid;
2002
2003 /* steal_a_tech() handles also notifying of the player */
2004 ttid = steal_a_tech(killer, pplayer, A_UNSET);
2005
2006 if (ttid == A_NONE) {
2007 log_debug("Worthless enemy doesn't have more techs to steal.");
2008 break;
2009 } else {
2010 log_debug("Pressed tech %s from captured enemy",
2012 if (!fc_rand(3)) {
2013 break; /* Out of luck */
2014 }
2015 n--;
2016 }
2017 }
2018
2019 {
2020 /* Try to submit some cities */
2021 int vcsize = city_list_size(pplayer->cities);
2022 int evcsize = vcsize;
2023 int conqsize;
2024
2025 if (evcsize < 3) {
2026 evcsize = 0;
2027 } else {
2028 evcsize -=3;
2029 }
2030
2031 /* About a quarter on average with high numbers less probable */
2032 conqsize = fc_rand(fc_rand(evcsize));
2033
2034 log_debug("conqsize=%d", conqsize);
2035
2036 if (conqsize > 0) {
2037 bool palace = game.server.savepalace;
2038 bool submit = FALSE;
2039
2040 game.server.savepalace = FALSE; /* Moving it around is dumb */
2041
2042 city_list_iterate_safe(pplayer->cities, pcity) {
2043 /* Kindly ask the citizens to submit */
2044 if (fc_rand(vcsize) < conqsize) {
2045 submit = TRUE;
2046 }
2047 vcsize--;
2048 if (submit) {
2049 conqsize--;
2050 /* Transfer city to the victorious player
2051 * kill all its units outside of a radius of 7,
2052 * give verbose messages of every unit transferred,
2053 * and raze buildings according to raze chance
2054 * (also removes palace) */
2055 notify_player(killer, city_tile(pcity), E_UNIT_WIN_ATT,
2056 ftc_server,
2057 /* TRANS: Getting a city as loot */
2058 _("You conquer %s as loot!"),
2059 city_link(pcity));
2060
2061 (void) transfer_city(killer, pcity, 7, TRUE, TRUE, TRUE,
2062 !is_barbarian(killer));
2063 submit = FALSE;
2064 }
2065 if (conqsize <= 0) {
2066 break;
2067 }
2069 game.server.savepalace = palace;
2070 }
2071 }
2072 }
2073
2074 /* The unit is doomed. */
2076
2077 /* If a unit is being lost due to loss of its city, ensure that we don't
2078 * try to teleport any of its cargo to that city (which may not yet
2079 * have changed hands or disappeared). (It is assumed that the unit's
2080 * home city is always the one that is being lost/transferred/etc.) */
2081 if (reason == ULR_CITY_LOST) {
2082 pexclcity = unit_home(punit);
2083 } else {
2084 pexclcity = NULL;
2085 }
2086
2087 /* Remove unit itself from its transport */
2088 if (ptrans != NULL) {
2090 send_unit_info(NULL, ptrans);
2091 }
2092
2093 /* First pull all units off of the transporter. */
2095 /* Use iterate_safe as unloaded units will be removed from the list
2096 * while iterating. */
2098 bool healthy = FALSE;
2099
2100 if (!can_unit_unload(pcargo, punit)) {
2101 unit_list_prepend(helpless, pcargo);
2102 } else {
2103 if (!can_unit_exist_at_tile(nmap, pcargo, ptile)) {
2104 unit_list_prepend(imperiled, pcargo);
2105 } else {
2106 /* These units do not need to be saved. */
2107 healthy = TRUE;
2108 }
2109 }
2110
2111 /* Could use unit_transport_unload_send() here, but that would
2112 * call send_unit_info() for the transporter unnecessarily.
2113 * Note that this means that unit might to get seen briefly
2114 * by clients other than owner's, for example as a result of
2115 * update of homecity common to this cargo and some other
2116 * destroyed unit. */
2117 unit_transport_unload(pcargo);
2118 if (pcargo->activity == ACTIVITY_SENTRY) {
2119 /* Activate sentried units - like planes on a disbanded carrier.
2120 * Note this will activate ground units even if they just change
2121 * transporter. */
2122 set_unit_activity(pcargo, ACTIVITY_IDLE);
2123 }
2124
2125 /* Unit info for unhealthy units will be sent when they are
2126 * assigned new transport or removed. */
2127 if (healthy) {
2128 send_unit_info(NULL, pcargo);
2129 }
2131 }
2132
2133 /* Now remove the unit. */
2134 server_remove_unit_full(punit, transported, reason);
2135
2136 switch (reason) {
2137 case ULR_KILLED:
2138 case ULR_EXECUTED:
2139 case ULR_SDI:
2140 case ULR_NUKE:
2141 case ULR_BRIBED:
2142 case ULR_CAPTURED:
2143 case ULR_CAUGHT:
2144 case ULR_ELIMINATED:
2145 case ULR_TRANSPORT_LOST:
2146 if (killer != NULL) {
2147 killer->score.units_killed++;
2148 }
2149 pplayer->score.units_lost++;
2150 break;
2151 case ULR_BARB_UNLEASH:
2152 case ULR_CITY_LOST:
2153 case ULR_STARVED:
2154 case ULR_UPKEEP:
2155 case ULR_NONNATIVE_TERR:
2156 case ULR_ARMISTICE:
2157 case ULR_HP_LOSS:
2158 case ULR_FUEL:
2159 case ULR_STACK_CONFLICT:
2160 case ULR_SOLD:
2161 pplayer->score.units_lost++;
2162 break;
2163 case ULR_RETIRED:
2164 case ULR_DISBANDED:
2165 case ULR_USED:
2166 case ULR_EDITOR:
2167 case ULR_PLAYER_DIED:
2168 case ULR_DETONATED:
2169 case ULR_MISSILE:
2170 break;
2171 }
2172
2173 /* First, sort out helpless cargo. */
2174 if (unit_list_size(helpless) > 0) {
2175 struct unit_list *remaining = unit_list_new();
2176
2177 /* Grant priority to gameloss units and units with the EvacuateFirst
2178 * unit type flag. */
2179 unit_list_iterate_safe(helpless, pcargo) {
2180 if (unit_has_type_flag(pcargo, UTYF_EVAC_FIRST)
2181 || unit_has_type_flag(pcargo, UTYF_GAMELOSS)) {
2182 if (!try_to_save_unit(pcargo, putype_save, TRUE,
2183 unit_has_type_flag(pcargo,
2184 UTYF_EVAC_FIRST),
2185 pexclcity)) {
2186 unit_list_prepend(unsaved, pcargo);
2187 }
2188 } else {
2189 unit_list_prepend(remaining, pcargo);
2190 }
2192
2193 /* Handle non-priority units. */
2194 unit_list_iterate_safe(remaining, pcargo) {
2195 if (!try_to_save_unit(pcargo, putype_save, TRUE, FALSE, pexclcity)) {
2196 unit_list_prepend(unsaved, pcargo);
2197 }
2199
2200 unit_list_destroy(remaining);
2201 }
2202 unit_list_destroy(helpless);
2203
2204 /* Then, save any imperiled cargo. */
2205 if (unit_list_size(imperiled) > 0) {
2206 struct unit_list *remaining = unit_list_new();
2207
2208 /* Grant priority to gameloss units and units with the EvacuateFirst
2209 * unit type flag. */
2210 unit_list_iterate_safe(imperiled, pcargo) {
2211 if (unit_has_type_flag(pcargo, UTYF_EVAC_FIRST)
2212 || unit_has_type_flag(pcargo, UTYF_GAMELOSS)) {
2213 if (!try_to_save_unit(pcargo, putype_save, FALSE,
2214 unit_has_type_flag(pcargo,
2215 UTYF_EVAC_FIRST),
2216 pexclcity)) {
2217 unit_list_prepend(unsaved, pcargo);
2218 }
2219 } else {
2220 unit_list_prepend(remaining, pcargo);
2221 }
2223
2224 /* Handle non-priority units. */
2225 unit_list_iterate_safe(remaining, pcargo) {
2226 if (!try_to_save_unit(pcargo, putype_save, FALSE, FALSE, pexclcity)) {
2227 unit_list_prepend(unsaved, pcargo);
2228 }
2230
2231 unit_list_destroy(remaining);
2232 }
2233 unit_list_destroy(imperiled);
2234
2235 /* Finally, kill off the unsaved units. */
2236 if (unit_list_size(unsaved) > 0) {
2237 unit_list_iterate_safe(unsaved, dying_unit) {
2238 unit_lost_with_transport(pplayer, dying_unit, putype_save, killer);
2240 }
2241 unit_list_destroy(unsaved);
2242}
2243
2244/**********************************************************************/
2248void wipe_unit(struct unit *punit, enum unit_loss_reason reason,
2249 struct player *killer)
2250{
2251 wipe_unit_full(punit, unit_transported(punit), reason, killer);
2252}
2253
2254/**********************************************************************/
2260static bool try_to_save_unit(struct unit *punit, const struct unit_type *pttype,
2261 bool helpless, bool teleporting,
2262 const struct city *pexclcity)
2263{
2264 struct tile *ptile = unit_tile(punit);
2265 struct player *pplayer = unit_owner(punit);
2266 struct unit *ptransport = transporter_for_unit(punit);
2267
2268 /* Helpless units cannot board a transport in their current state. */
2269 if (!helpless
2270 && ptransport != NULL) {
2272 send_unit_info(NULL, punit);
2273 return TRUE;
2274 } else {
2275 /* Only units that cannot find transport are considered for teleport. */
2276 if (teleporting) {
2277 struct city *pcity = find_closest_city(ptile, pexclcity,
2280 utype_class(pttype));
2281 if (pcity != NULL) {
2282 char tplink[MAX_LEN_LINK]; /* In case unit dies when teleported */
2283
2284 sz_strlcpy(tplink, unit_link(punit));
2285
2286 if (teleport_unit_to_city(punit, pcity, 0, FALSE)) {
2287 notify_player(pplayer, ptile, E_UNIT_RELOCATED, ftc_server,
2288 _("%s escaped the destruction of %s, and fled to %s."),
2289 tplink,
2290 utype_name_translation(pttype),
2291 city_link(pcity));
2292 return TRUE;
2293 }
2294 }
2295 }
2296 }
2297
2298 /* The unit could not use transport on the tile, and could not teleport. */
2299 return FALSE;
2300}
2301
2302/**********************************************************************/
2308struct unit *unit_change_owner(struct unit *punit, struct player *pplayer,
2309 int homecity, enum unit_loss_reason reason)
2310{
2311 struct unit *gained_unit;
2312 int id = 0;
2313
2314#ifndef FREECIV_NDEBUG
2315 bool placed;
2316#endif
2317
2320
2321 /* Convert the unit to your cause. It's supposed that the original unit
2322 * is on a valid tile and is not transported. */
2323 gained_unit = unit_virtual_prepare(pplayer, unit_tile(punit),
2326 fc_assert_action(gained_unit, goto uco_wipe); /* Tile must be valid */
2327
2328 /* Owner changes, nationality not. */
2329 gained_unit->nationality = punit->nationality;
2330
2331 /* Copy some more unit fields */
2332 gained_unit->fuel = punit->fuel;
2333 gained_unit->paradropped = punit->paradropped;
2334 gained_unit->server.birth_turn = punit->server.birth_turn;
2335
2336 /* Fog is lifted in the placing algorithm. */
2337#ifndef FREECIV_NDEBUG
2338 placed =
2339#endif
2340 place_unit(gained_unit, pplayer,
2342 NULL, FALSE);
2343
2344 fc_assert_action(placed, unit_virtual_destroy(gained_unit); goto uco_wipe);
2345
2346 id = gained_unit->id;
2347
2348 /* Update unit upkeep in the new homecity */
2349 if (homecity > 0) {
2351 }
2352
2353 /* Be sure to wipe the converted unit! */
2354 /* Old homecity upkeep is updated in process */
2355#ifndef FREECIV_NDEBUG
2356 uco_wipe:
2357#endif
2358
2359 wipe_unit(punit, reason, NULL);
2360
2361 if (!unit_is_alive(id)) {
2362 /* Destroyed by a script */
2363 return NULL;
2364 }
2365
2366 return gained_unit; /* Returns the replacement. */
2367}
2368
2369/**********************************************************************/
2374void kill_unit(struct unit *pkiller, struct unit *punit, bool vet)
2375{
2376 char pkiller_link[MAX_LEN_LINK], punit_link[MAX_LEN_LINK];
2377 struct player *pvictim = unit_owner(punit);
2378 struct player *pvictor = unit_owner(pkiller);
2379 struct tile *deftile = unit_tile(punit);
2380 int ransom, unitcount = 0;
2381 bool escaped;
2382 bool collect_ransom = FALSE;
2383 const struct civ_map *nmap = &(wld.map);
2384
2385 sz_strlcpy(pkiller_link, unit_link(pkiller));
2386 sz_strlcpy(punit_link, unit_tile_link(punit));
2387
2388 /* The unit is doomed. */
2390
2391 /* barbarian leader ransom hack */
2392 if (is_barbarian(pvictim)
2393 && uclass_has_flag(unit_class_get(pkiller), UCF_COLLECT_RANSOM)) {
2394 collect_ransom = TRUE;
2395
2396 unit_list_iterate(deftile->units, capture) {
2397 if (!unit_has_type_role(capture, L_BARBARIAN_LEADER)) {
2398 /* Cannot get ransom when there are other kind of units in the tile */
2399 collect_ransom = FALSE;
2400 break;
2401 }
2403
2404 if (collect_ransom) {
2405 unitcount = unit_list_size(deftile->units);
2406 ransom = unitcount * game.server.ransom_gold;
2407
2408 if (pvictim->economic.gold < ransom) {
2409 ransom = pvictim->economic.gold;
2410 }
2411
2412 notify_player(pvictor, unit_tile(pkiller), E_UNIT_WIN_ATT, ftc_server,
2413 PL_("%d Barbarian leader captured.",
2414 "%d Barbarian leaders captured.",
2415 unitcount),
2416 unitcount);
2417 notify_player(pvictor, unit_tile(pkiller), E_UNIT_WIN_ATT, ftc_server,
2418 PL_("%d gold ransom paid.",
2419 "%d gold ransom paid.",
2420 ransom),
2421 ransom);
2422 pvictor->economic.gold += ransom;
2423 pvictim->economic.gold -= ransom;
2424 send_player_info_c(pvictor, NULL); /* let me see my new gold :-) */
2425 }
2426 }
2427
2428 if (unitcount == 0) {
2429 unit_list_iterate(deftile->units, vunit) {
2430 if (pplayers_at_war(pvictor, unit_owner(vunit))
2431 && is_unit_reachable_at(vunit, pkiller, deftile)) {
2432 unitcount++;
2433 }
2435 }
2436
2437 if (!is_stack_vulnerable(deftile) || unitcount == 1) {
2438 if (vet) {
2439 notify_unit_experience(pkiller);
2440 }
2441 wipe_unit(punit, ULR_KILLED, pvictor);
2442 } else { /* unitcount > 1 */
2443 int i;
2444 int slots = player_slot_count();
2445 int num_killed[slots];
2446 int num_escaped[slots];
2447 struct unit *other_killed[slots];
2448
2449 fc_assert(unitcount > 1);
2450
2451 /* initialize */
2452 for (i = 0; i < slots; i++) {
2453 num_killed[i] = 0;
2454 other_killed[i] = NULL;
2455 num_escaped[i] = 0;
2456 }
2457
2458 /* count killed units */
2459 unit_list_iterate_safe(deftile->units, vunit) {
2460 struct player *vplayer = unit_owner(vunit);
2461
2462 if (pplayers_at_war(pvictor, vplayer)
2463 && is_unit_reachable_at(vunit, pkiller, deftile)) {
2464 escaped = FALSE;
2465
2466 if (unit_has_type_flag(vunit, UTYF_CANESCAPE)
2467 && !unit_has_type_flag(pkiller, UTYF_CANKILLESCAPING)
2468 && vunit->hp > 0
2469 && vunit->moves_left > pkiller->moves_left
2470 && fc_rand(2)) {
2471 int curr_def_bonus;
2472 int def_bonus = 0;
2473 struct tile *dsttile = NULL;
2474 int move_cost;
2475
2476 fc_assert(vunit->hp > 0);
2477
2478 adjc_iterate(nmap, deftile, ptile2) {
2479 if (can_exist_at_tile(nmap, vunit->utype, ptile2)
2480 && NULL == tile_city(ptile2)) {
2481 move_cost = map_move_cost_unit(nmap, vunit, ptile2);
2482 if (pkiller->moves_left <= vunit->moves_left - move_cost
2483 && (is_allied_unit_tile(ptile2, pvictim)
2484 || unit_list_size(ptile2->units)) == 0) {
2485 curr_def_bonus = tile_extras_defense_bonus(ptile2,
2486 vunit->utype);
2487 if (def_bonus <= curr_def_bonus) {
2488 def_bonus = curr_def_bonus;
2489 dsttile = ptile2;
2490 }
2491 }
2492 }
2494
2495 if (dsttile != NULL) {
2496 escaped = (action_auto_perf_unit_do(AAPC_UNIT_STACK_DEATH,
2497 vunit, tile_owner(dsttile),
2498 NULL, NULL, dsttile,
2499 tile_city(dsttile),
2500 NULL, NULL)
2501 != NULL);
2502
2503 if (escaped) {
2504 num_escaped[player_index(vplayer)]++;
2505 unitcount--;
2506 }
2507 }
2508 }
2509
2510 if (!escaped) {
2511 num_killed[player_index(vplayer)]++;
2512
2513 if (vunit != punit) {
2514 other_killed[player_index(vplayer)] = vunit;
2515 other_killed[player_index(pvictor)] = vunit;
2516 }
2517 }
2518 }
2520
2521 /* Inform the destroyer again if more than one unit was killed */
2522 if (unitcount > 1 && !collect_ransom) {
2523 notify_player(pvictor, unit_tile(pkiller), E_UNIT_WIN_ATT, ftc_server,
2524 /* TRANS: "... Cannon ... the Polish Destroyer ...." */
2525 PL_("Your attacking %s succeeded against the %s %s "
2526 "(and %d other unit)!",
2527 "Your attacking %s succeeded against the %s %s "
2528 "(and %d other units)!", unitcount - 1),
2529 pkiller_link,
2531 punit_link,
2532 unitcount - 1);
2533 }
2534
2535 if (vet) {
2536 notify_unit_experience(pkiller);
2537 }
2538
2539 /* inform the owners: this only tells about owned units that were killed.
2540 * there may have been 20 units who died but if only 2 belonged to the
2541 * particular player they'll only learn about those.
2542 *
2543 * Also if a large number of units die you don't find out what type
2544 * they all are. */
2545 for (i = 0; i < slots; i++) {
2546 if (num_killed[i] == 1) {
2547 if (i == player_index(pvictim)) {
2548 fc_assert(other_killed[i] == NULL);
2549 notify_player(player_by_number(i), deftile,
2550 E_UNIT_LOST_DEF, ftc_server,
2551 /* TRANS: "Cannon ... the Polish Destroyer." */
2552 _("%s lost to an attack by the %s %s."),
2553 punit_link,
2555 pkiller_link);
2556 } else {
2557 fc_assert(other_killed[i] != punit);
2558 notify_player(player_by_number(i), deftile,
2559 E_UNIT_LOST_DEF, ftc_server,
2560 /* TRANS: "Cannon lost when the Polish Destroyer
2561 * attacked the German Musketeers." */
2562 _("%s lost when the %s %s attacked the %s %s."),
2563 unit_link(other_killed[i]),
2565 pkiller_link,
2567 punit_link);
2568 }
2569 } else if (num_killed[i] > 1) {
2570 if (i == player_index(pvictim)) {
2571 int others = num_killed[i] - 1;
2572
2573 if (others == 1) {
2574 notify_player(player_by_number(i), deftile,
2575 E_UNIT_LOST_DEF, ftc_server,
2576 /* TRANS: "Musketeers (and Cannon) lost to an
2577 * attack from the Polish Destroyer." */
2578 _("%s (and %s) lost to an attack from the %s %s."),
2579 punit_link,
2580 unit_link(other_killed[i]),
2582 pkiller_link);
2583 } else {
2584 notify_player(player_by_number(i), deftile,
2585 E_UNIT_LOST_DEF, ftc_server,
2586 /* TRANS: "Musketeers and 3 other units lost to
2587 * an attack from the Polish Destroyer."
2588 * (only happens with at least 2 other units) */
2589 PL_("%s and %d other unit lost to an attack "
2590 "from the %s %s.",
2591 "%s and %d other units lost to an attack "
2592 "from the %s %s.", others),
2593 punit_link,
2594 others,
2596 pkiller_link);
2597 }
2598 } else {
2599 notify_player(player_by_number(i), deftile,
2600 E_UNIT_LOST_DEF, ftc_server,
2601 /* TRANS: "2 units lost when the Polish Destroyer
2602 * attacked the German Musketeers."
2603 * (only happens with at least 2 other units) */
2604 PL_("%d unit lost when the %s %s attacked the %s %s.",
2605 "%d units lost when the %s %s attacked the %s %s.",
2606 num_killed[i]),
2607 num_killed[i],
2609 pkiller_link,
2611 punit_link);
2612 }
2613 }
2614 }
2615
2616 /* Inform the owner of the units that escaped.
2617 * 'deftile' is the original tile they defended at, not where
2618 * they escaped to, as there might be multiple different tiles
2619 * different units escaped to. */
2620 for (i = 0; i < slots; i++) {
2621 if (0 < num_escaped[i]) {
2622 notify_player(player_by_number(i), deftile,
2623 E_UNIT_ESCAPED, ftc_server,
2624 PL_("%d unit escaped from attack by %s %s",
2625 "%d units escaped from attack by %s %s",
2626 num_escaped[i]),
2627 num_escaped[i],
2629 pkiller_link
2630 );
2631 }
2632 }
2633
2634 /* remove the units - note the logic of which units actually die
2635 * must be mimiced exactly in at least one place up above. */
2636 punit = NULL; /* wiped during following iteration so unsafe to use */
2637
2638 unit_list_iterate_safe(deftile->units, punit2) {
2639 if (pplayers_at_war(pvictor, unit_owner(punit2))
2640 && is_unit_reachable_at(punit2, pkiller, deftile)) {
2641 wipe_unit(punit2, ULR_KILLED, pvictor);
2642 }
2644 }
2645}
2646
2647/**********************************************************************/
2651void package_unit(struct unit *punit, struct packet_unit_info *packet)
2652{
2653 packet->id32 = punit->id;
2654 packet->id16 = packet->id32;
2655 packet->owner = player_number(unit_owner(punit));
2657 packet->tile = tile_index(unit_tile(punit));
2658 packet->facing = punit->facing;
2659 packet->homecity32 = punit->homecity;
2660 packet->homecity16 = packet->homecity32;
2662 packet->upkeep[o] = punit->upkeep[o];
2664 packet->veteran = punit->veteran;
2666 packet->movesleft = punit->moves_left;
2667 packet->hp = punit->hp;
2668 packet->activity = punit->activity;
2670
2671 if (punit->activity_target != NULL) {
2673 } else {
2674 packet->activity_tgt = EXTRA_NONE;
2675 }
2676
2677 packet->changed_from = punit->changed_from;
2679
2680 if (punit->changed_from_target != NULL) {
2682 } else {
2683 packet->changed_from_tgt = EXTRA_NONE;
2684 }
2685
2687 packet->fuel = punit->fuel;
2688 packet->goto_tile = (NULL != punit->goto_tile
2689 ? tile_index(punit->goto_tile) : -1);
2690 packet->paradropped = punit->paradropped;
2691 packet->done_moving = punit->done_moving;
2692 packet->stay = punit->stay;
2693 if (!unit_transported(punit)) {
2694 packet->transported = FALSE;
2695 packet->transported_by32 = 0;
2696 packet->transported_by16 = 0;
2697 } else {
2698 packet->transported = TRUE;
2700 packet->transported_by16 = packet->transported_by32;
2701 }
2702 if (punit->carrying != NULL) {
2703 packet->carrying = goods_index(punit->carrying);
2704 } else {
2705 packet->carrying = -1;
2706 }
2707 packet->occupied = (get_transporter_occupancy(punit) > 0);
2708 packet->battlegroup = punit->battlegroup;
2709 packet->has_orders = punit->has_orders;
2710 if (punit->has_orders) {
2711 packet->orders_length = punit->orders.length;
2712 packet->orders_index = punit->orders.index;
2713 packet->orders_repeat = punit->orders.repeat;
2715 memcpy(packet->orders, punit->orders.list,
2716 punit->orders.length * sizeof(struct unit_order));
2717 } else {
2718 packet->orders_length = packet->orders_index = 0;
2719 packet->orders_repeat = packet->orders_vigilant = FALSE;
2720 /* No need to initialize array. */
2721 }
2722
2727}
2728
2729/**********************************************************************/
2735 struct packet_unit_short_info *packet,
2736 enum unit_info_use packet_use, int info_city_id)
2737{
2738 packet->packet_use = packet_use;
2739 packet->info_city_id32 = info_city_id;
2740 packet->info_city_id16 = packet->info_city_id32;
2741
2742 packet->id32 = punit->id;
2743 packet->id16 = packet->id32;
2744 packet->owner = player_number(unit_owner(punit));
2745 packet->tile = tile_index(unit_tile(punit));
2746 packet->facing = punit->facing;
2747 packet->veteran = punit->veteran;
2749 packet->hp = punit->hp;
2750 packet->occupied = (get_transporter_occupancy(punit) > 0);
2751 if (punit->activity == ACTIVITY_EXPLORE
2752 || punit->activity == ACTIVITY_GOTO) {
2753 packet->activity = ACTIVITY_IDLE;
2754 } else {
2755 packet->activity = punit->activity;
2756 }
2757
2758 if (punit->activity_target == NULL) {
2759 packet->activity_tgt = EXTRA_NONE;
2760 } else {
2762 }
2763
2764 /* Transported_by information is sent to the client even for units that
2765 * aren't fully known. Note that for non-allied players, any transported
2766 * unit can't be seen at all. For allied players we have to know if
2767 * transporters have room in them so that we can load units properly. */
2768 if (!unit_transported(punit)) {
2769 packet->transported = FALSE;
2770 packet->transported_by32 = 0;
2771 packet->transported_by16 = 0;
2772 } else {
2773 packet->transported = TRUE;
2775 packet->transported_by16 = packet->transported_by32;
2776 }
2777}
2778
2779/**********************************************************************/
2782void unit_goes_out_of_sight(struct player *pplayer, struct unit *punit)
2783{
2785 if (punit->server.moving != NULL) {
2786 /* Update status of 'pplayer' vision for 'punit'. */
2788 }
2789}
2790
2791/**********************************************************************/
2795void send_unit_info(struct conn_list *dest, struct unit *punit)
2796{
2797 const struct player *powner;
2798 struct packet_unit_info info;
2799 struct packet_unit_short_info sinfo;
2800 struct unit_move_data *pdata;
2801
2802 if (dest == NULL) {
2803 dest = game.est_connections;
2804 }
2805
2807
2809 package_unit(punit, &info);
2811 pdata = punit->server.moving;
2812
2813 conn_list_iterate(dest, pconn) {
2814 struct player *pplayer = conn_get_player(pconn);
2815
2816 /* Be careful to consider all cases where pplayer is NULL... */
2817 if (pplayer == NULL) {
2818 if (pconn->observer) {
2819 send_packet_unit_info(pconn, &info);
2820 }
2821 } else if (pplayer == powner) {
2822 send_packet_unit_info(pconn, &info);
2823 if (pdata != NULL) {
2824 BV_SET(pdata->can_see_unit, player_index(pplayer));
2825 }
2826 } else if (can_player_see_unit(pplayer, punit)) {
2827 send_packet_unit_short_info(pconn, &sinfo, FALSE);
2828 if (pdata != NULL) {
2829 BV_SET(pdata->can_see_unit, player_index(pplayer));
2830 }
2831 }
2833}
2834
2835/**********************************************************************/
2839void send_all_known_units(struct conn_list *dest)
2840{
2841 conn_list_do_buffer(dest);
2842 conn_list_iterate(dest, pconn) {
2843 struct player *pplayer = pconn->playing;
2844
2845 if (NULL == pplayer && !pconn->observer) {
2846 continue;
2847 }
2848
2849 players_iterate(unitowner) {
2850 unit_list_iterate(unitowner->units, punit) {
2851 send_unit_info(dest, punit);
2854 }
2857 flush_packets();
2858}
2859
2860/**********************************************************************/
2867static void do_nuke_tile(struct player *pplayer, struct tile *ptile)
2868{
2869 struct city *pcity = NULL;
2870 int pop_loss;
2871
2872 pcity = tile_city(ptile);
2873
2875
2876 /* unit in a city may survive */
2877 if (pcity && fc_rand(100) < game.info.nuke_defender_survival_chance_pct) {
2878 continue;
2879 }
2880 notify_player(unit_owner(punit), ptile, E_UNIT_LOST_MISC, ftc_server,
2881 _("Your %s was nuked by %s."),
2883 pplayer == unit_owner(punit)
2884 ? _("yourself")
2885 : nation_plural_for_player(pplayer));
2886 if (unit_owner(punit) != pplayer) {
2887 notify_player(pplayer, ptile, E_UNIT_WIN_ATT, ftc_server,
2888 _("The %s %s was nuked."),
2891 }
2892 wipe_unit(punit, ULR_NUKE, pplayer);
2894
2895
2896 if (pcity) {
2897 struct player *owner = city_owner(pcity);
2898 char city_name[MAX_LEN_LINK];
2899
2900 sz_strlcpy(city_name, city_link(pcity));
2901
2902 notify_player(owner, ptile, E_CITY_NUKED, ftc_server,
2903 _("%s was nuked by %s."),
2904 city_name,
2905 pplayer == owner
2906 ? _("yourself")
2907 : nation_plural_for_player(pplayer));
2908
2909 if (owner != pplayer) {
2910 notify_player(pplayer, ptile, E_CITY_NUKED, ftc_server,
2911 _("You nuked %s."),
2912 city_name);
2913 }
2914
2915 pop_loss = round((game.info.nuke_pop_loss_pct * city_size_get(pcity)) / 100.0);
2916 if (city_reduce_size(pcity, pop_loss, pplayer, "nuke")) {
2917 /* Send city size reduction to everyone seeing it */
2918 send_city_info(NULL, pcity);
2919 } else {
2920 /* City was destroyed */
2921 notify_player(owner, ptile, E_CITY_NUKED, ftc_server,
2922 _("%s was destroyed by the nuke."),
2923 city_name);
2924 if (owner != pplayer) {
2925 notify_player(pplayer, ptile, E_CITY_NUKED, ftc_server,
2926 _("Your nuke destroyed %s."),
2927 city_name);
2928 }
2929 }
2930 }
2931
2932 if (fc_rand(2) == 1) {
2933 struct extra_type *pextra;
2934
2935 pextra = rand_extra_for_tile(ptile, EC_FALLOUT, FALSE);
2936 if (pextra != NULL && !tile_has_extra(ptile, pextra)) {
2937 tile_add_extra(ptile, pextra);
2938 update_tile_knowledge(ptile);
2939 }
2940 }
2941}
2942
2943/**********************************************************************/
2947void do_nuclear_explosion(struct player *pplayer, struct tile *ptile)
2948{
2949 square_iterate(&(wld.map), ptile, 1, ptile1) {
2950 do_nuke_tile(pplayer, ptile1);
2952
2953 script_server_signal_emit("nuke_exploded", 2, API_TYPE_TILE, ptile,
2954 API_TYPE_PLAYER, pplayer);
2955 notify_conn(NULL, ptile, E_NUKE, ftc_server,
2956 _("The %s detonated a nuke!"),
2957 nation_plural_for_player(pplayer));
2958}
2959
2960/**********************************************************************/
2964bool do_airline(struct unit *punit, struct city *pdest_city,
2965 const struct action *paction)
2966{
2967 struct city *psrc_city = tile_city(unit_tile(punit));
2968
2970 E_UNIT_RELOCATED, ftc_server,
2971 _("%s transported successfully."),
2972 unit_link(punit));
2973
2974 unit_move(punit, pdest_city->tile, punit->moves_left,
2975 NULL, BV_ISSET(paction->sub_results, ACT_SUB_RES_MAY_EMBARK),
2976 /* Can only airlift to allied and domestic cities */
2977 FALSE, FALSE,
2978 BV_ISSET(paction->sub_results, ACT_SUB_RES_HUT_ENTER),
2979 BV_ISSET(paction->sub_results, ACT_SUB_RES_HUT_FRIGHTEN));
2980
2981 /* Update airlift fields. */
2982 if (!(game.info.airlifting_style & AIRLIFTING_UNLIMITED_SRC)) {
2983 psrc_city->airlift--;
2984 send_city_info(city_owner(psrc_city), psrc_city);
2985 }
2986 if (!(game.info.airlifting_style & AIRLIFTING_UNLIMITED_DEST)) {
2987 pdest_city->airlift--;
2988 send_city_info(city_owner(pdest_city), pdest_city);
2989 }
2990
2991 return TRUE;
2992}
2993
2994/**********************************************************************/
2997void do_explore(struct unit *punit)
2998{
2999 switch (manage_auto_explorer(punit)) {
3000 case MR_DEATH:
3001 /* don't use punit! */
3002 return;
3003 case MR_NOT_ALLOWED:
3004 /* Needed for something else */
3005 return;
3006 case MR_OK:
3007 /* FIXME: manage_auto_explorer() isn't supposed to change the activity,
3008 * but don't count on this. See PR#39792.
3009 */
3010 if (punit->activity == ACTIVITY_EXPLORE) {
3011 break;
3012 }
3013
3015 default:
3016 unit_activity_handling(punit, ACTIVITY_IDLE);
3017
3018 /* FIXME: When the manage_auto_explorer() call changes the activity from
3019 * EXPLORE to IDLE, in unit_activity_handling() ai.control is left
3020 * alone. We reset it here. See PR#12931. */
3021 punit->ssa_controller = SSA_NONE;
3022 break;
3023 }
3024
3025 send_unit_info(NULL, punit); /* probably duplicate */
3026}
3027
3028/**********************************************************************/
3033bool do_paradrop(struct unit *punit, struct tile *ptile,
3034 const struct action *paction)
3035{
3036 struct player *pplayer = unit_owner(punit);
3037 struct player *tgt_player = tile_owner(ptile);
3038 const struct unit_type *act_utype = unit_type_get(punit);
3039 const struct city *pcity;
3040
3041 /* Hard requirements */
3042 /* FIXME: hard requirements belong in common/actions's
3043 * is_action_possible() and the explanation texts belong in
3044 * server/unithand's action not enabled system (expl_act_not_enabl(),
3045 * ane_kind, explain_why_no_action_enabled(), etc)
3046 */
3047 if (!map_is_known_and_seen(ptile, pplayer, V_MAIN)) {
3048 /* Only take in account values from player map. */
3049 const struct player_tile *plrtile = map_get_player_tile(ptile, pplayer);
3050
3051 if (NULL == plrtile->site
3053 &(plrtile->extras))) {
3054 notify_player(pplayer, ptile, E_BAD_COMMAND, ftc_server,
3055 _("This unit cannot paradrop into %s."),
3057 return FALSE;
3058 }
3059
3060 if (NULL != plrtile->site
3061 && plrtile->owner != NULL
3062 && !pplayers_allied(pplayer, plrtile->owner)
3063 && !action_has_result(paction, ACTRES_PARADROP_CONQUER)) {
3064 notify_player(pplayer, ptile, E_BAD_COMMAND, ftc_server,
3065 /* TRANS: Paratroopers ... Paradrop Unit */
3066 _("%s cannot conquer a city with \"%s\"."),
3068 action_name_translation(paction));
3069 return FALSE;
3070 }
3071
3072 if (NULL != plrtile->site
3073 && plrtile->owner != NULL
3074 && (pplayers_non_attack(pplayer, plrtile->owner)
3075 || (player_diplstate_get(pplayer, plrtile->owner)->type
3076 == DS_ALLIANCE)
3077 || (player_diplstate_get(pplayer, plrtile->owner)->type
3078 == DS_TEAM))
3079 && action_has_result(paction, ACTRES_PARADROP_CONQUER)) {
3080 notify_player(pplayer, ptile, E_BAD_COMMAND, ftc_server,
3081 _("Cannot attack unless you declare war first."));
3082 return FALSE;
3083 }
3084 }
3085
3086
3087 /* Kill the unit when the landing goes wrong. */
3088
3089 /* Safe terrain, really? Not transformed since player last saw it. */
3090 if (!can_unit_exist_at_tile(&(wld.map), punit, ptile)
3091 && (!BV_ISSET(paction->sub_results, ACT_SUB_RES_MAY_EMBARK)
3092 || !unit_could_load_at(punit, ptile))) {
3093 map_show_circle(pplayer, ptile, act_utype->vision_radius_sq);
3094 notify_player(pplayer, ptile, E_UNIT_LOST_MISC, ftc_server,
3095 _("Your %s paradropped into the %s and was lost."),
3098 pplayer->score.units_lost++;
3099 server_remove_unit(punit, ULR_NONNATIVE_TERR);
3100 return TRUE;
3101 }
3102
3103 pcity = tile_city(ptile);
3104
3105 if ((pcity != NULL && !pplayers_allied(pplayer, city_owner(pcity))
3106 && !action_has_result(paction, ACTRES_PARADROP_CONQUER))
3107 || is_non_allied_unit_tile(ptile, pplayer)) {
3108 struct player *main_victim = NULL;
3109 struct player *secondary_victim = NULL;
3110 char victim_link[MAX_LEN_LINK];
3111
3112 map_show_circle(pplayer, ptile, act_utype->vision_radius_sq);
3113 maybe_make_contact(ptile, pplayer);
3114 notify_player(pplayer, ptile, E_UNIT_LOST_MISC, ftc_server,
3115 _("Your %s was killed by enemy units at the "
3116 "paradrop destination."),
3118 /* TODO: Should defender score.units_killed get increased too?
3119 * What if there's units of several allied players? Should the
3120 * city owner or owner of the first/random unit get the kill? */
3121 pplayer->score.units_lost++;
3122
3123 if (pcity != NULL) {
3124 struct player *owner = city_owner(pcity);
3125
3126 if (!pplayers_at_war(pplayer, owner)) {
3127 main_victim = owner;
3128 } else {
3129 secondary_victim = owner;
3130 }
3131
3132 sz_strlcpy(victim_link, city_link(pcity));
3133 } else {
3134 sz_strlcpy(victim_link, tile_link(ptile));
3135 }
3136
3137 if (main_victim == NULL) {
3138 unit_list_iterate(ptile->units, tgt) {
3139 struct player *owner = unit_owner(tgt);
3140
3141 if (!pplayers_at_war(pplayer, owner)) {
3142 main_victim = owner;
3143 break;
3144 } else if (secondary_victim == NULL) {
3145 secondary_victim = owner;
3146 }
3148
3149 if (main_victim == NULL) {
3150 /* There's no victim with whom the attacker isn't in war,
3151 * fallback to one with whom there's already a war. */
3152 main_victim = secondary_victim;
3153 }
3154 }
3155
3156 action_consequence_caught(paction, pplayer, act_utype,
3157 main_victim, ptile,
3158 victim_link);
3159
3160 server_remove_unit(punit, ULR_KILLED);
3161 return TRUE;
3162 }
3163
3164 /* All ok */
3166 if (unit_move(punit, ptile,
3167 /* Done by Action_Success_Actor_Move_Cost */
3168 0,
3169 NULL, BV_ISSET(paction->sub_results,
3170 ACT_SUB_RES_MAY_EMBARK),
3171 paction->result == ACTRES_PARADROP_CONQUER,
3172 paction->result == ACTRES_PARADROP_CONQUER,
3173 BV_ISSET(paction->sub_results, ACT_SUB_RES_HUT_ENTER),
3174 BV_ISSET(paction->sub_results, ACT_SUB_RES_HUT_FRIGHTEN))) {
3175 /* Ensure we finished on valid state. */
3178 }
3179
3180 /* May cause an incident */
3181 action_consequence_success(paction, pplayer, act_utype, tgt_player,
3182 ptile, tile_link(ptile));
3183
3184 return TRUE;
3185}
3186
3187/**********************************************************************/
3191static bool hut_get_limited(struct unit *punit)
3192{
3193 bool ok = TRUE;
3194 int hut_chance = fc_rand(12);
3195 struct player *pplayer = unit_owner(punit);
3196 const struct civ_map *nmap = &(wld.map);
3197
3198 /* 1 in 12 to get barbarians */
3199 if (hut_chance != 0) {
3200 int cred = 25;
3201
3202 notify_player(pplayer, unit_tile(punit), E_HUT_GOLD, ftc_server,
3203 PL_("You found %d gold.",
3204 "You found %d gold.", cred), cred);
3205 pplayer->economic.gold += cred;
3207 || unit_has_type_flag(punit, UTYF_GAMELOSS)) {
3208 notify_player(pplayer, unit_tile(punit),
3209 E_HUT_BARB_CITY_NEAR, ftc_server,
3210 _("An abandoned village is here."));
3211 } else {
3212 notify_player(pplayer, unit_tile(punit), E_HUT_BARB_KILLED, ftc_server,
3213 _("Your %s has been killed by barbarians!"),
3215 wipe_unit(punit, ULR_BARB_UNLEASH, NULL);
3216 ok = FALSE;
3217 }
3218
3219 return ok;
3220}
3221
3222/**********************************************************************/
3226static void unit_enter_hut(struct unit *punit, bool frighten_hut)
3227{
3228 struct player *pplayer = unit_owner(punit);
3229 int id = punit->id;
3230 struct tile *ptile = unit_tile(punit);
3231 bool hut = FALSE;
3232 const struct req_context context = {
3233 .player = pplayer,
3234 .tile = ptile,
3235 };
3236
3237 extra_type_by_rmcause_iterate(ERM_ENTER, pextra) {
3238 if (tile_has_extra(ptile, pextra)
3239 && are_reqs_active(&context, tile_owner(ptile), &pextra->rmreqs,
3241 ) {
3242 hut = TRUE;
3243 /* FIXME: are all enter-removes extras worth counting? */
3244 pplayer->server.huts++;
3245
3246 destroy_extra(ptile, pextra);
3248
3249 /* FIXME: enable different classes
3250 * to behave differently with different huts */
3251 if (frighten_hut) {
3252 script_server_signal_emit("hut_frighten", punit,
3253 extra_rule_name(pextra));
3254 } else if (is_ai(pplayer) && has_handicap(pplayer, H_LIMITEDHUTS)) {
3255 /* AI with H_LIMITEDHUTS only gets 25 gold (or barbs if unlucky) */
3256 (void) hut_get_limited(punit);
3257 } else {
3258 script_server_signal_emit("hut_enter", punit, extra_rule_name(pextra));
3259 }
3260
3261 /* We need punit for the callbacks, can't continue if the unit died */
3262 if (!unit_is_alive(id)) {
3263 break;
3264 }
3265 }
3267
3268 if (hut) {
3269 send_player_info_c(pplayer, pplayer->connections); /* eg, gold */
3270 }
3271 return;
3272}
3273
3274/**********************************************************************/
3277void unit_transport_load_send(struct unit *punit, struct unit *ptrans)
3278{
3279 bv_player can_see_unit;
3280
3281 fc_assert_ret(punit != NULL);
3282 fc_assert_ret(ptrans != NULL);
3283
3284 BV_CLR_ALL(can_see_unit);
3285 players_iterate(pplayer) {
3286 if (can_player_see_unit(pplayer, punit)) {
3287 BV_SET(can_see_unit, player_index(pplayer));
3288 }
3290
3292
3293 players_iterate(pplayer) {
3294 if (BV_ISSET(can_see_unit, player_index(pplayer))
3295 && !can_player_see_unit(pplayer, punit)) {
3296 unit_goes_out_of_sight(pplayer, punit);
3297 }
3299
3300 send_unit_info(NULL, punit);
3301 send_unit_info(NULL, ptrans);
3302}
3303
3304/**********************************************************************/
3308 struct unit *ptrans,
3309 bool force)
3310{
3311 bool had_cargo;
3312
3313 fc_assert_ret(punit != NULL);
3314 fc_assert_ret(ptrans != NULL);
3315
3316 had_cargo = get_transporter_occupancy(ptrans) > 0;
3317
3318 unit_transport_load(punit, ptrans, force);
3319
3320 if (!had_cargo) {
3321 /* Transport's loaded status changed */
3322 send_unit_info(NULL, ptrans);
3323 }
3324}
3325
3326/**********************************************************************/
3330{
3331 struct unit *ptrans;
3332
3334
3335 ptrans = unit_transport_get(punit);
3336
3337 fc_assert_ret(ptrans);
3338
3340
3341 send_unit_info(NULL, punit);
3342 send_unit_info(NULL, ptrans);
3343}
3344
3345/**********************************************************************/
3349static void autoattack_prob_free(struct autoattack_prob *prob)
3350{
3351 free(prob);
3352}
3353
3354/**********************************************************************/
3363static int compare_units(const struct autoattack_prob *const *p1,
3364 const struct autoattack_prob *const *q1)
3365{
3366 const struct unit *p1unit = game_unit_by_number((*p1)->unit_id);
3367 const struct unit *q1unit = game_unit_by_number((*q1)->unit_id);
3368
3369 /* Sort by transport depth first. This makes sure that no transport
3370 * attacks before its cargo does -- cargo sorts earlier in the list. */
3371 {
3372 const struct unit *p1trans = p1unit, *q1trans = q1unit;
3373
3374 /* Walk the transport stacks in parallel, so as to bail out as soon as
3375 * one of them is empty (avoid walking deep stacks more often than
3376 * necessary). */
3377 while (p1trans && q1trans) {
3378 p1trans = unit_transport_get(p1trans);
3379 q1trans = unit_transport_get(q1trans);
3380 }
3381 if (!p1trans && q1trans) {
3382 /* q1 is at greater depth (perhaps it's p1's cargo). It should sort
3383 * earlier in the list (p1 > q1). */
3384 return 1;
3385 } else if (p1trans && !q1trans) {
3386 /* p1 is at greater depth, so should sort earlier (p1 < q1). */
3387 return -1;
3388 }
3389 /* else same depth, so move on to checking win chance: */
3390 }
3391
3392 /* Put the units with the highest probability of success first. The up
3393 * side of this is that units with bonuses against the victim attacks
3394 * before other units. The downside is that strong units can be led
3395 * away by sacrificial units. */
3396 return (-1
3397 /* Assume the worst. */
3398 * action_prob_cmp_pessimist((*p1)->prob, (*q1)->prob));
3399}
3400
3401/**********************************************************************/
3406{
3407 struct autoattack_prob_list *autoattack;
3408 int moves = punit->moves_left;
3409 int sanity1 = punit->id;
3410 struct civ_map *nmap = &(wld.map);
3411
3412 if (!game.server.autoattack) {
3413 return TRUE;
3414 }
3415
3416 autoattack = autoattack_prob_list_new_full(autoattack_prob_free);
3417
3418 /* Kludge to prevent attack power from dropping to zero during calc */
3420
3421 adjc_iterate(nmap, unit_tile(punit), ptile) {
3422 /* First add all eligible units to a autoattack list */
3423 unit_list_iterate(ptile->units, penemy) {
3424 struct autoattack_prob *probability = fc_malloc(sizeof(*probability));
3425 struct tile *tgt_tile = unit_tile(punit);
3426
3427 fc_assert_action(tgt_tile, continue);
3428
3429 probability->prob =
3430 action_auto_perf_unit_prob(AAPC_UNIT_MOVED_ADJ,
3431 penemy, unit_owner(punit), NULL, NULL,
3432 tgt_tile, tile_city(tgt_tile),
3433 punit, NULL);
3434
3435 if (action_prob_possible(probability->prob)) {
3436 probability->unit_id = penemy->id;
3437 autoattack_prob_list_prepend(autoattack, probability);
3438 } else {
3439 FC_FREE(probability);
3440 }
3443
3444 /* Sort the potential attackers from highest to lowest success
3445 * probability. */
3446 if (autoattack_prob_list_size(autoattack) >= 2) {
3447 autoattack_prob_list_sort(autoattack, &compare_units);
3448 }
3449
3450 autoattack_prob_list_iterate_safe(autoattack, peprob, penemy) {
3451 int sanity2 = penemy->id;
3452 struct tile *ptile = unit_tile(penemy);
3453 struct unit *enemy_defender = get_defender(nmap, punit, ptile);
3454 double punitwin, penemywin;
3455 double threshold = 0.25;
3456 struct tile *tgt_tile = unit_tile(punit);
3457
3458 fc_assert(tgt_tile);
3459
3460 if (tile_city(ptile) && unit_list_size(ptile->units) == 1) {
3461 /* Don't leave city defenseless */
3462 threshold = 0.90;
3463 }
3464
3465 if (NULL != enemy_defender) {
3466 punitwin = unit_win_chance(nmap, punit, enemy_defender);
3467 } else {
3468 /* 'penemy' can attack 'punit' but it may be not reciproque. */
3469 punitwin = 1.0;
3470 }
3471
3472 /* Previous attacks may have changed the odds. Recalculate. */
3473 peprob->prob =
3474 action_auto_perf_unit_prob(AAPC_UNIT_MOVED_ADJ,
3475 penemy, unit_owner(punit), NULL, NULL,
3476 tgt_tile, tile_city(tgt_tile),
3477 punit, NULL);
3478
3479 if (!action_prob_possible(peprob->prob)) {
3480 /* No longer legal. */
3481 continue;
3482 }
3483
3484 /* Assume the worst. */
3485 penemywin = action_prob_to_0_to_1_pessimist(peprob->prob);
3486
3487 if ((penemywin > 1.0 - punitwin
3488 || unit_has_type_flag(punit, UTYF_PROVOKING))
3489 && penemywin > threshold) {
3490
3491#ifdef REALLY_DEBUG_THIS
3492 log_test("AA %s -> %s (%d,%d) %.2f > %.2f && > %.2f",
3494 TILE_XY(unit_tile(punit)), penemywin,
3495 1.0 - punitwin, threshold);
3496#endif
3497
3498 unit_activity_handling(penemy, ACTIVITY_IDLE);
3499 action_auto_perf_unit_do(AAPC_UNIT_MOVED_ADJ,
3500 penemy, unit_owner(punit), NULL, NULL,
3501 tgt_tile, tile_city(tgt_tile), punit, NULL);
3502 } else {
3503#ifdef REALLY_DEBUG_THIS
3504 log_test("!AA %s -> %s (%d,%d) %.2f > %.2f && > %.2f",
3506 TILE_XY(unit_tile(punit)), penemywin,
3507 1.0 - punitwin, threshold);
3508#endif
3509 continue;
3510 }
3511
3512 if (game_unit_by_number(sanity2)) {
3513 send_unit_info(NULL, penemy);
3514 }
3515 if (game_unit_by_number(sanity1)) {
3516 send_unit_info(NULL, punit);
3517 } else {
3518 autoattack_prob_list_destroy(autoattack);
3519 return FALSE; /* moving unit dead */
3520 }
3522
3523 autoattack_prob_list_destroy(autoattack);
3524 if (game_unit_by_number(sanity1)) {
3525 /* We could have lost movement in combat */
3526 punit->moves_left = MIN(punit->moves_left, moves);
3527 send_unit_info(NULL, punit);
3528 return TRUE;
3529 } else {
3530 return FALSE;
3531 }
3532}
3533
3534/**********************************************************************/
3537static void cancel_orders(struct unit *punit, char *dbg_msg)
3538{
3540 send_unit_info(NULL, punit);
3541 log_debug("%s", dbg_msg);
3542}
3543
3544/**********************************************************************/
3549{
3550 bool alone_in_city;
3551
3552 if (NULL != tile_city(unit_tile(punit))) {
3553 int count = 0;
3554
3556 /* Consider only units not transported. */
3557 if (!unit_transported(aunit)) {
3558 count++;
3559 }
3561
3562 alone_in_city = (1 == count);
3563 } else {
3564 alone_in_city = FALSE;
3565 }
3566
3567 /* There may be sentried units with a sightrange > 3, but we don't
3568 wake them up if the punit is farther away than 3. */
3569 square_iterate(&(wld.map), unit_tile(punit), 3, ptile) {
3570 unit_list_iterate(ptile->units, penemy) {
3571 int distance_sq = sq_map_distance(unit_tile(punit), ptile);
3572 int radius_sq = get_unit_vision_at(penemy, unit_tile(penemy), V_MAIN);
3573
3575 && penemy->activity == ACTIVITY_SENTRY
3576 && radius_sq >= distance_sq
3577 /* If the unit moved on a city, and the unit is alone, consider
3578 * it is visible. */
3579 && (alone_in_city
3581 /* on board transport; don't awaken */
3582 && can_unit_exist_at_tile(&(wld.map), penemy, unit_tile(penemy))) {
3583 set_unit_activity(penemy, ACTIVITY_IDLE);
3584 send_unit_info(NULL, penemy);
3585 }
3588
3589 /* Wakeup patrolling units we bump into.
3590 We do not wakeup units further away than 3 squares... */
3591 square_iterate(&(wld.map), unit_tile(punit), 3, ptile) {
3592 unit_list_iterate(ptile->units, ppatrol) {
3593 if (punit != ppatrol
3594 && unit_has_orders(ppatrol)
3595 && ppatrol->orders.vigilant) {
3596 if (maybe_cancel_patrol_due_to_enemy(ppatrol)) {
3597 cancel_orders(ppatrol, " stopping because of nearby enemy");
3598 notify_player(unit_owner(ppatrol), unit_tile(ppatrol),
3599 E_UNIT_ORDERS, ftc_server,
3600 _("Orders for %s aborted after enemy movement was "
3601 "spotted."),
3602 unit_link(ppatrol));
3603 }
3604 }
3607}
3608
3609/**********************************************************************/
3619 struct tile *src_tile,
3620 struct tile *dst_tile,
3621 bool passenger,
3622 bool conquer_city_allowed)
3623{
3624 struct city *fromcity = tile_city(src_tile);
3625 struct city *tocity = tile_city(dst_tile);
3626 struct city *homecity_start_pos = NULL;
3627 struct city *homecity_end_pos = NULL;
3628 int homecity_id_start_pos = punit->homecity;
3629 int homecity_id_end_pos = punit->homecity;
3630 struct player *pplayer_start_pos = unit_owner(punit);
3631 struct player *pplayer_end_pos = pplayer_start_pos;
3632 const struct unit_type *type_start_pos = unit_type_get(punit);
3633 const struct unit_type *type_end_pos = type_start_pos;
3634 bool refresh_homecity_start_pos = FALSE;
3635 bool refresh_homecity_end_pos = FALSE;
3636 int saved_id = punit->id;
3637 bool alive = TRUE;
3638 const struct civ_map *nmap = &(wld.map);
3639
3640 if (tocity && conquer_city_allowed) {
3641 if (!passenger) {
3642 /* The unit that does the move may conquer. */
3643 unit_conquer_city(punit, tocity);
3644 }
3645
3646 /* Run for passengers too. A passenger may have been killed when its
3647 * transport conquered a city. (unit_conquer_city() can cause Lua code
3648 * to run) */
3649
3650 alive = unit_is_alive(saved_id);
3651 if (alive) {
3652 /* In case script has changed something about unit */
3653 pplayer_end_pos = unit_owner(punit);
3654 type_end_pos = unit_type_get(punit);
3655 homecity_id_end_pos = punit->homecity;
3656 }
3657 }
3658
3659 if (homecity_id_start_pos != 0) {
3660 homecity_start_pos = game_city_by_number(homecity_id_start_pos);
3661 }
3662 if (homecity_id_start_pos != homecity_id_end_pos) {
3663 homecity_end_pos = game_city_by_number(homecity_id_end_pos);
3664 } else {
3665 homecity_end_pos = homecity_start_pos;
3666 }
3667
3668 /* We only do refreshes for non-AI players to now make sure the AI turns
3669 doesn't take too long. Perhaps we should make a special refresh_city
3670 functions that only refreshed happines. */
3671
3672 /* might have changed owners or may be destroyed */
3673 tocity = tile_city(dst_tile);
3674
3675 if (tocity) { /* entering a city */
3676 if (tocity->owner == pplayer_end_pos) {
3677 if (tocity != homecity_end_pos && is_human(pplayer_end_pos)) {
3678 city_refresh(tocity);
3679 send_city_info(pplayer_end_pos, tocity);
3680 }
3681 }
3682 if (homecity_start_pos) {
3683 refresh_homecity_start_pos = TRUE;
3684 }
3685 }
3686
3687 if (fromcity) { /* leaving a city */
3688 if (homecity_start_pos) {
3689 refresh_homecity_start_pos = TRUE;
3690 }
3691 if (fromcity != homecity_start_pos
3692 && fromcity->owner == pplayer_start_pos
3693 && is_human(pplayer_start_pos)) {
3694 city_refresh(fromcity);
3695 send_city_info(pplayer_start_pos, fromcity);
3696 }
3697 }
3698
3699 /* Entering/leaving a fortress or friendly territory */
3700 if (homecity_start_pos || homecity_end_pos) {
3701 if ((game.info.happyborders != HB_DISABLED && tile_owner(src_tile) != tile_owner(dst_tile))
3703 type_end_pos)
3704 && is_friendly_city_near(nmap, pplayer_end_pos, dst_tile))
3706 type_start_pos)
3707 && is_friendly_city_near(nmap, pplayer_start_pos, src_tile))) {
3708 refresh_homecity_start_pos = TRUE;
3709 refresh_homecity_end_pos = TRUE;
3710 }
3711 }
3712
3713 if (refresh_homecity_start_pos && is_human(pplayer_start_pos)) {
3714 city_refresh(homecity_start_pos);
3715 send_city_info(pplayer_start_pos, homecity_start_pos);
3716 }
3717 if (refresh_homecity_end_pos
3718 && (!refresh_homecity_start_pos
3719 || homecity_start_pos != homecity_end_pos)
3720 && is_human(pplayer_end_pos)) {
3721 city_refresh(homecity_end_pos);
3722 send_city_info(pplayer_end_pos, homecity_end_pos);
3723 }
3724
3725 city_map_update_tile_now(dst_tile);
3726 sync_cities();
3727
3728 return alive;
3729}
3730
3731/**********************************************************************/
3735static void check_unit_activity(struct unit *punit)
3736{
3737 switch (punit->activity) {
3738 case ACTIVITY_IDLE:
3739 case ACTIVITY_SENTRY:
3740 case ACTIVITY_EXPLORE:
3741 case ACTIVITY_GOTO:
3742 break;
3743 case ACTIVITY_POLLUTION:
3744 case ACTIVITY_MINE:
3745 case ACTIVITY_IRRIGATE:
3746 case ACTIVITY_CULTIVATE:
3747 case ACTIVITY_PLANT:
3748 case ACTIVITY_FORTIFIED:
3749 case ACTIVITY_FORTRESS:
3750 case ACTIVITY_PILLAGE:
3751 case ACTIVITY_TRANSFORM:
3752 case ACTIVITY_UNKNOWN:
3753 case ACTIVITY_AIRBASE:
3754 case ACTIVITY_FORTIFYING:
3755 case ACTIVITY_FALLOUT:
3756 case ACTIVITY_PATROL_UNUSED:
3757 case ACTIVITY_BASE:
3758 case ACTIVITY_GEN_ROAD:
3759 case ACTIVITY_CONVERT:
3760 case ACTIVITY_OLD_ROAD:
3761 case ACTIVITY_OLD_RAILROAD:
3762 case ACTIVITY_LAST:
3763 set_unit_activity(punit, ACTIVITY_IDLE);
3764 break;
3765 };
3766}
3767
3768/**********************************************************************/
3772 struct tile *psrctile,
3773 struct tile *pdesttile)
3774{
3775 struct unit_move_data *pdata;
3776 struct player *powner = unit_owner(punit);
3777
3778 if (punit->server.moving) {
3779 /* Recursive moving (probably due to a script). */
3780 pdata = punit->server.moving;
3781 pdata->ref_count++;
3782 fc_assert_msg(pdata->punit == punit,
3783 "Unit number %d (%p) was going to die, but "
3784 "server attempts to move it.",
3785 punit->id, punit);
3786 fc_assert_msg(pdata->old_vision == NULL,
3787 "Unit number %d (%p) has done an incomplete move.",
3788 punit->id, punit);
3789 } else {
3790 pdata = fc_malloc(sizeof(*pdata));
3791 pdata->ref_count = 1;
3792 pdata->punit = punit;
3793 punit->server.moving = pdata;
3794 BV_CLR_ALL(pdata->can_see_unit);
3795 }
3796 pdata->powner = powner;
3797 BV_CLR_ALL(pdata->can_see_move);
3798 pdata->old_vision = punit->server.vision;
3799
3800 return pdata;
3801}
3802
3803/**********************************************************************/
3806static void unit_move_by_data(struct unit_move_data *pdata,
3807 struct tile *psrctile, struct tile *pdesttile)
3808{
3809 struct vision *new_vision;
3810 struct unit *punit = pdata->punit;
3811 int mod = unit_vision_range_modifiers(punit, pdesttile);
3812 const v_radius_t radius_sq =
3813 V_RADIUS(get_unit_vision_base(punit, V_MAIN, mod),
3814 get_unit_vision_base(punit, V_INVIS, mod),
3815 get_unit_vision_base(punit, V_SUBSURFACE, mod));
3816
3817 /* Remove unit from the source tile. */
3818 fc_assert(unit_tile(punit) == psrctile);
3819
3820#ifndef FREECIV_NDEBUG
3821 bool success =
3822#endif
3823 unit_list_remove(psrctile->units, punit);
3824 fc_assert(success);
3825
3826 /* Set new tile. */
3827 unit_tile_set(punit, pdesttile);
3828 unit_list_prepend(pdesttile->units, punit);
3829
3830 if (unit_transported(punit)) {
3831 /* Silently free orders since they won't be applicable anymore. */
3833 }
3834
3835 /* Check unit activity. */
3839
3840 /* We first unfog the destination, then send the move,
3841 * and then fog the old territory. This means that the player
3842 * gets a chance to see the newly explored territory while the
3843 * client moves the unit, and both areas are visible during the
3844 * move */
3845
3846 /* Enhance vision if unit steps into a fortress */
3847 new_vision = vision_new(pdata->powner, pdesttile);
3848 punit->server.vision = new_vision;
3849 vision_change_sight(new_vision, radius_sq);
3850 ASSERT_VISION(new_vision);
3851}
3852
3853/**********************************************************************/
3856static void unit_move_data_unref(struct unit_move_data *pdata)
3857{
3858 fc_assert_ret(pdata != NULL);
3859 fc_assert_ret(pdata->ref_count > 0);
3860 fc_assert_msg(pdata->old_vision == NULL,
3861 "Unit number %d (%p) has done an incomplete move.",
3862 pdata->punit != NULL ? pdata->punit->id : -1, pdata->punit);
3863
3864 pdata->ref_count--;
3865 if (pdata->ref_count == 0) {
3866 if (pdata->punit != NULL) {
3867 fc_assert(pdata->punit->server.moving == pdata);
3868 pdata->punit->server.moving = NULL;
3869 }
3870 free(pdata);
3871 }
3872}
3873
3874/**********************************************************************/
3885bool unit_move(struct unit *punit, struct tile *pdesttile, int move_cost,
3886 struct unit *embark_to, bool find_embark_target,
3887 bool conquer_city_allowed, bool conquer_extras_allowed,
3888 bool enter_hut, bool frighten_hut)
3889{
3890 struct player *pplayer;
3891 struct tile *psrctile;
3892 struct city *psrccity;
3893 struct city *pdestcity;
3894 struct unit *ptransporter;
3895 struct packet_unit_info src_info, dest_info;
3896 struct packet_unit_short_info src_sinfo, dest_sinfo;
3897 struct unit_move_data_list *plist =
3898 unit_move_data_list_new_full(unit_move_data_unref);
3899 struct unit_move_data *pdata;
3900 int saved_id;
3901 bool unit_lives;
3902 bool adj;
3903 enum direction8 facing;
3904
3905 /* Some checks. */
3906 fc_assert_ret_val(punit != NULL, FALSE);
3907 fc_assert_ret_val(pdesttile != NULL, FALSE);
3908
3909 pplayer = unit_owner(punit);
3910 saved_id = punit->id;
3911 psrctile = unit_tile(punit);
3912 adj = base_get_direction_for_step(&(wld.map), psrctile, pdesttile, &facing);
3913
3915
3916 /* Unload the unit if on a transport. */
3917 ptransporter = unit_transport_get(punit);
3918 if (ptransporter != NULL) {
3919 /* Unload unit _before_ setting the new tile! */
3921 /* Send updated information to anyone watching that transporter
3922 * was unloading cargo. */
3923 send_unit_info(NULL, ptransporter);
3924 }
3925
3926 /* Wakup units next to us before we move. */
3928
3929 /* Make info packets at 'psrctile'. */
3930 if (adj) {
3931 /* If tiles are adjacent, we will show the move to users able
3932 * to see it. */
3933 package_unit(punit, &src_info);
3935 }
3936
3937 /* Make new data for 'punit'. */
3938 pdata = unit_move_data(punit, psrctile, pdesttile);
3939 unit_move_data_list_prepend(plist, pdata);
3940
3941 /* Set unit orientation */
3942 if (adj) {
3943 /* Only change orientation when moving to adjacent tile */
3944 punit->facing = facing;
3945 }
3946
3947 /* Move magic. */
3948 punit->moved = TRUE;
3949 punit->moves_left = MAX(0, punit->moves_left - move_cost);
3950 if (punit->moves_left == 0 && !unit_has_orders(punit)) {
3951 /* The next order may not require any remaining move fragments. */
3953 }
3954
3955 /* No longer relevant. */
3957 punit->action_decision_want = ACT_DEC_NOTHING;
3958
3959 /* Claim ownership of fortress? */
3960 if (conquer_extras_allowed
3962 /* Yes. We claim *all* bases if there's *any* claimable base(s).
3963 * Even if original unit cannot claim other kind of bases, the
3964 * first claimed base will have influence over other bases,
3965 * or something like that. */
3966 tile_claim_bases(pdesttile, pplayer);
3967 }
3968
3969 /* Move all contained units. */
3970 unit_cargo_iterate(punit, pcargo) {
3971 pdata = unit_move_data(pcargo, psrctile, pdesttile);
3972 unit_move_data_list_append(plist, pdata);
3974
3975 /* Get data for 'punit'. */
3976 pdata = unit_move_data_list_front(plist);
3977
3978 /* Determine the players able to see the move(s), now that the player
3979 * vision has been increased. */
3980 if (adj) {
3981 /* Main unit for adjacent move: the move is visible for every player
3982 * able to see on the matching unit layer. */
3983 enum vision_layer vlayer = unit_type_get(punit)->vlayer;
3984
3985 players_iterate(oplayer) {
3986 if (map_is_known_and_seen(psrctile, oplayer, vlayer)
3987 || map_is_known_and_seen(pdesttile, oplayer, vlayer)) {
3988 BV_SET(pdata->can_see_unit, player_index(oplayer));
3989 BV_SET(pdata->can_see_move, player_index(oplayer));
3990 }
3992 }
3993
3994 unit_move_data_list_iterate(plist, pmove_data) {
3995
3996 unit_move_by_data(pmove_data, psrctile, pdesttile);
3997
3998 if (adj && pmove_data == pdata) {
3999 /* If positions are adjacent, we have already handled 'punit'. See
4000 * above. */
4001 continue;
4002 }
4003
4004 players_iterate(oplayer) {
4005 if ((adj
4006 && can_player_see_unit_at(oplayer, pmove_data->punit, psrctile,
4007 pmove_data != pdata))
4008 || can_player_see_unit_at(oplayer, pmove_data->punit, pdesttile,
4009 pmove_data != pdata)) {
4010 BV_SET(pmove_data->can_see_unit, player_index(oplayer));
4011 BV_SET(pmove_data->can_see_move, player_index(oplayer));
4012 }
4013 if (can_player_see_unit_at(oplayer, pmove_data->punit, psrctile,
4014 pmove_data != pdata)) {
4015 /* The unit was seen with its source tile even if it was
4016 * teleported. */
4017 BV_SET(pmove_data->can_see_unit, player_index(oplayer));
4018 }
4021
4022 /* Check timeout settings. */
4024 bool new_information_for_enemy = FALSE;
4025
4026 phase_players_iterate(penemy) {
4027 /* Increase the timeout if an enemy unit moves and the
4028 * timeoutaddenemymove setting is in use. */
4029 if (penemy->is_connected
4030 && pplayer != penemy
4031 && pplayers_at_war(pplayer, penemy)
4032 && BV_ISSET(pdata->can_see_move, player_index(penemy))) {
4033 new_information_for_enemy = TRUE;
4034 break;
4035 }
4037
4038 if (new_information_for_enemy) {
4040 }
4041 }
4042
4043 if (!adj
4044 && action_tgt_city(punit, pdesttile, FALSE)) {
4045 /* The unit can perform an action to the city at the destination tile.
4046 * A long distance move (like an airlift) doesn't ask what action to
4047 * perform before moving. Ask now. */
4048
4049 punit->action_decision_want = ACT_DEC_PASSIVE;
4050 punit->action_decision_tile = pdesttile;
4051 }
4052
4053 /* Notifications of the move to the clients. */
4054 if (adj) {
4055 /* Special case: 'punit' is moving to adjacent position. Then we show
4056 * 'punit' move to all users able to see 'psrctile' or 'pdesttile'. */
4057
4058 /* Make info packets at 'pdesttile'. */
4059 package_unit(punit, &dest_info);
4061
4063 struct player *aplayer = conn_get_player(pconn);
4064
4065 if (aplayer == NULL) {
4066 if (pconn->observer) {
4067 /* Global observers see all... */
4068 send_packet_unit_info(pconn, &src_info);
4069 send_packet_unit_info(pconn, &dest_info);
4070 }
4071 } else if (BV_ISSET(pdata->can_see_move, player_index(aplayer))) {
4072 if (aplayer == pplayer) {
4073 send_packet_unit_info(pconn, &src_info);
4074 send_packet_unit_info(pconn, &dest_info);
4075 } else {
4076 send_packet_unit_short_info(pconn, &src_sinfo, FALSE);
4077 send_packet_unit_short_info(pconn, &dest_sinfo, FALSE);
4078 }
4079 }
4081 }
4082
4083 /* Other moves. */
4084 unit_move_data_list_iterate(plist, pmove_data) {
4085 if (adj && pmove_data == pdata) {
4086 /* If positions are adjacent, we have already shown 'punit' move.
4087 * See above. */
4088 continue;
4089 }
4090
4091 /* Make info packets at 'pdesttile'. */
4092 package_unit(pmove_data->punit, &dest_info);
4093 package_short_unit(pmove_data->punit, &dest_sinfo,
4095
4097 struct player *aplayer = conn_get_player(pconn);
4098
4099 if (aplayer == NULL) {
4100 if (pconn->observer) {
4101 /* Global observers see all... */
4102 send_packet_unit_info(pconn, &dest_info);
4103 }
4104 } else if (BV_ISSET(pmove_data->can_see_move, player_index(aplayer))) {
4105 if (aplayer == pmove_data->powner) {
4106 send_packet_unit_info(pconn, &dest_info);
4107 } else {
4108 send_packet_unit_short_info(pconn, &dest_sinfo, FALSE);
4109 }
4110 }
4113
4114 /* Clear old vision. */
4115 unit_move_data_list_iterate(plist, pmove_data) {
4116 if (pmove_data->old_vision != NULL) {
4117 vision_clear_sight(pmove_data->old_vision);
4118 vision_free(pmove_data->old_vision);
4119 pmove_data->old_vision = NULL;
4120 }
4122
4123 /* Move consequences. */
4124 unit_move_data_list_iterate(plist, pmove_data) {
4125 struct unit *aunit = pmove_data->punit;
4126
4127 if (aunit != NULL
4128 && unit_owner(aunit) == pmove_data->powner
4129 && unit_tile(aunit) == pdesttile) {
4130 (void) unit_move_consequences(aunit, psrctile, pdesttile,
4131 pdata != pmove_data,
4132 conquer_city_allowed);
4133 }
4135
4136 unit_lives = (pdata->punit == punit);
4137
4138 /* Wakeup units and make contact. */
4139 if (unit_lives) {
4141 }
4142 maybe_make_contact(pdesttile, pplayer);
4143
4144 if (unit_lives) {
4145 /* Special checks for ground units in the ocean. */
4146 if (embark_to || !can_unit_survive_at_tile(&(wld.map), punit, pdesttile)) {
4147 if (embark_to != NULL) {
4148 ptransporter = embark_to;
4149 } else if (find_embark_target) {
4150 /* TODO: Consider to stop supporting find_embark_target and make all
4151 * callers that wants auto loading set embark_to. */
4152 ptransporter = transporter_for_unit(punit);
4153 } else {
4154 ptransporter = NULL;
4155 }
4156 if (ptransporter) {
4158
4159 /* Set activity to sentry if boarding a ship. */
4160 if (is_human(pplayer)
4162 && punit->ssa_controller == SSA_NONE
4163 && !can_unit_exist_at_tile(&(wld.map), punit, pdesttile)) {
4164 set_unit_activity(punit, ACTIVITY_SENTRY);
4165 }
4166
4167 send_unit_info(NULL, punit);
4168 }
4169 }
4170 }
4171
4172 /* Remove units going out of sight. */
4173 unit_move_data_list_iterate_rev(plist, pmove_data) {
4174 struct unit *aunit = pmove_data->punit;
4175
4176 if (aunit == NULL) {
4177 continue; /* Died! */
4178 }
4179
4180 players_iterate(aplayer) {
4181 if (BV_ISSET(pmove_data->can_see_unit, player_index(aplayer))
4182 && !can_player_see_unit(aplayer, aunit)) {
4183 unit_goes_out_of_sight(aplayer, aunit);
4184 }
4187
4188 /* Inform the owner's client about actor unit arrival. Can, depending on
4189 * the client settings, cause the client to start the process that makes
4190 * the action selection dialog pop up. */
4191 pdestcity = tile_city(pdesttile);
4192 if (pdestcity != NULL) {
4193 /* Arrival in a city counts. */
4194
4195 unit_move_data_list_iterate(plist, pmove_data) {
4196 struct unit *ptrans;
4197 bool ok;
4198 struct unit *act_unit;
4199 struct player *act_player;
4200
4201 act_unit = pmove_data->punit;
4202 act_player = unit_owner(act_unit);
4203
4204 if (act_unit == NULL
4205 || !unit_is_alive(act_unit->id)) {
4206 /* The unit died before reaching this point. */
4207 continue;
4208 }
4209
4210 if (unit_tile(act_unit) != pdesttile) {
4211 /* The unit didn't arrive at the destination tile. */
4212 continue;
4213 }
4214
4215 if (!is_human(act_player)) {
4216 /* Only humans need reminders. */
4217 continue;
4218 }
4219
4220 if (!unit_transported(act_unit)) {
4221 /* Don't show the action selection dialog again. Non transported
4222 * units are handled before they move to the tile. */
4223 continue;
4224 }
4225
4226 /* Open action dialog only if 'act_unit' and all its transporters
4227 * (recursively) don't have orders. */
4228 if (unit_has_orders(act_unit)) {
4229 /* The unit it self has orders. */
4230 continue;
4231 }
4232
4233 for (ptrans = unit_transport_get(act_unit);;
4234 ptrans = unit_transport_get(ptrans)) {
4235 if (NULL == ptrans) {
4236 /* No (recursive) transport has orders. */
4237 ok = TRUE;
4238 break;
4239 } else if (unit_has_orders(ptrans)) {
4240 /* A unit transporting the unit has orders */
4241 ok = FALSE;
4242 break;
4243 }
4244 }
4245
4246 if (!ok) {
4247 /* A unit transporting act_unit has orders. */
4248 continue;
4249 }
4250
4251 if (action_tgt_city(act_unit, pdesttile, FALSE)) {
4252 /* There is a valid target. */
4253
4254 act_unit->action_decision_want = ACT_DEC_PASSIVE;
4255 act_unit->action_decision_tile = pdesttile;
4256
4257 /* Let the client know that this unit wants the player to decide
4258 * what to do. */
4259 send_unit_info(player_reply_dest(act_player), act_unit);
4260 }
4262 }
4263
4264 unit_move_data_list_destroy(plist);
4265 /* Check cities at source and destination. */
4266 psrccity = tile_city(psrctile);
4267 if (psrccity != NULL) {
4268 refresh_dumb_city(psrccity);
4269 }
4270 if (pdestcity != NULL) {
4271 refresh_dumb_city(pdestcity);
4272 }
4273
4274 if (unit_lives) {
4275 /* Let the scripts run ... */
4276 script_server_signal_emit("unit_moved", punit, psrctile, pdesttile);
4277 unit_lives = unit_is_alive(saved_id);
4278 }
4279
4280 if (unit_lives) {
4281 /* Autoattack. */
4282 unit_lives = unit_survive_autoattack(punit);
4283 }
4284
4285 if (unit_lives && (enter_hut || frighten_hut)) {
4286 /* Is there a hut? */
4289 unit_lives = unit_is_alive(saved_id);
4290 }
4291
4293
4294 if (unit_lives) {
4295 CALL_FUNC_EACH_AI(unit_move_seen, punit);
4296 }
4297
4298 return unit_lives;
4299}
4300
4301/**********************************************************************/
4305 struct tile *ptile)
4306{
4307 return (is_non_allied_unit_tile(ptile, unit_owner(punit))
4309}
4310
4311/**********************************************************************/
4318{
4319 bool cancel = FALSE;
4320 int radius_sq = get_unit_vision_at(punit, unit_tile(punit), V_MAIN);
4321 struct player *pplayer = unit_owner(punit);
4322
4323 circle_iterate(&(wld.map), unit_tile(punit), radius_sq, ptile) {
4324 struct unit *penemy = tile_non_allied_unit(ptile, pplayer);
4325 struct vision_site *pdcity = map_get_player_site(ptile, pplayer);
4326
4327 if ((penemy && can_player_see_unit(pplayer, penemy))
4328 || (pdcity && !pplayers_allied(pplayer, vision_site_owner(pdcity))
4329 && pdcity->occupied)) {
4330 cancel = TRUE;
4331 break;
4332 }
4334
4335 return cancel;
4336}
4337
4338/**********************************************************************/
4346static inline bool player_is_watching(struct unit *punit, const bool fresh)
4347{
4348 /* The player just sent the orders to the unit. The unit has moves left.
4349 * It is therefore safe to assume that the player already is paying
4350 * attention to the unit. */
4351 return fresh && punit->moves_left > 0;
4352}
4353
4354/**********************************************************************/
4373bool execute_orders(struct unit *punit, const bool fresh)
4374{
4375 struct act_prob prob;
4376 bool performed;
4377 const char *name;
4378 bool res, last_order;
4379 int unitid = punit->id;
4380 struct player *pplayer = unit_owner(punit);
4381 int moves_made = 0;
4382 const struct civ_map *nmap = &(wld.map);
4383
4385
4386 if (punit->activity != ACTIVITY_IDLE) {
4387 /* Unit's in the middle of an activity; wait for it to finish. */
4389 return TRUE;
4390 }
4391
4392 log_debug("Executing orders for %s %d", unit_rule_name(punit), punit->id);
4393
4394 /* Any time the orders are canceled we should give the player a message. */
4395
4396 while (TRUE) {
4397 struct unit_order order;
4398
4399 struct action *oaction;
4400
4401 struct tile *dst_tile;
4402 struct city *tgt_city;
4403 struct unit *tgt_unit;
4404 int tgt_id;
4405 int sub_tgt_id;
4406 struct extra_type *pextra;
4407
4408 if (punit->done_moving) {
4409 log_debug(" stopping because we're done this turn");
4410 return TRUE;
4411 }
4412
4414 /* "Patrol" orders are stopped if an enemy is near. */
4415 cancel_orders(punit, " stopping because of nearby enemy");
4416 notify_player(pplayer, unit_tile(punit), E_UNIT_ORDERS, ftc_server,
4417 _("Orders for %s aborted as there are units nearby."),
4418 unit_link(punit));
4419 return TRUE;
4420 }
4421
4422 if (moves_made == punit->orders.length) {
4423 /* For repeating orders, don't repeat more than once per turn. */
4424 log_debug(" stopping because we ran a round");
4426 send_unit_info(NULL, punit);
4427 return TRUE;
4428 }
4429 moves_made++;
4430
4431 order = punit->orders.list[punit->orders.index];
4432
4433 /* An ORDER_PERFORM_ACTION that doesn't specify an action should not get
4434 * this far. */
4436 || action_id_exists(order.action)),
4437 continue);
4438
4439 switch (order.order) {
4440 case ORDER_MOVE:
4441 case ORDER_ACTION_MOVE:
4442 case ORDER_FULL_MP:
4443 if (0 == punit->moves_left) {
4444 log_debug(" stopping because of no more move points");
4445 return TRUE;
4446 }
4447 break;
4450 log_debug(" stopping. Not enough move points this turn");
4451 return TRUE;
4452 }
4453 break;
4454 case ORDER_ACTIVITY:
4455 case ORDER_LAST:
4456 /* Those actions don't require moves left. */
4457 break;
4458 }
4459
4460 last_order = (!punit->orders.repeat
4461 && punit->orders.index + 1 == punit->orders.length);
4462
4463 if (last_order) {
4464 /* Clear the orders before we engage in the move. That way any
4465 * has_orders checks will yield FALSE and this will be treated as
4466 * a normal move. This is important: for instance a caravan goto
4467 * will popup the caravan dialog on the last move only. */
4469 }
4470
4471 /* Advance the orders one step forward. This is needed because any
4472 * updates sent to the client as a result of the action should include
4473 * the new index value. Note that we have to send_unit_info somewhere
4474 * after this point so that the client is properly updated. */
4475 punit->orders.index++;
4476
4477 switch (order.order) {
4478 case ORDER_FULL_MP:
4480 /* If the unit doesn't have full MP then it just waits until the
4481 * next turn. We assume that the next turn it will have full MP
4482 * (there's no check for that). */
4484 log_debug(" waiting this turn");
4485 send_unit_info(NULL, punit);
4486 }
4487 break;
4488 case ORDER_ACTIVITY:
4489 {
4490 enum unit_activity activity = order.activity;
4491
4492 fc_assert(activity == ACTIVITY_SENTRY);
4493
4494 if (can_unit_do_activity(nmap, punit, activity)) {
4496 set_unit_activity(punit, activity);
4497 send_unit_info(NULL, punit);
4498
4499 break;
4500 }
4501 }
4502
4503 cancel_orders(punit, " orders canceled because of failed activity");
4504 notify_player(pplayer, unit_tile(punit), E_UNIT_ORDERS, ftc_server,
4505 _("Orders for %s aborted since they "
4506 "give an invalid activity."),
4507 unit_link(punit));
4508 return TRUE;
4509 case ORDER_MOVE:
4510 case ORDER_ACTION_MOVE:
4511 /* Move unit */
4512 if (!(dst_tile = mapstep(&(wld.map), unit_tile(punit), order.dir))) {
4513 cancel_orders(punit, " move order sent us to invalid location");
4514 notify_player(pplayer, unit_tile(punit), E_UNIT_ORDERS, ftc_server,
4515 _("Orders for %s aborted since they "
4516 "give an invalid location."),
4517 unit_link(punit));
4518 return TRUE;
4519 }
4520
4521 if (order.order != ORDER_ACTION_MOVE
4522 && maybe_cancel_goto_due_to_enemy(punit, dst_tile)) {
4523 /* Plain move required: no attack, trade route etc. */
4524 cancel_orders(punit, " orders canceled because of enemy");
4525 notify_player(pplayer, unit_tile(punit), E_UNIT_ORDERS, ftc_server,
4526 _("Orders for %s aborted as there "
4527 "are units in the way."),
4528 unit_link(punit));
4529 return TRUE;
4530 }
4531
4532 log_debug(" moving to %d,%d", TILE_XY(dst_tile));
4533 res = unit_move_handling(punit, dst_tile,
4534 order.order != ORDER_ACTION_MOVE);
4535 if (!player_unit_by_number(pplayer, unitid)) {
4536 log_debug(" unit died while moving.");
4537 /* A player notification should already have been sent. */
4538 return FALSE;
4539 }
4540
4541 if (res && !same_pos(dst_tile, unit_tile(punit))) {
4542 /* Movement succeeded but unit didn't move. */
4543 log_debug(" orders resulted in combat.");
4544 send_unit_info(NULL, punit);
4545 return TRUE;
4546 }
4547
4548 if (!res) {
4549 fc_assert(0 <= punit->moves_left);
4550
4551 /* Movement failed (ZOC, etc.) */
4552 cancel_orders(punit, " attempt to move failed.");
4553
4554 if (!player_is_watching(punit, fresh)
4555 /* The final move "failed" because the unit needs to ask the
4556 * player what action it should take.
4557 *
4558 * The action decision request notifies the player. Its
4559 * location at the unit's last order makes it clear to the
4560 * player who the decision is for. ("The Spy I sent to Berlin
4561 * has arrived.")
4562 *
4563 * A notification message is therefore redundant. */
4564 && !(last_order
4565 && punit->action_decision_want == ACT_DEC_ACTIVE
4566 && punit->action_decision_tile == dst_tile)) {
4567 /* The player may have missed this. No one else will announce it
4568 * in a satisfying manner. Inform the player. */
4569 notify_player(pplayer, unit_tile(punit),
4570 E_UNIT_ORDERS, ftc_server,
4571 _("Orders for %s aborted because of failed move."),
4572 unit_link(punit));
4573 }
4574
4575 return TRUE;
4576 }
4577 break;
4579 oaction = action_by_number(order.action);
4580
4581 /* Checked in unit_order_list_is_sane() */
4582 fc_assert_action(oaction != NULL, continue);
4583
4584 log_debug(" orders: doing action %s", action_rule_name(oaction));
4585
4586 dst_tile = index_to_tile(&(wld.map), order.target);
4587
4588 if (dst_tile == NULL) {
4589 /* Could be at the edge of the map while trying to target a tile
4590 * outside of it. */
4591
4592 cancel_orders(punit, " target location doesn't exist");
4593 illegal_action_msg(unit_owner(punit), E_UNIT_ORDERS, punit,
4594 order.action, dst_tile, NULL, NULL);
4595
4596 return TRUE;
4597 }
4598
4599 /* Get the target city from the target tile. */
4600 tgt_city = tile_city(dst_tile);
4601
4602 if (tgt_city == NULL
4603 && action_id_get_target_kind(order.action) == ATK_CITY) {
4604 /* This action targets a city but no city target was found. */
4605
4606 cancel_orders(punit, " perform action vs city with no city");
4607 illegal_action_msg(unit_owner(punit), E_UNIT_ORDERS, punit,
4608 order.action, dst_tile, tgt_city, NULL);
4609
4610 return TRUE;
4611 }
4612
4613 /* Get a target unit at the target tile. */
4614 tgt_unit = action_tgt_unit(punit, dst_tile, TRUE);
4615
4616 if (tgt_unit == NULL
4617 && action_id_get_target_kind(order.action) == ATK_UNIT) {
4618 /* This action targets a unit but no target unit was found. */
4619
4620 cancel_orders(punit, " perform action vs unit with no unit");
4621 illegal_action_msg(unit_owner(punit), E_UNIT_ORDERS, punit,
4622 order.action, dst_tile, tgt_city, tgt_unit);
4623
4624 return TRUE;
4625 }
4626
4627 /* Server side sub target assignment */
4628 if (oaction->target_complexity == ACT_TGT_COMPL_FLEXIBLE
4629 && order.sub_target == NO_TARGET) {
4630 /* Try to find a sub target. */
4631 sub_tgt_id = action_sub_target_id_for_action(oaction, punit);
4632 } else {
4633 /* The client should have specified a sub target if needed */
4634 sub_tgt_id = order.sub_target;
4635 }
4636
4637 /* Get a target extra at the target tile */
4638 pextra = (sub_tgt_id == NO_TARGET ?
4639 NULL :
4640 extra_by_number(sub_tgt_id));
4641
4642 if (action_get_sub_target_kind(oaction) == ASTK_EXTRA_NOT_THERE
4643 && pextra != NULL
4644 && action_creates_extra(oaction, pextra)
4645 && tile_has_extra(dst_tile, pextra)) {
4646 /* Already there. Move on to the next order. */
4647 break;
4648 }
4649
4650 if (action_get_sub_target_kind(oaction) == ASTK_EXTRA
4651 && pextra != NULL
4652 && action_removes_extra(oaction, pextra)
4653 && !tile_has_extra(dst_tile, pextra)) {
4654 /* Already not there. Move on to the next order. */
4655 break;
4656 }
4657
4658 /* No target selected. */
4659 tgt_id = -1;
4660
4661 /* Assume impossible until told otherwise. */
4662 prob = ACTPROB_IMPOSSIBLE;
4663
4664 switch (action_id_get_target_kind(order.action)) {
4665 case ATK_UNITS:
4666 prob = action_prob_vs_units(nmap, punit, order.action,
4667 dst_tile);
4668 tgt_id = dst_tile->index;
4669 break;
4670 case ATK_TILE:
4671 prob = action_prob_vs_tile(nmap, punit, order.action,
4672 dst_tile, pextra);
4673 tgt_id = dst_tile->index;
4674 break;
4675 case ATK_EXTRAS:
4676 prob = action_prob_vs_extras(nmap, punit, order.action,
4677 dst_tile, pextra);
4678 tgt_id = dst_tile->index;
4679 break;
4680 case ATK_CITY:
4681 prob = action_prob_vs_city(nmap, punit, order.action,
4682 tgt_city);
4683 tgt_id = tgt_city->id;
4684 break;
4685 case ATK_UNIT:
4686 prob = action_prob_vs_unit(nmap, punit, order.action,
4687 tgt_unit);
4688
4689 tgt_id = tgt_unit->id;
4690 break;
4691 case ATK_SELF:
4692 prob = action_prob_self(nmap, punit, order.action);
4693
4694 tgt_id = unitid;
4695 break;
4696 case ATK_COUNT:
4697 log_error("Invalid action target kind");
4698
4699 /* The check below will abort and cancel the orders because prob
4700 * was initialized to impossible above this switch statement. */
4701
4702 break;
4703 }
4704
4705 if (!action_prob_possible(prob)) {
4706 /* The player has enough information to know that this action is
4707 * against the rules. Don't risk any punishment by trying to
4708 * perform it. */
4709
4710 cancel_orders(punit, " illegal action");
4711 notify_player(pplayer, unit_tile(punit), E_UNIT_ORDERS, ftc_server,
4712 _("%s could not do %s to %s."),
4715 tile_link(dst_tile));
4716
4717 /* Try to explain what rule made it illegal. */
4718 illegal_action_msg(unit_owner(punit), E_BAD_COMMAND, punit,
4719 order.action, dst_tile, tgt_city, tgt_unit);
4720
4721 return TRUE;
4722 }
4723
4724 if (action_id_has_result_safe(order.action, ACTRES_FOUND_CITY)) {
4725 /* This action needs a name. */
4727 } else {
4728 /* This action doesn't need a name. */
4729 name = "";
4730 }
4731
4732 performed = unit_perform_action(pplayer,
4733 unitid,
4734 tgt_id,
4735 sub_tgt_id,
4736 name,
4737 order.action,
4738 ACT_REQ_PLAYER);
4739
4740 if (!player_unit_by_number(pplayer, unitid)) {
4741 /* The unit "died" while performing the action. */
4742 return FALSE;
4743 }
4744
4745 if (!performed) {
4746 /* The action wasn't performed as ordered. */
4747
4748 cancel_orders(punit, " failed action");
4749 notify_player(pplayer, unit_tile(punit), E_UNIT_ORDERS, ftc_server,
4750 _("Orders for %s aborted because "
4751 "doing %s to %s failed."),
4754 tile_link(dst_tile));
4755
4756 return TRUE;
4757 }
4758
4759 if (action_id_get_act_time(order.action, punit, dst_tile, pextra)
4761 /* Done at turn change. */
4763 send_unit_info(NULL, punit);
4764 break;
4765 }
4766
4767 break;
4768 case ORDER_LAST:
4769 /* Should be caught when loading the unit orders from the savegame or
4770 * when receiving the unit orders from the client. */
4771 fc_assert_msg(order.order != ORDER_LAST, "Invalid order: last.");
4772 cancel_orders(punit, " invalid order!");
4773 notify_player(pplayer, unit_tile(punit), E_UNIT_ORDERS, ftc_server,
4774 _("Your %s has invalid orders."),
4775 unit_link(punit));
4776 return TRUE;
4777 }
4778
4779 if (last_order) {
4781 log_debug(" stopping because orders are complete");
4782 return TRUE;
4783 }
4784
4785 if (punit->orders.index == punit->orders.length) {
4787 /* Start over. */
4788 log_debug(" repeating orders.");
4789 punit->orders.index = 0;
4790 }
4791 } /* end while */
4792}
4793
4794/**********************************************************************/
4801static int get_unit_vision_base(struct unit *punit, enum vision_layer vlayer,
4802 const int base)
4803{
4804 switch (vlayer) {
4805 case V_MAIN:
4806 return MAX(0, base);
4807 case V_INVIS:
4808 case V_SUBSURFACE:
4809 return CLIP(0, base, 2);
4810 case V_COUNT:
4811 break;
4812 }
4813
4814 log_error("Unsupported vision layer variant: %d.", vlayer);
4815
4816 return 0;
4817}
4818
4819/**********************************************************************/
4823 const struct tile *ptile)
4824{
4825 const struct unit_type *utype = unit_type_get(punit);
4826
4827 return (utype->vision_radius_sq
4829 utype, NULL,
4830 EFT_UNIT_VISION_RADIUS_SQ));
4831}
4832
4833/**********************************************************************/
4840int get_unit_vision_at(struct unit *punit, const struct tile *ptile,
4841 enum vision_layer vlayer)
4842{
4845}
4846
4847/**********************************************************************/
4854{
4855 struct vision *uvision = punit->server.vision;
4856 const struct tile *utile = unit_tile(punit);
4857 int mod = unit_vision_range_modifiers(punit, utile);
4858 const v_radius_t radius_sq =
4859 V_RADIUS(get_unit_vision_base(punit, V_MAIN, mod),
4860 get_unit_vision_base(punit, V_INVIS, mod),
4861 get_unit_vision_base(punit, V_SUBSURFACE, mod));
4862
4863 vision_change_sight(uvision, radius_sq);
4864 ASSERT_VISION(uvision);
4865}
4866
4867/**********************************************************************/
4870void unit_list_refresh_vision(struct unit_list *punitlist)
4871{
4872 unit_list_iterate(punitlist, punit) {
4875}
4876
4877/**********************************************************************/
4882{
4883 time_t dt;
4884
4885 if (!punit) {
4886 return FALSE;
4887 }
4888
4889 if (game.server.unitwaittime <= 0) {
4890 return TRUE;
4891 }
4892
4893 if (punit->server.action_turn != game.info.turn - 1) {
4894 return TRUE;
4895 }
4896
4897 dt = time(NULL) - punit->server.action_timestamp;
4898 if (dt < game.server.unitwaittime) {
4899 char buf[64];
4900 format_time_duration(game.server.unitwaittime - dt, buf, sizeof(buf));
4901 notify_player(unit_owner(punit), unit_tile(punit), E_BAD_COMMAND,
4902 ftc_server, _("Your unit may not act for another %s "
4903 "this turn. See /help unitwaittime."), buf);
4904 return FALSE;
4905 }
4906
4907 return TRUE;
4908}
4909
4910/**********************************************************************/
4915{
4916 if (!punit) {
4917 return;
4918 }
4919
4920 punit->server.action_timestamp = time(NULL);
4922}
4923
4924/**********************************************************************/
4930{
4931 /* check if there is enemy nearby */
4932 square_iterate(&(wld.map), unit_tile(punit), 3, ptile) {
4934 || is_enemy_unit_tile(ptile, unit_owner(punit))) {
4935 return FALSE;
4936 }
4937 }
4939
4940 return TRUE;
4941}
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:640
#define action_has_result(_act_, _res_)
Definition actions.h:450
#define action_id_get_act_time(act_id, actor_unit, tgt_tile, tgt_extra)
Definition actions.h:685
#define ACTPROB_IMPOSSIBLE
Definition actions.h:941
#define action_id_get_target_kind(act_id)
Definition actions.h:657
#define action_id_has_result_safe(act_id, result)
Definition actions.h:670
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:264
bool can_unit_exist_at_tile(const struct civ_map *nmap, const struct unit *punit, const struct tile *ptile)
Definition movement.c:336
bool is_native_tile(const struct unit_type *punittype, const struct tile *ptile)
Definition movement.c:348
int unit_move_rate(const struct unit *punit)
Definition movement.c:90
bool unit_could_load_at(const struct unit *punit, const struct tile *ptile)
Definition movement.c:901
bool is_native_to_class(const struct unit_class *punitclass, const struct terrain *pterrain, const bv_extras *extras)
Definition movement.c:359
bool can_unit_survive_at_tile(const struct civ_map *nmap, const struct unit *punit, const struct tile *ptile)
Definition movement.c:508
@ 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:3043
void maybe_make_contact(struct tile *ptile, struct player *pplayer)
Definition plrhand.c:2192
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:1426
#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:384
bv_action_sub_results sub_results
Definition actions.h:385
enum act_tgt_compl target_complexity
Definition actions.h:392
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:116
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:113
#define TILE_XY(ptile)
Definition tile.h:42
static const bv_extras * tile_extras(const struct tile *ptile)
Definition tile.h:123
#define tile_continent(_tile)
Definition tile.h:91
#define tile_has_extra(ptile, pextra)
Definition tile.h:150
#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:1340
int get_transporter_occupancy(const struct unit *ptrans)
Definition unit.c:1775
void free_unit_orders(struct unit *punit)
Definition unit.c:1761
bool unit_is_alive(int id)
Definition unit.c:2245
int get_activity_rate_this_turn(const struct unit *punit)
Definition unit.c:513
bool unit_transport_load(struct unit *pcargo, struct unit *ptrans, bool force)
Definition unit.c:2362
void set_unit_activity(struct unit *punit, enum unit_activity new_activity)
Definition unit.c:1115
struct player * unit_nationality(const struct unit *punit)
Definition unit.c:1279
struct unit * unit_transport_get(const struct unit *pcargo)
Definition unit.c:2433
bool unit_transport_unload(struct unit *pcargo)
Definition unit.c:2382
int unit_gain_hitpoints(const struct unit *punit)
Definition unit.c:2175
bool can_unit_continue_current_activity(const struct civ_map *nmap, struct unit *punit)
Definition unit.c:853
struct unit * unit_virtual_create(struct player *pplayer, struct city *pcity, const struct unit_type *punittype, int veteran_level)
Definition unit.c:1625
bool can_unit_do_activity(const struct civ_map *nmap, const struct unit *punit, enum unit_activity activity)
Definition unit.c:880
void unit_virtual_destroy(struct unit *punit)
Definition unit.c:1721
void unit_tile_set(struct unit *punit, struct tile *ptile)
Definition unit.c:1289
enum unit_upgrade_result unit_upgrade_test(const struct civ_map *nmap, const struct unit *punit, bool is_free)
Definition unit.c:1980
bool unit_transported(const struct unit *pcargo)
Definition unit.c:2417
bool can_unit_unload(const struct unit *pcargo, const struct unit *ptrans)
Definition unit.c:779
struct unit_list * unit_transport_cargo(const struct unit *ptrans)
Definition unit.c:2443
bool unit_has_orders(const struct unit *punit)
Definition unit.c:212
struct unit * transporter_for_unit(const struct unit *pcargo)
Definition unit.c:1904
bool unit_can_convert(const struct civ_map *nmap, const struct unit *punit)
Definition unit.c:2027
bool activity_requires_target(enum unit_activity activity)
Definition unit.c:549
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:919
#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:4914
static void autoattack_prob_free(struct autoattack_prob *prob)
Definition unittools.c:3349
bool do_airline(struct unit *punit, struct city *pdest_city, const struct action *paction)
Definition unittools.c:2964
void place_partisans(struct tile *pcenter, struct player *powner, int count, int sq_radius)
Definition unittools.c:1178
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:2260
static void unit_move_by_data(struct unit_move_data *pdata, struct tile *psrctile, struct tile *pdesttile)
Definition unittools.c:3806
bool execute_orders(struct unit *punit, const bool fresh)
Definition unittools.c:4373
static void unit_convert(struct unit *punit)
Definition unittools.c:763
void update_unit_activities(struct player *pplayer)
Definition unittools.c:659
static void throw_units_from_illegal_cities(struct player *pplayer, bool verbose)
Definition unittools.c:1321
#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:1566
static void server_remove_unit_full(struct unit *punit, bool transported, enum unit_loss_reason reason)
Definition unittools.c:1805
struct unit_list * get_units_seen_via_ally(const struct player *pplayer, const struct player *aplayer)
Definition unittools.c:1430
static bool is_refuel_tile(const struct tile *ptile, const struct player *pplayer, const struct unit *punit)
Definition unittools.c:1502
static void unit_lost_with_transport(const struct player *pplayer, struct unit *pcargo, const struct unit_type *ptransport, struct player *killer)
Definition unittools.c:1935
void remove_allied_visibility(struct player *pplayer, struct player *aplayer, const struct unit_list *seen_units)
Definition unittools.c:1465
static bool maybe_cancel_goto_due_to_enemy(struct unit *punit, struct tile *ptile)
Definition unittools.c:4304
void combat_veterans(struct unit *attacker, struct unit *defender, bool powerless, int att_vet, int def_vet)
Definition unittools.c:393
static int unit_vision_range_modifiers(struct unit *punit, const struct tile *ptile)
Definition unittools.c:4822
void resolve_unit_stacks(struct player *pplayer, struct player *aplayer, bool verbose)
Definition unittools.c:1415
static void unit_move_data_unref(struct unit_move_data *pdata)
Definition unittools.c:3856
void unit_set_removal_callback(struct unit *punit, void(*callback)(struct unit *punit))
Definition unittools.c:1782
void unit_bombs_unit(struct unit *attacker, struct unit *defender, int *att_hp, int *def_hp)
Definition unittools.c:353
static void unit_enter_hut(struct unit *punit, bool frighten_hut)
Definition unittools.c:3226
void package_unit(struct unit *punit, struct packet_unit_info *packet)
Definition unittools.c:2651
#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:2782
static void unit_restore_movepoints(struct player *pplayer, struct unit *punit)
Definition unittools.c:650
static void wakeup_neighbor_sentries(struct unit *punit)
Definition unittools.c:3548
static int total_activity(struct tile *ptile, enum unit_activity act, struct extra_type *tgt)
Definition unittools.c:707
void unit_activities_cancel_all_illegal_plr(const struct player *pplayer)
Definition unittools.c:807
static void unit_transport_load_tp_status(struct unit *punit, struct unit *ptrans, bool force)
Definition unittools.c:3307
#define autoattack_prob_list_iterate_safe_end
Definition unittools.c:131
static bool unit_survive_autoattack(struct unit *punit)
Definition unittools.c:3405
void finalize_unit_phase_beginning(struct player *pplayer)
Definition unittools.c:691
void execute_unit_orders(struct player *pplayer)
Definition unittools.c:669
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:1130
void send_unit_info(struct conn_list *dest, struct unit *punit)
Definition unittools.c:2795
static void wipe_unit_full(struct unit *punit, bool transported, enum unit_loss_reason reason, struct player *killer)
Definition unittools.c:1959
static void resolve_stack_conflicts(struct player *pplayer, struct player *aplayer, bool verbose)
Definition unittools.c:1386
static void check_unit_activity(struct unit *punit)
Definition unittools.c:3735
static void unit_restore_hitpoints(struct unit *punit)
Definition unittools.c:623
static void do_upgrade_effects(struct player *pplayer)
Definition unittools.c:417
int get_unit_vision_at(struct unit *punit, const struct tile *ptile, enum vision_layer vlayer)
Definition unittools.c:4840
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:1724
void notify_unit_experience(struct unit *punit)
Definition unittools.c:736
void unit_activities_cancel(struct unit *punit)
Definition unittools.c:789
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:2734
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:1676
void give_allied_visibility(struct player *pplayer, struct player *aplayer)
Definition unittools.c:1489
void unit_forget_last_activity(struct unit *punit)
Definition unittools.c:1070
#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:1643
static void server_remove_unit(struct unit *punit, enum unit_loss_reason reason)
Definition unittools.c:1926
void unit_unset_removal_callback(struct unit *punit)
Definition unittools.c:1796
bool maybe_make_veteran(struct unit *punit, int base_chance)
Definition unittools.c:217
void unit_refresh_vision(struct unit *punit)
Definition unittools.c:4853
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:1616
void do_explore(struct unit *punit)
Definition unittools.c:2997
void unit_transport_load_send(struct unit *punit, struct unit *ptrans)
Definition unittools.c:3277
bool unit_can_do_action_now(const struct unit *punit)
Definition unittools.c:4881
#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:2248
void unit_tc_effect_refresh(struct player *pplayer)
Definition unittools.c:681
bool do_paradrop(struct unit *punit, struct tile *ptile, const struct action *paction)
Definition unittools.c:3033
static bool player_is_watching(struct unit *punit, const bool fresh)
Definition unittools.c:4346
void player_restore_units(struct player *pplayer)
Definition unittools.c:470
void do_nuclear_explosion(struct player *pplayer, struct tile *ptile)
Definition unittools.c:2947
static void do_nuke_tile(struct player *pplayer, struct tile *ptile)
Definition unittools.c:2867
bool is_refuel_point(const struct tile *ptile, const struct player *pplayer, const struct unit *punit)
Definition unittools.c:1544
static void update_unit_activity(struct unit *punit)
Definition unittools.c:849
#define unit_move_data_list_iterate_rev(_plist, _pdata)
Definition unittools.c:105
void unit_transport_unload_send(struct unit *punit)
Definition unittools.c:3329
bool is_unit_being_refueled(const struct unit *punit)
Definition unittools.c:1535
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:3537
bool unit_can_be_retired(struct unit *punit)
Definition unittools.c:4929
static bool total_activity_done(struct tile *ptile, enum unit_activity act, struct extra_type *tgt)
Definition unittools.c:727
void unit_activities_cancel_all_illegal_tile(const struct tile *ptile)
Definition unittools.c:819
struct unit * unit_change_owner(struct unit *punit, struct player *pplayer, int homecity, enum unit_loss_reason reason)
Definition unittools.c:2308
bool teleport_unit_to_city(struct unit *punit, struct city *pcity, int move_cost, bool verbose)
Definition unittools.c:1204
static int get_unit_vision_base(struct unit *punit, enum vision_layer vlayer, const int base)
Definition unittools.c:4801
static bool hut_get_limited(struct unit *punit)
Definition unittools.c:3191
void unit_assign_specific_activity_target(struct unit *punit, enum unit_activity *activity, struct extra_type **target)
Definition unittools.c:1099
static int compare_units(const struct autoattack_prob *const *p1, const struct autoattack_prob *const *q1)
Definition unittools.c:3363
void unit_activities_cancel_all_illegal_area(const struct tile *ptile)
Definition unittools.c:834
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:3618
void unit_get_goods(struct unit *punit)
Definition unittools.c:1627
void send_all_known_units(struct conn_list *dest)
Definition unittools.c:2839
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:4317
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:3885
void unit_list_refresh_vision(struct unit_list *punitlist)
Definition unittools.c:4870
void kill_unit(struct unit *pkiller, struct unit *punit, bool vet)
Definition unittools.c:2374
void bounce_unit(struct unit *punit, bool verbose)
Definition unittools.c:1242
bool unit_activity_needs_target_from_client(enum unit_activity activity)
Definition unittools.c:1079
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:97
#define V_RADIUS(main_sq, invis_sq, subs_sq)
Definition vision.h:95
#define vision_site_owner(v)
Definition vision.h:127
short int v_radius_t[V_COUNT]
Definition vision.h:82