Freeciv21
Develop your civilization from humble roots to a global empire
aiferry.cpp
Go to the documentation of this file.
1 /*
2  Copyright (c) 1996-2020 Freeciv21 and Freeciv contributors. This file is
3  __ __ part of Freeciv21. Freeciv21 is free software: you can
4 / \\..// \ redistribute it and/or modify it under the terms of the GNU
5  ( oo ) General Public License as published by the Free Software
6  \__/ Foundation, either version 3 of the License, or (at your
7  option) any later version. You should have received
8  a copy of the GNU General Public License along with Freeciv21. If not,
9  see https://www.gnu.org/licenses/.
10  */
11 
12 // utility
13 #include "log.h"
14 
15 // common
16 #include "game.h"
17 #include "movement.h"
18 #include "unit.h"
19 #include "unitlist.h"
20 
21 // aicore
22 #include "path_finding.h"
23 #include "pf_tools.h"
24 
25 /* server/advisors */
26 #include "advgoto.h"
27 #include "autoexplorer.h"
28 
29 // server
30 #include "hand_gen.h"
31 #include "srv_log.h"
32 #include "unithand.h"
33 #include "unittools.h"
34 
35 /* server/advisors */
36 #include "advdata.h"
37 
38 // ai
39 #include "handicaps.h"
40 
41 /* ai/default */
42 #include "aidata.h"
43 #include "aiguard.h"
44 #include "ailog.h"
45 #include "aiplayer.h"
46 #include "aitools.h"
47 #include "aiunit.h"
48 
49 #include "aiferry.h"
50 
51 // =================== constants with special meaning ===================
52 
53 /*
54  * This one is used only by ferryboats in ai.passenger field
55  */
56 #define FERRY_AVAILABLE (-1) // Boat is looking for a passenger
57 #define FERRY_ABANDON_BOSS \
58  (-2) /* Passenger is assigned for boat, but boat \
59  * might take another passenger. Probably \
60  * passenger already left the boat*/
61 
62 /*
63  * The below is used only by passengers in ai.ferryboat field
64  */
65 #define FERRY_WANTED (-1) // Needs a boat
66 #define FERRY_NONE 0 // Has no boat and doesn't need one
67 
68 // =================== group log levels, debug options =================
69 
70 // Logging in ferry management functions
71 #define LOGLEVEL_FERRY LOG_DEBUG
72 // Logging in go_by_boat functions
73 #define LOGLEVEL_GOBYBOAT LOG_DEBUG
74 // Logging in find_ferry functions
75 #define LOGLEVEL_FINDFERRY LOG_DEBUG
76 // Extra consistency checks
77 #ifdef FREECIV_DEBUG
78 #define LOGLEVEL_FERRY_STATS LOG_NORMAL
79 #endif
80 
81 /* ========= managing statistics and boat/passanger assignments ======== */
82 
86 void aiferry_init_stats(struct ai_type *ait, struct player *pplayer)
87 {
88  /* def_ai_player_data() instead of dai_plr_data_get() is deliberate.
89  We are only initializing player data structures and dai_plr_data_get()
90  would try to use it uninitialized. We are only setting values to
91  data structure, not reading them, so we have no need for extra
92  arrangements dai_plr_data_get() would do compared to
93  def_ai_player_data()
94  */
95  struct ai_plr *ai = def_ai_player_data(pplayer, ait);
96 
97  ai->stats.passengers = 0;
98  ai->stats.boats = 0;
99  ai->stats.available_boats = 0;
100 
101  unit_list_iterate(pplayer->units, punit)
102  {
103  struct unit_ai *unit_data = def_ai_unit_data(punit, ait);
104 
105  if (dai_is_ferry(punit, ait)) {
106  ai->stats.boats++;
107  if (unit_data->passenger == FERRY_AVAILABLE) {
108  ai->stats.available_boats++;
109  }
110  }
111  if (unit_data->ferryboat == FERRY_WANTED) {
112  UNIT_LOG(LOG_DEBUG, punit, "wants a boat.");
113  ai->stats.passengers++;
114  }
115  }
117 }
118 
122 #ifdef LOGLEVEL_FERRY_STATS
123 static void aiferry_print_stats(struct ai_type *ait, struct player *pplayer)
124 {
125  struct ai_plr *ai = dai_plr_data_get(ait, pplayer, nullptr);
126  int n = 1;
127 
128  log_base(LOGLEVEL_FERRY_STATS, "Boat stats for %s[%d]",
129  player_name(pplayer), player_number(pplayer));
130  log_base(LOGLEVEL_FERRY_STATS, "Registered: %d free out of total %d",
131  ai->stats.available_boats, ai->stats.boats);
132  unit_list_iterate(pplayer->units, punit)
133  {
134  if (dai_is_ferry(punit, ait)) {
135  log_base(LOGLEVEL_FERRY_STATS, "#%d. %s[%d], psngr=%d", n,
136  unit_rule_name(punit), punit->id,
137  def_ai_unit_data(punit, ait)->passenger);
138  n++;
139  }
140  }
142 }
143 #endif // LOGLEVEL_FERRY_STATS
144 
148 bool dai_is_ferry_type(const struct unit_type *pferry, struct ai_type *ait)
149 {
150  struct unit_type_ai *utai =
151  static_cast<unit_type_ai *>(utype_ai_data(pferry, ait));
152 
153  return utai->ferry;
154 }
155 
159 bool dai_is_ferry(struct unit *pferry, struct ai_type *ait)
160 {
161  return dai_is_ferry_type(unit_type_get(pferry), ait);
162 }
163 
167 void dai_ferry_init_ferry(struct ai_type *ait, struct unit *ferry)
168 {
169  if (dai_is_ferry(ferry, ait)) {
170  bool caller_closes;
171  struct player *pplayer = unit_owner(ferry);
172  struct unit_ai *unit_data = def_ai_unit_data(ferry, ait);
173  struct ai_plr *ai = dai_plr_data_get(ait, pplayer, &caller_closes);
174 
175  unit_data->passenger = FERRY_AVAILABLE;
176  ai->stats.boats++;
177  ai->stats.available_boats++;
178 
179  if (caller_closes) {
180  dai_data_phase_finished(ait, pplayer);
181  }
182  }
183 }
184 
188 void dai_ferry_transformed(struct ai_type *ait, struct unit *ferry,
189  const struct unit_type *old)
190 {
191  bool old_f = dai_is_ferry_type(old, ait);
192  bool new_f = dai_is_ferry(ferry, ait);
193 
194  if (old_f && !new_f) {
195  struct ai_plr *ai = dai_plr_data_get(ait, unit_owner(ferry), nullptr);
196  struct unit_ai *unit_data = def_ai_unit_data(ferry, ait);
197 
198  ai->stats.boats--;
199 
200  if (unit_data->passenger == FERRY_AVAILABLE) {
201  ai->stats.available_boats--;
202  } else if (unit_data->passenger > 0) {
203  struct unit *passenger = game_unit_by_number(unit_data->passenger);
204 
205  if (passenger != nullptr) {
206  aiferry_clear_boat(ait, passenger);
207  }
208  }
209  } else if (!old_f && new_f) {
210  struct ai_plr *ai = dai_plr_data_get(ait, unit_owner(ferry), nullptr);
211 
212  ai->stats.boats++;
213  ai->stats.available_boats++;
214  }
215 }
216 
220 void dai_ferry_lost(struct ai_type *ait, struct unit *punit)
221 {
222  // Ignore virtual units.
223  if (punit->id != 0 && is_ai_data_phase_open(ait, unit_owner(punit))) {
224  bool close_here;
225  struct unit_ai *unit_data = def_ai_unit_data(punit, ait);
226  struct player *pplayer = unit_owner(punit);
227  struct ai_plr *ai = dai_plr_data_get(ait, pplayer, &close_here);
228 
229  if (dai_is_ferry(punit, ait)) {
230  ai->stats.boats--;
231  if (unit_data->passenger == FERRY_AVAILABLE) {
232  ai->stats.available_boats--;
233  }
234  } else {
235  // Not a ferry
236  if (unit_data->ferryboat > 0) {
237  aiferry_clear_boat(ait, punit);
238  }
239  }
240 
241  if (close_here) {
242  dai_data_phase_finished(ait, pplayer);
243  }
244  }
245 }
246 
250 void aiferry_clear_boat(struct ai_type *ait, struct unit *punit)
251 {
252  struct unit_ai *unit_data = def_ai_unit_data(punit, ait);
253 
254  if (unit_data->ferryboat == FERRY_WANTED) {
255  struct player *pplayer = unit_owner(punit);
256 
257  if (is_ai_data_phase_open(ait, pplayer)) {
258  struct ai_plr *ai = dai_plr_data_get(ait, pplayer, nullptr);
259 
260  ai->stats.passengers--;
261  }
262  } else {
263  struct unit *ferry = game_unit_by_number(unit_data->ferryboat);
264 
265  if (ferry) {
266  struct unit_ai *ferry_data = def_ai_unit_data(ferry, ait);
267 
268  if (ferry_data->passenger == punit->id) {
269  // punit doesn't want us anymore
270  struct player *pplayer = unit_owner(ferry);
271 
272  if (is_ai_data_phase_open(ait, pplayer)) {
273  dai_plr_data_get(ait, pplayer, nullptr)->stats.available_boats++;
274  }
275  ferry_data->passenger = FERRY_AVAILABLE;
276  }
277  }
278  }
279 
280  unit_data->ferryboat = FERRY_NONE;
281 }
282 
287 static void aiferry_request_boat(struct ai_type *ait, struct unit *punit)
288 {
289  struct ai_plr *ai = dai_plr_data_get(ait, unit_owner(punit), nullptr);
290  struct unit_ai *unit_data = def_ai_unit_data(punit, ait);
291 
292  /* First clear the previous assignments (just in case there are).
293  * Substract virtual units or already counted */
294  if ((punit->id == 0)
295  || ((ai->stats.passengers > 0)
296  && (unit_data->ferryboat == FERRY_WANTED))) {
297  aiferry_clear_boat(ait, punit);
298  }
299 
300  // Now add ourselves to the list of potential passengers
301  ai->stats.passengers++;
302  UNIT_LOG(LOG_DEBUG, punit, "requests a boat (total passengers=%d).",
303  ai->stats.passengers);
304  unit_data->ferryboat = FERRY_WANTED;
305 
306  // Lastly, wait for ferry.
307  unit_data->done = true;
308 }
309 
313 static void aiferry_psngr_meet_boat(struct ai_type *ait, struct unit *punit,
314  struct unit *pferry)
315 {
316  struct unit_ai *ferry_data = def_ai_unit_data(pferry, ait);
317  struct player *ferry_owner = unit_owner(pferry);
318 
319  fc_assert_ret(unit_owner(punit) == ferry_owner);
320 
321  /* First delete the unit from the list of passengers and
322  * release its previous ferry */
323  aiferry_clear_boat(ait, punit);
324 
325  // If ferry was available, update the stats
326  if (ferry_data->passenger == FERRY_AVAILABLE) {
327  dai_plr_data_get(ait, ferry_owner, nullptr)->stats.available_boats--;
328  }
329 
330  // Exchange the phone numbers
331  def_ai_unit_data(punit, ait)->ferryboat = pferry->id;
332  ferry_data->passenger = punit->id;
333 }
334 
338 static void aiferry_make_available(struct ai_type *ait, struct unit *pferry)
339 {
340  struct unit_ai *ferry_data = def_ai_unit_data(pferry, ait);
341 
342  if (ferry_data->passenger != FERRY_AVAILABLE) {
343  dai_plr_data_get(ait, unit_owner(pferry), nullptr)
345  ferry_data->passenger = FERRY_AVAILABLE;
346  }
347 }
348 
353 int aiferry_avail_boats(struct ai_type *ait, struct player *pplayer)
354 {
355  struct ai_plr *ai = dai_plr_data_get(ait, pplayer, nullptr);
356 
357  /* To developer: Switch this checking on when testing some new
358  * ferry code. */
359 #ifdef LOGLEVEL_FERRY_STATS
360  int boats = 0;
361 
362  unit_list_iterate(pplayer->units, punit)
363  {
364  if (dai_is_ferry(punit, ait)
365  && def_ai_unit_data(punit, ait)->passenger == FERRY_AVAILABLE) {
366  boats++;
367  }
368  }
370 
371  if (boats != ai->stats.available_boats) {
372  qCritical("Player[%d] in turn %d: boats miscounted.",
373  player_number(pplayer), game.info.turn);
374  aiferry_print_stats(ait, pplayer);
375  }
376 #endif // LOGLEVEL_FERRY_STATS
377 
378  return ai->stats.available_boats;
379 }
380 
381 // ================== functions to find a boat =========================
382 
396 static int combined_land_sea_move(const struct tile *src_tile,
397  enum pf_move_scope src_scope,
398  const struct tile *tgt_tile,
399  enum pf_move_scope dst_scope,
400  const struct pf_parameter *param)
401 {
402  int move_cost;
403 
404  if (!((PF_MS_NATIVE | PF_MS_CITY) & dst_scope)) {
405  // Any-to-Sea
406  move_cost = 0;
407  } else if (!((PF_MS_NATIVE | PF_MS_CITY) & src_scope)) {
408  // Sea-to-Land
409  move_cost = PF_IMPOSSIBLE_MC;
410  } else {
411  // Land-to-Land
412  move_cost = map_move_cost(&(wld.map), param->owner, param->utype,
413  src_tile, tgt_tile);
414  }
415 
416  return move_cost;
417 }
418 
423 static int sea_move(const struct tile *ptile, enum known_type known,
424  const struct pf_parameter *param)
425 {
426  if (is_ocean_tile(ptile)) {
427  /* Approximately TURN_FACTOR / average ferry move rate
428  * we can pass a better guess of the move rate through param->data
429  * but we don't know which boat we will find out there */
430  return SINGLE_MOVE * PF_TURN_FACTOR / 12;
431  } else {
432  return 0;
433  }
434 }
435 
440 bool is_boat_free(struct ai_type *ait, struct unit *boat, struct unit *punit,
441  int cap)
442 {
443  /* - Only transporters capable of transporting this unit are eligible.
444  * - Units with orders are skipped (the AI doesn't control units with
445  * orders).
446  * - Only boats that we own are eligible.
447  * - Only available boats or boats that are already dedicated to this unit
448  * are eligible.
449  * - Only boats with enough remaining capacity are eligible.
450  * - Only units that can travel at sea are eligible.
451  * - Units that require fuel, except "Coast" ones, or lose hitpoints are
452  * not eligible.
453  */
454  struct unit_class *ferry_class = unit_class_get(boat);
455  const struct unit_type *ferry_type = unit_type_get(boat);
456  struct unit_ai *boat_data = def_ai_unit_data(boat, ait);
457 
458  return (
459  can_unit_transport(boat, punit) && !unit_has_orders(boat)
460  && unit_owner(boat) == unit_owner(punit)
461  && (boat_data->passenger == FERRY_AVAILABLE
462  || boat_data->passenger == punit->id)
464  >= cap)
465  && ferry_class->adv.sea_move != MOVE_NONE && !is_losing_hp(boat)
466  && (ferry_type->fuel == 0 || utype_has_flag(ferry_type, UTYF_COAST)));
467 }
468 
472 bool is_boss_of_boat(struct ai_type *ait, struct unit *punit)
473 {
474  if (!unit_transported(punit)) {
475  // Not even in boat
476  return false;
477  }
478 
479  return unit_transported(punit)
481  == punit->id;
482 }
483 
492 int aiferry_find_boat(struct ai_type *ait, struct unit *punit, int cap,
493  PFPath *path)
494 {
495  int best_turns = FC_INFINITY;
496  int best_id = 0;
497  struct pf_parameter param;
498  struct pf_map *search_map;
499  struct player *pplayer = unit_owner(punit);
500 
501  // currently assigned ferry
502  int ferryboat = def_ai_unit_data(punit, ait)->ferryboat;
503 
504  /* We may end calling pf_destroy_path for *path if it's not nullptr.
505  * Most likely you are passing garbage or path you don't want
506  * destroyed if this assertion fails.
507  * Don't try to be clever and pass 'fallback' path that will be returned
508  * if no path is found. Instead check for nullptr return value and then
509  * use fallback path in calling function. */
510  fc_assert_ret_val(path->empty(), 0);
511 
512  fc_assert_ret_val(0 < ferryboat || FERRY_NONE == ferryboat
513  || FERRY_WANTED == ferryboat,
514  0);
515  UNIT_LOG(LOGLEVEL_FINDFERRY, punit, "asked aiferry_find_boat for a boat");
516 
517  if (aiferry_avail_boats(ait, pplayer) <= 0 && ferryboat <= 0) {
518  /* No boats to be found (the second check is to ensure that we are not
519  * the ones keeping the last boat busy) */
520  return 0;
521  }
522 
523  pft_fill_unit_parameter(&param, punit);
524  param.omniscience = !has_handicap(pplayer, H_MAP);
526  param.get_EC = sea_move;
528  param.ignore_none_scopes = false;
529 
530  search_map = pf_map_new(&param);
531 
532  pf_map_positions_iterate(search_map, pos, true)
533  {
534  /* Should this be !can_unit_exist_at_tile() instead of is_ocean() some
535  * day? That would allow special units to wade in shallow coast waters to
536  * meet ferry where deep sea starts. */
537  int radius = (is_ocean_tile(pos.tile) ? 1 : 0);
538 
539  if (pos.turn + pos.total_EC / PF_TURN_FACTOR > best_turns) {
540  // Won't find anything better
541  // FIXME: This condition is somewhat dodgy
542  break;
543  }
544 
545  square_iterate(&(wld.map), pos.tile, radius, ptile)
546  {
547  unit_list_iterate(ptile->units, aunit)
548  {
549  if (is_boat_free(ait, aunit, punit, cap)) {
550  // Turns for the unit to get to rendezvous pnt
551  int u_turns = pos.turn;
552  // Turns for the boat to get to the rendezvous pnt
553  int f_turns =
554  ((pos.total_EC / PF_TURN_FACTOR * 16 - aunit->moves_left)
555  / unit_type_get(aunit)->move_rate);
556  int turns = MAX(u_turns, f_turns);
557 
558  if (turns < best_turns) {
560  "Found a potential boat %s[%d](%d,%d)(moves left: %d)",
561  unit_rule_name(aunit), aunit->id,
562  TILE_XY(unit_tile(aunit)), aunit->moves_left);
563  *path = pf_map_iter_path(search_map);
564  best_turns = turns;
565  best_id = aunit->id;
566  }
567  }
568  }
570  }
572  }
574  pf_map_destroy(search_map);
575 
576  return best_id;
577 }
578 
582 static int aiferry_find_boat_nearby(struct ai_type *ait, struct unit *punit,
583  int cap)
584 {
585  UNIT_LOG(LOGLEVEL_FINDFERRY, punit, "asked find_ferry_nearby for a boat");
586 
587  square_iterate(&(wld.map), unit_tile(punit), 1, ptile)
588  {
589  unit_list_iterate(ptile->units, aunit)
590  {
591  if (is_boat_free(ait, aunit, punit, cap)) {
592  return aunit->id;
593  }
594  }
596  }
598 
599  return 0;
600 }
601 
602 // ============================= go by boat ==============================
603 
609 static void dai_activate_passengers(struct ai_type *ait, struct unit *ferry)
610 {
611  struct player *ferry_owner = unit_owner(ferry);
612 
613  unit_list_iterate_safe(unit_tile(ferry)->units, aunit)
614  {
615  if (unit_transport_get(aunit) == ferry) {
616  unit_activity_handling(aunit, ACTIVITY_IDLE);
617  def_ai_unit_data(aunit, ait)->done = false;
618 
619  if (unit_owner(aunit) == ferry_owner) {
620  // Move it only if it's our own.
621  dai_manage_unit(ait, ferry_owner, aunit);
622  }
623  }
624  }
626 }
627 
635 bool dai_amphibious_goto_constrained(struct ai_type *ait, struct unit *ferry,
636  struct unit *passenger,
637  struct tile *ptile,
638  struct pft_amphibious *parameter)
639 {
640  bool alive = true;
641  struct player *pplayer = unit_owner(passenger);
642  struct pf_map *pfm;
643  int pass_id = passenger->id;
644 
645  fc_assert_ret_val(is_ai(pplayer), true);
646  fc_assert_ret_val(!unit_has_orders(passenger), true);
647  fc_assert_ret_val(unit_tile(ferry) == unit_tile(passenger), true);
648 
649  ptile = immediate_destination(passenger, ptile);
650 
651  if (same_pos(unit_tile(passenger), ptile)) {
652  /* Not an error; sometimes immediate_destination instructs the unit
653  * to stay here. For example, to refuel.*/
654  send_unit_info(nullptr, passenger);
655  return true;
656  } else if (passenger->moves_left == 0 && ferry->moves_left == 0) {
657  send_unit_info(nullptr, passenger);
658  return true;
659  }
660 
661  pfm = pf_map_new(&parameter->combined);
662  auto path = pf_map_path(pfm, ptile);
663 
664  if (!path.empty()) {
665  dai_log_path(passenger, path, &parameter->combined);
666  // Sea leg
667  alive = adv_follow_path(ferry, path, ptile);
668  if (alive && unit_tile(passenger) != ptile) {
669  /* Ferry has stopped; it is at the landing beach or
670  * has run out of movement points */
671  struct tile *next_tile;
672 
673  if (!path.advance(unit_tile(passenger))) {
674  /* Somehow we got thrown away from our route.
675  * This can happen if our movement caused alliance breakup. */
676  return unit_is_alive(pass_id);
677  }
678  next_tile = path[1].tile;
679  if (!is_ocean_tile(next_tile)) {
680  int ferry_id = ferry->id;
681 
682  UNIT_LOG(LOG_DEBUG, passenger,
683  "Our boat has arrived "
684  "[%d](moves left: %d)",
685  ferry->id, ferry->moves_left);
686  UNIT_LOG(LOG_DEBUG, passenger, "Disembarking to (%d,%d)",
687  TILE_XY(next_tile));
688  // Land leg
689  alive = adv_follow_path(passenger, path, ptile);
690  /* Movement of the passenger outside the ferry can cause also
691  * ferry to die. That has happened at least when passenger
692  * destroyed city cutting the civ1-style channel (cities in
693  * a chain) ferry was in. */
694  if (unit_is_alive(ferry_id) && 0 < ferry->moves_left
695  && (!alive || unit_tile(ferry) != unit_tile(passenger))) {
696  /* The passenger is no longer on the ferry,
697  * and the ferry can still act.
698  * Give a chance for another passenger to take command
699  * of the ferry.
700  */
701  UNIT_LOG(LOG_DEBUG, ferry, "Activating passengers");
702  dai_activate_passengers(ait, ferry);
703 
704  /* It is theoretically possible passenger died here due to
705  * autoattack against another passing unit at its location. */
706  alive = unit_is_alive(pass_id);
707  }
708  }
709  // else at sea
710  }
711  // else dead or arrived
712  } else {
713  // Not always an error; enemy units might block all paths.
714  UNIT_LOG(LOG_DEBUG, passenger, "no path to destination");
715  }
716 
717  pf_map_destroy(pfm);
718 
719  return alive;
720 }
721 
726 bool aiferry_goto_amphibious(struct ai_type *ait, struct unit *ferry,
727  struct unit *passenger, struct tile *ptile)
728 {
729  struct pft_amphibious parameter;
730  struct adv_risk_cost land_risk_cost;
731  struct adv_risk_cost sea_risk_cost;
732 
733  dai_fill_unit_param(ait, &parameter.land, &land_risk_cost, passenger,
734  ptile);
735  if (parameter.land.get_TB != no_fights) {
736  // Use the ferry to go around danger areas:
737  parameter.land.get_TB = no_intermediate_fights;
738  }
739  dai_fill_unit_param(ait, &parameter.sea, &sea_risk_cost, ferry, ptile);
740  pft_fill_amphibious_parameter(&parameter);
741 
742  /* Move as far along the path to the destination as we can;
743  * that is, ignore the presence of enemy units when computing the
744  * path */
745  parameter.combined.get_zoc = nullptr;
746 
747  return dai_amphibious_goto_constrained(ait, ferry, passenger, ptile,
748  &parameter);
749 }
750 
761 bool aiferry_gobyboat(struct ai_type *ait, struct player *pplayer,
762  struct unit *punit, struct tile *dest_tile,
763  bool with_bodyguard)
764 {
765  if (!unit_transported(punit)) {
766  // We are not on a boat and we cannot walk
767  int boatid;
768  struct unit *ferryboat = nullptr;
769  int cap = with_bodyguard ? 2 : 1;
770 
771  UNIT_LOG(LOGLEVEL_GOBYBOAT, punit, "will have to go to (%d,%d) by boat",
772  TILE_XY(dest_tile));
773 
774  if (!is_terrain_class_near_tile(unit_tile(punit), TC_OCEAN)) {
775  PFPath path_to_ferry;
776 
777  boatid = aiferry_find_boat(ait, punit, cap, &path_to_ferry);
778  if (boatid <= 0) {
780  "in ai_gothere cannot find any boats.");
781  def_ai_unit_data(punit, ait)->done = true; // Nothing to do
782  return false;
783  }
784 
785  ferryboat = game_unit_by_number(boatid);
786  fc_assert_ret_val(ferryboat != nullptr, false);
788  "found boat[%d](%d,%d), going there", boatid,
789  TILE_XY(unit_tile(ferryboat)));
790  /* The path can be amphibious so we will stop at the coast.
791  * It might not lead _onto_ the boat. */
792  if (!adv_unit_execute_path(punit, path_to_ferry)) {
793  // Died.
794  return false;
795  }
796  }
797 
798  if (!is_terrain_class_near_tile(unit_tile(punit), TC_OCEAN)) {
799  // Still haven't reached the coast
800  return false;
801  }
802 
803  // We are on the coast, look around for a boat
804  boatid = aiferry_find_boat_nearby(ait, punit, cap);
805  if (boatid <= 0) {
806  UNIT_LOG(LOGLEVEL_GOBYBOAT, punit, "requesting a boat.");
807  aiferry_request_boat(ait, punit);
808  return false;
809  }
810 
811  // Ok, a boat found, try boarding it
812  ferryboat = game_unit_by_number(boatid);
813  fc_assert_ret_val(ferryboat != nullptr, false);
814  UNIT_LOG(LOGLEVEL_GOBYBOAT, punit, "found a nearby boat[%d](%d,%d)",
815  ferryboat->id, TILE_XY(unit_tile(ferryboat)));
816  /* Setting ferry now in hope it won't run away even
817  * if we can't board it right now */
818  aiferry_psngr_meet_boat(ait, punit, ferryboat);
819 
820  if (is_tiles_adjacent(unit_tile(punit), unit_tile(ferryboat))) {
821  (void) dai_unit_move(ait, punit, unit_tile(ferryboat));
822  }
823 
824  // FIXME: check if action is enabled.
825  if (!can_unit_load(punit, ferryboat)) {
826  // Something prevented us from boarding
827  /* FIXME: this is probably a serious bug, but we just skip past
828  * it and continue. */
829  UNIT_LOG(LOGLEVEL_GOBYBOAT, punit, "couldn't board boat[%d](%d,%d)",
830  ferryboat->id, TILE_XY(unit_tile(ferryboat)));
831  return false;
832  }
833 
834  handle_unit_do_action(pplayer, punit->id, ferryboat->id, 0, "",
835  // FIXME: don't hard code action id.
836  ACTION_TRANSPORT_BOARD);
837  fc_assert(unit_transported(punit));
838  }
839 
840  if (unit_transported(punit)) {
841  // We are on a boat, ride it!
842  struct unit *ferryboat = unit_transport_get(punit);
843 
844  // Check if we are the passenger-in-charge
845  if (is_boat_free(ait, ferryboat, punit, 0)) {
846  struct unit *bodyguard = aiguard_guard_of(ait, punit);
847 
849  "got boat[%d](moves left: %d), going (%d,%d)", ferryboat->id,
850  ferryboat->moves_left, TILE_XY(dest_tile));
851  aiferry_psngr_meet_boat(ait, punit, ferryboat);
852 
853  punit->goto_tile = dest_tile;
854  // Grab bodyguard
855  if (bodyguard && !same_pos(unit_tile(punit), unit_tile(bodyguard))) {
856  if (!goto_is_sane(bodyguard, unit_tile(punit))
857  || !dai_unit_goto(ait, bodyguard, unit_tile(punit))) {
858  // Bodyguard can't get there or died en route
859  aiguard_request_guard(ait, punit);
860  bodyguard = nullptr;
861  } else if (bodyguard->moves_left <= 0) {
862  // Wait for me, I'm cooooming!!
863  UNIT_LOG(LOGLEVEL_GOBYBOAT, punit, "waiting for bodyguard");
864  def_ai_unit_data(punit, ait)->done = true;
865  return false;
866  } else {
867  // Crap bodyguard. Got stuck somewhere. Ditch it!
868  UNIT_LOG(LOGLEVEL_GOBYBOAT, punit, "ditching useless bodyguard");
869  aiguard_request_guard(ait, punit);
870  dai_unit_new_task(ait, bodyguard, AIUNIT_NONE, nullptr);
871  bodyguard = nullptr;
872  }
873  }
874  if (bodyguard) {
875  // FIXME: check if action is enabled.
876  fc_assert(same_pos(unit_tile(punit), unit_tile(bodyguard)));
877  handle_unit_do_action(pplayer, bodyguard->id, ferryboat->id, 0, "",
878  // FIXME: don't hard code action id.
879  ACTION_TRANSPORT_BOARD);
880  }
881  if (!aiferry_goto_amphibious(ait, ferryboat, punit, dest_tile)) {
882  // died
883  return false;
884  }
885  if (same_pos(unit_tile(punit), dest_tile)) {
886  // Arrived
887  unit_activity_handling(punit, ACTIVITY_IDLE);
888  } else {
889  // We are in still transit
890  def_ai_unit_data(punit, ait)->done = true;
891  return false;
892  }
893  } else {
894  // Waiting for the boss to load and move us
896  "Cannot command boat [%d],"
897  " its boss is [%d]",
898  ferryboat->id, def_ai_unit_data(ferryboat, ait)->passenger);
899  return false;
900  }
901  }
902 
903  return true;
904 }
905 
906 // ===================== boat management =================================
907 
915 static bool aiferry_findcargo(struct ai_type *ait, struct unit *pferry)
916 {
917  // Path-finding stuff
918  struct pf_map *pfm;
919  struct pf_parameter parameter;
920  int passengers =
921  dai_plr_data_get(ait, unit_owner(pferry), nullptr)->stats.passengers;
922  struct player *pplayer;
923 
924  if (passengers <= 0) {
925  // No passangers anywhere
926  return false;
927  }
928 
929  UNIT_LOG(LOGLEVEL_FERRY, pferry, "Ferryboat is looking for cargo.");
930 
931  pplayer = unit_owner(pferry);
932  pft_fill_unit_overlap_param(&parameter, pferry);
933  parameter.omniscience = !has_handicap(pplayer, H_MAP);
934  /* If we have omniscience, we use it, since paths to some places
935  * might be "blocked" by unknown. We don't want to fight though */
936  parameter.get_TB = no_fights;
937 
938  pfm = pf_map_new(&parameter);
939  pf_map_tiles_iterate(pfm, ptile, true)
940  {
941  unit_list_iterate(ptile->units, aunit)
942  {
943  struct unit_ai *unit_data = def_ai_unit_data(aunit, ait);
944 
945  if (unit_owner(pferry) == unit_owner(aunit)
946  && (unit_data->ferryboat == FERRY_WANTED
947  || unit_data->ferryboat == pferry->id)) {
948  UNIT_LOG(LOGLEVEL_FERRY, pferry,
949  "Found a potential cargo %s[%d](%d,%d), going there",
950  unit_rule_name(aunit), aunit->id,
951  TILE_XY(unit_tile(aunit)));
952  pferry->goto_tile = unit_tile(aunit);
953  // Exchange phone numbers
954  aiferry_psngr_meet_boat(ait, aunit, pferry);
955  pf_map_destroy(pfm);
956  return true;
957  }
958  }
960  }
962 
963  /* False positive can happen if we cannot find a route to the passenger
964  * because of an internal sea or enemy blocking the route */
965  UNIT_LOG(LOGLEVEL_FERRY, pferry,
966  "AI Passengers counting reported false positive %d", passengers);
967  pf_map_destroy(pfm);
968  return false;
969 }
970 
983 static bool aiferry_find_interested_city(struct ai_type *ait,
984  struct unit *pferry)
985 {
986  // Path-finding stuff
987  struct pf_map *pfm;
988  struct pf_parameter parameter;
989  // Early termination condition
990  int turns_horizon = FC_INFINITY;
991  // Future return value
992  bool needed = false;
993 
994  UNIT_LOG(LOGLEVEL_FERRY, pferry, "Ferry looking for a city that needs it");
995 
996  pft_fill_unit_parameter(&parameter, pferry);
997  // We are looking for our own cities, no need to look into the unknown
998  parameter.get_TB = no_fights_or_unknown;
999  parameter.omniscience = false;
1000  pfm = pf_map_new(&parameter);
1001 
1002  pf_map_positions_iterate(pfm, pos, true)
1003  {
1004  struct city *pcity;
1005 
1006  if (pos.turn >= turns_horizon) {
1007  // Won't be able to find anything better than what we have
1008  break;
1009  }
1010 
1011  pcity = tile_city(pos.tile);
1012 
1013  if (pcity && city_owner(pcity) == unit_owner(pferry)
1014  && (def_ai_city_data(pcity, ait)->choice.need_boat
1015  || (VUT_UTYPE == pcity->production.kind
1017  L_FERRYBOAT)))) {
1018  bool really_needed = true;
1019  int turns = city_production_turns_to_build(pcity, true);
1020 
1021  UNIT_LOG(LOGLEVEL_FERRY, pferry, "%s (%d, %d) looks promising...",
1022  city_name_get(pcity), TILE_XY(pcity->tile));
1023 
1024  if (pos.turn > turns && VUT_UTYPE == pcity->production.kind
1025  && utype_has_role(pcity->production.value.utype, L_FERRYBOAT)) {
1026  UNIT_LOG(LOGLEVEL_FERRY, pferry,
1027  "%s is NOT suitable: "
1028  "will finish building its own ferry too soon",
1029  city_name_get(pcity));
1030  continue;
1031  }
1032 
1033  if (turns >= turns_horizon) {
1034  UNIT_LOG(LOGLEVEL_FERRY, pferry,
1035  "%s is NOT suitable: "
1036  "has just started building",
1037  city_name_get(pcity));
1038  continue;
1039  }
1040 
1041  unit_list_iterate(pos.tile->units, aunit)
1042  {
1043  if (aunit != pferry && unit_owner(aunit) == unit_owner(pferry)
1044  && unit_has_type_role(aunit, L_FERRYBOAT)) {
1045  UNIT_LOG(LOGLEVEL_FERRY, pferry,
1046  "%s is NOT suitable: "
1047  "has another ferry",
1048  city_name_get(pcity));
1049  really_needed = false;
1050  break;
1051  }
1052  }
1054 
1055  if (really_needed) {
1056  UNIT_LOG(LOGLEVEL_FERRY, pferry,
1057  "will go to %s unless we "
1058  "find something better",
1059  city_name_get(pcity));
1060  pferry->goto_tile = pos.tile;
1061  turns_horizon = turns;
1062  needed = true;
1063  }
1064  }
1065  }
1067 
1068  pf_map_destroy(pfm);
1069  return needed;
1070 }
1071 
1082 void dai_manage_ferryboat(struct ai_type *ait, struct player *pplayer,
1083  struct unit *punit)
1084 {
1085  struct city *pcity;
1086  int sanity = punit->id;
1087  struct unit_ai *unit_data;
1088  int bossid;
1089  const struct unit_type *ptype;
1090 
1091  CHECK_UNIT(punit);
1092 
1093  // Try to recover hitpoints if we are in a city, before we do anything
1094  if (punit->hp < unit_type_get(punit)->hp
1095  && (pcity = tile_city(unit_tile(punit)))) {
1096  UNIT_LOG(LOGLEVEL_FERRY, punit, "waiting in %s to recover hitpoints",
1097  city_name_get(pcity));
1098  def_ai_unit_data(punit, ait)->done = true;
1099  return;
1100  }
1101 
1102  // Check if we are an empty barbarian boat and so not needed
1103  if (is_barbarian(pplayer) && get_transporter_occupancy(punit) == 0) {
1104  wipe_unit(punit, ULR_RETIRED, nullptr);
1105  return;
1106  }
1107 
1108  unit_data = def_ai_unit_data(punit, ait);
1109 
1110  bossid = unit_data->passenger; // Old boss
1111 
1112  do {
1113  // Do we have the passenger-in-charge on board?
1114  if (unit_data->passenger > 0) {
1115  struct unit *psngr = game_unit_by_number(unit_data->passenger);
1116 
1117  /* If the passenger-in-charge is adjacent, we should wait for it to
1118  * board. We will pass control to it later. */
1119  if (!psngr
1120  || real_map_distance(unit_tile(punit), unit_tile(psngr)) > 1) {
1121  UNIT_LOG(LOGLEVEL_FERRY, punit,
1122  "recorded passenger[%d] is not on board, checking for "
1123  "others",
1124  unit_data->passenger);
1125  unit_data->passenger = FERRY_ABANDON_BOSS;
1126  }
1127  }
1128 
1129  if (unit_data->passenger == FERRY_AVAILABLE
1130  || unit_data->passenger == FERRY_ABANDON_BOSS) {
1131  struct unit *candidate = nullptr;
1132 
1133  // Try to select passanger-in-charge from among our passengers
1134  unit_list_iterate(punit->transporting, aunit)
1135  {
1136  if (unit_owner(aunit) != pplayer) {
1137  /* We used to check if ferryboat was set to us or to
1138  * FERRY_WANTED too, but this was a bit strict. Especially
1139  * when we don't save these values in a savegame. */
1140  continue;
1141  }
1142 
1143  if (def_ai_unit_data(aunit, ait)->task != AIUNIT_ESCORT) {
1144  candidate = aunit;
1145  break;
1146  } else {
1147  /* Bodyguards shouldn't be in charge of boats so continue looking
1148  */
1149  candidate = aunit;
1150  }
1151  }
1153 
1154  if (candidate) {
1155  UNIT_LOG(LOGLEVEL_FERRY, punit,
1156  "appointed %s[%d] our passenger-in-charge",
1157  unit_rule_name(candidate), candidate->id);
1158  bossid = candidate->id;
1159  aiferry_psngr_meet_boat(ait, candidate, punit);
1160  }
1161  }
1162 
1163  if (unit_data->passenger > 0) {
1164  struct unit *boss = game_unit_by_number(bossid);
1165 
1166  fc_assert_ret(nullptr != boss);
1167 
1168  if (unit_has_type_flag(boss, UTYF_SETTLERS)
1169  || unit_is_cityfounder(boss)) {
1170  /* Temporary hack: settlers all go in the end, forcing them
1171  * earlier might mean uninitialised cache, so just wait for them */
1172  return;
1173  }
1174 
1175  UNIT_LOG(LOGLEVEL_FERRY, punit, "passing control to %s[%d]",
1176  unit_rule_name(boss), boss->id);
1177  dai_manage_unit(ait, pplayer, boss);
1178 
1179  if (!game_unit_by_number(sanity) || punit->moves_left <= 0) {
1180  return;
1181  }
1182  if (game_unit_by_number(bossid)) {
1183  if (same_pos(unit_tile(punit), unit_tile(boss))) {
1184  // The boss decided to stay put on the ferry. We aren't moving.
1185  UNIT_LOG(LOG_DEBUG, boss, "drove ferry - done for now");
1186  def_ai_unit_data(boss, ait)->done = true;
1187  return;
1188  } else if (unit_data->passenger == bossid
1189  && get_transporter_occupancy(punit) != 0) {
1190  /* The boss isn't on the ferry, has not passed control away,
1191  * and we have other passengers?
1192  * Forget about him. */
1193  unit_data->passenger = FERRY_ABANDON_BOSS;
1194  }
1195  }
1196  if (unit_data->passenger != bossid
1197  && unit_data->passenger != FERRY_ABANDON_BOSS) {
1198  /* Boss handling resulted in boss change. Run next round with new
1199  * boss. */
1200  bossid = unit_data->passenger;
1201  }
1202  } else {
1203  // Cannot select a passenger-in-charge
1204  break;
1205  }
1206  } while (get_transporter_occupancy(punit) != 0);
1207 
1208  if (unit_data->passenger == FERRY_ABANDON_BOSS) {
1209  // As nobody else wanted the control, restore it to old boss.
1210  unit_data->passenger = bossid;
1211  }
1212 
1213  // Not carrying anyone, even the ferryman
1214 
1215  ptype = unit_type_get(punit);
1216 
1217  if (IS_ATTACKER(ptype) && punit->moves_left > 0) {
1218  /* AI used to build frigates to attack and then use them as ferries
1219  * -- Syela */
1220  dai_unit_new_task(ait, punit, AIUNIT_NONE, nullptr);
1221  UNIT_LOG(LOGLEVEL_FERRY, punit, "passing ferry over to attack code");
1222  dai_manage_military(ait, pplayer, punit);
1223  return;
1224  }
1225 
1226  UNIT_LOG(LOGLEVEL_FERRY, punit,
1227  "Ferryboat is not carrying anyone "
1228  "(moves left: %d).",
1229  punit->moves_left);
1230  aiferry_make_available(ait, punit);
1231  unit_activity_handling(punit, ACTIVITY_IDLE);
1232  dai_unit_new_task(ait, punit, AIUNIT_NONE, nullptr);
1233  CHECK_UNIT(punit);
1234 
1235  // Try to find passengers
1236  if (aiferry_findcargo(ait, punit)) {
1237  UNIT_LOG(LOGLEVEL_FERRY, punit, "picking up cargo (moves left: %d)",
1238  punit->moves_left);
1239  if (dai_unit_goto(ait, punit, punit->goto_tile)) {
1240  if (is_tiles_adjacent(unit_tile(punit), punit->goto_tile)
1241  || same_pos(unit_tile(punit), punit->goto_tile)) {
1242  struct unit *cargo = game_unit_by_number(unit_data->passenger);
1243 
1244  // See if passenger can jump on board!
1245  fc_assert_ret(cargo != punit);
1246  dai_manage_unit(ait, pplayer, cargo);
1247  }
1248  }
1249  return;
1250  }
1251 
1252  // Try to find a city that needs a ferry
1253  if (aiferry_find_interested_city(ait, punit)) {
1254  if (same_pos(unit_tile(punit), punit->goto_tile)) {
1255  UNIT_LOG(LOGLEVEL_FERRY, punit, "staying in city that needs us");
1256  unit_data->done = true;
1257  return;
1258  } else {
1259  UNIT_LOG(LOGLEVEL_FERRY, punit, "going to city that needs us");
1260  if (dai_unit_goto(ait, punit, punit->goto_tile)
1261  && same_pos(unit_tile(punit), punit->goto_tile)) {
1262  unit_data->done = true; // save some CPU
1263  }
1264  return;
1265  }
1266  }
1267 
1268  UNIT_LOG(LOGLEVEL_FERRY, punit,
1269  "Passing control of ferry to explorer code");
1270  switch (manage_auto_explorer(punit)) {
1271  case MR_DEATH:
1272  // don't use punit!
1273  return;
1274  case MR_OK:
1275  // FIXME: continue moving?
1276  break;
1277  default:
1278  unit_data->done = true;
1279  break;
1280  };
1281 
1282  if (punit->moves_left > 0) {
1283  struct city *safe_city = find_nearest_safe_city(punit);
1284 
1285  if (safe_city != nullptr) {
1286  punit->goto_tile = safe_city->tile;
1287  UNIT_LOG(LOGLEVEL_FERRY, punit, "No work, going home");
1288  unit_data->done = true;
1289  dai_unit_new_task(ait, punit, AIUNIT_NONE, nullptr);
1290  (void) dai_unit_goto(ait, punit, safe_city->tile);
1291  }
1292  }
1293 }
bool adv_unit_execute_path(struct unit *punit, const PFPath &path)
This is a function to execute paths returned by the path-finding engine, for units controlled by advi...
Definition: advgoto.cpp:78
bool adv_follow_path(struct unit *punit, const PFPath &path, struct tile *ptile)
Move a unit along a path without disturbing its activity, role or assigned destination Return FALSE i...
Definition: advgoto.cpp:43
bool is_ai_data_phase_open(struct ai_type *ait, struct player *pplayer)
Return whether data phase is currently open.
Definition: aidata.cpp:128
void dai_data_phase_finished(struct ai_type *ait, struct player *pplayer)
Clean up ai data after phase finished.
Definition: aidata.cpp:281
struct ai_plr * dai_plr_data_get(struct ai_type *ait, struct player *pplayer, bool *caller_closes)
Get current default ai data related to player.
Definition: aidata.cpp:304
static bool aiferry_findcargo(struct ai_type *ait, struct unit *pferry)
A helper for ai_manage_ferryboat.
Definition: aiferry.cpp:913
static int combined_land_sea_move(const struct tile *src_tile, enum pf_move_scope src_scope, const struct tile *tgt_tile, enum pf_move_scope dst_scope, const struct pf_parameter *param)
Combined cost function for a land unit looking for a ferry.
Definition: aiferry.cpp:394
static void dai_activate_passengers(struct ai_type *ait, struct unit *ferry)
Manage the passengers on a ferry, even if they are asleep.
Definition: aiferry.cpp:607
#define FERRY_WANTED
Definition: aiferry.cpp:63
bool aiferry_gobyboat(struct ai_type *ait, struct player *pplayer, struct unit *punit, struct tile *dest_tile, bool with_bodyguard)
This function is to be called if punit needs to use a boat to get to the destination.
Definition: aiferry.cpp:759
#define FERRY_NONE
Definition: aiferry.cpp:64
int aiferry_find_boat(struct ai_type *ait, struct unit *punit, int cap, PFPath *path)
Proper and real PF function for finding a boat.
Definition: aiferry.cpp:490
void dai_manage_ferryboat(struct ai_type *ait, struct player *pplayer, struct unit *punit)
It's about 12 feet square and has a capacity of almost 1000 pounds.
Definition: aiferry.cpp:1080
bool is_boat_free(struct ai_type *ait, struct unit *boat, struct unit *punit, int cap)
Runs a few checks to determine if "boat" is a free boat that can carry "cap" units of the same type a...
Definition: aiferry.cpp:438
static int sea_move(const struct tile *ptile, enum known_type known, const struct pf_parameter *param)
EC callback to account for the cost of sea moves by a ferry hurrying to pick our unit up.
Definition: aiferry.cpp:421
bool dai_is_ferry_type(const struct unit_type *pferry, struct ai_type *ait)
Print the list of boats of pplayer.
Definition: aiferry.cpp:146
void aiferry_init_stats(struct ai_type *ait, struct player *pplayer)
Call to initialize the ferryboat statistics.
Definition: aiferry.cpp:84
static bool aiferry_find_interested_city(struct ai_type *ait, struct unit *pferry)
A helper for ai_manage_ferryboat.
Definition: aiferry.cpp:981
#define LOGLEVEL_FINDFERRY
Definition: aiferry.cpp:73
void dai_ferry_lost(struct ai_type *ait, struct unit *punit)
Close ferry when player loses it.
Definition: aiferry.cpp:218
void dai_ferry_transformed(struct ai_type *ait, struct unit *ferry, const struct unit_type *old)
Update ferry system when unit is transformed.
Definition: aiferry.cpp:186
bool aiferry_goto_amphibious(struct ai_type *ait, struct unit *ferry, struct unit *passenger, struct tile *ptile)
Move a passenger on a ferry to a specified destination.
Definition: aiferry.cpp:724
bool is_boss_of_boat(struct ai_type *ait, struct unit *punit)
Check if unit is boss in ferry.
Definition: aiferry.cpp:470
static void aiferry_psngr_meet_boat(struct ai_type *ait, struct unit *punit, struct unit *pferry)
Assign the passenger to the boat and vice versa.
Definition: aiferry.cpp:311
static void aiferry_make_available(struct ai_type *ait, struct unit *pferry)
Mark the ferry as available and update the statistics.
Definition: aiferry.cpp:336
static int aiferry_find_boat_nearby(struct ai_type *ait, struct unit *punit, int cap)
Find a boat within one move from us (i.e.
Definition: aiferry.cpp:580
int aiferry_avail_boats(struct ai_type *ait, struct player *pplayer)
Returns the number of available boats.
Definition: aiferry.cpp:351
#define LOGLEVEL_GOBYBOAT
Definition: aiferry.cpp:71
bool dai_amphibious_goto_constrained(struct ai_type *ait, struct unit *ferry, struct unit *passenger, struct tile *ptile, struct pft_amphibious *parameter)
Move a passenger on a ferry to a specified destination.
Definition: aiferry.cpp:633
bool dai_is_ferry(struct unit *pferry, struct ai_type *ait)
Should unit be considered a ferry?
Definition: aiferry.cpp:157
#define FERRY_ABANDON_BOSS
Definition: aiferry.cpp:57
void dai_ferry_init_ferry(struct ai_type *ait, struct unit *ferry)
Initialize new ferry when player gets it.
Definition: aiferry.cpp:165
void aiferry_clear_boat(struct ai_type *ait, struct unit *punit)
Use on a unit which no longer needs a boat.
Definition: aiferry.cpp:248
#define FERRY_AVAILABLE
Definition: aiferry.cpp:56
static void aiferry_request_boat(struct ai_type *ait, struct unit *punit)
Request a boat for the unit.
Definition: aiferry.cpp:285
#define LOGLEVEL_FERRY
Definition: aiferry.cpp:69
void aiguard_request_guard(struct ai_type *ait, struct unit *punit)
Request a (new) bodyguard for the unit.
Definition: aiguard.cpp:218
struct unit * aiguard_guard_of(struct ai_type *ait, struct unit *charge)
Which unit, if any, is the body guard of a unit? Returns nullptr if the unit has not been assigned a ...
Definition: aiguard.cpp:260
static struct ai_plr * def_ai_player_data(const struct player *pplayer, struct ai_type *deftype)
Definition: aiplayer.h:47
static struct ai_city * def_ai_city_data(const struct city *pcity, struct ai_type *deftype)
Definition: aiplayer.h:35
static struct unit_ai * def_ai_unit_data(const struct unit *punit, struct ai_type *deftype)
Definition: aiplayer.h:41
void dai_fill_unit_param(struct ai_type *ait, struct pf_parameter *parameter, struct adv_risk_cost *risk_cost, struct unit *punit, struct tile *ptile)
Set up the constraints on a path for an AI unit.
Definition: aitools.cpp:475
bool goto_is_sane(struct unit *punit, struct tile *ptile)
Use pathfinding to determine whether a GOTO is possible, considering all aspects of the unit being mo...
Definition: aitools.cpp:436
void dai_log_path(struct unit *punit, const PFPath &path, struct pf_parameter *parameter)
Log the cost of travelling a path.
Definition: aitools.cpp:359
bool dai_unit_goto(struct ai_type *ait, struct unit *punit, struct tile *ptile)
Go to specified destination but do not disturb existing role or activity and do not clear the role's ...
Definition: aitools.cpp:609
struct tile * immediate_destination(struct unit *punit, struct tile *dest_tile)
Returns the destination for a unit moving towards a given final destination.
Definition: aitools.cpp:314
void dai_unit_new_task(struct ai_type *ait, struct unit *punit, enum ai_unit_task task, struct tile *ptile)
Ensure unit sanity by telling charge that we won't bodyguard it anymore, tell bodyguard it can roam f...
Definition: aitools.cpp:648
bool dai_unit_move(struct ai_type *ait, struct unit *punit, struct tile *ptile)
Move a unit.
Definition: aitools.cpp:947
void dai_manage_military(struct ai_type *ait, struct player *pplayer, struct unit *punit)
Decide what to do with a military unit.
Definition: aiunit.cpp:2399
struct city * find_nearest_safe_city(struct unit *punit)
Find safe city to recover in.
Definition: aiunit.cpp:1620
void dai_manage_unit(struct ai_type *ait, struct player *pplayer, struct unit *punit)
manage one unit Careful: punit may have been destroyed upon return from this routine!
Definition: aiunit.cpp:2551
@ AIUNIT_NONE
Definition: aiunit.h:26
@ AIUNIT_ESCORT
Definition: aiunit.h:31
#define IS_ATTACKER(ptype)
Definition: aiunit.h:75
enum unit_move_result manage_auto_explorer(struct unit *punit)
Handle eXplore mode of a unit (explorers are always in eXplore mode for AI) - explores unknown territ...
struct player * city_owner(const struct city *pcity)
Return the owner of the city.
Definition: city.cpp:1083
const char * city_name_get(const struct city *pcity)
Return the name of the city.
Definition: city.cpp:1077
int city_production_turns_to_build(const struct city *pcity, bool include_shield_stock)
Calculates the turns which are needed to build the requested production in the city.
Definition: city.cpp:784
bool advance(struct tile *ptile)
Remove the part of a path leading up to a given tile.
bool empty() const
struct unit * game_unit_by_number(int id)
Find unit out of all units in game: now uses fast idex method, instead of looking through all units o...
Definition: game.cpp:112
struct civ_game game
Definition: game.cpp:47
struct world wld
Definition: game.cpp:48
bool has_handicap(const struct player *pplayer, enum handicap_type htype)
AI players may have handicaps - allowing them to cheat or preventing them from using certain algorith...
Definition: handicaps.cpp:62
@ H_MAP
Definition: handicaps.h:27
constexpr auto LOG_DEBUG
Definition: log.h:27
#define fc_assert_ret(condition)
Definition: log.h:112
#define fc_assert(condition)
Definition: log.h:89
#define fc_assert_ret_val(condition, val)
Definition: log.h:114
#define log_base(level, message,...)
Definition: log.h:41
bool is_tiles_adjacent(const struct tile *tile0, const struct tile *tile1)
Are two tiles adjacent to each other.
Definition: map.cpp:878
bool same_pos(const struct tile *tile1, const struct tile *tile2)
Are (x1,y1) and (x2,y2) really the same when adjusted? This function might be necessary ALOT of place...
Definition: map.cpp:887
int real_map_distance(const struct tile *tile0, const struct tile *tile1)
Return real distance between two tiles.
Definition: map.cpp:599
#define square_iterate(nmap, center_tile, radius, tile_itr)
Definition: map.h:312
#define square_iterate_end
Definition: map.h:315
static int map_move_cost(const struct civ_map *nmap, const struct player *pplayer, const struct unit_type *punittype, const struct tile *src_tile, const struct tile *dst_tile)
Definition: map.h:232
bool can_unit_transport(const struct unit *transporter, const struct unit *transported)
Return true iff transporter has ability to transport transported.
Definition: movement.cpp:684
#define SINGLE_MOVE
Definition: movement.h:17
@ MR_OK
Definition: movement.h:26
@ MR_DEATH
Definition: movement.h:27
struct pf_map * pf_map_new(const struct pf_parameter *parameter)
Factory function to create a new map according to the parameter.
PFPath pf_map_path(struct pf_map *pfm, struct tile *ptile)
CHECK DOCS AFTER FULL CONVERSTION OF pf_path to class PFPath Tries to find the best path in the given...
void pf_map_destroy(struct pf_map *pfm)
After usage the map must be destroyed.
PFPath pf_map_iter_path(struct pf_map *pfm)
Return the path to our current position.This is equivalent to pf_map_path(pfm, pf_map_iter(pfm)).
#define PF_IMPOSSIBLE_MC
Definition: path_finding.h:244
pf_move_scope
Definition: path_finding.h:287
@ PF_MS_CITY
Definition: path_finding.h:290
@ PF_MS_NATIVE
Definition: path_finding.h:289
#define pf_map_positions_iterate_end
Definition: path_finding.h:564
#define PF_TURN_FACTOR
Definition: path_finding.h:250
#define pf_map_tiles_iterate(ARG_pfm, NAME_tile, COND_from_start)
Definition: path_finding.h:509
#define pf_map_positions_iterate(ARG_pfm, NAME_pos, COND_from_start)
Definition: path_finding.h:557
#define pf_map_tiles_iterate_end
Definition: path_finding.h:516
enum tile_behavior no_fights(const struct tile *ptile, enum known_type known, const struct pf_parameter *param)
PF callback to prohibit attacking anyone.
Definition: pf_tools.cpp:484
void pft_fill_unit_overlap_param(struct pf_parameter *parameter, const struct unit *punit)
Switch on one tile overlapping into the non-native terrain.
Definition: pf_tools.cpp:871
void pft_fill_unit_parameter(struct pf_parameter *parameter, const struct unit *punit)
Fill classic parameters for an unit.
Definition: pf_tools.cpp:822
enum tile_behavior no_intermediate_fights(const struct tile *ptile, enum known_type known, const struct pf_parameter *param)
PF callback to prohibit attacking anyone, except at the destination.
Definition: pf_tools.cpp:499
enum tile_behavior no_fights_or_unknown(const struct tile *ptile, enum known_type known, const struct pf_parameter *param)
PF callback to prohibit going into the unknown.
Definition: pf_tools.cpp:469
void pft_fill_amphibious_parameter(struct pft_amphibious *parameter)
Fill parameters for combined sea-land movement.
Definition: pf_tools.cpp:955
int player_number(const struct player *pplayer)
Return the player index/number/id.
Definition: player.cpp:756
const char * player_name(const struct player *pplayer)
Return the leader name of the player.
Definition: player.cpp:816
static bool is_barbarian(const struct player *pplayer)
Definition: player.h:474
#define is_ai(plr)
Definition: player.h:227
#define FC_INFINITY
Definition: shared.h:32
#define MAX(x, y)
Definition: shared.h:48
#define UNIT_LOG(_, punit, msg,...)
Definition: srv_log.h:95
Definition: aidata.h:63
int passengers
Definition: aidata.h:70
int boats
Definition: aidata.h:71
int available_boats
Definition: aidata.h:72
struct ai_plr::@155 stats
Definition: ai.h:42
Definition: city.h:291
struct universal production
Definition: city.h:368
struct tile * tile
Definition: city.h:293
struct packet_game_info info
Definition: game.h:80
bool ignore_none_scopes
Definition: path_finding.h:375
enum tile_behavior(* get_TB)(const struct tile *ptile, enum known_type known, const struct pf_parameter *param)
Definition: path_finding.h:380
int(* get_EC)(const struct tile *ptile, enum known_type known, const struct pf_parameter *param)
Definition: path_finding.h:387
const struct player * owner
Definition: path_finding.h:356
bool(* get_zoc)(const struct player *pplayer, const struct tile *ptile, const struct civ_map *zmap)
Definition: path_finding.h:412
int(* get_MC)(const struct tile *from_tile, enum pf_move_scope src_move_scope, const struct tile *to_tile, enum pf_move_scope dst_move_scope, const struct pf_parameter *param)
Definition: path_finding.h:364
const struct unit_type * utype
Definition: path_finding.h:355
struct pf_parameter combined
Definition: pf_tools.h:33
struct pf_parameter land sea
Definition: pf_tools.h:29
Definition: player.h:231
struct unit_list * units
Definition: player.h:264
Definition: tile.h:42
struct unit_list * units
Definition: tile.h:50
Definition: aiunit.h:39
bool done
Definition: aiunit.h:51
int ferryboat
Definition: aiunit.h:41
int passenger
Definition: aiunit.h:42
struct unit_class::@80 adv
enum move_level sea_move
Definition: unittype.h:136
bool ferry
Definition: aiunit.h:58
int move_rate
Definition: unittype.h:481
int hp
Definition: unittype.h:489
int fuel
Definition: unittype.h:497
Definition: unit.h:134
int moves_left
Definition: unit.h:147
int id
Definition: unit.h:141
struct unit_list * transporting
Definition: unit.h:181
int hp
Definition: unit.h:148
struct tile * goto_tile
Definition: unit.h:152
enum universals_n kind
Definition: fc_types.h:740
universals_u value
Definition: fc_types.h:739
struct civ_map map
Definition: world_object.h:21
bool is_terrain_class_near_tile(const struct tile *ptile, enum terrain_class tclass)
Is there terrain of the given class near tile? (Does not check ptile itself.)
Definition: terrain.cpp:495
#define is_ocean_tile(ptile)
Definition: terrain.h:279
struct city * tile_city(const struct tile *ptile)
Return the city on this tile (or nullptr), checking for city center.
Definition: tile.cpp:72
known_type
Definition: tile.h:28
#define TILE_XY(ptile)
Definition: tile.h:36
const struct unit_type * utype
Definition: fc_types.h:585
int get_transporter_occupancy(const struct unit *ptrans)
Return how many units are in the transport.
Definition: unit.cpp:1647
bool unit_is_alive(int id)
Check if unit with given id is still alive.
Definition: unit.cpp:2014
bool is_losing_hp(const struct unit *punit)
Does unit lose hitpoints each turn?
Definition: unit.cpp:1992
bool can_unit_load(const struct unit *pcargo, const struct unit *ptrans)
Return TRUE iff the given unit can be loaded into the transporter.
Definition: unit.cpp:693
struct unit * unit_transport_get(const struct unit *pcargo)
Returns the transporter of the unit or nullptr if it is not transported.
Definition: unit.cpp:2189
bool unit_is_cityfounder(const struct unit *punit)
Is a cityfounder unit?
Definition: unit.cpp:2389
int get_transporter_capacity(const struct unit *punit)
Return the number of units the transporter can hold (or 0).
Definition: unit.cpp:280
bool unit_transported(const struct unit *pcargo)
Returns TRUE iff the unit is transported.
Definition: unit.cpp:2176
bool unit_has_orders(const struct unit *punit)
Return TRUE iff the unit is following client-side orders.
Definition: unit.cpp:195
#define unit_tile(_pu)
Definition: unit.h:371
#define CHECK_UNIT(punit)
Definition: unit.h:264
#define unit_owner(_pu)
Definition: unit.h:370
void handle_unit_do_action(struct player *pplayer, const int actor_id, const int target_id, const int sub_tgt_id, const char *name, const action_id action_type)
Handle a request to do an action.
Definition: unithand.cpp:2705
bool unit_activity_handling(struct unit *punit, enum unit_activity new_activity)
Handle request for changing activity.
Definition: unithand.cpp:5485
#define unit_list_iterate(unitlist, punit)
Definition: unitlist.h:25
#define unit_list_iterate_safe(unitlist, _unit)
Definition: unitlist.h:33
#define unit_list_iterate_end
Definition: unitlist.h:27
#define unit_list_iterate_safe_end
Definition: unitlist.h:54
void send_unit_info(struct conn_list *dest, struct unit *punit)
Send the unit to the players who need the info.
Definition: unittools.cpp:2808
void wipe_unit(struct unit *punit, enum unit_loss_reason reason, struct player *killer)
Remove the unit, and passengers if it is a carrying any.
Definition: unittools.cpp:2248
const char * unit_rule_name(const struct unit *punit)
Return the (untranslated) rule name of the unit.
Definition: unittype.cpp:1283
const struct unit_type * unit_type_get(const struct unit *punit)
Return the unit type for this unit.
Definition: unittype.cpp:114
bool utype_has_role(const struct unit_type *punittype, int role)
Return whether the given unit type has the role.
Definition: unittype.cpp:186
struct unit_class * unit_class_get(const struct unit *punit)
Returns unit class pointer for a unit.
Definition: unittype.cpp:2151
bool unit_has_type_role(const struct unit *punit, enum unit_role_id role)
Return whether the unit has the given role.
Definition: unittype.cpp:195
bool unit_has_type_flag(const struct unit *punit, enum unit_type_flag_id flag)
Return whether the unit has the given flag.
Definition: unittype.cpp:176
void * utype_ai_data(const struct unit_type *ptype, const struct ai_type *ai)
Return pointer to ai data of given unit type and ai type.
Definition: unittype.cpp:2332
@ MOVE_NONE
Definition: unittype.h:115
static bool utype_has_flag(const struct unit_type *punittype, int flag)
Definition: unittype.h:584