Freeciv21
Develop your civilization from humble roots to a global empire
aiguard.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 "unit.h"
18 
19 // server
20 #include "srv_log.h"
21 
22 // ai
23 #include "ailog.h"
24 #include "aiplayer.h"
25 #include "aiunit.h"
26 
27 #include "aiguard.h"
28 
30 
39 void aiguard_check_guard(struct ai_type *ait, const struct unit *guard)
40 {
41  struct unit_ai *guard_data = def_ai_unit_data(guard, ait);
42  const struct unit *charge_unit = game_unit_by_number(guard_data->charge);
43  const struct city *charge_city = game_city_by_number(guard_data->charge);
44  const struct player *guard_owner = unit_owner(guard);
45  const struct player *charge_owner = nullptr;
46  struct unit_ai *charge_data = nullptr;
47 
48  fc_assert_ret(BODYGUARD_NONE <= guard_data->charge);
49  // IDs always distinct
50  fc_assert_ret(charge_unit == nullptr || charge_city == nullptr);
51 
52  if (charge_unit) {
53  charge_owner = unit_owner(charge_unit);
54  charge_data = def_ai_unit_data(charge_unit, ait);
55  } else if (charge_city) {
56  charge_owner = city_owner(charge_city);
57  }
58 
59  if (charge_unit && charge_data->bodyguard != guard->id) {
60  BODYGUARD_LOG(ait, LOG_DEBUG, guard, "inconsistent guard references");
61  } else if (!charge_unit && !charge_city && 0 < guard_data->charge) {
62  BODYGUARD_LOG(ait, LOG_DEBUG, guard, "dangling guard reference");
63  }
64  if (charge_owner && pplayers_at_war(charge_owner, guard_owner)) {
65  // Probably due to civil war
66  BODYGUARD_LOG(ait, LOG_DEBUG, guard, "enemy charge");
67  } else if (charge_owner && charge_owner != guard_owner) {
68  // Probably sold a city with its supported units.
69  BODYGUARD_LOG(ait, LOG_DEBUG, guard, "foreign charge");
70  }
71 }
72 
82  const struct unit *charge)
83 {
84  struct unit_ai *charge_data = def_ai_unit_data(charge, ait);
85  const struct player *charge_owner = unit_owner(charge);
86  const struct unit *guard = game_unit_by_number(charge_data->bodyguard);
87  struct unit_ai *guard_data = nullptr;
88 
89  if (guard) {
90  guard_data = def_ai_unit_data(guard, ait);
91  }
92 
94  guard == nullptr
95  || (guard_data && BODYGUARD_WANTED <= guard_data->bodyguard));
96 
97  if (guard && guard_data->charge != charge->id) {
98  UNIT_LOG(LOG_DEBUG, charge, "inconsistent guard references");
99  } else if (guard && unit_owner(guard) != charge_owner) {
100  UNIT_LOG(LOG_DEBUG, charge, "foreign guard");
101  }
102 }
103 
109 void aiguard_clear_charge(struct ai_type *ait, struct unit *guard)
110 {
111  struct unit_ai *guard_data = def_ai_unit_data(guard, ait);
112  struct unit *charge_unit = game_unit_by_number(guard_data->charge);
113  struct city *charge_city = game_city_by_number(guard_data->charge);
114 
115  // IDs always distinct
116  fc_assert_ret(charge_unit == nullptr || charge_city == nullptr);
117 
118  if (charge_unit) {
119  BODYGUARD_LOG(ait, LOGLEVEL_BODYGUARD, guard, "unassigned (unit)");
120  def_ai_unit_data(charge_unit, ait)->bodyguard = BODYGUARD_NONE;
121  } else if (charge_city) {
122  BODYGUARD_LOG(ait, LOGLEVEL_BODYGUARD, guard, "unassigned (city)");
123  }
124  // else not assigned or charge was destroyed
125  guard_data->charge = BODYGUARD_NONE;
126 
127  CHECK_GUARD(ait, guard);
128 }
129 
138 void aiguard_clear_guard(struct ai_type *ait, struct unit *charge)
139 {
140  struct unit_ai *charge_data = def_ai_unit_data(charge, ait);
141 
142  if (0 < charge_data->bodyguard) {
143  struct unit *guard = game_unit_by_number(charge_data->bodyguard);
144 
145  if (guard) {
146  struct unit_ai *guard_data = def_ai_unit_data(guard, ait);
147 
148  if (guard_data->charge == charge->id) {
149  // charge doesn't want us anymore
150  guard_data->charge = BODYGUARD_NONE;
151  }
152  }
153  }
154 
155  charge_data->bodyguard = BODYGUARD_NONE;
156 
158 }
159 
165 void aiguard_assign_guard_unit(struct ai_type *ait, struct unit *charge,
166  struct unit *guard)
167 {
168  fc_assert_ret(nullptr != charge);
169  fc_assert_ret(nullptr != guard);
170  fc_assert_ret(charge != guard);
172 
173  // Remove previous assignment:
174  aiguard_clear_charge(ait, guard);
176 
177  def_ai_unit_data(guard, ait)->charge = charge->id;
178  def_ai_unit_data(charge, ait)->bodyguard = guard->id;
179 
180  BODYGUARD_LOG(ait, LOGLEVEL_BODYGUARD, guard, "assigned charge");
181  CHECK_GUARD(ait, guard);
183 }
184 
188 void aiguard_assign_guard_city(struct ai_type *ait, struct city *charge,
189  struct unit *guard)
190 {
191  struct unit_ai *guard_data = def_ai_unit_data(guard, ait);
192 
193  fc_assert_ret(charge != nullptr);
194  fc_assert_ret(guard != nullptr);
195  /*
196  * Usually, but not always, city_owner(charge) == unit_owner(guard).
197  */
198 
199  if (0 < guard_data->charge && guard_data->charge != charge->id) {
200  // Remove previous assignment:
201  aiguard_clear_charge(ait, guard);
202  }
203 
204  guard_data->charge = charge->id;
205  if (city_owner(charge) != unit_owner(guard)) {
206  // Peculiar, but not always an error
207  BODYGUARD_LOG(ait, LOGLEVEL_BODYGUARD, guard, "assigned foreign charge");
208  } else {
209  BODYGUARD_LOG(ait, LOGLEVEL_BODYGUARD, guard, "assigned charge");
210  }
211 
212  CHECK_GUARD(ait, guard);
213 }
214 
218 void aiguard_request_guard(struct ai_type *ait, struct unit *punit)
219 {
220  // Remove previous assignment
221  aiguard_clear_guard(ait, punit);
222 
223  UNIT_LOG(LOGLEVEL_BODYGUARD, punit, "requests a guard");
225 
226  CHECK_CHARGE_UNIT(ait, punit);
227 }
228 
232 bool aiguard_wanted(struct ai_type *ait, struct unit *charge)
233 {
236 }
237 
241 bool aiguard_has_charge(struct ai_type *ait, struct unit *guard)
242 {
243  CHECK_GUARD(ait, guard);
244  return (def_ai_unit_data(guard, ait)->charge != BODYGUARD_NONE);
245 }
246 
250 bool aiguard_has_guard(struct ai_type *ait, struct unit *charge)
251 {
253  return (0 < def_ai_unit_data(charge, ait)->bodyguard);
254 }
255 
260 struct unit *aiguard_guard_of(struct ai_type *ait, struct unit *charge)
261 {
262  CHECK_CHARGE_UNIT(ait, charge);
263  return game_unit_by_number(def_ai_unit_data(charge, ait)->bodyguard);
264 }
265 
270 struct unit *aiguard_charge_unit(struct ai_type *ait, struct unit *guard)
271 {
272  CHECK_GUARD(ait, guard);
273  return game_unit_by_number(def_ai_unit_data(guard, ait)->charge);
274 }
275 
280 struct city *aiguard_charge_city(struct ai_type *ait, struct unit *guard)
281 {
282  CHECK_GUARD(ait, guard);
283  return game_city_by_number(def_ai_unit_data(guard, ait)->charge);
284 }
285 
291 void aiguard_update_charge(struct ai_type *ait, struct unit *guard)
292 {
293  struct unit_ai *guard_data = def_ai_unit_data(guard, ait);
294  const struct unit *charge_unit = game_unit_by_number(guard_data->charge);
295  const struct city *charge_city = game_city_by_number(guard_data->charge);
296  const struct player *guard_owner = unit_owner(guard);
297  const struct player *charge_owner = nullptr;
298 
299  fc_assert_ret(BODYGUARD_NONE <= guard_data->charge);
300  // IDs always distinct
301  fc_assert_ret(charge_unit == nullptr || charge_city == nullptr);
302 
303  if (charge_unit) {
304  charge_owner = unit_owner(charge_unit);
305  } else if (charge_city) {
306  charge_owner = city_owner(charge_city);
307  }
308 
309  if (!charge_unit && !charge_city && 0 < guard_data->charge) {
310  guard_data->charge = BODYGUARD_NONE;
311  BODYGUARD_LOG(ait, LOGLEVEL_BODYGUARD, guard, "charge was destroyed");
312  }
313  if (charge_owner && charge_owner != guard_owner) {
314  BODYGUARD_LOG(ait, LOGLEVEL_BODYGUARD, guard,
315  "charge transferred, dismiss");
316  aiguard_clear_charge(ait, guard);
317  }
318 
319  CHECK_GUARD(ait, guard);
320 }
struct unit * aiguard_charge_unit(struct ai_type *ait, struct unit *guard)
Which unit (if any) has a guard been assigned to? Returns nullptr if the unit is not the guard for a ...
Definition: aiguard.cpp:270
void aiguard_clear_charge(struct ai_type *ait, struct unit *guard)
Remove the assignment of a charge to a guard.
Definition: aiguard.cpp:109
void aiguard_request_guard(struct ai_type *ait, struct unit *punit)
Request a (new) bodyguard for the unit.
Definition: aiguard.cpp:218
bool aiguard_has_guard(struct ai_type *ait, struct unit *charge)
Has a guard been assigned to a charge?
Definition: aiguard.cpp:250
void aiguard_assign_guard_unit(struct ai_type *ait, struct unit *charge, struct unit *guard)
Assign a bodyguard to a unit.
Definition: aiguard.cpp:165
bool aiguard_wanted(struct ai_type *ait, struct unit *charge)
Has a unit requested a guard and not (yet) been provided with one?
Definition: aiguard.cpp:232
void aiguard_assign_guard_city(struct ai_type *ait, struct city *charge, struct unit *guard)
Assign a guard to a city.
Definition: aiguard.cpp:188
bodyguard_enum
Definition: aiguard.cpp:29
@ BODYGUARD_NONE
Definition: aiguard.cpp:29
@ BODYGUARD_WANTED
Definition: aiguard.cpp:29
struct city * aiguard_charge_city(struct ai_type *ait, struct unit *guard)
Which city (if any) has a guard been assigned to? Returns nullptr if the unit is not a guard for a ci...
Definition: aiguard.cpp:280
void aiguard_clear_guard(struct ai_type *ait, struct unit *charge)
Remove assignment of bodyguard for a unit.
Definition: aiguard.cpp:138
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
bool aiguard_has_charge(struct ai_type *ait, struct unit *guard)
Has a charge unit been assigned to a guard?
Definition: aiguard.cpp:241
void aiguard_update_charge(struct ai_type *ait, struct unit *guard)
Check whether the assignment of a guard is still sane, and fix and problems.
Definition: aiguard.cpp:291
void aiguard_check_charge_unit(struct ai_type *ait, const struct unit *charge)
Do sanity checks on a charge, reporting error messages to the log if necessary.
Definition: aiguard.cpp:81
void aiguard_check_guard(struct ai_type *ait, const struct unit *guard)
Do sanity checks on a guard, reporting error messages to the log if necessary.
Definition: aiguard.cpp:39
#define CHECK_CHARGE_UNIT(ait, charge)
Definition: aiguard.h:17
#define CHECK_GUARD(ait, guard)
Definition: aiguard.h:16
#define BODYGUARD_LOG(ait, loglevel, punit, msg,...)
Definition: ailog.h:65
static struct unit_ai * def_ai_unit_data(const struct unit *punit, struct ai_type *deftype)
Definition: aiplayer.h:41
struct player * city_owner(const struct city *pcity)
Return the owner of the city.
Definition: city.cpp:1083
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 city * game_city_by_number(int id)
Often used function to get a city pointer from a city ID.
Definition: game.cpp:103
constexpr auto LOG_DEBUG
Definition: log.h:27
#define fc_assert_ret(condition)
Definition: log.h:112
bool pplayers_at_war(const struct player *pplayer, const struct player *pplayer2)
Returns true iff players can attack each other.
Definition: player.cpp:1317
#define UNIT_LOG(_, punit, msg,...)
Definition: srv_log.h:95
#define LOGLEVEL_BODYGUARD
Definition: srv_log.h:32
Definition: ai.h:42
Definition: city.h:291
Definition: player.h:231
Definition: aiunit.h:39
int bodyguard
Definition: aiunit.h:43
int charge
Definition: aiunit.h:44
Definition: unit.h:134
int id
Definition: unit.h:141
#define unit_owner(_pu)
Definition: unit.h:370