Freeciv-3.3: /fast/freeciv/nightly/main/server/unittools.c Source File

Freeciv-3.3

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