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 "aiiface.h"
62 #include "barbarian.h"
63 #include "citytools.h"
64 #include "cityturn.h"
65 #include "diplhand.h"
66 #include "gamehand.h"
67 #include "maphand.h"
68 #include "notify.h"
69 #include "plrhand.h"
70 #include "sanitycheck.h"
71 #include "sernet.h"
72 #include "srv_main.h"
73 #include "techtools.h"
74 #include "unithand.h"
75
76 /* server/advisors */
77 #include "advgoto.h"
78 #include "autoexplorer.h"
79 #include "autosettlers.h"
80
81 /* ai */
82 #include "handicaps.h"
83
84 #include "unittools.h"
85
86
87 /* Tools for controlling the client vision of every unit when a unit
88 * moves + script effects. See unit_move(). You can access this data with
89 * punit->server.moving; it may be NULL if the unit is not moving). */
90 struct unit_move_data {
91 int ref_count;
92 struct unit *punit; /* NULL for invalidating. */
93 struct player *powner;
94 bv_player can_see_unit;
95 bv_player can_see_move;
96 struct vision *old_vision;
97 };
98
99 #define SPECLIST_TAG unit_move_data
100 #include "speclist.h"
101 #define unit_move_data_list_iterate(_plist, _pdata) \
102 TYPED_LIST_ITERATE(struct unit_move_data, _plist, _pdata)
103 #define unit_move_data_list_iterate_end LIST_ITERATE_END
104 #define unit_move_data_list_iterate_rev(_plist, _pdata) \
105 TYPED_LIST_ITERATE_REV(struct unit_move_data, _plist, _pdata)
106 #define unit_move_data_list_iterate_rev_end LIST_ITERATE_REV_END
107
108 /* We need this global variable for our sort algorithm */
109 static struct tile *autoattack_target;
110
111 static void unit_restore_hitpoints(struct unit *punit);
112 static void unit_restore_movepoints(struct player *pplayer, struct unit *punit);
113 static void update_unit_activity(struct unit *punit);
114 static bool try_to_save_unit(struct unit *punit, struct unit_type *pttype,
115 bool helpless, bool teleporting,
116 const struct city *pexclcity);
117 static void wakeup_neighbor_sentries(struct unit *punit);
118 static void do_upgrade_effects(struct player *pplayer);
119
120 static bool maybe_cancel_patrol_due_to_enemy(struct unit *punit);
121
122 static bool maybe_become_veteran_real(struct unit *punit, bool settler);
123
124 static void unit_transport_load_tp_status(struct unit *punit,
125 struct unit *ptrans,
126 bool force);
127
128 static void wipe_unit_full(struct unit *punit, bool transported,
129 enum unit_loss_reason reason,
130 struct player *killer);
131 static bool unit_enter_hut(struct unit *punit);
132
133 /**************************************************************************
134 Returns a unit type that matches the role_tech or role roles.
135
136 If role_tech is given, then we look at all units with this role
137 whose requirements are met by any player, and return a random one. This
138 can be used to give a unit to barbarians taken from the set of most
139 advanced units researched by the 'real' players.
140
141 If role_tech is not give (-1) or if there are no matching unit types,
142 then we look at 'role' value and return a random matching unit type.
143
144 It is an error if there are no available units. This function will
145 always return a valid unit.
146 **************************************************************************/
find_a_unit_type(enum unit_role_id role,enum unit_role_id role_tech)147 struct unit_type *find_a_unit_type(enum unit_role_id role,
148 enum unit_role_id role_tech)
149 {
150 struct unit_type *which[U_LAST];
151 int i, num=0;
152
153 if (role_tech != -1) {
154 for(i=0; i<num_role_units(role_tech); i++) {
155 struct unit_type *iunit = get_role_unit(role_tech, i);
156 const int minplayers = 2;
157 int players = 0;
158
159 /* Note, if there's only one player in the game this check will always
160 * fail. */
161 players_iterate(pplayer) {
162 if (!is_barbarian(pplayer)
163 && can_player_build_unit_direct(pplayer, iunit)) {
164 players++;
165 }
166 } players_iterate_end;
167 if (players > minplayers) {
168 which[num++] = iunit;
169 }
170 }
171 }
172 if(num==0) {
173 for(i=0; i<num_role_units(role); i++) {
174 which[num++] = get_role_unit(role, i);
175 }
176 }
177
178 /* Ruleset code should ensure there is at least one unit for each
179 * possibly-required role, or check before calling this function. */
180 fc_assert_exit_msg(0 < num, "No unit types in find_a_unit_type(%d, %d)!",
181 role, role_tech);
182
183 return which[fc_rand(num)];
184 }
185
186 /*****************************************************************************
187 Unit has a chance to become veteran. This should not be used for settlers
188 for the work they do.
189 *****************************************************************************/
maybe_make_veteran(struct unit * punit)190 bool maybe_make_veteran(struct unit *punit)
191 {
192 return maybe_become_veteran_real(punit, FALSE);
193 }
194
195 /*****************************************************************************
196 After a battle, after diplomatic aggression and after surviving trireme
197 loss chance, this routine is called to decide whether or not the unit
198 should become more experienced.
199
200 There is a specified chance for it to happen, (+50% if player got SUNTZU)
201 the chances are specified in the units.ruleset file.
202
203 If 'settler' is TRUE the veteran level is increased due to work done by
204 the unit.
205 *****************************************************************************/
maybe_become_veteran_real(struct unit * punit,bool settler)206 static bool maybe_become_veteran_real(struct unit *punit, bool settler)
207 {
208 const struct veteran_system *vsystem;
209 const struct veteran_level *vlevel;
210 int chance;
211
212 fc_assert_ret_val(punit != NULL, FALSE);
213
214 vsystem = utype_veteran_system(unit_type_get(punit));
215 fc_assert_ret_val(vsystem != NULL, FALSE);
216 fc_assert_ret_val(vsystem->levels > punit->veteran, FALSE);
217
218 vlevel = utype_veteran_level(unit_type_get(punit), punit->veteran);
219 fc_assert_ret_val(vlevel != NULL, FALSE);
220
221 if (punit->veteran + 1 >= vsystem->levels
222 || unit_has_type_flag(punit, UTYF_NO_VETERAN)) {
223 return FALSE;
224 } else if (!settler) {
225 int mod = 100 + get_unit_bonus(punit, EFT_VETERAN_COMBAT);
226
227 /* The modification is tacked on as a multiplier to the base chance.
228 * For example with a base chance of 50% for green units and a modifier
229 * of +50% the end chance is 75%. */
230 chance = vlevel->raise_chance * mod / 100;
231 } else if (settler && unit_has_type_flag(punit, UTYF_SETTLERS)) {
232 chance = vlevel->work_raise_chance;
233 } else {
234 /* No battle and no work done. */
235 return FALSE;
236 }
237
238 if (fc_rand(100) < chance) {
239 punit->veteran++;
240 return TRUE;
241 }
242
243 return FALSE;
244 }
245
246 /**************************************************************************
247 This is the basic unit versus unit combat routine.
248 1) ALOT of modifiers bonuses etc is added to the 2 units rates.
249 2) If the attack is a bombardment, do rate attacks and don't kill the
250 defender, then return.
251 3) the combat loop, which continues until one of the units are dead
252 4) the aftermath, the loser (and potentially the stack which is below it)
253 is wiped, and the winner gets a chance of gaining veteran status
254 **************************************************************************/
unit_versus_unit(struct unit * attacker,struct unit * defender,bool bombard,int * att_hp,int * def_hp)255 void unit_versus_unit(struct unit *attacker, struct unit *defender,
256 bool bombard, int *att_hp, int *def_hp)
257 {
258 int attackpower = get_total_attack_power(attacker, defender);
259 int defensepower = get_total_defense_power(attacker, defender);
260 int attack_firepower, defense_firepower;
261 struct player *plr1 = unit_owner(attacker);
262 struct player *plr2 = unit_owner(defender);
263
264 *att_hp = attacker->hp;
265 *def_hp = defender->hp;
266 get_modified_firepower(attacker, defender,
267 &attack_firepower, &defense_firepower);
268
269 log_verbose("attack:%d, defense:%d, attack firepower:%d, "
270 "defense firepower:%d", attackpower, defensepower,
271 attack_firepower, defense_firepower);
272
273 player_update_last_war_action(plr1);
274 player_update_last_war_action(plr2);
275
276 if (bombard) {
277 int i;
278 int rate = unit_type_get(attacker)->bombard_rate;
279
280 for (i = 0; i < rate; i++) {
281 if (fc_rand(attackpower+defensepower) >= defensepower) {
282 *def_hp -= attack_firepower;
283 }
284 }
285
286 /* Don't kill the target. */
287 if (*def_hp <= 0) {
288 *def_hp = 1;
289 }
290 return;
291 }
292
293 if (attackpower == 0) {
294 *att_hp = 0;
295 } else if (defensepower == 0) {
296 *def_hp = 0;
297 }
298 while (*att_hp > 0 && *def_hp > 0) {
299 if (fc_rand(attackpower + defensepower) >= defensepower) {
300 *def_hp -= attack_firepower;
301 } else {
302 *att_hp -= defense_firepower;
303 }
304 }
305 if (*att_hp < 0) {
306 *att_hp = 0;
307 }
308 if (*def_hp < 0) {
309 *def_hp = 0;
310 }
311 }
312
313 /***************************************************************************
314 Make maybe make either side of combat veteran
315 ****************************************************************************/
combat_veterans(struct unit * attacker,struct unit * defender)316 void combat_veterans(struct unit *attacker, struct unit *defender)
317 {
318 if (attacker->hp > 0) {
319 maybe_make_veteran(attacker);
320 } else if (defender->hp > 0) {
321 maybe_make_veteran(defender);
322 }
323 }
324
325 /***************************************************************************
326 Do unit auto-upgrades to players with the EFT_UNIT_UPGRADE effect
327 (traditionally from Leonardo's Workshop).
328 ****************************************************************************/
do_upgrade_effects(struct player * pplayer)329 static void do_upgrade_effects(struct player *pplayer)
330 {
331 int upgrades = get_player_bonus(pplayer, EFT_UPGRADE_UNIT);
332 struct unit_list *candidates;
333
334 if (upgrades <= 0) {
335 return;
336 }
337 candidates = unit_list_new();
338
339 unit_list_iterate(pplayer->units, punit) {
340 /* We have to be careful not to strand units at sea, for example by
341 * upgrading a frigate to an ironclad while it was carrying a unit. */
342 if (UU_OK == unit_upgrade_test(punit, TRUE)) {
343 unit_list_prepend(candidates, punit); /* Potential candidate :) */
344 }
345 } unit_list_iterate_end;
346
347 while (upgrades > 0 && unit_list_size(candidates) > 0) {
348 /* Upgrade one unit. The unit is chosen at random from the list of
349 * available candidates. */
350 int candidate_to_upgrade = fc_rand(unit_list_size(candidates));
351 struct unit *punit = unit_list_get(candidates, candidate_to_upgrade);
352 struct unit_type *type_from = unit_type_get(punit);
353 struct unit_type *type_to = can_upgrade_unittype(pplayer, type_from);
354
355 transform_unit(punit, type_to, TRUE);
356 notify_player(pplayer, unit_tile(punit), E_UNIT_UPGRADED, ftc_server,
357 _("%s was upgraded for free to %s."),
358 utype_name_translation(type_from),
359 unit_link(punit));
360 unit_list_remove(candidates, punit);
361 upgrades--;
362 }
363
364 unit_list_destroy(candidates);
365 }
366
367 /***************************************************************************
368 1. Do Leonardo's Workshop upgrade if applicable.
369
370 2. Restore/decrease unit hitpoints.
371
372 3. Kill dead units.
373
374 4. Rescue airplanes by returning them to base automatically.
375
376 5. Decrease fuel of planes in the air.
377
378 6. Refuel planes that are in bases.
379
380 7. Kill planes that are out of fuel.
381 ****************************************************************************/
player_restore_units(struct player * pplayer)382 void player_restore_units(struct player *pplayer)
383 {
384 /* 1) get Leonardo out of the way first: */
385 do_upgrade_effects(pplayer);
386
387 unit_list_iterate_safe(pplayer->units, punit) {
388
389 /* 2) Modify unit hitpoints. Helicopters can even lose them. */
390 unit_restore_hitpoints(punit);
391
392 /* 3) Check that unit has hitpoints */
393 if (punit->hp <= 0) {
394 /* This should usually only happen for heli units, but if any other
395 * units get 0 hp somehow, catch them too. --dwp */
396 /* if 'game.server.killunhomed' is activated unhomed units are slowly
397 * killed; notify player here */
398 if (!punit->homecity && 0 < game.server.killunhomed) {
399 notify_player(pplayer, unit_tile(punit), E_UNIT_LOST_MISC,
400 ftc_server, _("Your %s has run out of hit points "
401 "because it was not supported by a city."),
402 unit_tile_link(punit));
403 } else {
404 notify_player(pplayer, unit_tile(punit), E_UNIT_LOST_MISC, ftc_server,
405 _("Your %s has run out of hit points."),
406 unit_tile_link(punit));
407 }
408
409 wipe_unit(punit, ULR_HP_LOSS, NULL);
410 continue; /* Continue iterating... */
411 }
412
413 /* 4) Rescue planes if needed */
414 if (utype_fuel(unit_type_get(punit))) {
415 /* Shall we emergency return home on the last vapors? */
416
417 /* I think this is strongly against the spirit of client goto.
418 * The problem is (again) that here we know too much. -- Zamar */
419
420 if (punit->fuel <= 1
421 && !is_unit_being_refueled(punit)) {
422 struct unit *carrier;
423
424 carrier = transporter_for_unit(punit);
425 if (carrier) {
426 unit_transport_load_tp_status(punit, carrier, FALSE);
427 } else {
428 bool alive = true;
429
430 struct pf_map *pfm;
431 struct pf_parameter parameter;
432
433 pft_fill_unit_parameter(¶meter, punit);
434 parameter.omniscience = !has_handicap(pplayer, H_MAP);
435 pfm = pf_map_new(¶meter);
436
437 pf_map_move_costs_iterate(pfm, ptile, move_cost, TRUE) {
438 if (move_cost > punit->moves_left) {
439 /* Too far */
440 break;
441 }
442
443 if (is_airunit_refuel_point(ptile, pplayer, punit)) {
444 struct pf_path *path;
445 int id = punit->id;
446
447 /* Client orders may be running for this unit - if so
448 * we free them before engaging goto. */
449 free_unit_orders(punit);
450
451 path = pf_map_path(pfm, ptile);
452
453 alive = adv_follow_path(punit, path, ptile);
454
455 if (!alive) {
456 log_error("rescue plane: unit %d died enroute!", id);
457 } else if (!same_pos(unit_tile(punit), ptile)) {
458 /* Enemy units probably blocked our route
459 * FIXME: We should try find alternative route around
460 * the enemy unit instead of just giving up and crashing. */
461 log_debug("rescue plane: unit %d could not move to "
462 "refuel point!", punit->id);
463 }
464
465 if (alive) {
466 /* Clear activity. Unit info will be sent in the end of
467 * the function. */
468 unit_activity_handling(punit, ACTIVITY_IDLE);
469 adv_unit_new_task(punit, AUT_NONE, NULL);
470 punit->goto_tile = NULL;
471
472 if (!is_unit_being_refueled(punit)) {
473 carrier = transporter_for_unit(punit);
474 if (carrier) {
475 unit_transport_load_tp_status(punit, carrier, FALSE);
476 }
477 }
478
479 notify_player(pplayer, unit_tile(punit),
480 E_UNIT_ORDERS, ftc_server,
481 _("Your %s has returned to refuel."),
482 unit_link(punit));
483 }
484 pf_path_destroy(path);
485 break;
486 }
487 } pf_map_move_costs_iterate_end;
488 pf_map_destroy(pfm);
489
490 if (!alive) {
491 /* Unit died trying to move to refuel point. */
492 return;
493 }
494 }
495 }
496
497 /* 5) Update fuel */
498 punit->fuel--;
499
500 /* 6) Automatically refuel air units in cities, airbases, and
501 * transporters (carriers). */
502 if (is_unit_being_refueled(punit)) {
503 punit->fuel = utype_fuel(unit_type_get(punit));
504 }
505 }
506 } unit_list_iterate_safe_end;
507
508 /* 7) Check if there are air units without fuel */
509 unit_list_iterate_safe(pplayer->units, punit) {
510 if (punit->fuel <= 0 && utype_fuel(unit_type_get(punit))) {
511 notify_player(pplayer, unit_tile(punit), E_UNIT_LOST_MISC, ftc_server,
512 _("Your %s has run out of fuel."),
513 unit_tile_link(punit));
514 wipe_unit(punit, ULR_FUEL, NULL);
515 }
516 } unit_list_iterate_safe_end;
517
518 /* Send all updates. */
519 unit_list_iterate(pplayer->units, punit) {
520 send_unit_info(NULL, punit);
521 } unit_list_iterate_end;
522 }
523
524 /****************************************************************************
525 add hitpoints to the unit, hp_gain_coord returns the amount to add
526 united nations will speed up the process by 2 hp's / turn, means helicopters
527 will actually not lose hp's every turn if player have that wonder.
528 Units which have moved don't gain hp, except the United Nations and
529 helicopter effects still occur.
530
531 If 'game.server.killunhomed' is greater than 0, unhomed units lose
532 'game.server.killunhomed' hitpoints each turn, killing the unit at the end.
533 *****************************************************************************/
unit_restore_hitpoints(struct unit * punit)534 static void unit_restore_hitpoints(struct unit *punit)
535 {
536 bool was_lower;
537 int save_hp;
538 struct unit_class *pclass = unit_class_get(punit);
539 struct city *pcity = tile_city(unit_tile(punit));
540
541 was_lower = (punit->hp < unit_type_get(punit)->hp);
542 save_hp = punit->hp;
543
544 if (!punit->moved) {
545 punit->hp += hp_gain_coord(punit);
546 }
547
548 /* Bonus recovery HP (traditionally from the United Nations) */
549 punit->hp += get_unit_bonus(punit, EFT_UNIT_RECOVER);
550
551 if (!punit->homecity && 0 < game.server.killunhomed
552 && !unit_has_type_flag(punit, UTYF_GAMELOSS)) {
553 /* Hit point loss of units without homecity; at least 1 hp! */
554 /* Gameloss units are immune to this effect. */
555 int hp_loss = MAX(unit_type_get(punit)->hp * game.server.killunhomed / 100,
556 1);
557 punit->hp = MIN(punit->hp - hp_loss, save_hp - 1);
558 }
559
560 if (!pcity && !tile_has_native_base(unit_tile(punit), unit_type_get(punit))
561 && !unit_transported(punit)) {
562 punit->hp -= unit_type_get(punit)->hp * pclass->hp_loss_pct / 100;
563 }
564
565 if (punit->hp >= unit_type_get(punit)->hp) {
566 punit->hp = unit_type_get(punit)->hp;
567 if (was_lower && punit->activity == ACTIVITY_SENTRY) {
568 set_unit_activity(punit, ACTIVITY_IDLE);
569 }
570 }
571
572 if (punit->hp < 0) {
573 punit->hp = 0;
574 }
575
576 punit->moved = FALSE;
577 punit->paradropped = FALSE;
578 }
579
580 /***************************************************************************
581 Move points are trivial, only modifiers to the base value is if it's
582 sea units and the player has certain wonders/techs. Then add veteran
583 bonus, if any.
584 ***************************************************************************/
unit_restore_movepoints(struct player * pplayer,struct unit * punit)585 static void unit_restore_movepoints(struct player *pplayer, struct unit *punit)
586 {
587 punit->moves_left = unit_move_rate(punit);
588 punit->done_moving = FALSE;
589 }
590
591 /****************************************************************************
592 Iterate through all units and update them.
593 ****************************************************************************/
update_unit_activities(struct player * pplayer)594 void update_unit_activities(struct player *pplayer)
595 {
596 unit_list_iterate_safe(pplayer->units, punit) {
597 update_unit_activity(punit);
598 } unit_list_iterate_safe_end;
599 }
600
601 /****************************************************************************
602 Iterate through all units and execute their orders.
603 ****************************************************************************/
execute_unit_orders(struct player * pplayer)604 void execute_unit_orders(struct player *pplayer)
605 {
606 unit_list_iterate_safe(pplayer->units, punit) {
607 if (unit_has_orders(punit)) {
608 execute_orders(punit, FALSE);
609 }
610 } unit_list_iterate_safe_end;
611 }
612
613 /****************************************************************************
614 Iterate through all units and remember their current activities.
615 ****************************************************************************/
finalize_unit_phase_beginning(struct player * pplayer)616 void finalize_unit_phase_beginning(struct player *pplayer)
617 {
618 /* Remember activities only after all knock-on effects of unit activities
619 * on other units have been resolved */
620 unit_list_iterate(pplayer->units, punit) {
621 punit->changed_from = punit->activity;
622 punit->changed_from_target = punit->activity_target;
623 punit->changed_from_count = punit->activity_count;
624 send_unit_info(NULL, punit);
625 } unit_list_iterate_end;
626 }
627
628 /**************************************************************************
629 Calculate the total amount of activity performed by all units on a tile
630 for a given task and target.
631 **************************************************************************/
total_activity(struct tile * ptile,enum unit_activity act,struct extra_type * tgt)632 static int total_activity(struct tile *ptile, enum unit_activity act,
633 struct extra_type *tgt)
634 {
635 int total = 0;
636 bool tgt_matters = activity_requires_target(act);
637
638 unit_list_iterate (ptile->units, punit) {
639 if (punit->activity == act
640 && (!tgt_matters || punit->activity_target == tgt)) {
641 total += punit->activity_count;
642 }
643 } unit_list_iterate_end;
644
645 return total;
646 }
647
648 /**************************************************************************
649 Check the total amount of activity performed by all units on a tile
650 for a given task.
651 **************************************************************************/
total_activity_done(struct tile * ptile,enum unit_activity act,struct extra_type * tgt)652 static bool total_activity_done(struct tile *ptile, enum unit_activity act,
653 struct extra_type *tgt)
654 {
655 return total_activity(ptile, act, tgt) >= tile_activity_time(act, ptile, tgt);
656 }
657
658 /**************************************************************************
659 Common notification for all experience levels.
660 **************************************************************************/
notify_unit_experience(struct unit * punit)661 void notify_unit_experience(struct unit *punit)
662 {
663 const struct veteran_system *vsystem;
664 const struct veteran_level *vlevel;
665
666 if (!punit) {
667 return;
668 }
669
670 vsystem = utype_veteran_system(unit_type_get(punit));
671 fc_assert_ret(vsystem != NULL);
672 fc_assert_ret(vsystem->levels > punit->veteran);
673
674 vlevel = utype_veteran_level(unit_type_get(punit), punit->veteran);
675 fc_assert_ret(vlevel != NULL);
676
677 notify_player(unit_owner(punit), unit_tile(punit),
678 E_UNIT_BECAME_VET, ftc_server,
679 /* TRANS: Your <unit> became ... rank of <veteran level>. */
680 _("Your %s became more experienced and achieved the rank "
681 "of %s."),
682 unit_link(punit), name_translation_get(&vlevel->name));
683 }
684
685 /**************************************************************************
686 Convert a single unit to another type.
687 **************************************************************************/
unit_convert(struct unit * punit)688 static void unit_convert(struct unit *punit)
689 {
690 struct unit_type *to_type, *from_type;
691
692 from_type = unit_type_get(punit);
693 to_type = from_type->converted_to;
694
695 if (unit_can_convert(punit)) {
696 transform_unit(punit, to_type, TRUE);
697 notify_player(unit_owner(punit), unit_tile(punit),
698 E_UNIT_UPGRADED, ftc_server,
699 _("%s converted to %s."),
700 utype_name_translation(from_type),
701 utype_name_translation(to_type));
702 } else {
703 notify_player(unit_owner(punit), unit_tile(punit),
704 E_UNIT_UPGRADED, ftc_server,
705 _("%s cannot be converted."),
706 utype_name_translation(from_type));
707 }
708 }
709
710 /**************************************************************************
711 progress settlers in their current tasks,
712 and units that is pillaging.
713 also move units that is on a goto.
714 restore unit move points (information needed for settler tasks)
715 **************************************************************************/
update_unit_activity(struct unit * punit)716 static void update_unit_activity(struct unit *punit)
717 {
718 const enum unit_activity tile_changing_actions[] =
719 { ACTIVITY_PILLAGE, ACTIVITY_GEN_ROAD, ACTIVITY_IRRIGATE, ACTIVITY_MINE,
720 ACTIVITY_BASE, ACTIVITY_TRANSFORM, ACTIVITY_POLLUTION,
721 ACTIVITY_FALLOUT, ACTIVITY_LAST };
722
723 struct player *pplayer = unit_owner(punit);
724 bool unit_activity_done = FALSE;
725 enum unit_activity activity = punit->activity;
726 struct tile *ptile = unit_tile(punit);
727 int i;
728
729 switch (activity) {
730 case ACTIVITY_IDLE:
731 case ACTIVITY_EXPLORE:
732 case ACTIVITY_FORTIFIED:
733 case ACTIVITY_SENTRY:
734 case ACTIVITY_GOTO:
735 case ACTIVITY_PATROL_UNUSED:
736 case ACTIVITY_UNKNOWN:
737 case ACTIVITY_LAST:
738 /* We don't need the activity_count for the above */
739 break;
740
741 case ACTIVITY_FORTIFYING:
742 case ACTIVITY_CONVERT:
743 punit->activity_count += get_activity_rate_this_turn(punit);
744 break;
745
746 case ACTIVITY_POLLUTION:
747 case ACTIVITY_MINE:
748 case ACTIVITY_IRRIGATE:
749 case ACTIVITY_PILLAGE:
750 case ACTIVITY_TRANSFORM:
751 case ACTIVITY_FALLOUT:
752 case ACTIVITY_BASE:
753 case ACTIVITY_GEN_ROAD:
754 punit->activity_count += get_activity_rate_this_turn(punit);
755
756 /* settler may become veteran when doing something useful */
757 if (maybe_become_veteran_real(punit, TRUE)) {
758 notify_unit_experience(punit);
759 }
760 break;
761 case ACTIVITY_OLD_ROAD:
762 case ACTIVITY_OLD_RAILROAD:
763 case ACTIVITY_FORTRESS:
764 case ACTIVITY_AIRBASE:
765 fc_assert(FALSE);
766 break;
767 };
768
769 unit_restore_movepoints(pplayer, punit);
770
771 switch (activity) {
772 case ACTIVITY_IDLE:
773 case ACTIVITY_FORTIFIED:
774 case ACTIVITY_SENTRY:
775 case ACTIVITY_GOTO:
776 case ACTIVITY_UNKNOWN:
777 case ACTIVITY_FORTIFYING:
778 case ACTIVITY_CONVERT:
779 case ACTIVITY_PATROL_UNUSED:
780 case ACTIVITY_LAST:
781 /* no default, ensure all handled */
782 break;
783
784 case ACTIVITY_EXPLORE:
785 do_explore(punit);
786 return;
787
788 case ACTIVITY_PILLAGE:
789 if (total_activity_done(ptile, ACTIVITY_PILLAGE,
790 punit->activity_target)) {
791 struct player *victim = tile_owner(ptile); /* Owner before fortress gets destroyed */
792
793 destroy_extra(ptile, punit->activity_target);
794 unit_activity_done = TRUE;
795
796 bounce_units_on_terrain_change(ptile);
797
798 call_incident(INCIDENT_PILLAGE, unit_owner(punit), victim);
799
800 /* Change vision if effects have changed. */
801 unit_list_refresh_vision(ptile->units);
802 }
803 break;
804
805 case ACTIVITY_POLLUTION:
806 /* TODO: Remove this fallback target setting when target always correctly
807 * set */
808 if (punit->activity_target == NULL) {
809 punit->activity_target = prev_extra_in_tile(ptile, ERM_CLEANPOLLUTION,
810 NULL, punit);
811 }
812 if (total_activity_done(ptile, ACTIVITY_POLLUTION, punit->activity_target)) {
813 destroy_extra(ptile, punit->activity_target);
814 unit_activity_done = TRUE;
815 }
816 break;
817
818 case ACTIVITY_FALLOUT:
819 /* TODO: Remove this fallback target setting when target always correctly
820 * set */
821 if (punit->activity_target == NULL) {
822 punit->activity_target = prev_extra_in_tile(ptile, ERM_CLEANFALLOUT,
823 NULL, punit);
824 }
825 if (total_activity_done(ptile, ACTIVITY_FALLOUT, punit->activity_target)) {
826 destroy_extra(ptile, punit->activity_target);
827 unit_activity_done = TRUE;
828 }
829 break;
830
831 case ACTIVITY_BASE:
832 {
833 if (total_activity(ptile, ACTIVITY_BASE, punit->activity_target)
834 >= tile_activity_time(ACTIVITY_BASE, ptile, punit->activity_target)) {
835 create_extra(ptile, punit->activity_target, unit_owner(punit));
836 unit_activity_done = TRUE;
837 }
838 }
839 break;
840
841 case ACTIVITY_GEN_ROAD:
842 {
843 if (total_activity(ptile, ACTIVITY_GEN_ROAD, punit->activity_target)
844 >= tile_activity_time(ACTIVITY_GEN_ROAD, ptile, punit->activity_target)) {
845 create_extra(ptile, punit->activity_target, unit_owner(punit));
846 unit_activity_done = TRUE;
847 }
848 }
849 break;
850
851 case ACTIVITY_IRRIGATE:
852 case ACTIVITY_MINE:
853 case ACTIVITY_TRANSFORM:
854 if (total_activity_done(ptile, activity, punit->activity_target)) {
855 struct terrain *old = tile_terrain(ptile);
856
857 /* The function below could change the terrain. Therefore, we have to
858 * check the terrain (which will also do a sanity check for the tile). */
859 tile_apply_activity(ptile, activity, punit->activity_target);
860 check_terrain_change(ptile, old);
861 unit_activity_done = TRUE;
862 }
863 break;
864
865 case ACTIVITY_OLD_ROAD:
866 case ACTIVITY_OLD_RAILROAD:
867 case ACTIVITY_FORTRESS:
868 case ACTIVITY_AIRBASE:
869 fc_assert(FALSE);
870 break;
871 }
872
873 if (unit_activity_done) {
874 update_tile_knowledge(ptile);
875 if (ACTIVITY_IRRIGATE == activity
876 || ACTIVITY_MINE == activity
877 || ACTIVITY_TRANSFORM == activity) {
878 /* FIXME: As we might probably do the activity again, because of the
879 * terrain change cycles, we need to treat these cases separatly.
880 * Probably ACTIVITY_TRANSFORM should be associated to its terrain
881 * target, whereas ACTIVITY_IRRIGATE and ACTIVITY_MINE should only
882 * used for extras. */
883 unit_list_iterate(ptile->units, punit2) {
884 if (punit2->activity == activity) {
885 set_unit_activity(punit2, ACTIVITY_IDLE);
886 send_unit_info(NULL, punit2);
887 }
888 } unit_list_iterate_end;
889 } else {
890 unit_list_iterate(ptile->units, punit2) {
891 if (!can_unit_continue_current_activity(punit2)) {
892 set_unit_activity(punit2, ACTIVITY_IDLE);
893 send_unit_info(NULL, punit2);
894 }
895 } unit_list_iterate_end;
896 }
897
898 for (i = 0; tile_changing_actions[i] != ACTIVITY_LAST; i++) {
899 if (tile_changing_actions[i] == activity) {
900 /* Some units nearby may not be able to continue their action,
901 * such as building irrigation if we removed the only source
902 * of water from them. */
903 adjc_iterate(ptile, ptile2) {
904 unit_list_iterate(ptile2->units, punit2) {
905 if (!can_unit_continue_current_activity(punit2)) {
906 if (unit_has_orders(punit2)) {
907 notify_player(unit_owner(punit2), unit_tile(punit2),
908 E_UNIT_ORDERS, ftc_server,
909 _("Orders for %s aborted because activity "
910 "is no longer available."),
911 unit_link(punit2));
912 free_unit_orders(punit2);
913 }
914 set_unit_activity(punit2, ACTIVITY_IDLE);
915 send_unit_info(NULL, punit2);
916 }
917 } unit_list_iterate_end;
918 } adjc_iterate_end;
919 break;
920 }
921 }
922 }
923
924 if (activity == ACTIVITY_FORTIFYING) {
925 if (punit->activity_count >= 1) {
926 set_unit_activity(punit, ACTIVITY_FORTIFIED);
927 }
928 }
929
930 if (activity == ACTIVITY_CONVERT) {
931 if (punit->activity_count >= unit_type_get(punit)->convert_time * ACTIVITY_FACTOR) {
932 unit_convert(punit);
933 set_unit_activity(punit, ACTIVITY_IDLE);
934 }
935 }
936 }
937
938 /**************************************************************************
939 Forget the unit's last activity so that it can't be resumed. This is
940 used for example when the unit moves or attacks.
941 **************************************************************************/
unit_forget_last_activity(struct unit * punit)942 void unit_forget_last_activity(struct unit *punit)
943 {
944 punit->changed_from = ACTIVITY_IDLE;
945 }
946
947 /**************************************************************************
948 Return TRUE iff activity requires some sort of target to be specified by
949 the client.
950 **************************************************************************/
unit_activity_needs_target_from_client(enum unit_activity activity)951 bool unit_activity_needs_target_from_client(enum unit_activity activity)
952 {
953 switch (activity) {
954 case ACTIVITY_PILLAGE:
955 /* Can be set server side. */
956 return FALSE;
957 default:
958 return activity_requires_target(activity);
959 }
960 }
961
962 /**************************************************************************
963 For some activities (currently only pillaging), the precise target can
964 be assigned by the server rather than explicitly requested by the client.
965 This function assigns a specific activity+target if the current
966 settings are open-ended (otherwise leaves them unchanged).
967
968 Please update unit_activity_needs_target_from_client() if you add server
969 side unit activity target setting to more activities.
970 **************************************************************************/
unit_assign_specific_activity_target(struct unit * punit,enum unit_activity * activity,struct extra_type ** target)971 void unit_assign_specific_activity_target(struct unit *punit,
972 enum unit_activity *activity,
973 struct extra_type **target)
974 {
975 if (*activity == ACTIVITY_PILLAGE
976 && *target == NULL) {
977 struct tile *ptile = unit_tile(punit);
978 struct extra_type *tgt;
979
980 bv_extras extras = *tile_extras(ptile);
981
982 while ((tgt = get_preferred_pillage(extras))) {
983
984 BV_CLR(extras, extra_index(tgt));
985
986 if (can_unit_do_activity_targeted(punit, *activity, tgt)) {
987 *target = tgt;
988 return;
989 }
990 }
991 /* Nothing we can pillage here. */
992 *activity = ACTIVITY_IDLE;
993 }
994 }
995
996 /**************************************************************************
997 Find place to place partisans. Returns whether such spot was found, and
998 if it has been found, dst_tile contains that tile.
999 **************************************************************************/
find_a_good_partisan_spot(struct tile * pcenter,struct player * powner,struct unit_type * u_type,int sq_radius,struct tile ** dst_tile)1000 static bool find_a_good_partisan_spot(struct tile *pcenter,
1001 struct player *powner,
1002 struct unit_type *u_type,
1003 int sq_radius,
1004 struct tile **dst_tile)
1005 {
1006 int bestvalue = 0;
1007
1008 /* coords of best tile in arg pointers */
1009 circle_iterate(pcenter, sq_radius, ptile) {
1010 int value;
1011
1012 if (!is_native_tile(u_type, ptile)) {
1013 continue;
1014 }
1015
1016 if (NULL != tile_city(ptile)) {
1017 continue;
1018 }
1019
1020 if (0 < unit_list_size(ptile->units)) {
1021 continue;
1022 }
1023
1024 /* City may not have changed hands yet; see place_partisans(). */
1025 value = get_virtual_defense_power(NULL, u_type, powner,
1026 ptile, FALSE, 0);
1027 value *= 10;
1028
1029 if (tile_continent(ptile) != tile_continent(pcenter)) {
1030 value /= 2;
1031 }
1032
1033 value -= fc_rand(value/3);
1034
1035 if (value > bestvalue) {
1036 *dst_tile = ptile;
1037 bestvalue = value;
1038 }
1039 } circle_iterate_end;
1040
1041 return bestvalue > 0;
1042 }
1043
1044 /**************************************************************************
1045 Place partisans for powner around pcenter (normally around a city).
1046 **************************************************************************/
place_partisans(struct tile * pcenter,struct player * powner,int count,int sq_radius)1047 void place_partisans(struct tile *pcenter, struct player *powner,
1048 int count, int sq_radius)
1049 {
1050 struct tile *ptile = NULL;
1051 struct unit_type *u_type = get_role_unit(L_PARTISAN, 0);
1052
1053 while (count-- > 0
1054 && find_a_good_partisan_spot(pcenter, powner, u_type,
1055 sq_radius, &ptile)) {
1056 struct unit *punit;
1057
1058 punit = create_unit(powner, ptile, u_type, 0, 0, -1);
1059 if (can_unit_do_activity(punit, ACTIVITY_FORTIFYING)) {
1060 punit->activity = ACTIVITY_FORTIFIED; /* yes; directly fortified */
1061 send_unit_info(NULL, punit);
1062 }
1063 }
1064 }
1065
1066 /**************************************************************************
1067 Teleport punit to city at cost specified. Returns success. Note that unit
1068 may die if it succesfully moves, i.e., even when return value is TRUE.
1069 (If specified cost is -1, then teleportation costs all movement.)
1070 **************************************************************************/
teleport_unit_to_city(struct unit * punit,struct city * pcity,int move_cost,bool verbose)1071 bool teleport_unit_to_city(struct unit *punit, struct city *pcity,
1072 int move_cost, bool verbose)
1073 {
1074 struct tile *src_tile = unit_tile(punit), *dst_tile = pcity->tile;
1075
1076 if (city_owner(pcity) == unit_owner(punit)){
1077 log_verbose("Teleported %s %s from (%d,%d) to %s",
1078 nation_rule_name(nation_of_unit(punit)),
1079 unit_rule_name(punit), TILE_XY(src_tile), city_name_get(pcity));
1080 if (verbose) {
1081 notify_player(unit_owner(punit), city_tile(pcity),
1082 E_UNIT_RELOCATED, ftc_server,
1083 _("Teleported your %s to %s."),
1084 unit_link(punit),
1085 city_link(pcity));
1086 }
1087
1088 /* Silently free orders since they won't be applicable anymore. */
1089 free_unit_orders(punit);
1090
1091 if (move_cost == -1) {
1092 move_cost = punit->moves_left;
1093 }
1094 unit_move(punit, dst_tile, move_cost, NULL);
1095
1096 return TRUE;
1097 }
1098 return FALSE;
1099 }
1100
1101 /**************************************************************************
1102 Move or remove a unit due to stack conflicts. This function will try to
1103 find a random safe tile within a two tile distance of the unit's current
1104 tile and move the unit there. If no tiles are found, the unit is
1105 disbanded. If 'verbose' is TRUE, a message is sent to the unit owner
1106 regarding what happened.
1107 **************************************************************************/
bounce_unit(struct unit * punit,bool verbose)1108 void bounce_unit(struct unit *punit, bool verbose)
1109 {
1110 struct player *pplayer;
1111 struct tile *punit_tile;
1112 struct unit_list *pcargo_units;
1113 int count = 0;
1114
1115 /* I assume that there are no topologies that have more than
1116 * (2d + 1)^2 tiles in the "square" of "radius" d. */
1117 const int DIST = 2;
1118 struct tile *tiles[(2 * DIST + 1) * (2 * DIST + 1)];
1119
1120 if (!punit) {
1121 return;
1122 }
1123
1124 pplayer = unit_owner(punit);
1125 punit_tile = unit_tile(punit);
1126
1127 square_iterate(punit_tile, DIST, ptile) {
1128 if (count >= ARRAY_SIZE(tiles)) {
1129 break;
1130 }
1131
1132 if (ptile == punit_tile) {
1133 continue;
1134 }
1135
1136 if (can_unit_survive_at_tile(punit, ptile)
1137 && !is_non_allied_city_tile(ptile, pplayer)
1138 && !is_non_allied_unit_tile(ptile, pplayer)) {
1139 tiles[count++] = ptile;
1140 }
1141 } square_iterate_end;
1142
1143 if (count > 0) {
1144 struct tile *ptile = tiles[fc_rand(count)];
1145
1146 if (verbose) {
1147 notify_player(pplayer, ptile, E_UNIT_RELOCATED, ftc_server,
1148 /* TRANS: A unit is moved to resolve stack conflicts. */
1149 _("Moved your %s."),
1150 unit_link(punit));
1151 }
1152 unit_move(punit, ptile, 0, NULL);
1153 return;
1154 }
1155
1156 /* Didn't find a place to bounce the unit, going to disband it.
1157 * Try to bounce transported units. */
1158 if (0 < get_transporter_occupancy(punit)) {
1159 pcargo_units = unit_transport_cargo(punit);
1160 unit_list_iterate(pcargo_units, pcargo) {
1161 bounce_unit(pcargo, verbose);
1162 } unit_list_iterate_end;
1163 }
1164
1165 if (verbose) {
1166 notify_player(pplayer, punit_tile, E_UNIT_LOST_MISC, ftc_server,
1167 /* TRANS: A unit is disbanded to resolve stack conflicts. */
1168 _("Disbanded your %s."),
1169 unit_tile_link(punit));
1170 }
1171 wipe_unit(punit, ULR_STACK_CONFLICT, NULL);
1172 }
1173
1174
1175 /**************************************************************************
1176 Throw pplayer's units from non allied cities
1177
1178 If verbose is true, pplayer gets messages about where each units goes.
1179 **************************************************************************/
throw_units_from_illegal_cities(struct player * pplayer,bool verbose)1180 static void throw_units_from_illegal_cities(struct player *pplayer,
1181 bool verbose)
1182 {
1183 struct tile *ptile;
1184 struct city *pcity;
1185 struct unit *ptrans;
1186 struct unit_list *pcargo_units;
1187
1188 /* Unload undesired units from transports, if possible. */
1189 unit_list_iterate(pplayer->units, punit) {
1190 ptile = unit_tile(punit);
1191 pcity = tile_city(ptile);
1192 if (NULL != pcity
1193 && !pplayers_allied(city_owner(pcity), pplayer)
1194 && 0 < get_transporter_occupancy(punit)) {
1195 pcargo_units = unit_transport_cargo(punit);
1196 unit_list_iterate(pcargo_units, pcargo) {
1197 if (!pplayers_allied(unit_owner(pcargo), pplayer)) {
1198 if (can_unit_exist_at_tile(pcargo, ptile)) {
1199 unit_transport_unload_send(pcargo);
1200 }
1201 }
1202 } unit_list_iterate_end;
1203 }
1204 } unit_list_iterate_end;
1205
1206 /* Bounce units except transported ones which will be bounced with their
1207 * transport. */
1208 unit_list_iterate_safe(pplayer->units, punit) {
1209 ptile = unit_tile(punit);
1210 pcity = tile_city(ptile);
1211 if (NULL != pcity
1212 && !pplayers_allied(city_owner(pcity), pplayer)) {
1213 ptrans = unit_transport_get(punit);
1214 if (NULL == ptrans || pplayer != unit_owner(ptrans)) {
1215 bounce_unit(punit, verbose);
1216 }
1217 }
1218 } unit_list_iterate_safe_end;
1219
1220 #ifdef FREECIV_DEBUG
1221 /* Sanity check. */
1222 unit_list_iterate(pplayer->units, punit) {
1223 ptile = unit_tile(punit);
1224 pcity = tile_city(ptile);
1225 fc_assert_msg(NULL == pcity
1226 || pplayers_allied(city_owner(pcity), pplayer),
1227 "Failed to throw %s %d from %s %d (%d, %d)",
1228 unit_rule_name(punit),
1229 punit->id,
1230 city_name_get(pcity),
1231 pcity->id,
1232 TILE_XY(ptile));
1233 } unit_list_iterate_end;
1234 #endif /* FREECIV_DEBUG */
1235 }
1236
1237 /**************************************************************************
1238 For each pplayer's unit, check if we stack illegally, if so,
1239 bounce both players' units. If on ocean tile, bounce everyone but ships
1240 to avoid drowning. This function assumes that cities are clean.
1241
1242 If verbose is true, the unit owner gets messages about where each
1243 units goes.
1244 **************************************************************************/
resolve_stack_conflicts(struct player * pplayer,struct player * aplayer,bool verbose)1245 static void resolve_stack_conflicts(struct player *pplayer,
1246 struct player *aplayer, bool verbose)
1247 {
1248 unit_list_iterate_safe(pplayer->units, punit) {
1249 struct tile *ptile = unit_tile(punit);
1250
1251 if (is_non_allied_unit_tile(ptile, pplayer)) {
1252 unit_list_iterate_safe(ptile->units, aunit) {
1253 if (unit_owner(aunit) == pplayer
1254 || unit_owner(aunit) == aplayer
1255 || !can_unit_survive_at_tile(aunit, ptile)) {
1256 bounce_unit(aunit, verbose);
1257 }
1258 } unit_list_iterate_safe_end;
1259 }
1260 } unit_list_iterate_safe_end;
1261 }
1262
1263 /**************************************************************************
1264 When in civil war or an alliance breaks there will potentially be units
1265 from both sides coexisting on the same squares. This routine resolves
1266 this by first bouncing off non-allied units from their cities, then by
1267 bouncing both players' units in now illegal multiowner stacks. To avoid
1268 drowning due to removal of transports, we bounce everyone (including
1269 third parties' units) from ocean tiles.
1270
1271 If verbose is true, the unit owner gets messages about where each
1272 units goes.
1273 **************************************************************************/
resolve_unit_stacks(struct player * pplayer,struct player * aplayer,bool verbose)1274 void resolve_unit_stacks(struct player *pplayer, struct player *aplayer,
1275 bool verbose)
1276 {
1277 throw_units_from_illegal_cities(pplayer, verbose);
1278 throw_units_from_illegal_cities(aplayer, verbose);
1279
1280 resolve_stack_conflicts(pplayer, aplayer, verbose);
1281 resolve_stack_conflicts(aplayer, pplayer, verbose);
1282 }
1283
1284 /****************************************************************************
1285 Returns the list of the units seen by 'pplayer' potentially seen only
1286 thanks to an alliance with 'aplayer'. The returned pointer is newly
1287 allocated and should be freed by the caller, using unit_list_destroy().
1288 ****************************************************************************/
get_units_seen_via_ally(const struct player * pplayer,const struct player * aplayer)1289 struct unit_list *get_units_seen_via_ally(const struct player *pplayer,
1290 const struct player *aplayer)
1291 {
1292 struct unit_list *seen_units = unit_list_new();
1293
1294 /* Anybody's units inside ally's cities */
1295 city_list_iterate(aplayer->cities, pcity) {
1296 unit_list_iterate(city_tile(pcity)->units, punit) {
1297 if (can_player_see_unit(pplayer, punit)) {
1298 unit_list_append(seen_units, punit);
1299 }
1300 } unit_list_iterate_end;
1301 } city_list_iterate_end;
1302
1303 /* Ally's own units inside transports */
1304 unit_list_iterate(aplayer->units, punit) {
1305 if (unit_transported(punit) && can_player_see_unit(pplayer, punit)) {
1306 unit_list_append(seen_units, punit);
1307 }
1308 } unit_list_iterate_end;
1309
1310 /* Make sure the same unit is not added in multiple phases
1311 * (unit within transport in a city) */
1312 unit_list_unique(seen_units);
1313
1314 return seen_units;
1315 }
1316
1317 /****************************************************************************
1318 When two players cancel an alliance, a lot of units that were visible may
1319 no longer be visible (this includes units in transporters and cities).
1320 Call this function to inform the clients that these units are no longer
1321 visible. Pass the list of seen units returned by get_units_seen_via_ally()
1322 before alliance was broken up.
1323 ****************************************************************************/
remove_allied_visibility(struct player * pplayer,struct player * aplayer,const struct unit_list * seen_units)1324 void remove_allied_visibility(struct player *pplayer, struct player *aplayer,
1325 const struct unit_list *seen_units)
1326 {
1327 unit_list_iterate(seen_units, punit) {
1328 /* We need to hide units previously seen by the client. */
1329 if (!can_player_see_unit(pplayer, punit)) {
1330 unit_goes_out_of_sight(pplayer, punit);
1331 }
1332 } unit_list_iterate_end;
1333
1334 city_list_iterate(aplayer->cities, pcity) {
1335 /* The player used to know what units were in these cities. Now that he
1336 * doesn't, he needs to get a new short city packet updating the
1337 * occupied status. */
1338 if (map_is_known_and_seen(pcity->tile, pplayer, V_MAIN)) {
1339 send_city_info(pplayer, pcity);
1340 }
1341 } city_list_iterate_end;
1342 }
1343
1344 /****************************************************************************
1345 Refresh units visibility of 'aplayer' for 'pplayer' after alliance have
1346 been contracted.
1347 ****************************************************************************/
give_allied_visibility(struct player * pplayer,struct player * aplayer)1348 void give_allied_visibility(struct player *pplayer,
1349 struct player *aplayer)
1350 {
1351 unit_list_iterate(aplayer->units, punit) {
1352 if (can_player_see_unit(pplayer, punit)) {
1353 send_unit_info(pplayer->connections, punit);
1354 }
1355 } unit_list_iterate_end;
1356 }
1357
1358 /**************************************************************************
1359 Is unit being refueled in its current position
1360 **************************************************************************/
is_unit_being_refueled(const struct unit * punit)1361 bool is_unit_being_refueled(const struct unit *punit)
1362 {
1363 return (unit_transported(punit) /* Carrier */
1364 || tile_city(unit_tile(punit)) /* City */
1365 || tile_has_refuel_extra(unit_tile(punit),
1366 unit_type_get(punit))); /* Airbase */
1367 }
1368
1369 /**************************************************************************
1370 Can unit refuel on tile. Considers also carrier capacity on tile.
1371 **************************************************************************/
is_airunit_refuel_point(const struct tile * ptile,const struct player * pplayer,const struct unit * punit)1372 bool is_airunit_refuel_point(const struct tile *ptile,
1373 const struct player *pplayer,
1374 const struct unit *punit)
1375 {
1376 const struct unit_class *pclass;
1377
1378 if (NULL != is_non_allied_unit_tile(ptile, pplayer)) {
1379 return FALSE;
1380 }
1381
1382 if (NULL != is_allied_city_tile(ptile, pplayer)) {
1383 return TRUE;
1384 }
1385
1386 pclass = unit_class_get(punit);
1387 if (NULL != pclass->cache.refuel_bases) {
1388 const struct player_tile *plrtile = map_get_player_tile(ptile, pplayer);
1389
1390 extra_type_list_iterate(pclass->cache.refuel_bases, pextra) {
1391 if (BV_ISSET(plrtile->extras, extra_index(pextra))) {
1392 return TRUE;
1393 }
1394 } extra_type_list_iterate_end;
1395 }
1396
1397 return unit_could_load_at(punit, ptile);
1398 }
1399
1400 /**************************************************************************
1401 Really transforms a single unit to another type.
1402
1403 This function performs no checks. You should perform the appropriate
1404 test first to check that the transformation is legal (test_unit_upgrade()
1405 or test_unit_convert()).
1406
1407 is_free: Does unit owner need to pay upgrade price.
1408
1409 Note that this function is strongly tied to unit.c:test_unit_upgrade().
1410 **************************************************************************/
transform_unit(struct unit * punit,struct unit_type * to_unit,bool is_free)1411 void transform_unit(struct unit *punit, struct unit_type *to_unit,
1412 bool is_free)
1413 {
1414 struct player *pplayer = unit_owner(punit);
1415 struct unit_type *old_type = punit->utype;
1416 int old_mr = unit_move_rate(punit);
1417 int old_hp = unit_type_get(punit)->hp;
1418
1419 if (!is_free) {
1420 pplayer->economic.gold -=
1421 unit_upgrade_price(pplayer, unit_type_get(punit), to_unit);
1422 }
1423
1424 punit->utype = to_unit;
1425
1426 /* New type may not have the same veteran system, and we may want to
1427 * knock some levels off. */
1428 punit->veteran = MIN(punit->veteran,
1429 utype_veteran_system(to_unit)->levels - 1);
1430 if (is_free) {
1431 punit->veteran = MAX(punit->veteran
1432 - game.server.autoupgrade_veteran_loss, 0);
1433 } else {
1434 punit->veteran = MAX(punit->veteran
1435 - game.server.upgrade_veteran_loss, 0);
1436 }
1437
1438 /* Scale HP and MP, rounding down. Be careful with integer arithmetic,
1439 * and don't kill the unit. unit_move_rate() is used to take into account
1440 * global effects like Magellan's Expedition. */
1441 punit->hp = MAX(punit->hp * unit_type_get(punit)->hp / old_hp, 1);
1442 if (old_mr == 0) {
1443 punit->moves_left = unit_move_rate(punit);
1444 } else {
1445 punit->moves_left = punit->moves_left * unit_move_rate(punit) / old_mr;
1446 }
1447
1448 unit_forget_last_activity(punit);
1449
1450 /* update unit upkeep */
1451 city_units_upkeep(game_city_by_number(punit->homecity));
1452
1453 conn_list_do_buffer(pplayer->connections);
1454
1455 unit_refresh_vision(punit);
1456
1457 CALL_PLR_AI_FUNC(unit_transformed, pplayer, punit, old_type);
1458
1459 send_unit_info(NULL, punit);
1460 conn_list_do_unbuffer(pplayer->connections);
1461 }
1462
1463 /*************************************************************************
1464 Wrapper of the below
1465 *************************************************************************/
create_unit(struct player * pplayer,struct tile * ptile,struct unit_type * type,int veteran_level,int homecity_id,int moves_left)1466 struct unit *create_unit(struct player *pplayer, struct tile *ptile,
1467 struct unit_type *type, int veteran_level,
1468 int homecity_id, int moves_left)
1469 {
1470 return create_unit_full(pplayer, ptile, type, veteran_level, homecity_id,
1471 moves_left, -1, NULL);
1472 }
1473
1474 /**************************************************************************
1475 Creates a unit, and set it's initial values, and put it into the right
1476 lists.
1477 If moves_left is less than zero, unit will get max moves.
1478 **************************************************************************/
create_unit_full(struct player * pplayer,struct tile * ptile,struct unit_type * type,int veteran_level,int homecity_id,int moves_left,int hp_left,struct unit * ptrans)1479 struct unit *create_unit_full(struct player *pplayer, struct tile *ptile,
1480 struct unit_type *type, int veteran_level,
1481 int homecity_id, int moves_left, int hp_left,
1482 struct unit *ptrans)
1483 {
1484 struct unit *punit = unit_virtual_create(pplayer, NULL, type, veteran_level);
1485 struct city *pcity;
1486
1487 /* Register unit */
1488 punit->id = identity_number();
1489 idex_register_unit(punit);
1490
1491 fc_assert_ret_val(ptile != NULL, NULL);
1492 unit_tile_set(punit, ptile);
1493
1494 pcity = game_city_by_number(homecity_id);
1495 if (utype_has_flag(type, UTYF_NOHOME)) {
1496 punit->homecity = 0; /* none */
1497 } else {
1498 punit->homecity = homecity_id;
1499 }
1500
1501 if (hp_left >= 0) {
1502 /* Override default full HP */
1503 punit->hp = hp_left;
1504 }
1505
1506 if (moves_left >= 0) {
1507 /* Override default full MP */
1508 punit->moves_left = MIN(moves_left, unit_move_rate(punit));
1509 }
1510
1511 if (ptrans) {
1512 /* Set transporter for unit. */
1513 unit_transport_load_tp_status(punit, ptrans, FALSE);
1514 } else {
1515 fc_assert_ret_val(!ptile || can_unit_exist_at_tile(punit, ptile), NULL);
1516 }
1517
1518 /* Assume that if moves_left < 0 then the unit is "fresh",
1519 * and not moved; else the unit has had something happen
1520 * to it (eg, bribed) which we treat as equivalent to moved.
1521 * (Otherwise could pass moved arg too...) --dwp */
1522 punit->moved = (moves_left >= 0);
1523
1524 unit_list_prepend(pplayer->units, punit);
1525 unit_list_prepend(ptile->units, punit);
1526 if (pcity && !utype_has_flag(type, UTYF_NOHOME)) {
1527 fc_assert(city_owner(pcity) == pplayer);
1528 unit_list_prepend(pcity->units_supported, punit);
1529 /* Refresh the unit's homecity. */
1530 city_refresh(pcity);
1531 send_city_info(pplayer, pcity);
1532 }
1533
1534 punit->server.vision = vision_new(pplayer, ptile);
1535 unit_refresh_vision(punit);
1536
1537 send_unit_info(NULL, punit);
1538 maybe_make_contact(ptile, unit_owner(punit));
1539 wakeup_neighbor_sentries(punit);
1540
1541 /* update unit upkeep */
1542 city_units_upkeep(game_city_by_number(homecity_id));
1543
1544 /* The unit may have changed the available tiles in nearby cities. */
1545 city_map_update_tile_now(ptile);
1546 sync_cities();
1547
1548 CALL_PLR_AI_FUNC(unit_got, pplayer, punit);
1549
1550 return punit;
1551 }
1552
1553 /****************************************************************************
1554 We remove the unit and see if it's disappearance has affected the homecity
1555 and the city it was in.
1556 ****************************************************************************/
server_remove_unit_full(struct unit * punit,bool transported,enum unit_loss_reason reason)1557 static void server_remove_unit_full(struct unit *punit, bool transported,
1558 enum unit_loss_reason reason)
1559 {
1560 struct packet_unit_remove packet;
1561 struct tile *ptile = unit_tile(punit);
1562 struct city *pcity = tile_city(ptile);
1563 struct city *phomecity = game_city_by_number(punit->homecity);
1564 struct unit *ptrans;
1565 struct player *pplayer = unit_owner(punit);
1566
1567 /* The unit is doomed. */
1568 punit->server.dying = TRUE;
1569
1570 #ifdef DEBUG
1571 unit_list_iterate(ptile->units, pcargo) {
1572 fc_assert(unit_transport_get(pcargo) != punit);
1573 } unit_list_iterate_end;
1574 #endif
1575
1576 CALL_PLR_AI_FUNC(unit_lost, pplayer, punit);
1577
1578 /* Save transporter for updating below. */
1579 ptrans = unit_transport_get(punit);
1580 /* Unload unit. */
1581 unit_transport_unload(punit);
1582
1583 /* Since settlers plot in new cities in the minimap before they
1584 are built, so that no two settlers head towards the same city
1585 spot, we need to ensure this reservation is cleared should
1586 the settler disappear on the way. */
1587 adv_unit_new_task(punit, AUT_NONE, NULL);
1588
1589 /* Clear the vision before sending unit remove. Else, we might duplicate
1590 * the PACKET_UNIT_REMOVE if we lose vision of the unit tile. */
1591 vision_clear_sight(punit->server.vision);
1592 vision_free(punit->server.vision);
1593 punit->server.vision = NULL;
1594
1595 packet.unit_id = punit->id;
1596 /* Send to onlookers. */
1597 players_iterate(aplayer) {
1598 if (can_player_see_unit_at(aplayer, punit, unit_tile(punit),
1599 transported)) {
1600 lsend_packet_unit_remove(aplayer->connections, &packet);
1601 }
1602 } players_iterate_end;
1603 /* Send to global observers. */
1604 conn_list_iterate(game.est_connections, pconn) {
1605 if (conn_is_global_observer(pconn)) {
1606 send_packet_unit_remove(pconn, &packet);
1607 }
1608 } conn_list_iterate_end;
1609
1610 if (punit->server.moving != NULL) {
1611 /* Do not care of this unit for running moves. */
1612 punit->server.moving->punit = NULL;
1613 }
1614
1615 /* check if this unit had UTYF_GAMELOSS flag */
1616 if (unit_has_type_flag(punit, UTYF_GAMELOSS) && unit_owner(punit)->is_alive) {
1617 notify_conn(game.est_connections, ptile, E_UNIT_LOST_MISC, ftc_server,
1618 _("Unable to defend %s, %s has lost the game."),
1619 unit_link(punit),
1620 player_name(pplayer));
1621 notify_player(pplayer, ptile, E_GAME_END, ftc_server,
1622 _("Losing %s meant losing the game! "
1623 "Be more careful next time!"),
1624 unit_link(punit));
1625 player_status_add(unit_owner(punit), PSTATUS_DYING);
1626 }
1627
1628 script_server_signal_emit("unit_lost", 3,
1629 API_TYPE_UNIT, punit,
1630 API_TYPE_PLAYER, unit_owner(punit),
1631 API_TYPE_STRING, unit_loss_reason_name(reason));
1632
1633 script_server_remove_exported_object(punit);
1634 game_remove_unit(punit);
1635 punit = NULL;
1636
1637 if (NULL != ptrans) {
1638 /* Update the occupy info. */
1639 send_unit_info(NULL, ptrans);
1640 }
1641
1642 /* This unit may have blocked tiles of adjacent cities. Update them. */
1643 city_map_update_tile_now(ptile);
1644 sync_cities();
1645
1646 if (phomecity) {
1647 city_refresh(phomecity);
1648 send_city_info(city_owner(phomecity), phomecity);
1649 }
1650
1651 if (pcity && pcity != phomecity) {
1652 city_refresh(pcity);
1653 send_city_info(city_owner(pcity), pcity);
1654 }
1655
1656 if (pcity && unit_list_size(ptile->units) == 0) {
1657 /* The last unit in the city was killed: update the occupied flag. */
1658 send_city_info(NULL, pcity);
1659 }
1660 }
1661
1662 /****************************************************************************
1663 We remove the unit and see if it's disappearance has affected the homecity
1664 and the city it was in.
1665 ****************************************************************************/
server_remove_unit(struct unit * punit,enum unit_loss_reason reason)1666 static void server_remove_unit(struct unit *punit,
1667 enum unit_loss_reason reason)
1668 {
1669 server_remove_unit_full(punit, unit_transported(punit), reason);
1670 }
1671
1672 /**************************************************************************
1673 Handle units destroyed when their transport is destroyed
1674 **************************************************************************/
unit_lost_with_transport(const struct player * pplayer,struct unit * pcargo,struct unit_type * ptransport,struct player * killer)1675 static void unit_lost_with_transport(const struct player *pplayer,
1676 struct unit *pcargo,
1677 struct unit_type *ptransport,
1678 struct player *killer)
1679 {
1680 notify_player(pplayer, unit_tile(pcargo), E_UNIT_LOST_MISC, ftc_server,
1681 _("%s lost when %s was lost."),
1682 unit_tile_link(pcargo),
1683 utype_name_translation(ptransport));
1684 /* Unit is not transported any more at this point, but it has jumped
1685 * off the transport and drowns outside. So it must be removed from
1686 * all clients.
1687 * However, we don't know if given client has received ANY updates
1688 * about the swimming unit, and we can't remove it if it's not there
1689 * in the first place -> we send it once here just to be sure it's
1690 * there. */
1691 send_unit_info(NULL, pcargo);
1692 wipe_unit_full(pcargo, FALSE, ULR_TRANSPORT_LOST, killer);
1693 }
1694
1695 /****************************************************************************
1696 Remove the unit, and passengers if it is a carrying any. Remove the
1697 _minimum_ number, eg there could be another boat on the square.
1698 ****************************************************************************/
wipe_unit_full(struct unit * punit,bool transported,enum unit_loss_reason reason,struct player * killer)1699 static void wipe_unit_full(struct unit *punit, bool transported,
1700 enum unit_loss_reason reason,
1701 struct player *killer)
1702 {
1703 struct tile *ptile = unit_tile(punit);
1704 struct player *pplayer = unit_owner(punit);
1705 struct unit_type *putype_save = unit_type_get(punit); /* for notify messages */
1706 struct unit_list *helpless = unit_list_new();
1707 struct unit_list *imperiled = unit_list_new();
1708 struct unit_list *unsaved = unit_list_new();
1709 struct unit *ptrans = unit_transport_get(punit);
1710 struct city *pexclcity;
1711
1712 /* The unit is doomed. */
1713 punit->server.dying = TRUE;
1714
1715 /* If a unit is being lost due to loss of its city, ensure that we don't
1716 * try to teleport any of its cargo to that city (which may not yet
1717 * have changed hands or disappeared). (It is assumed that the unit's
1718 * home city is always the one that is being lost/transferred/etc.) */
1719 if (reason == ULR_CITY_LOST) {
1720 pexclcity = unit_home(punit);
1721 } else {
1722 pexclcity = NULL;
1723 }
1724
1725 /* Remove unit itself from its transport */
1726 if (ptrans != NULL) {
1727 unit_transport_unload(punit);
1728 send_unit_info(NULL, ptrans);
1729 }
1730
1731 /* First pull all units off of the transporter. */
1732 if (get_transporter_occupancy(punit) > 0) {
1733 /* Use iterate_safe as unloaded units will be removed from the list
1734 * while iterating. */
1735 unit_list_iterate_safe(unit_transport_cargo(punit), pcargo) {
1736 bool healthy = FALSE;
1737
1738 if (!can_unit_unload(pcargo, punit)) {
1739 unit_list_prepend(helpless, pcargo);
1740 } else {
1741 if (!can_unit_exist_at_tile(pcargo, ptile)) {
1742 unit_list_prepend(imperiled, pcargo);
1743 } else {
1744 /* These units do not need to be saved. */
1745 healthy = TRUE;
1746 }
1747 }
1748
1749 /* Could use unit_transport_unload_send here, but that would
1750 * call send_unit_info for the transporter unnecessarily.
1751 * Note that this means that unit might to get seen briefly
1752 * by clients other than owner's, for example as a result of
1753 * update of homecity common to this cargo and some other
1754 * destroyed unit. */
1755 unit_transport_unload(pcargo);
1756 if (pcargo->activity == ACTIVITY_SENTRY) {
1757 /* Activate sentried units - like planes on a disbanded carrier.
1758 * Note this will activate ground units even if they just change
1759 * transporter. */
1760 set_unit_activity(pcargo, ACTIVITY_IDLE);
1761 }
1762
1763 /* Unit info for unhealthy units will be sent when they are
1764 * assigned new transport or removed. */
1765 if (healthy) {
1766 send_unit_info(NULL, pcargo);
1767 }
1768 } unit_list_iterate_safe_end;
1769 }
1770
1771 /* Now remove the unit. */
1772 server_remove_unit_full(punit, transported, reason);
1773
1774 switch (reason) {
1775 case ULR_KILLED:
1776 case ULR_EXECUTED:
1777 case ULR_SDI:
1778 case ULR_NUKE:
1779 case ULR_BRIBED:
1780 case ULR_CAPTURED:
1781 case ULR_CAUGHT:
1782 case ULR_ELIMINATED:
1783 case ULR_TRANSPORT_LOST:
1784 if (killer != NULL) {
1785 killer->score.units_killed++;
1786 }
1787 pplayer->score.units_lost++;
1788 break;
1789 case ULR_BARB_UNLEASH:
1790 case ULR_CITY_LOST:
1791 case ULR_STARVED:
1792 case ULR_NONNATIVE_TERR:
1793 case ULR_ARMISTICE:
1794 case ULR_HP_LOSS:
1795 case ULR_FUEL:
1796 case ULR_STACK_CONFLICT:
1797 case ULR_SOLD:
1798 pplayer->score.units_lost++;
1799 break;
1800 case ULR_RETIRED:
1801 case ULR_DISBANDED:
1802 case ULR_USED:
1803 case ULR_EDITOR:
1804 case ULR_PLAYER_DIED:
1805 case ULR_DETONATED:
1806 case ULR_MISSILE:
1807 break;
1808 }
1809
1810 /* First, sort out helpless cargo. */
1811 if (unit_list_size(helpless) > 0) {
1812 struct unit_list *remaining = unit_list_new();
1813
1814 /* Grant priority to undisbandable and gameloss units. */
1815 unit_list_iterate_safe(helpless, pcargo) {
1816 if (unit_has_type_flag(pcargo, UTYF_UNDISBANDABLE)
1817 || unit_has_type_flag(pcargo, UTYF_GAMELOSS)) {
1818 if (!try_to_save_unit(pcargo, putype_save, TRUE,
1819 unit_has_type_flag(pcargo,
1820 UTYF_UNDISBANDABLE),
1821 pexclcity)) {
1822 unit_list_prepend(unsaved, pcargo);
1823 }
1824 } else {
1825 unit_list_prepend(remaining, pcargo);
1826 }
1827 } unit_list_iterate_safe_end;
1828
1829 /* Handle non-priority units. */
1830 unit_list_iterate_safe(remaining, pcargo) {
1831 if (!try_to_save_unit(pcargo, putype_save, TRUE, FALSE, pexclcity)) {
1832 unit_list_prepend(unsaved, pcargo);
1833 }
1834 } unit_list_iterate_safe_end;
1835
1836 unit_list_destroy(remaining);
1837 }
1838 unit_list_destroy(helpless);
1839
1840 /* Then, save any imperiled cargo. */
1841 if (unit_list_size(imperiled) > 0) {
1842 struct unit_list *remaining = unit_list_new();
1843
1844 /* Grant priority to undisbandable and gameloss units. */
1845 unit_list_iterate_safe(imperiled, pcargo) {
1846 if (unit_has_type_flag(pcargo, UTYF_UNDISBANDABLE)
1847 || unit_has_type_flag(pcargo, UTYF_GAMELOSS)) {
1848 if (!try_to_save_unit(pcargo, putype_save, FALSE,
1849 unit_has_type_flag(pcargo,
1850 UTYF_UNDISBANDABLE),
1851 pexclcity)) {
1852 unit_list_prepend(unsaved, pcargo);
1853 }
1854 } else {
1855 unit_list_prepend(remaining, pcargo);
1856 }
1857 } unit_list_iterate_safe_end;
1858
1859 /* Handle non-priority units. */
1860 unit_list_iterate_safe(remaining, pcargo) {
1861 if (!try_to_save_unit(pcargo, putype_save, FALSE, FALSE, pexclcity)) {
1862 unit_list_prepend(unsaved, pcargo);
1863 }
1864 } unit_list_iterate_safe_end;
1865
1866 unit_list_destroy(remaining);
1867 }
1868 unit_list_destroy(imperiled);
1869
1870 /* Finally, kill off the unsaved units. */
1871 if (unit_list_size(unsaved) > 0) {
1872 unit_list_iterate_safe(unsaved, dying_unit) {
1873 unit_lost_with_transport(pplayer, dying_unit, putype_save, killer);
1874 } unit_list_iterate_safe_end;
1875 }
1876 unit_list_destroy(unsaved);
1877 }
1878
1879 /****************************************************************************
1880 Remove the unit, and passengers if it is a carrying any. Remove the
1881 _minimum_ number, eg there could be another boat on the square.
1882 ****************************************************************************/
wipe_unit(struct unit * punit,enum unit_loss_reason reason,struct player * killer)1883 void wipe_unit(struct unit *punit, enum unit_loss_reason reason,
1884 struct player *killer)
1885 {
1886 wipe_unit_full(punit, unit_transported(punit), reason, killer);
1887 }
1888
1889 /****************************************************************************
1890 Determine if it is possible to save a given unit, and if so, save them.
1891 'pexclcity' is a city to avoid teleporting to, if 'teleporting' is set.
1892 Note that despite being saved from drowning, teleporting the units to
1893 "safety" may have killed them in the end.
1894 ****************************************************************************/
try_to_save_unit(struct unit * punit,struct unit_type * pttype,bool helpless,bool teleporting,const struct city * pexclcity)1895 static bool try_to_save_unit(struct unit *punit, struct unit_type *pttype,
1896 bool helpless, bool teleporting,
1897 const struct city *pexclcity)
1898 {
1899 struct tile *ptile = unit_tile(punit);
1900 struct player *pplayer = unit_owner(punit);
1901 struct unit *ptransport = transporter_for_unit(punit);
1902
1903 /* Helpless units cannot board a transport in their current state. */
1904 if (!helpless
1905 && ptransport != NULL) {
1906 unit_transport_load_tp_status(punit, ptransport, FALSE);
1907 send_unit_info(NULL, punit);
1908 return TRUE;
1909 } else {
1910 /* Only units that cannot find transport are considered for teleport. */
1911 if (teleporting) {
1912 struct city *pcity = find_closest_city(ptile, pexclcity,
1913 unit_owner(punit),
1914 FALSE, FALSE, FALSE, TRUE, FALSE,
1915 utype_class(pttype));
1916 if (pcity != NULL) {
1917 char tplink[MAX_LEN_LINK]; /* In case unit dies when teleported */
1918
1919 sz_strlcpy(tplink, unit_link(punit));
1920
1921 if (teleport_unit_to_city(punit, pcity, 0, FALSE)) {
1922 notify_player(pplayer, ptile, E_UNIT_RELOCATED, ftc_server,
1923 _("%s escaped the destruction of %s, and fled to %s."),
1924 tplink,
1925 utype_name_translation(pttype),
1926 city_link(pcity));
1927 return TRUE;
1928 }
1929 }
1930 }
1931 }
1932 /* The unit could not use transport on the tile, and could not teleport. */
1933 return FALSE;
1934 }
1935
1936 /****************************************************************************
1937 We don't really change owner of the unit, but create completely new
1938 unit as its copy. The new pointer to 'punit' is returned.
1939 ****************************************************************************/
unit_change_owner(struct unit * punit,struct player * pplayer,int homecity,enum unit_loss_reason reason)1940 struct unit *unit_change_owner(struct unit *punit, struct player *pplayer,
1941 int homecity, enum unit_loss_reason reason)
1942 {
1943 struct unit *gained_unit;
1944
1945 fc_assert(!utype_player_already_has_this_unique(pplayer,
1946 unit_type_get(punit)));
1947
1948 /* Convert the unit to your cause. Fog is lifted in the create algorithm. */
1949 gained_unit = create_unit_full(pplayer, unit_tile(punit),
1950 unit_type_get(punit), punit->veteran,
1951 homecity, punit->moves_left,
1952 punit->hp, NULL);
1953
1954 /* Owner changes, nationality not. */
1955 gained_unit->nationality = punit->nationality;
1956
1957 /* Copy some more unit fields */
1958 gained_unit->fuel = punit->fuel;
1959 gained_unit->paradropped = punit->paradropped;
1960 gained_unit->server.birth_turn = punit->server.birth_turn;
1961
1962 send_unit_info(NULL, gained_unit);
1963
1964 /* update unit upkeep in the homecity of the victim */
1965 if (punit->homecity > 0) {
1966 /* update unit upkeep */
1967 city_units_upkeep(game_city_by_number(punit->homecity));
1968 }
1969 /* update unit upkeep in the new homecity */
1970 if (homecity > 0) {
1971 city_units_upkeep(game_city_by_number(homecity));
1972 }
1973
1974 /* Be sure to wipe the converted unit! */
1975 wipe_unit(punit, reason, NULL);
1976
1977 return gained_unit; /* Returns the replacement. */
1978 }
1979
1980 /**************************************************************************
1981 Called when one unit kills another in combat (this function is only
1982 called in one place). It handles all side effects including
1983 notifications and killstack.
1984 **************************************************************************/
kill_unit(struct unit * pkiller,struct unit * punit,bool vet)1985 void kill_unit(struct unit *pkiller, struct unit *punit, bool vet)
1986 {
1987 char pkiller_link[MAX_LEN_LINK], punit_link[MAX_LEN_LINK];
1988 struct player *pvictim = unit_owner(punit);
1989 struct player *pvictor = unit_owner(pkiller);
1990 int ransom, unitcount = 0;
1991
1992 sz_strlcpy(pkiller_link, unit_link(pkiller));
1993 sz_strlcpy(punit_link, unit_tile_link(punit));
1994
1995 /* The unit is doomed. */
1996 punit->server.dying = TRUE;
1997
1998 if ((game.info.gameloss_style & GAMELOSS_STYLE_LOOT)
1999 && unit_has_type_flag(punit, UTYF_GAMELOSS)) {
2000 ransom = fc_rand(1 + pvictim->economic.gold);
2001 int n;
2002
2003 /* give map */
2004 give_distorted_map(pvictim, pvictor, 1, 1, TRUE);
2005
2006 log_debug("victim has money: %d", pvictim->economic.gold);
2007 pvictor->economic.gold += ransom;
2008 pvictim->economic.gold -= ransom;
2009
2010 n = 1 + fc_rand(3);
2011
2012 while (n > 0) {
2013 Tech_type_id ttid = steal_a_tech(pvictor, pvictim, A_UNSET);
2014
2015 if (ttid == A_NONE) {
2016 log_debug("Worthless enemy doesn't have more techs to steal.");
2017 break;
2018 } else {
2019 log_debug("Pressed tech %s from captured enemy",
2020 research_advance_rule_name(research_get(pvictor), ttid));
2021 if (!fc_rand(3)) {
2022 break; /* out of luck */
2023 }
2024 n--;
2025 }
2026 }
2027
2028 { /* try to submit some cities */
2029 int vcsize = city_list_size(pvictim->cities);
2030 int evcsize = vcsize;
2031 int conqsize = evcsize;
2032
2033 if (evcsize < 3) {
2034 evcsize = 0;
2035 } else {
2036 evcsize -=3;
2037 }
2038 /* about a quarter on average with high numbers less probable */
2039 conqsize = fc_rand(fc_rand(evcsize));
2040
2041 log_debug("conqsize=%d", conqsize);
2042
2043 if (conqsize > 0) {
2044 bool palace = game.server.savepalace;
2045 bool submit = FALSE;
2046
2047 game.server.savepalace = FALSE; /* moving it around is dumb */
2048
2049 city_list_iterate_safe(pvictim->cities, pcity) {
2050 /* kindly ask the citizens to submit */
2051 if (fc_rand(vcsize) < conqsize) {
2052 submit = TRUE;
2053 }
2054 vcsize--;
2055 if (submit) {
2056 conqsize--;
2057 /* Transfer city to the victorious player
2058 * kill all its units outside of a radius of 7,
2059 * give verbose messages of every unit transferred,
2060 * and raze buildings according to raze chance
2061 * (also removes palace) */
2062 (void) transfer_city(pvictor, pcity, 7, TRUE, TRUE, TRUE,
2063 !is_barbarian(pvictor));
2064 submit = FALSE;
2065 }
2066 if (conqsize <= 0) {
2067 break;
2068 }
2069 } city_list_iterate_safe_end;
2070 game.server.savepalace = palace;
2071 }
2072 }
2073 }
2074
2075 /* barbarian leader ransom hack */
2076 if( is_barbarian(pvictim) && unit_has_type_role(punit, L_BARBARIAN_LEADER)
2077 && (unit_list_size(unit_tile(punit)->units) == 1)
2078 && uclass_has_flag(unit_class_get(pkiller), UCF_COLLECT_RANSOM)) {
2079 /* Occupying units can collect ransom if leader is alone in the tile */
2080 ransom = (pvictim->economic.gold >= game.server.ransom_gold)
2081 ? game.server.ransom_gold : pvictim->economic.gold;
2082 notify_player(pvictor, unit_tile(pkiller), E_UNIT_WIN_ATT, ftc_server,
2083 PL_("Barbarian leader captured; %d gold ransom paid.",
2084 "Barbarian leader captured; %d gold ransom paid.",
2085 ransom),
2086 ransom);
2087 pvictor->economic.gold += ransom;
2088 pvictim->economic.gold -= ransom;
2089 send_player_info_c(pvictor, NULL); /* let me see my new gold :-) */
2090 unitcount = 1;
2091 }
2092
2093 if (unitcount == 0) {
2094 unit_list_iterate(unit_tile(punit)->units, vunit) {
2095 if (pplayers_at_war(pvictor, unit_owner(vunit))) {
2096 unitcount++;
2097 }
2098 } unit_list_iterate_end;
2099 }
2100
2101 if (!is_stack_vulnerable(unit_tile(punit)) || unitcount == 1) {
2102 if (vet) {
2103 notify_unit_experience(pkiller);
2104 }
2105 wipe_unit(punit, ULR_KILLED, pvictor);
2106 } else { /* unitcount > 1 */
2107 int i;
2108 int num_killed[player_slot_count()];
2109 struct unit *other_killed[player_slot_count()];
2110 struct tile *ptile = unit_tile(punit);
2111
2112 fc_assert(unitcount > 1);
2113
2114 /* initialize */
2115 for (i = 0; i < player_slot_count(); i++) {
2116 num_killed[i] = 0;
2117 other_killed[i] = NULL;
2118 }
2119
2120 /* count killed units */
2121 unit_list_iterate(ptile->units, vunit) {
2122 struct player *vplayer = unit_owner(vunit);
2123 if (pplayers_at_war(pvictor, vplayer)
2124 && is_unit_reachable_at(vunit, pkiller, ptile)) {
2125 num_killed[player_index(vplayer)]++;
2126 if (vunit != punit) {
2127 other_killed[player_index(vplayer)] = vunit;
2128 other_killed[player_index(pvictor)] = vunit;
2129 }
2130 }
2131 } unit_list_iterate_end;
2132
2133 /* Inform the destroyer again if more than one unit was killed */
2134 if (unitcount > 1) {
2135 notify_player(pvictor, unit_tile(pkiller), E_UNIT_WIN_ATT, ftc_server,
2136 /* TRANS: "... Cannon ... the Polish Destroyer ...." */
2137 PL_("Your attacking %s succeeded against the %s %s "
2138 "(and %d other unit)!",
2139 "Your attacking %s succeeded against the %s %s "
2140 "(and %d other units)!", unitcount - 1),
2141 pkiller_link,
2142 nation_adjective_for_player(pvictim),
2143 punit_link,
2144 unitcount - 1);
2145 }
2146 if (vet) {
2147 notify_unit_experience(pkiller);
2148 }
2149
2150 /* inform the owners: this only tells about owned units that were killed.
2151 * there may have been 20 units who died but if only 2 belonged to the
2152 * particular player they'll only learn about those.
2153 *
2154 * Also if a large number of units die you don't find out what type
2155 * they all are. */
2156 for (i = 0; i < player_slot_count(); i++) {
2157 if (num_killed[i] == 1) {
2158 if (i == player_index(pvictim)) {
2159 fc_assert(other_killed[i] == NULL);
2160 notify_player(player_by_number(i), ptile,
2161 E_UNIT_LOST_DEF, ftc_server,
2162 /* TRANS: "Cannon ... the Polish Destroyer." */
2163 _("%s lost to an attack by the %s %s."),
2164 punit_link,
2165 nation_adjective_for_player(pvictor),
2166 pkiller_link);
2167 } else {
2168 fc_assert(other_killed[i] != punit);
2169 notify_player(player_by_number(i), ptile,
2170 E_UNIT_LOST_DEF, ftc_server,
2171 /* TRANS: "Cannon lost when the Polish Destroyer
2172 * attacked the German Musketeers." */
2173 _("%s lost when the %s %s attacked the %s %s."),
2174 unit_link(other_killed[i]),
2175 nation_adjective_for_player(pvictor),
2176 pkiller_link,
2177 nation_adjective_for_player(pvictim),
2178 punit_link);
2179 }
2180 } else if (num_killed[i] > 1) {
2181 if (i == player_index(pvictim)) {
2182 int others = num_killed[i] - 1;
2183
2184 if (others == 1) {
2185 notify_player(player_by_number(i), ptile,
2186 E_UNIT_LOST_DEF, ftc_server,
2187 /* TRANS: "Musketeers (and Cannon) lost to an
2188 * attack from the Polish Destroyer." */
2189 _("%s (and %s) lost to an attack from the %s %s."),
2190 punit_link,
2191 unit_link(other_killed[i]),
2192 nation_adjective_for_player(pvictor),
2193 pkiller_link);
2194 } else {
2195 notify_player(player_by_number(i), ptile,
2196 E_UNIT_LOST_DEF, ftc_server,
2197 /* TRANS: "Musketeers and 3 other units lost to
2198 * an attack from the Polish Destroyer."
2199 * (only happens with at least 2 other units) */
2200 PL_("%s and %d other unit lost to an attack "
2201 "from the %s %s.",
2202 "%s and %d other units lost to an attack "
2203 "from the %s %s.", others),
2204 punit_link,
2205 others,
2206 nation_adjective_for_player(pvictor),
2207 pkiller_link);
2208 }
2209 } else {
2210 notify_player(player_by_number(i), ptile,
2211 E_UNIT_LOST_DEF, ftc_server,
2212 /* TRANS: "2 units lost when the Polish Destroyer
2213 * attacked the German Musketeers."
2214 * (only happens with at least 2 other units) */
2215 PL_("%d unit lost when the %s %s attacked the %s %s.",
2216 "%d units lost when the %s %s attacked the %s %s.",
2217 num_killed[i]),
2218 num_killed[i],
2219 nation_adjective_for_player(pvictor),
2220 pkiller_link,
2221 nation_adjective_for_player(pvictim),
2222 punit_link);
2223 }
2224 }
2225 }
2226
2227 /* remove the units - note the logic of which units actually die
2228 * must be mimiced exactly in at least one place up above. */
2229 punit = NULL; /* wiped during following iteration so unsafe to use */
2230
2231 unit_list_iterate_safe(ptile->units, punit2) {
2232 if (pplayers_at_war(pvictor, unit_owner(punit2))
2233 && is_unit_reachable_at(punit2, pkiller, ptile)) {
2234 wipe_unit(punit2, ULR_KILLED, pvictor);
2235 }
2236 } unit_list_iterate_safe_end;
2237 }
2238 }
2239
2240 /**************************************************************************
2241 Package a unit_info packet. This packet contains basically all
2242 information about a unit.
2243 **************************************************************************/
package_unit(struct unit * punit,struct packet_unit_info * packet)2244 void package_unit(struct unit *punit, struct packet_unit_info *packet)
2245 {
2246 packet->id = punit->id;
2247 packet->owner = player_number(unit_owner(punit));
2248 packet->nationality = player_number(unit_nationality(punit));
2249 packet->tile = tile_index(unit_tile(punit));
2250 packet->facing = punit->facing;
2251 packet->homecity = punit->homecity;
2252 output_type_iterate(o) {
2253 packet->upkeep[o] = punit->upkeep[o];
2254 } output_type_iterate_end;
2255 packet->veteran = punit->veteran;
2256 packet->type = utype_number(unit_type_get(punit));
2257 packet->movesleft = punit->moves_left;
2258 packet->hp = punit->hp;
2259 packet->activity = punit->activity;
2260 packet->activity_count = punit->activity_count;
2261
2262 if (punit->activity_target != NULL) {
2263 packet->activity_tgt = extra_index(punit->activity_target);
2264 } else {
2265 packet->activity_tgt = EXTRA_NONE;
2266 }
2267
2268 packet->changed_from = punit->changed_from;
2269 packet->changed_from_count = punit->changed_from_count;
2270
2271 if (punit->changed_from_target != NULL) {
2272 packet->changed_from_tgt = extra_index(punit->changed_from_target);
2273 } else {
2274 packet->changed_from_tgt = EXTRA_NONE;
2275 }
2276
2277 packet->ai = punit->ai_controlled;
2278 packet->fuel = punit->fuel;
2279 packet->goto_tile = (NULL != punit->goto_tile
2280 ? tile_index(punit->goto_tile) : -1);
2281 packet->paradropped = punit->paradropped;
2282 packet->done_moving = punit->done_moving;
2283 if (!unit_transported(punit)) {
2284 packet->transported = FALSE;
2285 packet->transported_by = 0;
2286 } else {
2287 packet->transported = TRUE;
2288 packet->transported_by = unit_transport_get(punit)->id;
2289 }
2290 packet->occupied = (get_transporter_occupancy(punit) > 0);
2291 packet->battlegroup = punit->battlegroup;
2292 packet->has_orders = punit->has_orders;
2293 if (punit->has_orders) {
2294 int i;
2295
2296 packet->orders_length = punit->orders.length;
2297 packet->orders_index = punit->orders.index;
2298 packet->orders_repeat = punit->orders.repeat;
2299 packet->orders_vigilant = punit->orders.vigilant;
2300 for (i = 0; i < punit->orders.length; i++) {
2301 packet->orders[i] = punit->orders.list[i].order;
2302 packet->orders_dirs[i] = punit->orders.list[i].dir;
2303 packet->orders_activities[i] = punit->orders.list[i].activity;
2304 packet->orders_targets[i] = punit->orders.list[i].target;
2305 }
2306 } else {
2307 packet->orders_length = packet->orders_index = 0;
2308 packet->orders_repeat = packet->orders_vigilant = FALSE;
2309 /* No need to initialize array. */
2310 }
2311
2312 packet->action_decision_want = punit->action_decision_want;
2313 packet->action_decision_tile = (punit->action_decision_tile
2314 ? tile_index(punit->action_decision_tile)
2315 : IDENTITY_NUMBER_ZERO);
2316 }
2317
2318 /**************************************************************************
2319 Package a short_unit_info packet. This contains a limited amount of
2320 information about the unit, and is sent to players who shouldn't know
2321 everything (like the unit's owner's enemies).
2322 **************************************************************************/
package_short_unit(struct unit * punit,struct packet_unit_short_info * packet,enum unit_info_use packet_use,int info_city_id)2323 void package_short_unit(struct unit *punit,
2324 struct packet_unit_short_info *packet,
2325 enum unit_info_use packet_use, int info_city_id)
2326 {
2327 packet->packet_use = packet_use;
2328 packet->info_city_id = info_city_id;
2329
2330 packet->id = punit->id;
2331 packet->owner = player_number(unit_owner(punit));
2332 packet->tile = tile_index(unit_tile(punit));
2333 packet->facing = punit->facing;
2334 packet->veteran = punit->veteran;
2335 packet->type = utype_number(unit_type_get(punit));
2336 packet->hp = punit->hp;
2337 packet->occupied = (get_transporter_occupancy(punit) > 0);
2338 if (punit->activity == ACTIVITY_EXPLORE
2339 || punit->activity == ACTIVITY_GOTO) {
2340 packet->activity = ACTIVITY_IDLE;
2341 } else {
2342 packet->activity = punit->activity;
2343 }
2344
2345 if (punit->activity_target == NULL) {
2346 packet->activity_tgt = EXTRA_NONE;
2347 } else {
2348 packet->activity_tgt = extra_index(punit->activity_target);
2349 }
2350
2351 /* Transported_by information is sent to the client even for units that
2352 * aren't fully known. Note that for non-allied players, any transported
2353 * unit can't be seen at all. For allied players we have to know if
2354 * transporters have room in them so that we can load units properly. */
2355 if (!unit_transported(punit)) {
2356 packet->transported = FALSE;
2357 packet->transported_by = 0;
2358 } else {
2359 packet->transported = TRUE;
2360 packet->transported_by = unit_transport_get(punit)->id;
2361 }
2362 }
2363
2364 /**************************************************************************
2365 Handle situation where unit goes out of player sight.
2366 **************************************************************************/
unit_goes_out_of_sight(struct player * pplayer,struct unit * punit)2367 void unit_goes_out_of_sight(struct player *pplayer, struct unit *punit)
2368 {
2369 dlsend_packet_unit_remove(pplayer->connections, punit->id);
2370 if (punit->server.moving != NULL) {
2371 /* Update status of 'pplayer' vision for 'punit'. */
2372 BV_CLR(punit->server.moving->can_see_unit, player_index(pplayer));
2373 }
2374 }
2375
2376 /****************************************************************************
2377 send the unit to the players who need the info.
2378 dest = NULL means all connections (game.est_connections)
2379 ****************************************************************************/
send_unit_info(struct conn_list * dest,struct unit * punit)2380 void send_unit_info(struct conn_list *dest, struct unit *punit)
2381 {
2382 const struct player *powner;
2383 struct packet_unit_info info;
2384 struct packet_unit_short_info sinfo;
2385 struct unit_move_data *pdata;
2386
2387 if (dest == NULL) {
2388 dest = game.est_connections;
2389 }
2390
2391 CHECK_UNIT(punit);
2392
2393 powner = unit_owner(punit);
2394 package_unit(punit, &info);
2395 package_short_unit(punit, &sinfo, UNIT_INFO_IDENTITY, 0);
2396 pdata = punit->server.moving;
2397
2398 conn_list_iterate(dest, pconn) {
2399 struct player *pplayer = conn_get_player(pconn);
2400
2401 /* Be careful to consider all cases where pplayer is NULL... */
2402 if (pplayer == NULL) {
2403 if (pconn->observer) {
2404 send_packet_unit_info(pconn, &info);
2405 }
2406 } else if (pplayer == powner) {
2407 send_packet_unit_info(pconn, &info);
2408 if (pdata != NULL) {
2409 BV_SET(pdata->can_see_unit, player_index(pplayer));
2410 }
2411 } else if (can_player_see_unit(pplayer, punit)) {
2412 send_packet_unit_short_info(pconn, &sinfo, FALSE);
2413 if (pdata != NULL) {
2414 BV_SET(pdata->can_see_unit, player_index(pplayer));
2415 }
2416 }
2417 } conn_list_iterate_end;
2418 }
2419
2420 /**************************************************************************
2421 For each specified connections, send information about all the units
2422 known to that player/conn.
2423 **************************************************************************/
send_all_known_units(struct conn_list * dest)2424 void send_all_known_units(struct conn_list *dest)
2425 {
2426 conn_list_do_buffer(dest);
2427 conn_list_iterate(dest, pconn) {
2428 struct player *pplayer = pconn->playing;
2429
2430 if (NULL == pplayer && !pconn->observer) {
2431 continue;
2432 }
2433
2434 players_iterate(unitowner) {
2435 unit_list_iterate(unitowner->units, punit) {
2436 send_unit_info(dest, punit);
2437 } unit_list_iterate_end;
2438 } players_iterate_end;
2439 }
2440 conn_list_iterate_end;
2441 conn_list_do_unbuffer(dest);
2442 flush_packets();
2443 }
2444
2445 /**************************************************************************
2446 Nuke a square: 1) remove all units on the square, and 2) halve the
2447 size of the city on the square.
2448
2449 If it isn't a city square or an ocean square then with 50% chance add
2450 some fallout, then notify the client about the changes.
2451 **************************************************************************/
do_nuke_tile(struct player * pplayer,struct tile * ptile)2452 static void do_nuke_tile(struct player *pplayer, struct tile *ptile)
2453 {
2454 struct city *pcity = NULL;
2455
2456 unit_list_iterate_safe(ptile->units, punit) {
2457 notify_player(unit_owner(punit), ptile, E_UNIT_LOST_MISC, ftc_server,
2458 _("Your %s was nuked by %s."),
2459 unit_tile_link(punit),
2460 pplayer == unit_owner(punit)
2461 ? _("yourself")
2462 : nation_plural_for_player(pplayer));
2463 if (unit_owner(punit) != pplayer) {
2464 notify_player(pplayer, ptile, E_UNIT_WIN_ATT, ftc_server,
2465 _("The %s %s was nuked."),
2466 nation_adjective_for_player(unit_owner(punit)),
2467 unit_tile_link(punit));
2468 }
2469 wipe_unit(punit, ULR_NUKE, pplayer);
2470 } unit_list_iterate_safe_end;
2471
2472 pcity = tile_city(ptile);
2473
2474 if (pcity) {
2475 notify_player(city_owner(pcity), ptile, E_CITY_NUKED, ftc_server,
2476 _("%s was nuked by %s."),
2477 city_link(pcity),
2478 pplayer == city_owner(pcity)
2479 ? _("yourself")
2480 : nation_plural_for_player(pplayer));
2481
2482 if (city_owner(pcity) != pplayer) {
2483 notify_player(pplayer, ptile, E_CITY_NUKED, ftc_server,
2484 _("You nuked %s."),
2485 city_link(pcity));
2486 }
2487
2488 if (city_reduce_size(pcity, city_size_get(pcity) / 2, pplayer, "nuke")) {
2489 /* Send city size reduction to everyone seeing it */
2490 send_city_info(NULL, pcity);
2491 }
2492 }
2493
2494 if (fc_rand(2) == 1) {
2495 struct extra_type *pextra;
2496
2497 pextra = rand_extra_for_tile(ptile, EC_FALLOUT);
2498 if (pextra != NULL && !tile_has_extra(ptile, pextra)) {
2499 tile_add_extra(ptile, pextra);
2500 update_tile_knowledge(ptile);
2501 }
2502 }
2503 }
2504
2505 /**************************************************************************
2506 Nuke all the squares in a 3x3 square around the center of the explosion
2507 pplayer is the player that caused the explosion.
2508 **************************************************************************/
do_nuclear_explosion(struct player * pplayer,struct tile * ptile)2509 void do_nuclear_explosion(struct player *pplayer, struct tile *ptile)
2510 {
2511 struct player *victim = tile_owner(ptile);
2512
2513 call_incident(INCIDENT_NUCLEAR, pplayer, victim);
2514
2515 if (pplayer == victim) {
2516 players_iterate(oplayer) {
2517 if (victim != oplayer) {
2518 call_incident(INCIDENT_NUCLEAR_SELF, pplayer, oplayer);
2519 }
2520 } players_iterate_end;
2521 } else {
2522 players_iterate(oplayer) {
2523 if (victim != oplayer) {
2524 call_incident(INCIDENT_NUCLEAR_NOT_TARGET, pplayer, oplayer);
2525 }
2526 } players_iterate_end;
2527 }
2528
2529 square_iterate(ptile, 1, ptile1) {
2530 do_nuke_tile(pplayer, ptile1);
2531 } square_iterate_end;
2532
2533 notify_conn(NULL, ptile, E_NUKE, ftc_server,
2534 _("The %s detonated a nuke!"),
2535 nation_plural_for_player(pplayer));
2536 }
2537
2538 /**************************************************************************
2539 go by airline, if both cities have an airport and neither has been used this
2540 turn the unit will be transported by it and have its moves set to 0
2541 **************************************************************************/
do_airline(struct unit * punit,struct city * pdest_city)2542 bool do_airline(struct unit *punit, struct city *pdest_city)
2543 {
2544 struct city *psrc_city = tile_city(unit_tile(punit));
2545
2546 {
2547 enum unit_airlift_result result =
2548 test_unit_can_airlift_to(NULL, punit, pdest_city);
2549 if (!is_successful_airlift_result(result)) {
2550 switch (result) {
2551 /* These two can happen through no fault of the client (for allied
2552 * airlifts), so we give useful messages. */
2553 case AR_SRC_NO_FLIGHTS:
2554 notify_player(unit_owner(punit), unit_tile(punit),
2555 E_UNIT_RELOCATED, ftc_server,
2556 /* TRANS: Airlift failure message.
2557 * "Paris has no capacity to transport Warriors." */
2558 _("%s has no capacity to transport %s."),
2559 city_link(psrc_city), unit_link(punit));
2560 break;
2561 case AR_DST_NO_FLIGHTS:
2562 notify_player(unit_owner(punit), unit_tile(punit),
2563 E_UNIT_RELOCATED, ftc_server,
2564 /* TRANS: Airlift failure message.
2565 * "Paris has no capacity to transport Warriors." */
2566 _("%s has no capacity to transport %s."),
2567 city_link(pdest_city), unit_link(punit));
2568 break;
2569 default:
2570 /* The client should have been able to foresee all the other
2571 * causes of failure, so it's not worth having specific messages for
2572 * all of them. */
2573 notify_player(unit_owner(punit), unit_tile(punit),
2574 E_UNIT_RELOCATED, ftc_server,
2575 /* TRANS: Airlift failure message.
2576 * "Warriors cannot be transported to Paris." */
2577 _("%s cannot be transported to %s."),
2578 unit_link(punit), city_link(pdest_city));
2579 break;
2580 }
2581 return FALSE;
2582 }
2583 }
2584
2585 notify_player(unit_owner(punit), city_tile(pdest_city),
2586 E_UNIT_RELOCATED, ftc_server,
2587 _("%s transported successfully."),
2588 unit_link(punit));
2589
2590 unit_move(punit, pdest_city->tile, punit->moves_left, NULL);
2591
2592 /* Update airlift fields. */
2593 if (!(game.info.airlifting_style & AIRLIFTING_UNLIMITED_SRC)) {
2594 psrc_city->airlift--;
2595 send_city_info(city_owner(psrc_city), psrc_city);
2596 }
2597 if (!(game.info.airlifting_style & AIRLIFTING_UNLIMITED_DEST)) {
2598 pdest_city->airlift--;
2599 send_city_info(city_owner(pdest_city), pdest_city);
2600 }
2601
2602 return TRUE;
2603 }
2604
2605 /**************************************************************************
2606 Autoexplore with unit.
2607 **************************************************************************/
do_explore(struct unit * punit)2608 void do_explore(struct unit *punit)
2609 {
2610 switch (manage_auto_explorer(punit)) {
2611 case MR_DEATH:
2612 /* don't use punit! */
2613 return;
2614 case MR_NOT_ALLOWED:
2615 /* Needed for something else */
2616 return;
2617 case MR_OK:
2618 /* FIXME: manage_auto_explorer() isn't supposed to change the activity,
2619 * but don't count on this. See PR#39792.
2620 */
2621 if (punit->activity == ACTIVITY_EXPLORE) {
2622 break;
2623 }
2624 /* fallthru */
2625 default:
2626 unit_activity_handling(punit, ACTIVITY_IDLE);
2627
2628 /* FIXME: When the manage_auto_explorer() call changes the activity from
2629 * EXPLORE to IDLE, in unit_activity_handling() ai.control is left
2630 * alone. We reset it here. See PR#12931. */
2631 punit->ai_controlled = FALSE;
2632 break;
2633 }
2634
2635 send_unit_info(NULL, punit); /* probably duplicate */
2636 }
2637
2638 /**************************************************************************
2639 Returns whether the drop was made or not. Note that it also returns 1
2640 in the case where the drop was succesful, but the unit was killed by
2641 barbarians in a hut.
2642 **************************************************************************/
do_paradrop(struct unit * punit,struct tile * ptile)2643 bool do_paradrop(struct unit *punit, struct tile *ptile)
2644 {
2645 struct player *pplayer = unit_owner(punit);
2646 int range, distance;
2647
2648 if (!unit_has_type_flag(punit, UTYF_PARATROOPERS)) {
2649 notify_player(pplayer, unit_tile(punit), E_BAD_COMMAND, ftc_server,
2650 _("This unit type can not be paradropped."));
2651 return FALSE;
2652 }
2653
2654 if (!can_unit_paradrop(punit)) {
2655 return FALSE;
2656 }
2657
2658 if (get_transporter_occupancy(punit) > 0) {
2659 notify_player(pplayer, unit_tile(punit), E_BAD_COMMAND, ftc_server,
2660 _("You cannot paradrop a unit that is "
2661 "transporting other units."));
2662 return FALSE;
2663 }
2664
2665 if (!map_is_known(ptile, pplayer)) {
2666 notify_player(pplayer, ptile, E_BAD_COMMAND, ftc_server,
2667 _("The destination location is not known."));
2668 return FALSE;
2669 }
2670
2671 range = unit_type_get(punit)->paratroopers_range;
2672 distance = real_map_distance(unit_tile(punit), ptile);
2673 if (distance > range) {
2674 notify_player(pplayer, ptile, E_BAD_COMMAND, ftc_server,
2675 _("The distance to the target (%i) "
2676 "is greater than the unit's range (%i)."),
2677 distance, range);
2678 return FALSE;
2679 } else if (distance < 1) {
2680 notify_player(pplayer, ptile, E_BAD_COMMAND, ftc_server,
2681 _("Already there."));
2682 return FALSE;
2683 }
2684
2685 if (map_is_known_and_seen(ptile, pplayer, V_MAIN)) {
2686 if (!can_unit_exist_at_tile(punit, ptile)
2687 && (!game.info.paradrop_to_transport
2688 || !unit_could_load_at(punit, ptile))) {
2689 notify_player(pplayer, ptile, E_BAD_COMMAND, ftc_server,
2690 _("This unit cannot paradrop into %s."),
2691 terrain_name_translation(tile_terrain(ptile)));
2692 return FALSE;
2693 }
2694
2695 if (NULL != is_non_attack_city_tile(ptile, pplayer)) {
2696 notify_player(pplayer, ptile, E_BAD_COMMAND, ftc_server,
2697 _("Cannot attack unless you declare war first."));
2698 return FALSE;
2699 }
2700
2701 unit_list_iterate(ptile->units, pother) {
2702 if (can_player_see_unit(pplayer, pother)
2703 && !pplayers_allied(pplayer, unit_owner(pother))) {
2704 notify_player(pplayer, ptile, E_BAD_COMMAND, ftc_server,
2705 /* TRANS: Paratroopers ... Drop Paratrooper */
2706 _("Your %s can't do %s to tiles with non allied"
2707 " units."),
2708 unit_name_translation(punit),
2709 _("Drop Paratrooper"));
2710 return FALSE;
2711 }
2712 } unit_list_iterate_end;
2713
2714 if (is_military_unit(punit)
2715 && !player_can_invade_tile(pplayer, ptile)) {
2716 notify_player(pplayer, ptile, E_BAD_COMMAND, ftc_server,
2717 _("Cannot invade unless you break peace with "
2718 "%s first."),
2719 player_name(tile_owner(ptile)));
2720 return FALSE;
2721 }
2722 } else {
2723 /* Only take in account values from player map. */
2724 const struct player_tile *plrtile = map_get_player_tile(ptile, pplayer);
2725
2726 if (NULL == plrtile->site
2727 && !is_native_to_class(unit_class_get(punit), plrtile->terrain,
2728 &(plrtile->extras))) {
2729 notify_player(pplayer, ptile, E_BAD_COMMAND, ftc_server,
2730 _("This unit cannot paradrop into %s."),
2731 terrain_name_translation(plrtile->terrain));
2732 return FALSE;
2733 }
2734
2735 if (NULL != plrtile->site
2736 && plrtile->owner != NULL
2737 && pplayers_non_attack(pplayer, plrtile->owner)) {
2738 notify_player(pplayer, ptile, E_BAD_COMMAND, ftc_server,
2739 _("Cannot attack unless you declare war first."));
2740 return FALSE;
2741 }
2742
2743 if (is_military_unit(punit)
2744 && NULL != plrtile->owner
2745 && players_non_invade(pplayer, plrtile->owner)) {
2746 notify_player(pplayer, ptile, E_BAD_COMMAND, ftc_server,
2747 _("Cannot invade unless you break peace with "
2748 "%s first."),
2749 player_name(plrtile->owner));
2750 return FALSE;
2751 }
2752
2753 /* Safe terrain, really? Not transformed since player last saw it. */
2754 if (!can_unit_exist_at_tile(punit, ptile)
2755 && (!game.info.paradrop_to_transport
2756 || !unit_could_load_at(punit, ptile))) {
2757 map_show_circle(pplayer, ptile, unit_type_get(punit)->vision_radius_sq);
2758 notify_player(pplayer, ptile, E_UNIT_LOST_MISC, ftc_server,
2759 _("Your %s paradropped into the %s and was lost."),
2760 unit_tile_link(punit),
2761 terrain_name_translation(tile_terrain(ptile)));
2762 pplayer->score.units_lost++;
2763 server_remove_unit(punit, ULR_NONNATIVE_TERR);
2764 return TRUE;
2765 }
2766 }
2767
2768 if (is_non_attack_city_tile(ptile, pplayer)
2769 || (is_non_allied_city_tile(ptile, pplayer)
2770 && (pplayer->ai_common.barbarian_type == ANIMAL_BARBARIAN
2771 || !uclass_has_flag(unit_class_get(punit),
2772 UCF_CAN_OCCUPY_CITY)
2773 || unit_has_type_flag(punit, UTYF_CIVILIAN)))
2774 || is_non_allied_unit_tile(ptile, pplayer)) {
2775 map_show_circle(pplayer, ptile, unit_type_get(punit)->vision_radius_sq);
2776 maybe_make_contact(ptile, pplayer);
2777 notify_player(pplayer, ptile, E_UNIT_LOST_MISC, ftc_server,
2778 _("Your %s was killed by enemy units at the "
2779 "paradrop destination."),
2780 unit_tile_link(punit));
2781 /* TODO: Should defender score.units_killed get increased too?
2782 * What if there's units of several allied players? Should the
2783 * city owner or owner of the first/random unit get the kill? */
2784 pplayer->score.units_lost++;
2785 server_remove_unit(punit, ULR_KILLED);
2786 return TRUE;
2787 }
2788
2789 /* All ok */
2790 punit->paradropped = TRUE;
2791 if (unit_move(punit, ptile, unit_type_get(punit)->paratroopers_mr_sub, NULL)) {
2792 /* Ensure we finished on valid state. */
2793 fc_assert(can_unit_exist_at_tile(punit, unit_tile(punit))
2794 || unit_transported(punit));
2795 }
2796 return TRUE;
2797 }
2798
2799 /**************************************************************************
2800 Give 25 Gold or kill the unit. For H_LIMITEDHUTS
2801 Return TRUE if unit is alive, and FALSE if it was killed
2802 **************************************************************************/
hut_get_limited(struct unit * punit)2803 static bool hut_get_limited(struct unit *punit)
2804 {
2805 bool ok = TRUE;
2806 int hut_chance = fc_rand(12);
2807 struct player *pplayer = unit_owner(punit);
2808 /* 1 in 12 to get barbarians */
2809 if (hut_chance != 0) {
2810 int cred = 25;
2811 notify_player(pplayer, unit_tile(punit), E_HUT_GOLD, ftc_server,
2812 PL_("You found %d gold.",
2813 "You found %d gold.", cred), cred);
2814 pplayer->economic.gold += cred;
2815 } else if (city_exists_within_max_city_map(unit_tile(punit), TRUE)
2816 || unit_has_type_flag(punit, UTYF_GAMELOSS)) {
2817 notify_player(pplayer, unit_tile(punit),
2818 E_HUT_BARB_CITY_NEAR, ftc_server,
2819 _("An abandoned village is here."));
2820 } else {
2821 notify_player(pplayer, unit_tile(punit), E_HUT_BARB_KILLED, ftc_server,
2822 _("Your %s has been killed by barbarians!"),
2823 unit_tile_link(punit));
2824 wipe_unit(punit, ULR_BARB_UNLEASH, NULL);
2825 ok = FALSE;
2826 }
2827 return ok;
2828 }
2829
2830 /**************************************************************************
2831 Enter huts in iteration order as long as unit lives.
2832 Iff survived to the last one, return TRUE.
2833 **************************************************************************/
unit_enter_hut(struct unit * punit)2834 static bool unit_enter_hut(struct unit *punit)
2835 {
2836 struct player *pplayer = unit_owner(punit);
2837 int id = punit->id;
2838 enum hut_behavior behavior = unit_class_get(punit)->hut_behavior;
2839 struct tile *ptile = unit_tile(punit);
2840 bool hut = FALSE, res = TRUE;
2841
2842 /* FIXME: Should we still run "hut_enter" script when
2843 * hut_behavior is HUT_NOTHING or HUT_FRIGHTEN? */
2844 if (behavior == HUT_NOTHING) {
2845 return TRUE;
2846 }
2847
2848 extra_type_by_cause_iterate(EC_HUT, pextra) {
2849 if (tile_has_extra(ptile, pextra)) {
2850 hut = TRUE;
2851 pplayer->server.huts++;
2852
2853 destroy_extra(ptile, pextra);
2854 update_tile_knowledge(unit_tile(punit));
2855
2856 if (behavior == HUT_FRIGHTEN) {
2857 notify_player(pplayer, unit_tile(punit), E_HUT_BARB, ftc_server,
2858 _("Your overflight frightens the tribe;"
2859 " they scatter in terror."));
2860 } else if (pplayer->ai_controlled
2861 && has_handicap(pplayer, H_LIMITEDHUTS)) {
2862 /* AI with H_LIMITEDHUTS only gets 25 gold (or barbs if unlucky) */
2863 (void) hut_get_limited(punit);
2864 } else {
2865 script_server_signal_emit("hut_enter", 1,
2866 API_TYPE_UNIT, punit);
2867 }
2868
2869 /* We need punit for the callbacks, can't continue if the unit died */
2870 if (!unit_is_alive(id)) {
2871 res = FALSE;
2872 break;
2873 }
2874 }
2875 } extra_type_by_cause_iterate_end;
2876
2877 if (hut) {
2878 send_player_info_c(pplayer, pplayer->connections); /* eg, gold */
2879 }
2880
2881 return res;
2882 }
2883
2884 /****************************************************************************
2885 Put the unit onto the transporter, and tell everyone.
2886 ****************************************************************************/
unit_transport_load_send(struct unit * punit,struct unit * ptrans)2887 void unit_transport_load_send(struct unit *punit, struct unit *ptrans)
2888 {
2889 bv_player can_see_unit;
2890
2891 fc_assert_ret(punit != NULL);
2892 fc_assert_ret(ptrans != NULL);
2893
2894 BV_CLR_ALL(can_see_unit);
2895 players_iterate(pplayer) {
2896 if (can_player_see_unit(pplayer, punit)) {
2897 BV_SET(can_see_unit, player_index(pplayer));
2898 }
2899 } players_iterate_end;
2900
2901 unit_transport_load(punit, ptrans, FALSE);
2902
2903 players_iterate(pplayer) {
2904 if (BV_ISSET(can_see_unit, player_index(pplayer))
2905 && !can_player_see_unit(pplayer, punit)) {
2906 unit_goes_out_of_sight(pplayer, punit);
2907 }
2908 } players_iterate_end;
2909
2910 send_unit_info(NULL, punit);
2911 send_unit_info(NULL, ptrans);
2912 }
2913
2914 /****************************************************************************
2915 Load unit to transport, send transport's loaded status to everyone.
2916 ****************************************************************************/
unit_transport_load_tp_status(struct unit * punit,struct unit * ptrans,bool force)2917 static void unit_transport_load_tp_status(struct unit *punit,
2918 struct unit *ptrans,
2919 bool force)
2920 {
2921 bool had_cargo;
2922
2923 fc_assert_ret(punit != NULL);
2924 fc_assert_ret(ptrans != NULL);
2925
2926 had_cargo = get_transporter_occupancy(ptrans) > 0;
2927
2928 unit_transport_load(punit, ptrans, force);
2929
2930 if (!had_cargo) {
2931 /* Transport's loaded status changed */
2932 send_unit_info(NULL, ptrans);
2933 }
2934 }
2935
2936 /****************************************************************************
2937 Pull the unit off of the transporter, and tell everyone.
2938 ****************************************************************************/
unit_transport_unload_send(struct unit * punit)2939 void unit_transport_unload_send(struct unit *punit)
2940 {
2941 struct unit *ptrans;
2942
2943 fc_assert_ret(punit);
2944
2945 ptrans = unit_transport_get(punit);
2946
2947 fc_assert_ret(ptrans);
2948
2949 unit_transport_unload(punit);
2950
2951 send_unit_info(NULL, punit);
2952 send_unit_info(NULL, ptrans);
2953 }
2954
2955 /**************************************************************************
2956 This function is passed to unit_list_sort() to sort a list of units
2957 according to their win chance against autoattack_target, modified by
2958 transportation relationships.
2959
2960 The reason for making sure that a cargo unit is ahead of its
2961 transporter(s) is to leave transports out of combat if at all possible.
2962 (The transport could be destroyed during combat.)
2963 **************************************************************************/
compare_units(const struct unit * const * p1,const struct unit * const * q1)2964 static int compare_units(const struct unit *const *p1,
2965 const struct unit *const *q1)
2966 {
2967 struct unit *p1def = get_defender(*p1, autoattack_target);
2968 struct unit *q1def = get_defender(*q1, autoattack_target);
2969 int p1uwc = unit_win_chance(*p1, p1def);
2970 int q1uwc = unit_win_chance(*q1, q1def);
2971
2972 /* Sort by transport depth first. This makes sure that no transport
2973 * attacks before its cargo does -- cargo sorts earlier in the list. */
2974 {
2975 const struct unit *p1trans = *p1, *q1trans = *q1;
2976
2977 /* Walk the transport stacks in parallel, so as to bail out as soon as
2978 * one of them is empty (avoid walking deep stacks more often than
2979 * necessary). */
2980 while (p1trans && q1trans) {
2981 p1trans = unit_transport_get(p1trans);
2982 q1trans = unit_transport_get(q1trans);
2983 }
2984 if (!p1trans && q1trans) {
2985 /* q1 is at greater depth (perhaps it's p1's cargo). It should sort
2986 * earlier in the list (p1 > q1). */
2987 return 1;
2988 } else if (p1trans && !q1trans) {
2989 /* p1 is at greater depth, so should sort earlier (p1 < q1). */
2990 return -1;
2991 }
2992 /* else same depth, so move on to checking win chance: */
2993 }
2994
2995 /* Put the units with the highest probability of success first. The up
2996 * side of this is that units with bonuses against the victim attacks
2997 * before other units. The downside is that strong units can be lead
2998 * away by sacrificial units. */
2999 if (p1uwc < q1uwc) {
3000 return +1; /* q is better */
3001 } else if (p1uwc == q1uwc) {
3002 return 0;
3003 } else {
3004 return -1; /* p is better */
3005 }
3006 }
3007
3008 /*****************************************************************
3009 Can this unit be used in autoattack
3010 *****************************************************************/
is_suitable_autoattack_unit(struct unit * punit)3011 static bool is_suitable_autoattack_unit(struct unit *punit)
3012 {
3013 if (unit_has_type_flag(punit, UTYF_NUCLEAR)) {
3014 /* Not a good idea to nuke our own area */
3015 return FALSE;
3016 }
3017
3018 return TRUE;
3019 }
3020
3021 /*****************************************************************
3022 Check if unit survives enemy autoattacks. We assume that any
3023 unit that is adjacent to us can see us.
3024 *****************************************************************/
unit_survive_autoattack(struct unit * punit)3025 static bool unit_survive_autoattack(struct unit *punit)
3026 {
3027 struct unit_list *autoattack;
3028 int moves = punit->moves_left;
3029 int sanity1 = punit->id;
3030
3031 if (!game.server.autoattack) {
3032 return TRUE;
3033 }
3034
3035 autoattack = unit_list_new();
3036
3037 /* Kludge to prevent attack power from dropping to zero during calc */
3038 punit->moves_left = MAX(punit->moves_left, 1);
3039
3040 adjc_iterate(unit_tile(punit), ptile) {
3041 /* First add all eligible units to a unit list */
3042 unit_list_iterate(ptile->units, penemy) {
3043 struct player *enemyplayer = unit_owner(penemy);
3044 enum diplstate_type ds =
3045 player_diplstate_get(unit_owner(punit), enemyplayer)->type;
3046
3047 if (penemy->moves_left > 0
3048 && ds == DS_WAR
3049 && is_suitable_autoattack_unit(penemy)
3050 && (unit_attack_unit_at_tile_result(penemy, punit, unit_tile(punit))
3051 == ATT_OK)) {
3052 unit_list_prepend(autoattack, penemy);
3053 }
3054 } unit_list_iterate_end;
3055 } adjc_iterate_end;
3056
3057 /* Sort the potential attackers from highest to lowest success
3058 * probability. */
3059 autoattack_target = unit_tile(punit); /* global variable */
3060 if (unit_list_size(autoattack) >= 2) {
3061 unit_list_sort(autoattack, &compare_units);
3062 }
3063
3064 unit_list_iterate_safe(autoattack, penemy) {
3065 int sanity2 = penemy->id;
3066 struct tile *ptile = unit_tile(penemy);
3067 struct unit *enemy_defender = get_defender(punit, ptile);
3068 struct unit *punit_defender = get_defender(penemy, unit_tile(punit));
3069 double punitwin, penemywin;
3070 double threshold = 0.25;
3071
3072 fc_assert_action(NULL != punit_defender, continue);
3073
3074 if (tile_city(ptile) && unit_list_size(ptile->units) == 1) {
3075 /* Don't leave city defenseless */
3076 threshold = 0.90;
3077 }
3078
3079 if (NULL != enemy_defender) {
3080 punitwin = unit_win_chance(punit, enemy_defender);
3081 } else {
3082 /* 'penemy' can attack 'punit' but it may be not reciproque. */
3083 punitwin = 1.0;
3084 }
3085 penemywin = unit_win_chance(penemy, punit_defender);
3086
3087 if ((penemywin > 1.0 - punitwin
3088 || utype_acts_hostile(unit_type_get(punit))
3089 || get_transporter_capacity(punit) > 0)
3090 && penemywin > threshold) {
3091 #ifdef REALLY_DEBUG_THIS
3092 log_test("AA %s -> %s (%d,%d) %.2f > %.2f && > %.2f",
3093 unit_rule_name(penemy), unit_rule_name(punit),
3094 TILE_XY(unit_tile(punit)), penemywin,
3095 1.0 - punitwin, threshold);
3096 #endif
3097
3098 unit_activity_handling(penemy, ACTIVITY_IDLE);
3099 /* Attack */
3100 (void) unit_move_handling(penemy, unit_tile(punit),
3101 FALSE, TRUE, NULL);
3102 } else {
3103 #ifdef REALLY_DEBUG_THIS
3104 log_test("!AA %s -> %s (%d,%d) %.2f > %.2f && > %.2f",
3105 unit_rule_name(penemy), unit_rule_name(punit),
3106 TILE_XY(unit_tile(punit)), penemywin,
3107 1.0 - punitwin, threshold);
3108 #endif
3109 continue;
3110 }
3111
3112 if (game_unit_by_number(sanity2)) {
3113 send_unit_info(NULL, penemy);
3114 }
3115 if (game_unit_by_number(sanity1)) {
3116 send_unit_info(NULL, punit);
3117 } else {
3118 unit_list_destroy(autoattack);
3119 return FALSE; /* moving unit dead */
3120 }
3121 } unit_list_iterate_safe_end;
3122
3123 unit_list_destroy(autoattack);
3124 if (game_unit_by_number(sanity1)) {
3125 /* We could have lost movement in combat */
3126 punit->moves_left = MIN(punit->moves_left, moves);
3127 send_unit_info(NULL, punit);
3128 return TRUE;
3129 } else {
3130 return FALSE;
3131 }
3132 }
3133
3134 /****************************************************************************
3135 Cancel orders for the unit.
3136 ****************************************************************************/
cancel_orders(struct unit * punit,char * dbg_msg)3137 static void cancel_orders(struct unit *punit, char *dbg_msg)
3138 {
3139 free_unit_orders(punit);
3140 send_unit_info(NULL, punit);
3141 log_debug("%s", dbg_msg);
3142 }
3143
3144 /*****************************************************************
3145 Will wake up any neighboring enemy sentry units or patrolling
3146 units.
3147 *****************************************************************/
wakeup_neighbor_sentries(struct unit * punit)3148 static void wakeup_neighbor_sentries(struct unit *punit)
3149 {
3150 bool alone_in_city;
3151
3152 if (NULL != tile_city(unit_tile(punit))) {
3153 int count = 0;
3154
3155 unit_list_iterate(unit_tile(punit)->units, aunit) {
3156 /* Consider only units not transported. */
3157 if (!unit_transported(aunit)) {
3158 count++;
3159 }
3160 } unit_list_iterate_end;
3161
3162 alone_in_city = (1 == count);
3163 } else {
3164 alone_in_city = FALSE;
3165 }
3166
3167 /* There may be sentried units with a sightrange > 3, but we don't
3168 wake them up if the punit is farther away than 3. */
3169 square_iterate(unit_tile(punit), 3, ptile) {
3170 unit_list_iterate(ptile->units, penemy) {
3171 int distance_sq = sq_map_distance(unit_tile(punit), ptile);
3172 int radius_sq = get_unit_vision_at(penemy, unit_tile(penemy), V_MAIN);
3173
3174 if (!pplayers_allied(unit_owner(punit), unit_owner(penemy))
3175 && penemy->activity == ACTIVITY_SENTRY
3176 && radius_sq >= distance_sq
3177 /* If the unit moved on a city, and the unit is alone, consider
3178 * it is visible. */
3179 && (alone_in_city
3180 || can_player_see_unit(unit_owner(penemy), punit))
3181 /* on board transport; don't awaken */
3182 && can_unit_exist_at_tile(penemy, unit_tile(penemy))) {
3183 set_unit_activity(penemy, ACTIVITY_IDLE);
3184 send_unit_info(NULL, penemy);
3185 }
3186 } unit_list_iterate_end;
3187 } square_iterate_end;
3188
3189 /* Wakeup patrolling units we bump into.
3190 We do not wakeup units further away than 3 squares... */
3191 square_iterate(unit_tile(punit), 3, ptile) {
3192 unit_list_iterate(ptile->units, ppatrol) {
3193 if (punit != ppatrol
3194 && unit_has_orders(ppatrol)
3195 && ppatrol->orders.vigilant) {
3196 if (maybe_cancel_patrol_due_to_enemy(ppatrol)) {
3197 cancel_orders(ppatrol, " stopping because of nearby enemy");
3198 notify_player(unit_owner(ppatrol), unit_tile(ppatrol),
3199 E_UNIT_ORDERS, ftc_server,
3200 _("Orders for %s aborted after enemy movement was "
3201 "spotted."),
3202 unit_link(ppatrol));
3203 }
3204 }
3205 } unit_list_iterate_end;
3206 } square_iterate_end;
3207 }
3208
3209 /**************************************************************************
3210 Does: 1) updates the unit's homecity and the city it enters/leaves (the
3211 city's happiness varies). This also takes into account when the
3212 unit enters/leaves a fortress.
3213 2) updates adjacent cities' unavailable tiles.
3214
3215 FIXME: Sometimes it is not necessary to send cities because the goverment
3216 doesn't care whether a unit is away or not.
3217 **************************************************************************/
unit_move_consequences(struct unit * punit,struct tile * src_tile,struct tile * dst_tile,bool passenger)3218 static bool unit_move_consequences(struct unit *punit,
3219 struct tile *src_tile,
3220 struct tile *dst_tile,
3221 bool passenger)
3222 {
3223 struct city *fromcity = tile_city(src_tile);
3224 struct city *tocity = tile_city(dst_tile);
3225 struct city *homecity_start_pos = NULL;
3226 struct city *homecity_end_pos = NULL;
3227 int homecity_id_start_pos = punit->homecity;
3228 int homecity_id_end_pos = punit->homecity;
3229 struct player *pplayer_start_pos = unit_owner(punit);
3230 struct player *pplayer_end_pos = pplayer_start_pos;
3231 struct unit_type *type_start_pos = unit_type_get(punit);
3232 struct unit_type *type_end_pos = type_start_pos;
3233 bool refresh_homecity_start_pos = FALSE;
3234 bool refresh_homecity_end_pos = FALSE;
3235 int saved_id = punit->id;
3236 bool alive = TRUE;
3237
3238 if (tocity) {
3239 unit_enter_city(punit, tocity, passenger);
3240
3241 alive = unit_is_alive(saved_id);
3242 if (alive) {
3243 /* In case script has changed something about unit */
3244 pplayer_end_pos = unit_owner(punit);
3245 type_end_pos = unit_type_get(punit);
3246 homecity_id_end_pos = punit->homecity;
3247 }
3248 }
3249
3250 if (homecity_id_start_pos != 0) {
3251 homecity_start_pos = game_city_by_number(homecity_id_start_pos);
3252 }
3253 if (homecity_id_start_pos != homecity_id_end_pos) {
3254 homecity_end_pos = game_city_by_number(homecity_id_end_pos);
3255 } else {
3256 homecity_end_pos = homecity_start_pos;
3257 }
3258
3259 /* We only do refreshes for non-AI players to now make sure the AI turns
3260 doesn't take too long. Perhaps we should make a special refresh_city
3261 functions that only refreshed happines. */
3262
3263 /* might have changed owners or may be destroyed */
3264 tocity = tile_city(dst_tile);
3265
3266 if (tocity) { /* entering a city */
3267 if (tocity->owner == pplayer_end_pos) {
3268 if (tocity != homecity_end_pos && !pplayer_end_pos->ai_controlled) {
3269 city_refresh(tocity);
3270 send_city_info(pplayer_end_pos, tocity);
3271 }
3272 }
3273 if (homecity_start_pos) {
3274 refresh_homecity_start_pos = TRUE;
3275 }
3276 }
3277
3278 if (fromcity) { /* leaving a city */
3279 if (homecity_start_pos) {
3280 refresh_homecity_start_pos = TRUE;
3281 }
3282 if (fromcity != homecity_start_pos
3283 && fromcity->owner == pplayer_start_pos
3284 && !pplayer_start_pos->ai_controlled) {
3285 city_refresh(fromcity);
3286 send_city_info(pplayer_start_pos, fromcity);
3287 }
3288 }
3289
3290 /* entering/leaving a fortress or friendly territory */
3291 if (homecity_start_pos || homecity_end_pos) {
3292 if ((game.info.happyborders != HB_DISABLED && tile_owner(src_tile) != tile_owner(dst_tile))
3293 || (tile_has_base_flag_for_unit(dst_tile,
3294 type_end_pos,
3295 BF_NOT_AGGRESSIVE)
3296 && is_friendly_city_near(pplayer_end_pos, dst_tile))
3297 || (tile_has_base_flag_for_unit(src_tile,
3298 type_start_pos,
3299 BF_NOT_AGGRESSIVE)
3300 && is_friendly_city_near(pplayer_start_pos, src_tile))) {
3301 refresh_homecity_start_pos = TRUE;
3302 refresh_homecity_end_pos = TRUE;
3303 }
3304 }
3305
3306 if (refresh_homecity_start_pos && !pplayer_start_pos->ai_controlled) {
3307 city_refresh(homecity_start_pos);
3308 send_city_info(pplayer_start_pos, homecity_start_pos);
3309 }
3310 if (refresh_homecity_end_pos
3311 && (!refresh_homecity_start_pos
3312 || homecity_start_pos != homecity_end_pos)
3313 && !pplayer_end_pos->ai_controlled) {
3314 city_refresh(homecity_end_pos);
3315 send_city_info(pplayer_end_pos, homecity_end_pos);
3316 }
3317
3318 city_map_update_tile_now(dst_tile);
3319 sync_cities();
3320
3321 return alive;
3322 }
3323
3324 /**************************************************************************
3325 Check if the units activity is legal for a move , and reset it if it isn't.
3326 **************************************************************************/
check_unit_activity(struct unit * punit)3327 static void check_unit_activity(struct unit *punit)
3328 {
3329 switch (punit->activity) {
3330 case ACTIVITY_IDLE:
3331 case ACTIVITY_SENTRY:
3332 case ACTIVITY_EXPLORE:
3333 case ACTIVITY_GOTO:
3334 break;
3335 case ACTIVITY_POLLUTION:
3336 case ACTIVITY_MINE:
3337 case ACTIVITY_IRRIGATE:
3338 case ACTIVITY_FORTIFIED:
3339 case ACTIVITY_FORTRESS:
3340 case ACTIVITY_PILLAGE:
3341 case ACTIVITY_TRANSFORM:
3342 case ACTIVITY_UNKNOWN:
3343 case ACTIVITY_AIRBASE:
3344 case ACTIVITY_FORTIFYING:
3345 case ACTIVITY_FALLOUT:
3346 case ACTIVITY_PATROL_UNUSED:
3347 case ACTIVITY_BASE:
3348 case ACTIVITY_GEN_ROAD:
3349 case ACTIVITY_CONVERT:
3350 case ACTIVITY_OLD_ROAD:
3351 case ACTIVITY_OLD_RAILROAD:
3352 case ACTIVITY_LAST:
3353 set_unit_activity(punit, ACTIVITY_IDLE);
3354 break;
3355 };
3356 }
3357
3358 /****************************************************************************
3359 Create a new unit move data, or use previous one if available.
3360 ****************************************************************************/
unit_move_data(struct unit * punit,struct tile * psrctile,struct tile * pdesttile)3361 static struct unit_move_data *unit_move_data(struct unit *punit,
3362 struct tile *psrctile,
3363 struct tile *pdesttile)
3364 {
3365 struct unit_move_data *pdata;
3366 struct player *powner = unit_owner(punit);
3367 const v_radius_t radius_sq =
3368 V_RADIUS(get_unit_vision_at(punit, pdesttile, V_MAIN),
3369 get_unit_vision_at(punit, pdesttile, V_INVIS));
3370 struct vision *new_vision;
3371 bool success;
3372
3373 if (punit->server.moving) {
3374 /* Recursive moving (probably due to a script). */
3375 pdata = punit->server.moving;
3376 pdata->ref_count++;
3377 fc_assert_msg(pdata->punit == punit,
3378 "Unit number %d (%p) was going to die, but "
3379 "server attempts to move it.",
3380 punit->id, punit);
3381 fc_assert_msg(pdata->old_vision == NULL,
3382 "Unit number %d (%p) has done an incomplete move.",
3383 punit->id, punit);
3384 } else {
3385 pdata = fc_malloc(sizeof(*pdata));
3386 pdata->ref_count = 1;
3387 pdata->punit = punit;
3388 punit->server.moving = pdata;
3389 BV_CLR_ALL(pdata->can_see_unit);
3390 }
3391 pdata->powner = powner;
3392 BV_CLR_ALL(pdata->can_see_move);
3393 pdata->old_vision = punit->server.vision;
3394
3395 /* Remove unit from the source tile. */
3396 fc_assert(unit_tile(punit) == psrctile);
3397 success = unit_list_remove(psrctile->units, punit);
3398 fc_assert(success == TRUE);
3399
3400 /* Set new tile. */
3401 unit_tile_set(punit, pdesttile);
3402 unit_list_prepend(pdesttile->units, punit);
3403
3404 if (unit_transported(punit)) {
3405 /* Silently free orders since they won't be applicable anymore. */
3406 free_unit_orders(punit);
3407 }
3408
3409 /* Check unit activity. */
3410 check_unit_activity(punit);
3411 unit_did_action(punit);
3412 unit_forget_last_activity(punit);
3413
3414 /* We first unfog the destination, then send the move,
3415 * and then fog the old territory. This means that the player
3416 * gets a chance to see the newly explored territory while the
3417 * client moves the unit, and both areas are visible during the
3418 * move */
3419
3420 /* Enhance vision if unit steps into a fortress */
3421 new_vision = vision_new(powner, pdesttile);
3422 punit->server.vision = new_vision;
3423 vision_change_sight(new_vision, radius_sq);
3424 ASSERT_VISION(new_vision);
3425
3426 return pdata;
3427 }
3428
3429 /****************************************************************************
3430 Decrease the reference counter and destroy if needed.
3431 ****************************************************************************/
unit_move_data_unref(struct unit_move_data * pdata)3432 static void unit_move_data_unref(struct unit_move_data *pdata)
3433 {
3434 fc_assert_ret(pdata != NULL);
3435 fc_assert_ret(pdata->ref_count > 0);
3436 fc_assert_msg(pdata->old_vision == NULL,
3437 "Unit number %d (%p) has done an incomplete move.",
3438 pdata->punit != NULL ? pdata->punit->id : -1, pdata->punit);
3439
3440 pdata->ref_count--;
3441 if (pdata->ref_count == 0) {
3442 if (pdata->punit != NULL) {
3443 fc_assert(pdata->punit->server.moving == pdata);
3444 pdata->punit->server.moving = NULL;
3445 }
3446 free(pdata);
3447 }
3448 }
3449
3450 /*****************************************************************************
3451 Moves a unit. No checks whatsoever! This is meant as a practical
3452 function for other functions, like do_airline, which do the checking
3453 themselves.
3454
3455 If you move a unit you should always use this function, as it also sets
3456 the transport status of the unit correctly. Note that the source tile (the
3457 current tile of the unit) and pdesttile need not be adjacent.
3458
3459 Returns TRUE iff unit still alive.
3460 *****************************************************************************/
unit_move(struct unit * punit,struct tile * pdesttile,int move_cost,struct unit * embark_to)3461 bool unit_move(struct unit *punit, struct tile *pdesttile, int move_cost,
3462 struct unit *embark_to)
3463 {
3464 struct player *pplayer;
3465 struct tile *psrctile;
3466 struct city *pcity;
3467 struct unit *ptransporter;
3468 struct packet_unit_info src_info, dest_info;
3469 struct packet_unit_short_info src_sinfo, dest_sinfo;
3470 struct unit_move_data_list *plist =
3471 unit_move_data_list_new_full(unit_move_data_unref);
3472 struct unit_move_data *pdata;
3473 int saved_id;
3474 bool unit_lives;
3475 bool adj;
3476 enum direction8 facing;
3477 struct player *bowner;
3478
3479 /* Some checks. */
3480 fc_assert_ret_val(punit != NULL, FALSE);
3481 fc_assert_ret_val(pdesttile != NULL, FALSE);
3482
3483 pplayer = unit_owner(punit);
3484 saved_id = punit->id;
3485 psrctile = unit_tile(punit);
3486 adj = base_get_direction_for_step(psrctile, pdesttile, &facing);
3487
3488 conn_list_do_buffer(game.est_connections);
3489
3490 /* Unload the unit if on a transport. */
3491 ptransporter = unit_transport_get(punit);
3492 if (ptransporter != NULL) {
3493 /* Unload unit _before_ setting the new tile! */
3494 unit_transport_unload(punit);
3495 /* Send updated information to anyone watching that transporter
3496 * was unloading cargo. */
3497 send_unit_info(NULL, ptransporter);
3498 }
3499
3500 /* Wakup units next to us before we move. */
3501 wakeup_neighbor_sentries(punit);
3502
3503 /* Make info packets at 'psrctile'. */
3504 if (adj) {
3505 /* If tiles are adjacent, we will show the move to users able
3506 * to see it. */
3507 package_unit(punit, &src_info);
3508 package_short_unit(punit, &src_sinfo, UNIT_INFO_IDENTITY, 0);
3509 }
3510
3511 /* Make new data for 'punit'. */
3512 pdata = unit_move_data(punit, psrctile, pdesttile);
3513 unit_move_data_list_prepend(plist, pdata);
3514
3515 /* Set unit orientation */
3516 if (adj) {
3517 /* Only change orientation when moving to adjacent tile */
3518 punit->facing = facing;
3519 }
3520
3521 /* Move magic. */
3522 punit->moved = TRUE;
3523 punit->moves_left = MAX(0, punit->moves_left - move_cost);
3524 if (punit->moves_left == 0 && !unit_has_orders(punit)) {
3525 /* The next order may not require any remaining move fragments. */
3526 punit->done_moving = TRUE;
3527 }
3528
3529 /* No longer relevant. */
3530 punit->action_decision_tile = NULL;
3531 punit->action_decision_want = ACT_DEC_NOTHING;
3532
3533 if (!adj
3534 && action_tgt_city(punit, pdesttile)) {
3535 /* The unit can perform an action to the city at the destination tile.
3536 * A long distance move (like an airlift) doesn't ask what action to
3537 * perform before moving. Ask now. */
3538
3539 punit->action_decision_want = ACT_DEC_PASSIVE;
3540 punit->action_decision_tile = pdesttile;
3541 }
3542
3543 /* Claim ownership of fortress? */
3544 bowner = extra_owner(pdesttile);
3545 if ((bowner == NULL || pplayers_at_war(bowner, pplayer))
3546 && tile_has_claimable_base(pdesttile, unit_type_get(punit))) {
3547 /* Yes. We claim *all* bases if there's *any* claimable base(s).
3548 * Even if original unit cannot claim other kind of bases, the
3549 * first claimed base will have influence over other bases,
3550 * or something like that. */
3551 tile_claim_bases(pdesttile, pplayer);
3552 }
3553
3554 /* Move all contained units. */
3555 unit_cargo_iterate(punit, pcargo) {
3556 pdata = unit_move_data(pcargo, psrctile, pdesttile);
3557 unit_move_data_list_append(plist, pdata);
3558 } unit_cargo_iterate_end;
3559
3560 /* Get data for 'punit'. */
3561 pdata = unit_move_data_list_front(plist);
3562
3563 /* Determine the players able to see the move(s), now that the player
3564 * vision has been increased. */
3565 if (adj) {
3566 /* Main unit for adjacent move: the move is visible for every player
3567 * able to see on the matching unit layer. */
3568 enum vision_layer vlayer = is_hiding_unit(punit) ? V_INVIS : V_MAIN;
3569
3570 players_iterate(oplayer) {
3571 if (map_is_known_and_seen(psrctile, oplayer, vlayer)
3572 || map_is_known_and_seen(pdesttile, oplayer, vlayer)) {
3573 BV_SET(pdata->can_see_unit, player_index(oplayer));
3574 BV_SET(pdata->can_see_move, player_index(oplayer));
3575 }
3576 } players_iterate_end;
3577 }
3578 unit_move_data_list_iterate(plist, pmove_data) {
3579 if (adj && pmove_data == pdata) {
3580 /* If positions are adjacent, we have already handled 'punit'. See
3581 * above. */
3582 continue;
3583 }
3584
3585 players_iterate(oplayer) {
3586 if ((adj
3587 && can_player_see_unit_at(oplayer, pmove_data->punit, psrctile,
3588 pmove_data != pdata))
3589 || can_player_see_unit_at(oplayer, pmove_data->punit, pdesttile,
3590 pmove_data != pdata)) {
3591 BV_SET(pmove_data->can_see_unit, player_index(oplayer));
3592 BV_SET(pmove_data->can_see_move, player_index(oplayer));
3593 }
3594 if (can_player_see_unit_at(oplayer, pmove_data->punit, psrctile,
3595 pmove_data != pdata)) {
3596 /* The unit was seen with its source tile even if it was
3597 * teleported. */
3598 BV_SET(pmove_data->can_see_unit, player_index(oplayer));
3599 }
3600 } players_iterate_end;
3601 } unit_move_data_list_iterate_end;
3602
3603 /* Check timeout settings. */
3604 if (current_turn_timeout() != 0 && game.server.timeoutaddenemymove > 0) {
3605 bool new_information_for_enemy = FALSE;
3606
3607 phase_players_iterate(penemy) {
3608 /* Increase the timeout if an enemy unit moves and the
3609 * timeoutaddenemymove setting is in use. */
3610 if (penemy->is_connected
3611 && pplayer != penemy
3612 && pplayers_at_war(pplayer, penemy)
3613 && BV_ISSET(pdata->can_see_move, player_index(penemy))) {
3614 new_information_for_enemy = TRUE;
3615 break;
3616 }
3617 } phase_players_iterate_end;
3618
3619 if (new_information_for_enemy) {
3620 increase_timeout_because_unit_moved();
3621 }
3622 }
3623
3624 /* Notifications of the move to the clients. */
3625 if (adj) {
3626 /* Special case: 'punit' is moving to adjacent position. Then we show
3627 * 'punit' move to all users able to see 'psrctile' or 'pdesttile'. */
3628
3629 /* Make info packets at 'pdesttile'. */
3630 package_unit(punit, &dest_info);
3631 package_short_unit(punit, &dest_sinfo, UNIT_INFO_IDENTITY, 0);
3632
3633 conn_list_iterate(game.est_connections, pconn) {
3634 struct player *aplayer = conn_get_player(pconn);
3635
3636 if (aplayer == NULL) {
3637 if (pconn->observer) {
3638 /* Global observers see all... */
3639 send_packet_unit_info(pconn, &src_info);
3640 send_packet_unit_info(pconn, &dest_info);
3641 }
3642 } else if (BV_ISSET(pdata->can_see_move, player_index(aplayer))) {
3643 if (aplayer == pplayer) {
3644 send_packet_unit_info(pconn, &src_info);
3645 send_packet_unit_info(pconn, &dest_info);
3646 } else {
3647 send_packet_unit_short_info(pconn, &src_sinfo, FALSE);
3648 send_packet_unit_short_info(pconn, &dest_sinfo, FALSE);
3649 }
3650 }
3651 } conn_list_iterate_end;
3652 }
3653
3654 /* Other moves. */
3655 unit_move_data_list_iterate(plist, pmove_data) {
3656 if (adj && pmove_data == pdata) {
3657 /* If positions are adjacent, we have already shown 'punit' move.
3658 * See above. */
3659 continue;
3660 }
3661
3662 /* Make info packets at 'pdesttile'. */
3663 package_unit(pmove_data->punit, &dest_info);
3664 package_short_unit(pmove_data->punit, &dest_sinfo,
3665 UNIT_INFO_IDENTITY, 0);
3666
3667 conn_list_iterate(game.est_connections, pconn) {
3668 struct player *aplayer = conn_get_player(pconn);
3669
3670 if (aplayer == NULL) {
3671 if (pconn->observer) {
3672 /* Global observers see all... */
3673 send_packet_unit_info(pconn, &dest_info);
3674 }
3675 } else if (BV_ISSET(pmove_data->can_see_move, player_index(aplayer))) {
3676 if (aplayer == pmove_data->powner) {
3677 send_packet_unit_info(pconn, &dest_info);
3678 } else {
3679 send_packet_unit_short_info(pconn, &dest_sinfo, FALSE);
3680 }
3681 }
3682 } conn_list_iterate_end;
3683 } unit_move_data_list_iterate_end;
3684
3685 /* Clear old vision. */
3686 unit_move_data_list_iterate(plist, pmove_data) {
3687 vision_clear_sight(pmove_data->old_vision);
3688 vision_free(pmove_data->old_vision);
3689 pmove_data->old_vision = NULL;
3690 } unit_move_data_list_iterate_end;
3691
3692 /* Move consequences. */
3693 unit_move_data_list_iterate(plist, pmove_data) {
3694 struct unit *aunit = pmove_data->punit;
3695
3696 if (aunit != NULL
3697 && unit_owner(aunit) == pmove_data->powner
3698 && unit_tile(aunit) == pdesttile) {
3699 (void) unit_move_consequences(aunit, psrctile, pdesttile,
3700 pdata != pmove_data);
3701 }
3702 } unit_move_data_list_iterate_end;
3703
3704 unit_lives = (pdata->punit == punit);
3705
3706 /* Wakeup units and make contact. */
3707 if (unit_lives) {
3708 wakeup_neighbor_sentries(punit);
3709 }
3710 maybe_make_contact(pdesttile, pplayer);
3711
3712 if (unit_lives) {
3713 /* Special checks for ground units in the ocean. */
3714 if (embark_to || !can_unit_survive_at_tile(punit, pdesttile)) {
3715 if (embark_to != NULL) {
3716 ptransporter = embark_to;
3717 } else {
3718 ptransporter = transporter_for_unit(punit);
3719 }
3720 if (ptransporter) {
3721 unit_transport_load_tp_status(punit, ptransporter, FALSE);
3722
3723 /* Set activity to sentry if boarding a ship. */
3724 if (!pplayer->ai_controlled
3725 && !unit_has_orders(punit)
3726 && !punit->ai_controlled
3727 && !can_unit_exist_at_tile(punit, pdesttile)) {
3728 set_unit_activity(punit, ACTIVITY_SENTRY);
3729 }
3730
3731 send_unit_info(NULL, punit);
3732 }
3733 }
3734 }
3735
3736 /* Remove units going out of sight. */
3737 unit_move_data_list_iterate_rev(plist, pmove_data) {
3738 struct unit *aunit = pmove_data->punit;
3739
3740 if (aunit == NULL) {
3741 continue; /* Died! */
3742 }
3743
3744 players_iterate(aplayer) {
3745 if (BV_ISSET(pmove_data->can_see_unit, player_index(aplayer))
3746 && !can_player_see_unit(aplayer, aunit)) {
3747 unit_goes_out_of_sight(aplayer, aunit);
3748 }
3749 } players_iterate_end;
3750 } unit_move_data_list_iterate_rev_end;
3751
3752 /* Inform the owner's client about actor unit arrival. Can, depending on
3753 * the client settings, cause the client to start the process that makes
3754 * the action selection dialog pop up. */
3755 if ((pcity = tile_city(pdesttile))) {
3756 /* Arrival in a city counts. */
3757
3758 unit_move_data_list_iterate(plist, pmove_data) {
3759 struct unit *ptrans;
3760 bool ok;
3761 struct unit *act_unit;
3762 struct player *act_player;
3763
3764 act_unit = pmove_data->punit;
3765 act_player = unit_owner(act_unit);
3766
3767 if (act_unit == NULL
3768 || !unit_is_alive(act_unit->id)) {
3769 /* The unit died before reaching this point. */
3770 continue;
3771 }
3772
3773 if (unit_tile(act_unit) != pdesttile) {
3774 /* The unit didn't arrive at the destination tile. */
3775 continue;
3776 }
3777
3778 if (act_player->ai_controlled) {
3779 /* The AI doesn't need reminders. */
3780 continue;
3781 }
3782
3783 if (!unit_transported(act_unit)) {
3784 /* Don't show the action selection dialog again. Non transported
3785 * units are handled before they move to the tile. */
3786 continue;
3787 }
3788
3789 /* Open action dialog only if 'act_unit' and all its transporters
3790 * (recursively) don't have orders. */
3791 if (unit_has_orders(act_unit)) {
3792 /* The unit it self has orders. */
3793 continue;
3794 }
3795
3796 for (ptrans = unit_transport_get(act_unit);;
3797 ptrans = unit_transport_get(ptrans)) {
3798 if (NULL == ptrans) {
3799 /* No (recursive) transport has orders. */
3800 ok = TRUE;
3801 break;
3802 } else if (unit_has_orders(ptrans)) {
3803 /* A unit transporting the unit has orders */
3804 ok = FALSE;
3805 break;
3806 }
3807 }
3808
3809 if (!ok) {
3810 /* A unit transporting act_unit has orders. */
3811 continue;
3812 }
3813
3814 if (action_tgt_city(act_unit, pdesttile)) {
3815 /* There is a valid target. */
3816
3817 act_unit->action_decision_want = ACT_DEC_PASSIVE;
3818 act_unit->action_decision_tile = pdesttile;
3819
3820 /* Let the client know that this unit wants the player to decide
3821 * what to do. */
3822 send_unit_info(player_reply_dest(act_player), act_unit);
3823 }
3824 } unit_move_data_list_iterate_end;
3825 }
3826
3827 unit_move_data_list_destroy(plist);
3828
3829 /* Check cities at source and destination. */
3830 if ((pcity = tile_city(psrctile))) {
3831 refresh_dumb_city(pcity);
3832 }
3833 if ((pcity = tile_city(pdesttile))) {
3834 refresh_dumb_city(pcity);
3835 }
3836
3837 if (unit_lives) {
3838 /* Let the scripts run ... */
3839 script_server_signal_emit("unit_moved", 3,
3840 API_TYPE_UNIT, punit,
3841 API_TYPE_TILE, psrctile,
3842 API_TYPE_TILE, pdesttile);
3843 unit_lives = unit_is_alive(saved_id);
3844 }
3845
3846 if (unit_lives) {
3847 /* Autoattack. */
3848 unit_lives = unit_survive_autoattack(punit);
3849 }
3850
3851 if (unit_lives) {
3852 /* Entering huts */
3853 unit_lives = unit_enter_hut(punit);
3854 }
3855
3856 conn_list_do_unbuffer(game.est_connections);
3857
3858 return unit_lives;
3859 }
3860
3861 /**************************************************************************
3862 Maybe cancel the goto if there is an enemy in the way
3863 **************************************************************************/
maybe_cancel_goto_due_to_enemy(struct unit * punit,struct tile * ptile)3864 static bool maybe_cancel_goto_due_to_enemy(struct unit *punit,
3865 struct tile *ptile)
3866 {
3867 return (is_non_allied_unit_tile(ptile, unit_owner(punit))
3868 || is_non_allied_city_tile(ptile, unit_owner(punit)));
3869 }
3870
3871 /**************************************************************************
3872 Maybe cancel the patrol as there is an enemy near.
3873
3874 If you modify the wakeup range you should change it in
3875 wakeup_neighbor_sentries() too.
3876 **************************************************************************/
maybe_cancel_patrol_due_to_enemy(struct unit * punit)3877 static bool maybe_cancel_patrol_due_to_enemy(struct unit *punit)
3878 {
3879 bool cancel = FALSE;
3880 int radius_sq = get_unit_vision_at(punit, unit_tile(punit), V_MAIN);
3881 struct player *pplayer = unit_owner(punit);
3882
3883 circle_iterate(unit_tile(punit), radius_sq, ptile) {
3884 struct unit *penemy = is_non_allied_unit_tile(ptile, pplayer);
3885
3886 struct vision_site *pdcity = map_get_player_site(ptile, pplayer);
3887
3888 if ((penemy && can_player_see_unit(pplayer, penemy))
3889 || (pdcity && !pplayers_allied(pplayer, vision_site_owner(pdcity))
3890 && pdcity->occupied)) {
3891 cancel = TRUE;
3892 break;
3893 }
3894 } circle_iterate_end;
3895
3896 return cancel;
3897 }
3898
3899 /**************************************************************************
3900 Returns the action id corresponding to the specified order id.
3901 **************************************************************************/
order_to_action(struct unit * punit,enum unit_orders order)3902 static int order_to_action(struct unit *punit, enum unit_orders order)
3903 {
3904 switch (order) {
3905 case ORDER_BUILD_WONDER:
3906 return ACTION_HELP_WONDER;
3907 case ORDER_TRADE_ROUTE:
3908 return ACTION_TRADE_ROUTE;
3909 case ORDER_MOVE:
3910 case ORDER_ACTION_MOVE:
3911 case ORDER_FULL_MP:
3912 case ORDER_BUILD_CITY:
3913 case ORDER_ACTIVITY:
3914 case ORDER_DISBAND:
3915 case ORDER_HOMECITY:
3916 case ORDER_LAST:
3917 /* Not action enabler controlled. */
3918 break;
3919 }
3920
3921 fc_assert_msg(FALSE, "No action to map order to.");
3922 return ACTION_COUNT;
3923 }
3924
3925 /**************************************************************************
3926 Returns TRUE iff it is reasonable to assume that the player is wathing
3927 the unit.
3928
3929 Since the player is watching the unit there is no need to inform him
3930 about things he could see happening. Remember that it still may
3931 be necessary to explain why something happened.
3932 **************************************************************************/
player_is_watching(struct unit * punit,const bool fresh)3933 static inline bool player_is_watching(struct unit *punit, const bool fresh)
3934 {
3935 /* The player just sent the orders to the unit. The unit has moves left.
3936 * It is therefore safe to assume that the player already is paying
3937 * attention to the unit. */
3938 return fresh && punit->moves_left > 0;
3939 }
3940
3941 /****************************************************************************
3942 Executes a unit's orders stored in punit->orders. The unit is put on idle
3943 if an action fails or if "patrol" is set and an enemy unit is encountered.
3944
3945 The return value will be TRUE if the unit lives, FALSE otherwise. (This
3946 function used to return a goto_result enumeration, declared in gotohand.h.
3947 But this enumeration was never checked by the caller and just lead to
3948 confusion. All the caller really needs to know is if the unit lived or
3949 died; everything else is handled internally within execute_orders.)
3950
3951 If the orders are repeating the loop starts over at the beginning once it
3952 completes. To avoid infinite loops on railroad we stop for this
3953 turn when the unit is back where it started, even if it have moves left.
3954
3955 A unit will attack under orders only on its final action.
3956
3957 The fresh parameter is true if the order execution happens because the
3958 orders just were received.
3959 ****************************************************************************/
execute_orders(struct unit * punit,const bool fresh)3960 bool execute_orders(struct unit *punit, const bool fresh)
3961 {
3962 struct tile *dst_tile;
3963 bool res, last_order;
3964 int unitid = punit->id;
3965 struct player *pplayer = unit_owner(punit);
3966 int moves_made = 0;
3967 enum unit_activity activity;
3968
3969 fc_assert_ret_val(unit_has_orders(punit), TRUE);
3970
3971 if (punit->activity != ACTIVITY_IDLE) {
3972 /* Unit's in the middle of an activity; wait for it to finish. */
3973 punit->done_moving = TRUE;
3974 return TRUE;
3975 }
3976
3977 log_debug("Executing orders for %s %d", unit_rule_name(punit), punit->id);
3978
3979 /* Any time the orders are canceled we should give the player a message. */
3980
3981 while (TRUE) {
3982 struct unit_order order;
3983
3984 if (punit->done_moving) {
3985 log_debug(" stopping because we're done this turn");
3986 return TRUE;
3987 }
3988
3989 if (punit->orders.vigilant && maybe_cancel_patrol_due_to_enemy(punit)) {
3990 /* "Patrol" orders are stopped if an enemy is near. */
3991 cancel_orders(punit, " stopping because of nearby enemy");
3992 notify_player(pplayer, unit_tile(punit), E_UNIT_ORDERS, ftc_server,
3993 _("Orders for %s aborted as there are units nearby."),
3994 unit_link(punit));
3995 return TRUE;
3996 }
3997
3998 if (moves_made == punit->orders.length) {
3999 /* For repeating orders, don't repeat more than once per turn. */
4000 log_debug(" stopping because we ran a round");
4001 punit->done_moving = TRUE;
4002 send_unit_info(NULL, punit);
4003 return TRUE;
4004 }
4005 moves_made++;
4006
4007 order = punit->orders.list[punit->orders.index];
4008
4009 switch (order.order) {
4010 case ORDER_MOVE:
4011 case ORDER_ACTION_MOVE:
4012 case ORDER_FULL_MP:
4013 case ORDER_BUILD_CITY:
4014 if (0 == punit->moves_left) {
4015 log_debug(" stopping because of no more move points");
4016 return TRUE;
4017 }
4018 break;
4019 case ORDER_BUILD_WONDER:
4020 case ORDER_TRADE_ROUTE:
4021 if (action_mp_full_makes_legal(punit, order_to_action(punit, order.order))) {
4022 log_debug(" stopping. Not enough move points this turn");
4023 return TRUE;
4024 }
4025 break;
4026 case ORDER_ACTIVITY:
4027 case ORDER_DISBAND:
4028 case ORDER_HOMECITY:
4029 case ORDER_LAST:
4030 /* Those actions don't require moves left. */
4031 break;
4032 }
4033
4034 last_order = (!punit->orders.repeat
4035 && punit->orders.index + 1 == punit->orders.length);
4036
4037 if (last_order) {
4038 /* Clear the orders before we engage in the move. That way any
4039 * has_orders checks will yield FALSE and this will be treated as
4040 * a normal move. This is important: for instance a caravan goto
4041 * will popup the caravan dialog on the last move only. */
4042 free_unit_orders(punit);
4043 }
4044
4045 /* Advance the orders one step forward. This is needed because any
4046 * updates sent to the client as a result of the action should include
4047 * the new index value. Note that we have to send_unit_info somewhere
4048 * after this point so that the client is properly updated. */
4049 punit->orders.index++;
4050
4051 switch (order.order) {
4052 case ORDER_FULL_MP:
4053 if (punit->moves_left < unit_move_rate(punit)) {
4054 /* If the unit doesn't have full MP then it just waits until the
4055 * next turn. We assume that the next turn it will have full MP
4056 * (there's no check for that). */
4057 punit->done_moving = TRUE;
4058 log_debug(" waiting this turn");
4059 send_unit_info(NULL, punit);
4060 }
4061 break;
4062 case ORDER_BUILD_CITY:
4063 unit_build_city(pplayer, punit,
4064 city_name_suggestion(pplayer, unit_tile(punit)));
4065 log_debug(" building city");
4066 if (player_unit_by_number(pplayer, unitid)) {
4067 /* Build failed. */
4068 cancel_orders(punit, " orders canceled; failed to build city");
4069 notify_player(pplayer, unit_tile(punit), E_UNIT_ORDERS, ftc_server,
4070 _("Orders for %s aborted because building "
4071 "of city failed."),
4072 unit_link(punit));
4073 return TRUE;
4074 } else {
4075 /* Build succeeded => unit "died" */
4076 return FALSE;
4077 }
4078 case ORDER_ACTIVITY:
4079 activity = order.activity;
4080 {
4081 struct extra_type *pextra = (order.target == EXTRA_NONE ?
4082 NULL :
4083 extra_by_number(order.target));
4084
4085 if (pextra == NULL && activity_requires_target(order.activity)) {
4086 /* Try to find a target extra before giving up this order or, if
4087 * serious enough, all orders. */
4088
4089 enum unit_activity new_activity = order.activity;
4090
4091 unit_assign_specific_activity_target(punit,
4092 &new_activity, &pextra);
4093
4094 if (new_activity != order.activity) {
4095 /* At the time this code was written the only possible activity
4096 * change from unit_assign_specific_activity_target() was from
4097 * ACTIVITY_PILLAGE to ACTIVITY_IDLE. That would only happen
4098 * when a target extra couldn't be found. -- Sveinung */
4099 fc_assert_msg((order.activity == ACTIVITY_PILLAGE
4100 && new_activity == ACTIVITY_IDLE),
4101 "Skipping an order when canceling all orders may"
4102 " have been the correct thing to do.");
4103
4104 /* Already removed, let's continue. */
4105 break;
4106 }
4107
4108 /* Should have given up or, if supported, changed the order's
4109 * activity to the activity suggested by
4110 * unit_activity_handling_targeted() before this line was
4111 * reached.
4112 * Remember that unit_activity_handling_targeted() has the power
4113 * to change the order's target extra directly. */
4114 fc_assert_msg(new_activity == order.activity,
4115 "Activity not updated. Target may have changed.");
4116
4117 /* Should have found a target or given up before reaching this
4118 * line. */
4119 fc_assert_msg((pextra != NULL
4120 || !activity_requires_target(order.activity)),
4121 "Activity requires a target. No target found.");
4122 }
4123
4124 if (can_unit_do_activity_targeted(punit, activity, pextra)) {
4125 punit->done_moving = TRUE;
4126 set_unit_activity_targeted(punit, activity, pextra);
4127 send_unit_info(NULL, punit);
4128 break;
4129 } else {
4130 if ((activity == ACTIVITY_BASE
4131 || activity == ACTIVITY_GEN_ROAD
4132 || activity == ACTIVITY_IRRIGATE
4133 || activity == ACTIVITY_MINE)
4134 && tile_has_extra(unit_tile(punit), pextra)) {
4135 break; /* Already built, let's continue. */
4136 } else if ((activity == ACTIVITY_POLLUTION
4137 || activity == ACTIVITY_FALLOUT
4138 || activity == ACTIVITY_PILLAGE)
4139 && !tile_has_extra(unit_tile(punit), pextra)) {
4140 break; /* Already removed, let's continue. */
4141 }
4142 }
4143 }
4144
4145 cancel_orders(punit, " orders canceled because of failed activity");
4146 notify_player(pplayer, unit_tile(punit), E_UNIT_ORDERS, ftc_server,
4147 _("Orders for %s aborted since they "
4148 "give an invalid activity."),
4149 unit_link(punit));
4150 return TRUE;
4151 case ORDER_MOVE:
4152 case ORDER_ACTION_MOVE:
4153 /* Move unit */
4154 if (!(dst_tile = mapstep(unit_tile(punit), order.dir))) {
4155 cancel_orders(punit, " move order sent us to invalid location");
4156 notify_player(pplayer, unit_tile(punit), E_UNIT_ORDERS, ftc_server,
4157 _("Orders for %s aborted since they "
4158 "give an invalid location."),
4159 unit_link(punit));
4160 return TRUE;
4161 }
4162
4163 if (order.order != ORDER_ACTION_MOVE
4164 && maybe_cancel_goto_due_to_enemy(punit, dst_tile)) {
4165 /* Plain move required: no attack, trade route etc. */
4166 cancel_orders(punit, " orders canceled because of enemy");
4167 notify_player(pplayer, unit_tile(punit), E_UNIT_ORDERS, ftc_server,
4168 _("Orders for %s aborted as there "
4169 "are units in the way."),
4170 unit_link(punit));
4171 return TRUE;
4172 }
4173
4174 log_debug(" moving to %d,%d", TILE_XY(dst_tile));
4175 res = unit_move_handling(punit, dst_tile, FALSE,
4176 order.order != ORDER_ACTION_MOVE, NULL);
4177 if (!player_unit_by_number(pplayer, unitid)) {
4178 log_debug(" unit died while moving.");
4179 /* A player notification should already have been sent. */
4180 return FALSE;
4181 }
4182
4183 if (res && !same_pos(dst_tile, unit_tile(punit))) {
4184 /* Movement succeeded but unit didn't move. */
4185 log_debug(" orders resulted in combat.");
4186 send_unit_info(NULL, punit);
4187 return TRUE;
4188 }
4189
4190 if (!res) {
4191 fc_assert(0 <= punit->moves_left);
4192
4193 /* Movement failed (ZOC, etc.) */
4194 cancel_orders(punit, " attempt to move failed.");
4195
4196 if (!player_is_watching(punit, fresh)
4197 /* The final move "failed" because the unit needs to ask the
4198 * player what action it should take.
4199 *
4200 * The action decision request notifies the player. Its
4201 * location at the unit's last order makes it clear to the
4202 * player who the decision is for. ("The Spy I sent to Berlin
4203 * has arrived.")
4204 *
4205 * A notification message is therefore redundant. */
4206 && !(last_order
4207 && punit->action_decision_want == ACT_DEC_ACTIVE
4208 && punit->action_decision_tile == dst_tile)) {
4209 /* The player may have missed this. No one else will announce it
4210 * in a satisfying manner. Inform the player. */
4211 notify_player(pplayer, unit_tile(punit),
4212 E_UNIT_ORDERS, ftc_server,
4213 _("Orders for %s aborted because of failed move."),
4214 unit_link(punit));
4215 }
4216
4217 return TRUE;
4218 }
4219 break;
4220 case ORDER_DISBAND:
4221 log_debug(" orders: disbanding");
4222 handle_unit_disband(pplayer, unitid);
4223 return FALSE;
4224 case ORDER_HOMECITY:
4225 log_debug(" orders: changing homecity");
4226 if (tile_city(unit_tile(punit))) {
4227 handle_unit_change_homecity(pplayer, unitid,
4228 tile_city(unit_tile(punit))->id);
4229 } else {
4230 cancel_orders(punit, " no homecity");
4231 notify_player(pplayer, unit_tile(punit), E_UNIT_ORDERS, ftc_server,
4232 _("Attempt to change homecity for %s failed."),
4233 unit_link(punit));
4234 return TRUE;
4235 }
4236 break;
4237 case ORDER_TRADE_ROUTE:
4238 log_debug(" orders: establishing trade route.");
4239 dst_tile = unit_tile(punit);
4240
4241 fc_assert_ret_val_msg(dst_tile, FALSE, "No tile for ordered unit");
4242
4243 if (tile_city(dst_tile) == NULL) {
4244 cancel_orders(punit, " trade route order with no city");
4245 notify_player(pplayer, unit_tile(punit), E_UNIT_ORDERS, ftc_server,
4246 _("Orders for %s aborted since they "
4247 "give a location without a city."),
4248 unit_link(punit));
4249 return TRUE;
4250 }
4251
4252 handle_unit_do_action(pplayer,
4253 unitid, tile_city(dst_tile)->id,
4254 0, ACTION_TRADE_ROUTE);
4255 if (player_unit_by_number(pplayer, unitid)) {
4256 cancel_orders(punit, " no trade route city");
4257 notify_player(pplayer, unit_tile(punit), E_UNIT_ORDERS, ftc_server,
4258 _("Attempt to establish trade route for %s failed."),
4259 unit_link(punit));
4260 return TRUE;
4261 } else {
4262 return FALSE;
4263 }
4264 case ORDER_BUILD_WONDER:
4265 log_debug(" orders: building wonder");
4266 dst_tile = unit_tile(punit);
4267
4268 fc_assert_ret_val_msg(dst_tile, FALSE, "No tile for ordered unit");
4269
4270 if (tile_city(dst_tile) == NULL) {
4271 cancel_orders(punit, " build wonder order with no city");
4272 notify_player(pplayer, unit_tile(punit), E_UNIT_ORDERS, ftc_server,
4273 _("Orders for %s aborted since they "
4274 "give a location without a city."),
4275 unit_link(punit));
4276 return TRUE;
4277 }
4278
4279 handle_unit_do_action(pplayer,
4280 unitid,
4281 tile_city(dst_tile)->id,
4282 0, ACTION_HELP_WONDER);
4283 if (player_unit_by_number(pplayer, unitid)) {
4284 cancel_orders(punit, " no wonder city");
4285 notify_player(pplayer, unit_tile(punit), E_UNIT_ORDERS, ftc_server,
4286 _("Attempt to build wonder for %s failed."),
4287 unit_link(punit));
4288 return TRUE;
4289 } else {
4290 return FALSE;
4291 }
4292 case ORDER_LAST:
4293 cancel_orders(punit, " client sent invalid order!");
4294 notify_player(pplayer, unit_tile(punit), E_UNIT_ORDERS, ftc_server,
4295 _("Your %s has invalid orders."),
4296 unit_link(punit));
4297 return TRUE;
4298 }
4299
4300 if (last_order) {
4301 fc_assert(punit->has_orders == FALSE);
4302 log_debug(" stopping because orders are complete");
4303 return TRUE;
4304 }
4305
4306 if (punit->orders.index == punit->orders.length) {
4307 fc_assert(punit->orders.repeat);
4308 /* Start over. */
4309 log_debug(" repeating orders.");
4310 punit->orders.index = 0;
4311 }
4312 } /* end while */
4313 }
4314
4315 /****************************************************************************
4316 Return the vision the unit will have at the given tile. The base vision
4317 range may be modified by effects.
4318
4319 Note that vision MUST be independent of transported_by for this to work
4320 properly.
4321 ****************************************************************************/
get_unit_vision_at(struct unit * punit,struct tile * ptile,enum vision_layer vlayer)4322 int get_unit_vision_at(struct unit *punit, struct tile *ptile,
4323 enum vision_layer vlayer)
4324 {
4325 const int base = (unit_type_get(punit)->vision_radius_sq
4326 + get_unittype_bonus(unit_owner(punit), ptile,
4327 unit_type_get(punit),
4328 EFT_UNIT_VISION_RADIUS_SQ));
4329 switch (vlayer) {
4330 case V_MAIN:
4331 return MAX(0, base);
4332 case V_INVIS:
4333 return CLIP(0, base, 2);
4334 case V_COUNT:
4335 break;
4336 }
4337
4338 log_error("Unsupported vision layer variant: %d.", vlayer);
4339 return 0;
4340 }
4341
4342 /****************************************************************************
4343 Refresh the unit's vision.
4344
4345 This function has very small overhead and can be called any time effects
4346 may have changed the vision range of the city.
4347 ****************************************************************************/
unit_refresh_vision(struct unit * punit)4348 void unit_refresh_vision(struct unit *punit)
4349 {
4350 struct vision *uvision = punit->server.vision;
4351 const v_radius_t radius_sq =
4352 V_RADIUS(get_unit_vision_at(punit, unit_tile(punit), V_MAIN),
4353 get_unit_vision_at(punit, unit_tile(punit), V_INVIS));
4354
4355 vision_change_sight(uvision, radius_sq);
4356 ASSERT_VISION(uvision);
4357 }
4358
4359 /****************************************************************************
4360 Refresh the vision of all units in the list - see unit_refresh_vision.
4361 ****************************************************************************/
unit_list_refresh_vision(struct unit_list * punitlist)4362 void unit_list_refresh_vision(struct unit_list *punitlist)
4363 {
4364 unit_list_iterate(punitlist, punit) {
4365 unit_refresh_vision(punit);
4366 } unit_list_iterate_end;
4367 }
4368
4369 /****************************************************************************
4370 Used to implement the game rule controlled by the unitwaittime setting.
4371 Notifies the unit owner if the unit is unable to act.
4372 ****************************************************************************/
unit_can_do_action_now(const struct unit * punit)4373 bool unit_can_do_action_now(const struct unit *punit)
4374 {
4375 time_t dt;
4376
4377 if (!punit) {
4378 return FALSE;
4379 }
4380
4381 if (game.server.unitwaittime <= 0) {
4382 return TRUE;
4383 }
4384
4385 if (punit->server.action_turn != game.info.turn - 1) {
4386 return TRUE;
4387 }
4388
4389 dt = time(NULL) - punit->server.action_timestamp;
4390 if (dt < game.server.unitwaittime) {
4391 char buf[64];
4392 format_time_duration(game.server.unitwaittime - dt, buf, sizeof(buf));
4393 notify_player(unit_owner(punit), unit_tile(punit), E_BAD_COMMAND,
4394 ftc_server, _("Your unit may not act for another %s "
4395 "this turn. See /help unitwaittime."), buf);
4396 return FALSE;
4397 }
4398
4399 return TRUE;
4400 }
4401
4402 /****************************************************************************
4403 Mark a unit as having done something at the current time. This is used
4404 in conjunction with unit_can_do_action_now() and the unitwaittime setting.
4405 ****************************************************************************/
unit_did_action(struct unit * punit)4406 void unit_did_action(struct unit *punit)
4407 {
4408 if (!punit) {
4409 return;
4410 }
4411
4412 punit->server.action_timestamp = time(NULL);
4413 punit->server.action_turn = game.info.turn;
4414 }
4415
4416 /**************************************************************************
4417 Units (usually barbarian units) may disband spontaneously if they are
4418 far from any enemy units or cities. It is to remove barbarians that do
4419 not engage into any activity for a long time.
4420 **************************************************************************/
unit_can_be_retired(struct unit * punit)4421 bool unit_can_be_retired(struct unit *punit)
4422 {
4423 /* check if there is enemy nearby */
4424 square_iterate(unit_tile(punit), 3, ptile) {
4425 if (is_enemy_city_tile(ptile, unit_owner(punit))
4426 || is_enemy_unit_tile(ptile, unit_owner(punit))) {
4427 return FALSE;
4428 }
4429 }
4430 square_iterate_end;
4431
4432 return TRUE;
4433 }
4434