Skip to content

Commit

Permalink
Fix crash on placing a unit with the scenario editor
Browse files Browse the repository at this point in the history
The unit::get_ability_bool() function accessed resources::gameboard that
is not set in the editor. Now the function receives the display context
as a parameter instead.

I also fixed two crashes on editor startup in MSVC debug builds (both
caused by indexing the teams vector when there aren't any teams), and the
GUI2 unit list dialog showing wrong status icons.
  • Loading branch information
jyrkive committed Sep 6, 2016
1 parent 206096c commit 7573678
Show file tree
Hide file tree
Showing 31 changed files with 80 additions and 68 deletions.
6 changes: 3 additions & 3 deletions src/actions/create.cpp
Expand Up @@ -86,7 +86,7 @@ const std::set<std::string> get_recruits(int side, const map_location &recruit_l
local_result.insert(find_it->recruits().begin(),
find_it->recruits().end());
}
else if ( find_it->is_visible_to_team(current_team, resources::gameboard->map(), false) )
else if ( find_it->is_visible_to_team(current_team, resources::gameboard->map(), *resources::gameboard, false) )
{
// This hex is visibly occupied, so we cannot recruit here.
allow_local = false;
Expand Down Expand Up @@ -187,7 +187,7 @@ std::vector<unit_const_ptr > get_recalls(int side, const map_location &recall_lo
add_leader_filtered_recalls(find_it.get_shared_ptr(), result);
return result;
}
else if ( find_it->is_visible_to_team(resources::gameboard->teams()[side-1], resources::gameboard->map(), false) )
else if ( find_it->is_visible_to_team(resources::gameboard->teams()[side-1], resources::gameboard->map(), *resources::gameboard, false) )
{
// This hex is visibly occupied, so we cannot recall here.
allow_local = false;
Expand Down Expand Up @@ -588,7 +588,7 @@ namespace { // Helpers for place_recruit()

for ( unit_itor = units.begin(); unit_itor != units.end(); ++unit_itor ) {
if (resources::gameboard->teams()[unit_itor->side()-1].is_enemy(new_unit.side()) &&
unit_itor->is_visible_to_team(resources::gameboard->teams()[new_unit.side()-1], *map, false)) {
unit_itor->is_visible_to_team(resources::gameboard->teams()[new_unit.side()-1], *map, *resources::gameboard, false)) {
int dist = distance_between(unit_itor->get_location(),recruit_loc) - unit_itor->level();
if (dist < min_dist) {
min_dist = dist;
Expand Down
2 changes: 1 addition & 1 deletion src/actions/heal.cpp
Expand Up @@ -351,7 +351,7 @@ void calculate_healing(int side, bool update_display)
const team & viewing_team =
resources::gameboard->teams()[resources::screen->viewing_team()];
if (!resources::controller->is_skipping_replay() && update_display &&
patient.is_visible_to_team(viewing_team, resources::gameboard->map(), false) )
patient.is_visible_to_team(viewing_team, resources::gameboard->map(), *resources::gameboard, false) )
{
unit_list.push_front(heal_unit(patient, healers, healing, curing == POISON_CURE));
}
Expand Down
6 changes: 3 additions & 3 deletions src/actions/move.cpp
Expand Up @@ -427,7 +427,7 @@ namespace { // Private helpers for move_unit()

if ( neighbor_it != units.end() &&
current_team_->is_enemy(neighbor_it->side()) &&
neighbor_it->invisible(adjacent[i]) )
neighbor_it->invisible(adjacent[i], *resources::gameboard) )
{
// Ambushed!
ambushed_ = true;
Expand Down Expand Up @@ -735,7 +735,7 @@ namespace { // Private helpers for move_unit()

if ( start != begin_ ) {
// Check for being unable to leave the current hex.
if ( !move_it_->get_ability_bool("skirmisher", *start) &&
if ( !move_it_->get_ability_bool("skirmisher", *start, *resources::gameboard) &&
pathfind::enemy_zoc(*current_team_, *start, *current_team_) )
zoc_stop_ = *start;
}
Expand All @@ -758,7 +758,7 @@ namespace { // Private helpers for move_unit()
moves_left_.push_back(remaining_moves);

// Check for being unable to leave this hex.
if ( !move_it_->get_ability_bool("skirmisher", *end) &&
if ( !move_it_->get_ability_bool("skirmisher", *end, *resources::gameboard) &&
pathfind::enemy_zoc(*current_team_, *end, *current_team_) )
zoc_stop_ = *end;
}
Expand Down
4 changes: 2 additions & 2 deletions src/actions/vision.cpp
Expand Up @@ -600,7 +600,7 @@ std::vector<int> get_sides_not_seeing(const unit & target)

size_t team_size = teams.size();
for ( size_t i = 0; i != team_size; ++i)
if ( !target.is_visible_to_team(teams[i], resources::gameboard->map(), false) )
if ( !target.is_visible_to_team(teams[i], resources::gameboard->map(), *resources::gameboard, false) )
// not_see contains side numbers; i is a team index, so add 1.
not_seeing.push_back(i+1);

Expand Down Expand Up @@ -646,7 +646,7 @@ bool actor_sighted(const unit & target, const std::vector<int> * cache)
needs_event[target.side()-1] = false;
// Exclude those teams that cannot see the target.
for ( size_t i = 0; i != teams_size; ++i )
needs_event[i] = needs_event[i] && target.is_visible_to_team(teams[i], resources::gameboard->map(), false);
needs_event[i] = needs_event[i] && target.is_visible_to_team(teams[i], resources::gameboard->map(), *resources::gameboard, false);

// Cache "jamming".
std::vector< std::map<map_location, int> > jamming_cache(teams_size);
Expand Down
2 changes: 1 addition & 1 deletion src/ai/composite/goal.cpp
Expand Up @@ -302,7 +302,7 @@ void protect_goal::add_targets(std::back_insert_iterator< std::vector< target >
{
int distance = distance_between(u.get_location(), loc);
if (current_team().is_enemy(u.side()) && distance < radius_ &&
!u.invisible(u.get_location()))
!u.invisible(u.get_location(), *resources::gameboard))
{
DBG_AI_GOAL << "side " << get_side() << ": in " << goal_type << ": found threat target. " << u.get_location() << " is a threat to "<< loc << '\n';
*target_list = target(u.get_location(),
Expand Down
2 changes: 1 addition & 1 deletion src/ai/contexts.cpp
Expand Up @@ -379,7 +379,7 @@ void readonly_context_impl::calculate_moves(const unit_map& units, std::map<map_
}

// We can't see where invisible enemy units might move.
if (enemy && un_it->invisible(un_it->get_location()) && !see_all) {
if (enemy && un_it->invisible(un_it->get_location(), *resources::gameboard) && !see_all) {
continue;
}
// If it's an enemy unit, reset its moves while we do the calculations.
Expand Down
6 changes: 3 additions & 3 deletions src/ai/default/aspect_attacks.cpp
Expand Up @@ -104,7 +104,7 @@ std::shared_ptr<attacks_vector> aspect_attacks_base::analyze_targets() const
// Attack anyone who is on the enemy side,
// and who is not invisible or petrified.
if (current_team().is_enemy(j->side()) && !j->incapacitated() &&
!j->invisible(j->get_location()))
!j->invisible(j->get_location(), *resources::gameboard))
{
if (!is_allowed_enemy(*j)) {
continue;
Expand Down Expand Up @@ -288,7 +288,7 @@ void aspect_attacks_base::do_attack_analysis(
}

// No surround bonus if target is skirmisher
if (!itor->get_ability_bool("skirmisher"))
if (!itor->get_ability_bool("skirmisher", *resources::gameboard))
surround_bonus = 1.2;
}

Expand Down Expand Up @@ -360,7 +360,7 @@ int aspect_attacks_base::rate_terrain(const unit& u, const map_location& loc)
const int neutral_village_value = 10;
const int enemy_village_value = 15;

if(map_.gives_healing(terrain) && u.get_ability_bool("regenerate",loc) == false) {
if(map_.gives_healing(terrain) && u.get_ability_bool("regenerate", loc, *resources::gameboard) == false) {
rating += healing_value;
}

Expand Down
2 changes: 1 addition & 1 deletion src/ai/default/ca.cpp
Expand Up @@ -1342,7 +1342,7 @@ double get_healing_phase::evaluate()
if(u.side() == get_side() &&
(u.max_hitpoints() - u.hitpoints() >= game_config::poison_amount/2
|| u.get_state(unit::STATE_POISONED)) &&
!u.get_ability_bool("regenerate"))
!u.get_ability_bool("regenerate", *resources::gameboard))
{
// Look for the village which is the least vulnerable to enemy attack.
typedef std::multimap<map_location,map_location>::const_iterator Itor;
Expand Down
6 changes: 3 additions & 3 deletions src/ai/default/contexts.cpp
Expand Up @@ -81,7 +81,7 @@ int default_ai_context_impl::count_free_hexes_in_castle(const map_location &loc,
ret += count_free_hexes_in_castle(adj[n], checked_hexes);
if (u == units_.end()
|| (current_team().is_enemy(u->side())
&& u->invisible(adj[n]))
&& u->invisible(adj[n], *resources::gameboard))
|| ((&resources::gameboard->teams()[u->side() - 1]) == &current_team()
&& u->movement_left() > 0)) {
ret += 1;
Expand Down Expand Up @@ -109,7 +109,7 @@ int default_ai_context_impl::rate_terrain(const unit& u, const map_location& loc
const int neutral_village_value = 10;
const int enemy_village_value = 15;

if(map_.gives_healing(terrain) && u.get_ability_bool("regenerate",loc) == false) {
if(map_.gives_healing(terrain) && u.get_ability_bool("regenerate", loc, *resources::gameboard) == false) {
rating += healing_value;
}

Expand Down Expand Up @@ -228,7 +228,7 @@ std::vector<target> default_ai_context_impl::find_targets(const move_map& enemy_
for(u = units_.begin(); u != units_.end(); ++u) {
//is a visible enemy leader
if (u->can_recruit() && current_team().is_enemy(u->side())
&& !u->invisible(u->get_location())) {
&& !u->invisible(u->get_location(), *resources::gameboard)) {
assert(map_.on_board(u->get_location()));
LOG_AI << "found enemy leader (side: " << u->side() << ") target... " << u->get_location() << " with value: " << get_leader_value() << "\n";
targets.push_back(target(u->get_location(), get_leader_value(), target::TYPE::LEADER));
Expand Down
2 changes: 1 addition & 1 deletion src/ai/formula/callable_objects.cpp
Expand Up @@ -210,7 +210,7 @@ void attack_map_callable::collect_possible_attacks(std::vector<variant>& vars, m
/* if tile is occupied by friendly or petrified/invisible unit */
if (!ai_.current_team().is_enemy(unit->side()) ||
unit->incapacitated() ||
unit->invisible(unit->get_location()))
unit->invisible(unit->get_location(), *resources::gameboard))
continue;
/* add attacks with default weapon */
attack_callable* item = new attack_callable(attacker_location, attack_position, adj[n], -1);
Expand Down
3 changes: 2 additions & 1 deletion src/ai/formula/candidates.cpp
Expand Up @@ -19,6 +19,7 @@

#include "ai/formula/ai.hpp"
#include "ai/formula/candidates.hpp"
#include "game_board.hpp"
#include "log.hpp"
#include "resources.hpp"

Expand Down Expand Up @@ -164,7 +165,7 @@ void attack_candidate_action::evaluate(ai::formula_ai* ai, unit_map& units)
}
} else
{
if (ai->current_team().is_enemy(i->side()) && !i->incapacitated() && !i->invisible(i->get_location())) {
if (ai->current_team().is_enemy(i->side()) && !i->incapacitated() && !i->invisible(i->get_location(), *resources::gameboard)) {
enemy_res.push_back(variant(new unit_callable(*i)));
}
}
Expand Down
12 changes: 10 additions & 2 deletions src/display.cpp
Expand Up @@ -2102,7 +2102,9 @@ void display::draw_minimap()
draw_minimap_units();
#else
if(minimap_ == nullptr || minimap_->w > area.w || minimap_->h > area.h) {
minimap_ = image::getMinimap(area.w, area.h, get_map(), &dc_->teams()[currentTeam_], (selectedHex_.valid() && !is_blindfolded()) ? &reach_map_ : nullptr);
minimap_ = image::getMinimap(area.w, area.h, get_map(),
dc_->teams().empty() ? nullptr : &dc_->teams()[currentTeam_],
(selectedHex_.valid() && !is_blindfolded()) ? &reach_map_ : nullptr);
if(minimap_ == nullptr) {
return;
}
Expand Down Expand Up @@ -2159,7 +2161,7 @@ void display::draw_minimap_units()
for(unit_map::const_iterator u = dc_->units().begin(); u != dc_->units().end(); ++u) {
if (fogged(u->get_location()) ||
(dc_->teams()[currentTeam_].is_enemy(u->side()) &&
u->invisible(u->get_location())) ||
u->invisible(u->get_location(), *dc_)) ||
u->get_hidden()) {
continue;
}
Expand Down Expand Up @@ -2830,6 +2832,12 @@ void display::draw_invalidated() {
}
invalidated_hexes_ += invalidated_.size();

if (dc_->teams().empty())
{
// The unit drawer can't function without teams
return;
}

unit_drawer drawer = unit_drawer(*this, energy_bar_rects_);

for (const map_location& loc : invalidated_) {
Expand Down
4 changes: 2 additions & 2 deletions src/display_context.cpp
Expand Up @@ -46,7 +46,7 @@ bool display_context::would_be_discovered(const map_location & loc, int side_num
if(see_all) {
return true;
} else if (!teams()[side_num-1].fogged(u_loc)
&& !u.invisible(u_loc, true)) {
&& !u.invisible(u_loc, *this, true)) {
return true;
}
}
Expand All @@ -58,7 +58,7 @@ const unit * display_context::get_visible_unit(const map_location & loc, const t
{
if (!map().on_board(loc)) return nullptr;
const unit_map::const_iterator u = units().find(loc);
if (!u.valid() || !u->is_visible_to_team(current_team, map(), see_all)) {
if (!u.valid() || !u->is_visible_to_team(current_team, map(), *this, see_all)) {
return nullptr;
}
return &*u;
Expand Down
4 changes: 2 additions & 2 deletions src/game_board.cpp
Expand Up @@ -175,7 +175,7 @@ unit_map::iterator game_board::find_visible_unit(const map_location &loc,
{
if (!map_->on_board(loc)) return units_.end();
unit_map::iterator u = units_.find(loc);
if (!u.valid() || !u->is_visible_to_team(current_team, *map_, see_all))
if (!u.valid() || !u->is_visible_to_team(current_team, *map_, *this, see_all))
return units_.end();
return u;
}
Expand All @@ -184,7 +184,7 @@ bool game_board::has_visible_unit(const map_location & loc, const team& current_
{
if (!map_->on_board(loc)) return false;
unit_map::const_iterator u = units_.find(loc);
if (!u.valid() || !u->is_visible_to_team(current_team, *map_, see_all))
if (!u.valid() || !u->is_visible_to_team(current_team, *map_, *this, see_all))
return false;
return true;
}
Expand Down
10 changes: 6 additions & 4 deletions src/gui/dialogs/unit_list.cpp
Expand Up @@ -33,7 +33,9 @@
#include "gui/widgets/window.hpp"
#include "display.hpp"
#include "formatter.hpp"
#include "game_board.hpp"
#include "marked-up_text.hpp"
#include "resources.hpp"
#include "units/map.hpp"
#include "units/ptr.hpp"
#include "units/unit.hpp"
Expand Down Expand Up @@ -149,19 +151,19 @@ void tunit_list::pre_show(twindow& window)
// NOTE: this needs to be done *after* the row is added
// TODO: show custom statuses
if(!unit->get_state(unit::STATE_PETRIFIED)) {
find_widget<timage>(row_grid, "unit_status_slowed", false).set_visible(twidget::tvisible::invisible);
find_widget<timage>(row_grid, "unit_status_petrified", false).set_visible(twidget::tvisible::invisible);
}

if(!unit->get_state(unit::STATE_POISONED)) {
find_widget<timage>(row_grid, "unit_status_poisoned", false).set_visible(twidget::tvisible::invisible);
}

if(!unit->get_state(unit::STATE_SLOWED)) {
find_widget<timage>(row_grid, "unit_status_invisible", false).set_visible(twidget::tvisible::invisible);
find_widget<timage>(row_grid, "unit_status_slowed", false).set_visible(twidget::tvisible::invisible);
}

if(!unit->invisible(unit->get_location(), false)) {
find_widget<timage>(row_grid, "unit_status_petrified", false).set_visible(twidget::tvisible::invisible);
if(!unit->invisible(unit->get_location(), *resources::gameboard, false)) {
find_widget<timage>(row_grid, "unit_status_invisible", false).set_visible(twidget::tvisible::invisible);
}
}

Expand Down
4 changes: 2 additions & 2 deletions src/menu_events.cpp
Expand Up @@ -435,7 +435,7 @@ void menu_handler::show_enemy_moves(bool ignore_units, int side_num)

// Compute enemy movement positions
for(unit_map::iterator u = units().begin(); u != units().end(); ++u) {
bool invisible = u->invisible(u->get_location());
bool invisible = u->invisible(u->get_location(), gui_->get_disp_context());

if (teams()[side_num - 1].is_enemy(u->side()) &&
!gui_->fogged(u->get_location()) && !u->incapacitated() && !invisible)
Expand Down Expand Up @@ -1293,7 +1293,7 @@ void menu_handler::do_search(const std::string& new_search)
last_search_.begin(), last_search_.end(),
chars_equal_insensitive) != name.end()) {
if (!teams()[gui_->viewing_team()].is_enemy(ui->side()) ||
!ui->invisible(ui->get_location())) {
!ui->invisible(ui->get_location(), gui_->get_disp_context())) {
found = true;
}
}
Expand Down
6 changes: 3 additions & 3 deletions src/mouse_events.cpp
Expand Up @@ -779,7 +779,7 @@ void mouse_handler::select_hex(const map_location& hex, const bool browse, const
clicked_location.destinations.insert(hex);

for(unit_map::iterator u = pc_.gamestate().board_.units_.begin(); u != pc_.gamestate().board_.units_.end(); ++u) {
bool invisible = u->invisible(u->get_location());
bool invisible = u->invisible(u->get_location(), gui_->get_disp_context());

if (!gui_->fogged(u->get_location()) && !u->incapacitated() && !invisible)
{
Expand Down Expand Up @@ -1097,7 +1097,7 @@ void mouse_handler::show_attack_options(const unit_map::const_iterator &u)
// (Visible to current team, not necessarily the unit's team.)
if (!pc_.get_map_const().on_board(loc)) continue;
unit_map::const_iterator i = pc_.gamestate().board_.units().find(loc);
if ( !i || !i->is_visible_to_team(cur_team, pc_.gamestate().board_.map(), false) )
if ( !i || !i->is_visible_to_team(cur_team, pc_.gamestate().board_.map(), gui_->get_disp_context(), false) )
continue;
const unit &target = *i;
// Can only attack non-petrified enemies.
Expand All @@ -1119,7 +1119,7 @@ bool mouse_handler::unit_in_cycle(unit_map::const_iterator it)
return false;

if (current_team().is_enemy(int(gui().viewing_team()+1)) &&
it->invisible(it->get_location()))
it->invisible(it->get_location(), gui().get_disp_context()))
return false;

if (it->get_hidden())
Expand Down
8 changes: 4 additions & 4 deletions src/pathfind/pathfind.cpp
Expand Up @@ -401,7 +401,7 @@ static void find_routes(

if ( skirmisher && next.moves_left > 0 &&
enemy_zoc(*current_team, next_hex, *viewing_team, see_all) &&
!skirmisher->get_ability_bool("skirmisher", next_hex) ) {
!skirmisher->get_ability_bool("skirmisher", next_hex, *resources::gameboard) ) {
next.moves_left = 0;
}
}
Expand Down Expand Up @@ -656,7 +656,7 @@ marked_route mark_route(const plain_route &rt)

++turns;

bool invisible = u.invisible(*i,false);
bool invisible = u.invisible(*i, *resources::gameboard, false);

res.marks[*i] = marked_route::mark(turns, zoc, capture, invisible);

Expand All @@ -669,7 +669,7 @@ marked_route mark_route(const plain_route &rt)
}

zoc = enemy_zoc(unit_team, *(i + 1), viewing_team)
&& !u.get_ability_bool("skirmisher", *(i+1));
&& !u.get_ability_bool("skirmisher", *(i+1), *resources::gameboard);

if (zoc) {
movement = 0;
Expand Down Expand Up @@ -752,7 +752,7 @@ double shortest_path_calculator::cost(const map_location& loc, const double so_f
// check ZoC
if (!ignore_unit_ && remaining_movement != terrain_cost
&& enemy_zoc(teams_[unit_.side()-1], loc, viewing_team_, see_all_)
&& !unit_.get_ability_bool("skirmisher", loc)) {
&& !unit_.get_ability_bool("skirmisher", loc, *resources::gameboard)) {
// entering ZoC cost all remaining MP
move_cost += remaining_movement;
} else {
Expand Down
2 changes: 1 addition & 1 deletion src/pathfind/teleport.cpp
Expand Up @@ -236,7 +236,7 @@ const teleport_map get_teleport_locations(const unit &u,
{
std::vector<teleport_group> groups;

if (u.get_ability_bool("teleport")) {
if (u.get_ability_bool("teleport", *resources::gameboard)) {
for (const unit_ability & teleport : u.get_abilities("teleport")) {
const int tunnel_count = (teleport.first)->child_count("tunnel");
for(int i = 0; i < tunnel_count; ++i) {
Expand Down
2 changes: 1 addition & 1 deletion src/play_controller.cpp
Expand Up @@ -623,7 +623,7 @@ void play_controller::tab()
for (const unit& u : gamestate().board_.units()){
const map_location& loc = u.get_location();
if(!gui_->fogged(loc) &&
!(gamestate().board_.teams()[gui_->viewing_team()].is_enemy(u.side()) && u.invisible(loc)))
!(gamestate().board_.teams()[gui_->viewing_team()].is_enemy(u.side()) && u.invisible(loc, gui_->get_disp_context())))
dictionary.insert(u.name());
}
//TODO List map labels
Expand Down

0 comments on commit 7573678

Please sign in to comment.