The Battle for Wesnoth  1.19.5+dev
display_context.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2014 - 2024
3  by Chris Beck <render787@gmail.com>
4  Part of the Battle for Wesnoth Project https://www.wesnoth.org/
5 
6  This program is free software; you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation; either version 2 of the License, or
9  (at your option) any later version.
10  This program is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY.
12 
13  See the COPYING file for more details.
14 */
15 
16 #include "display_context.hpp"
17 
18 #include "map/map.hpp"
19 #include "map/location.hpp"
20 #include "team.hpp"
21 #include "units/unit.hpp"
22 #include "units/map.hpp"
23 
24 const team& display_context::get_team(int side) const
25 {
26  return teams().at(side - 1);
27 }
28 
29 bool display_context::has_team(int side) const
30 {
31  return side > 0 && side <= static_cast<int>(teams().size());
32 }
33 
34 bool display_context::would_be_discovered(const map_location & loc, int side_num, bool see_all)
35 {
36  for(const map_location& u_loc : get_adjacent_tiles(loc)) {
37  unit_map::const_iterator u_it = units().find(u_loc);
38  if (!u_it.valid()) {
39  continue;
40  }
41  const unit & u = *u_it;
42  if (get_team(side_num).is_enemy(u.side()) && !u.incapacitated()) {
43  // Enemy spotted in adjacent tiles, check if we can see him.
44  // Watch out to call invisible with see_all=true to avoid infinite recursive calls!
45  if(see_all) {
46  return true;
47  } else if (!get_team(side_num).fogged(u_loc)
48  && !u.invisible(u_loc, true)) {
49  return true;
50  }
51  }
52  }
53  return false;
54 }
55 
56 const unit * display_context::get_visible_unit(const map_location & loc, const team &current_team, bool see_all) const
57 {
58  if (!map().on_board(loc)) return nullptr;
59  const unit_map::const_iterator u = units().find(loc);
60  if (!u.valid() || !u->is_visible_to_team(current_team, see_all)) {
61  return nullptr;
62  }
63  return &*u;
64 }
65 
66 unit_const_ptr display_context::get_visible_unit_shared_ptr(const map_location & loc, const team &current_team, bool see_all) const
67 {
68  if (!map().on_board(loc)) return nullptr;
69  const unit_map::const_iterator u = units().find(loc);
70  if (!u.valid() || !u->is_visible_to_team(current_team, see_all)) {
71  return unit_const_ptr();
72  }
73  return u.get_shared_ptr();
74 }
75 
77 {
78  if(!u.attacks_left() && u.movement_left() == 0)
79  return {false, false};
80 
81  // Units with goto commands that have already done their gotos this turn
82  // (i.e. don't have full movement left) should have red globes.
83  if(u.has_moved() && u.has_goto()) {
84  return {false, false};
85  }
86 
87  const team& current_team = get_team(u.side());
88 
89  can_move_result result = {false, false};
90  if(u.attacks_left() > 0 && !u.attacks().empty()) {
91  const auto& attacks = u.attacks();
92 
93  std::set<int> attackable_distances;
94  for (const auto& attack : attacks) {
95  for (int i = attack.min_range(); i <= attack.max_range(); ++i) {
96  attackable_distances.insert(i);
97  }
98  }
99 
100  if(!attackable_distances.empty()) {
101  int max_distance = *std::prev(attackable_distances.end());
102 
103  for (int dx = -max_distance; dx <= max_distance; ++dx) {
104  for (int dy = -max_distance; dy <= max_distance && !result.attack_here; ++dy) {
105  // Adjust for hex grid
106  int adjusted_dy = dy + floor(dx / 2.0);
107 
108  map_location locs(u.get_location().x + dx, u.get_location().y + adjusted_dy);
109  int distance = distance_between(u.get_location(), locs);
110 
111  if (attackable_distances.find(distance) == attackable_distances.end()) {
112  continue;
113  }
114  if (map().on_board(locs)) {
115  const unit_map::const_iterator i = units().find(locs);
116  if (i.valid() && !i->incapacitated() && current_team.is_enemy(i->side()) && i->is_visible_to_team(get_team(u.side()), false)) {
117  result.attack_here = true;
118  }
119  }
120  }
121  }
122  }
123  }
124  for(const map_location& adj : get_adjacent_tiles(u.get_location())) {
125  if (map().on_board(adj)) {
126  if (!result.move && u.movement_cost(map()[adj]) <= u.movement_left()) {
127  result.move = true;
128  }
129  }
130  }
131  // This should probably check if the unit can teleport too
132 
133  return result;
134 }
135 
137 {
138  if(u.user_end_turn())
139  return orb_status::moved;
140  if(u.movement_left() == u.total_movement() && u.attacks_left() == u.max_attacks())
141  return orb_status::unmoved;
142  auto can_move = unit_can_move(u);
143  if(!can_move)
144  return orb_status::moved;
145  if(can_move.move && u.attacks_left() == 0)
146  return orb_status::disengaged;
147  return orb_status::partial;
148 }
149 
151 {
152  for(const team& t : teams()) {
153  if(t.owns_village(loc)) {
154  return t.side();
155  }
156  }
157  return 0;
158 }
159 
160 /**
161  * Determine if we are an observer, by checking if every team is not locally controlled
162  */
164 {
165  for (const team &t : teams()) {
166  if (t.is_local())
167  return false;
168  }
169 
170  return true;
171 }
172 
173 // Static info getters previously declared at global scope in unit.?pp
174 
175 int display_context::side_units(int side) const
176 {
177  int res = 0;
178  for (const unit &u : units()) {
179  if (u.side() == side) ++res;
180  }
181  return res;
182 }
183 
185 {
186  int res = 0;
187  for (const unit &u : units()) {
188  if (u.side() == side) res += u.cost();
189  }
190  return res;
191 }
192 
193 int display_context::side_upkeep(int side) const
194 {
195  int res = 0;
196  for (const unit &u : units()) {
197  if (u.side() == side) res += u.upkeep();
198  }
199  return res;
200 }
201 
203  : side(tm.side())
204  , units(dc.side_units(side))
205  , upkeep(dc.side_upkeep(side))
206  , expenses(std::max<int>(0, upkeep - tm.support()))
207  , net_income(tm.total_income() - expenses)
208 {
209 }
double t
Definition: astarsearch.cpp:63
map_location prev
Definition: astarsearch.cpp:64
Abstract class for exposing game data that doesn't depend on the GUI, however which for historical re...
const team & get_team(int side) const
This getter takes a 1-based side number, not a 0-based team number.
orb_status unit_orb_status(const unit &u) const
Returns an enumurated summary of whether this unit can move and/or attack.
int village_owner(const map_location &loc) const
Given the location of a village, will return the 1-based number of the team that currently owns it,...
const unit * get_visible_unit(const map_location &loc, const team &current_team, bool see_all=false) const
bool is_observer() const
Check if we are an observer in this game.
can_move_result unit_can_move(const unit &u) const
Work out what u can do - this does not check which player's turn is currently active,...
virtual const gamemap & map() const =0
bool has_team(int side) const
int side_units(int side_num) const
Returns the number of units of the side side_num.
virtual const std::vector< team > & teams() const =0
unit_const_ptr get_visible_unit_shared_ptr(const map_location &loc, const team &current_team, bool see_all=false) const
int side_units_cost(int side_num) const
Returns the total cost of units of side side_num.
virtual const unit_map & units() const =0
bool would_be_discovered(const map_location &loc, int side_num, bool see_all=true)
Given a location and a side number, indicates whether an invisible unit of that side at that location...
int side_upkeep(int side_num) const
This class stores all the data for a single 'side' (in game nomenclature).
Definition: team.hpp:74
bool is_enemy(int n) const
Definition: team.hpp:229
unit_iterator find(std::size_t id)
Definition: map.cpp:302
This class represents a single unit of a specific type.
Definition: unit.hpp:133
std::size_t i
Definition: function.cpp:1023
bool invisible(const map_location &loc, bool see_all=true) const
Definition: unit.cpp:2579
bool user_end_turn() const
Check whether the user ended their turn.
Definition: unit.hpp:792
bool incapacitated() const
Check if the unit has been petrified.
Definition: unit.hpp:911
int cost() const
How much gold is required to recruit this unit.
Definition: unit.hpp:633
int side() const
The side this unit belongs to.
Definition: unit.hpp:343
attack_itors attacks()
Gets an iterator over this unit's attacks.
Definition: unit.hpp:933
int max_attacks() const
The maximum number of attacks this unit may perform per turn, usually 1.
Definition: unit.hpp:984
int attacks_left() const
Gets the remaining number of attacks this unit can perform this turn.
Definition: unit.hpp:1000
bool has_goto() const
Gets whether this unit has a multi-turn destination set.
Definition: unit.hpp:1429
const map_location & get_location() const
The current map location this unit is at.
Definition: unit.hpp:1404
bool has_moved() const
Checks if this unit has moved.
Definition: unit.hpp:1359
int movement_cost(const t_translation::terrain_code &terrain) const
Get the unit's movement cost on a particular terrain.
Definition: unit.hpp:1487
int movement_left() const
Gets how far a unit can move, considering the incapacitated flag.
Definition: unit.hpp:1329
int total_movement() const
The maximum moves this unit has.
Definition: unit.hpp:1313
int upkeep() const
Gets the amount of gold this unit costs a side per turn.
Definition: unit.cpp:1690
void get_adjacent_tiles(const map_location &a, map_location *res)
Function which, given a location, will place all adjacent locations in res.
Definition: location.cpp:479
std::size_t distance_between(const map_location &a, const map_location &b)
Function which gives the number of hexes between two tiles (i.e.
Definition: location.cpp:550
std::size_t size(const std::string &str)
Length in characters of a UTF-8 string.
Definition: unicode.cpp:85
orb_status
Corresponds to the colored orbs displayed above units' hp-bar and xp-bar.
Definition: orb_status.hpp:23
@ partial
There are still moves and/or attacks possible, but the unit doesn't fit in the "unmoved" status.
@ moved
All moves and possible attacks have been done.
@ unmoved
The unit still has full movement and all attacks available.
@ disengaged
The unit can move but can't attack, and wouldn't be able to attack even if it was moved to a hex adja...
std::shared_ptr< const unit > unit_const_ptr
Definition: ptr.hpp:27
bool attack_here
The unit can make an attack from the hex that it's currently on, this requires attack points and a no...
bool move
The unit can move to another hex, taking account of enemies' locations, ZoC and terrain costs vs curr...
Encapsulates the map of the game.
Definition: location.hpp:45
team_data(const display_context &dc, const team &tm)
bool valid() const
Definition: map.hpp:273
pointer get_shared_ptr() const
This is exactly the same as operator-> but it's slightly more readable, and can replace &*iter syntax...
Definition: map.hpp:217