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