Freeciv21
Develop your civilization from humble roots to a global empire
unit_utils.cpp
Go to the documentation of this file.
1 // SPDX-FileCopyrightText: Louis Moureaux <m_louis30@yahoo.com>
2 // SPDX-License-Identifier: GPLv3-or-later
3 
4 #include "unit_utils.h"
5 
6 #include "player.h"
7 #include "unit.h"
8 #include "unitlist.h"
9 
10 #include <algorithm>
11 
12 namespace /* anonymous */ {
16 int transport_depth(const unit *unit)
17 {
18  int depth = 0;
19  for (auto parent = unit->transporter; parent != nullptr;
20  parent = parent->transporter) {
21  depth++;
22  }
23  return depth;
24 }
25 
30 bool units_sort(const unit *lhs, const unit *rhs)
31 {
32  if (lhs == rhs) {
33  return 0;
34  }
35 
36  // Transports are shown before the units they transport.
37  if (lhs == rhs->transporter) {
38  return true;
39  } else if (lhs->transporter == rhs) {
40  return false;
41  }
42 
43  // When one unit is deeper or the two transporters are different, compare
44  // the parents instead.
45  int lhs_depth = transport_depth(lhs);
46  int rhs_depth = transport_depth(rhs);
47  if (lhs_depth > rhs_depth) {
48  return units_sort(lhs->transporter, rhs);
49  } else if (lhs_depth < rhs_depth) {
50  return units_sort(lhs, rhs->transporter);
51  } else if (lhs->transporter != rhs->transporter) {
52  return units_sort(lhs->transporter, rhs->transporter);
53  }
54 
55  // Put defensive units on the left - these are least likely to move, having
56  // them first makes the list more stable
57  const auto lhs_def = lhs->utype->defense_strength * lhs->utype->hp;
58  const auto rhs_def = rhs->utype->defense_strength * rhs->utype->hp;
59  if (lhs_def != rhs_def) {
60  return lhs_def > rhs_def;
61  }
62 
63  // More veteran units further left
64  if (lhs->veteran != rhs->veteran) {
65  return lhs->veteran > rhs->veteran;
66  }
67 
68  // Reverse order by unit type - in most ruleset this means old units last
69  if (lhs->utype != rhs->utype) {
70  return lhs->utype->item_number > rhs->utype->item_number;
71  }
72 
73  // By nationality so units from the same player are grouped together
74  if (player_index(lhs->nationality) != player_index(rhs->nationality)) {
75  return player_index(lhs->nationality) < player_index(rhs->nationality);
76  }
77 
78  // Then unit id
79  return lhs->id < rhs->id;
80 }
81 } // anonymous namespace
82 
87 std::vector<unit *> sorted(const unit_list *units)
88 {
89  std::vector<unit *> vec;
90  unit_list_iterate(units, unit) { vec.push_back(unit); }
92 
93  std::sort(vec.begin(), vec.end(), units_sort);
94 
95  return vec;
96 }
std::vector< unit * > sorted(const unit_list *units)
Returns a version of units sorted in the way the user would like to see them.
Definition: unit_utils.cpp:87
int player_index(const struct player *pplayer)
Return the player index.
Definition: player.cpp:748
Unit_type_id item_number
Definition: unittype.h:466
int defense_strength
Definition: unittype.h:480
int hp
Definition: unittype.h:489
Definition: unit.h:134
int id
Definition: unit.h:141
struct player * nationality
Definition: unit.h:140
struct unit * transporter
Definition: unit.h:180
const struct unit_type * utype
Definition: unit.h:135
int veteran
Definition: unit.h:149
#define unit_list_iterate(unitlist, punit)
Definition: unitlist.h:25
#define unit_list_iterate_end
Definition: unitlist.h:27