diff --git a/src/actions/vision.cpp b/src/actions/vision.cpp index 9fa1999a02d..d1bbe275271 100644 --- a/src/actions/vision.cpp +++ b/src/actions/vision.cpp @@ -230,7 +230,7 @@ bool shroud_clearer::clear_loc(team &tm, const map_location &loc, size_t &enemy_count, size_t &friend_count, move_unit_spectator * spectator) { - gamemap &map = *resources::game_map; + const gamemap &map = resources::gameboard->map(); // This counts as clearing a tile for the return value if it is on the // board and currently fogged under shared vision. (No need to explicitly // check for shrouded since shrouded implies fogged.) diff --git a/src/ai/contexts.cpp b/src/ai/contexts.cpp index a50b039acc1..39ffae46713 100644 --- a/src/ai/contexts.cpp +++ b/src/ai/contexts.cpp @@ -242,7 +242,7 @@ readonly_context_impl::readonly_context_impl(side_context &context, const config add_known_aspect("support_villages",support_villages_); add_known_aspect("village_value",village_value_); add_known_aspect("villages_per_scout",villages_per_scout_); - keeps_.init(*resources::game_map); + keeps_.init(resources::gameboard->map()); } @@ -1002,7 +1002,7 @@ void keeps_cache::clear() } -void keeps_cache::init(gamemap &map) +void keeps_cache::init(const gamemap &map) { map_ = ↦ } @@ -1095,7 +1095,7 @@ double readonly_context_impl::power_projection(const map_location& loc, const mo map_location locs[6]; get_adjacent_tiles(loc,locs); - gamemap& map_ = *resources::game_map; + const gamemap& map_ = resources::gameboard->map(); unit_map& units_ = *resources::units; int res = 0; diff --git a/src/ai/contexts.hpp b/src/ai/contexts.hpp index 090836b8684..b51bbd35393 100644 --- a/src/ai/contexts.hpp +++ b/src/ai/contexts.hpp @@ -115,9 +115,9 @@ public: void handle_generic_event(const std::string& event_name); void clear(); const std::set& get(); - void init(gamemap &map); + void init(const gamemap &map); private: - gamemap *map_; + const gamemap *map_; std::set keeps_; }; diff --git a/src/ai/default/ai.cpp b/src/ai/default/ai.cpp index f7d1f46f783..b14e036cbd3 100644 --- a/src/ai/default/ai.cpp +++ b/src/ai/default/ai.cpp @@ -530,8 +530,8 @@ ai_default_recruitment_stage::~ai_default_recruitment_stage() void ai_default_recruitment_stage::analyze_potential_recruit_movements() { - unit_map &units_ = *resources::units; - gamemap &map_ = *resources::game_map; + const unit_map &units_ = *resources::units; + const gamemap &map_ = *resources::game_map; if(unit_movement_scores_.empty() == false || get_recruitment_ignore_bad_movement()) { diff --git a/src/ai/default/contexts.cpp b/src/ai/default/contexts.cpp index d228da7c2b3..32dafe50640 100644 --- a/src/ai/default/contexts.cpp +++ b/src/ai/default/contexts.cpp @@ -97,7 +97,7 @@ default_ai_context& default_ai_context_impl::get_default_ai_context(){ int default_ai_context_impl::rate_terrain(const unit& u, const map_location& loc) const { - gamemap &map_ = *resources::game_map; + const gamemap &map_ = *resources::game_map; const t_translation::t_terrain terrain = map_.get_terrain(loc); const int defense = u.defense_modifier(terrain); int rating = 100 - defense; @@ -132,7 +132,7 @@ std::vector default_ai_context_impl::find_targets(const move_map& enemy_ log_scope2(log_ai, "finding targets..."); unit_map &units_ = *resources::units; unit_map::iterator leader = units_.find_leader(get_side()); - gamemap &map_ = *resources::game_map; + const gamemap &map_ = *resources::game_map; std::vector teams_ = *resources::teams; const bool has_leader = leader != units_.end(); diff --git a/src/ai/testing/aspect_attacks.cpp b/src/ai/testing/aspect_attacks.cpp index 6a9b48a0957..187434e82cb 100644 --- a/src/ai/testing/aspect_attacks.cpp +++ b/src/ai/testing/aspect_attacks.cpp @@ -136,7 +136,7 @@ void aspect_attacks::do_attack_analysis( //std::cerr << "ANALYSIS " << cur_analysis.movements.size() << " >= " << get_attack_depth() << "\n"; return; } - gamemap &map_ = *resources::game_map; + const gamemap &map_ = *resources::game_map; unit_map &units_ = *resources::units; std::vector &teams_ = *resources::teams; @@ -359,7 +359,7 @@ void aspect_attacks::do_attack_analysis( int aspect_attacks::rate_terrain(const unit& u, const map_location& loc) { - gamemap &map_ = *resources::game_map; + const gamemap &map_ = *resources::game_map; const t_translation::t_terrain terrain = map_.get_terrain(loc); const int defense = u.defense_modifier(terrain); int rating = 100 - defense; diff --git a/src/ai/testing/ca.cpp b/src/ai/testing/ca.cpp index 038eaf2112a..4460956da95 100644 --- a/src/ai/testing/ca.cpp +++ b/src/ai/testing/ca.cpp @@ -64,7 +64,7 @@ double goto_phase::evaluate() // Execute goto-movements - first collect gotos in a list std::vector gotos; unit_map &units_ = *resources::units; - gamemap &map_ = *resources::game_map; + const gamemap &map_ = *resources::game_map; for(unit_map::iterator ui = units_.begin(); ui != units_.end(); ++ui) { if (ui->get_goto() == ui->get_location()) { @@ -222,9 +222,9 @@ void recruitment_phase::execute() unit_combat_scores_.clear(); unit_movement_scores_.clear(); - unit_map &units_ = *resources::units; - gamemap &map_ = *resources::game_map; - std::vector &teams_ = *resources::teams; + const unit_map &units_ = *resources::units; + const gamemap &map_ = *resources::game_map; + const std::vector &teams_ = *resources::teams; map_location start_pos = units_.find_leader(get_side())->get_location(); @@ -1046,7 +1046,7 @@ void get_villages_phase::find_villages( const bool passive_leader = get_passive_leader(); size_t min_distance = 100000; - gamemap &map_ = *resources::game_map; + const gamemap &map_ = *resources::game_map; std::vector &teams_ = *resources::teams; // When a unit is dispatched we need to make sure we don't diff --git a/src/ai/testing/ca_testing_move_to_targets.cpp b/src/ai/testing/ca_testing_move_to_targets.cpp index abb996a8016..7306fb57e64 100644 --- a/src/ai/testing/ca_testing_move_to_targets.cpp +++ b/src/ai/testing/ca_testing_move_to_targets.cpp @@ -273,7 +273,7 @@ std::pair testing_move_to_targets_phase::choose_move( raise_user_interact(); unit_map &units_ = *resources::units; - gamemap &map_ = *resources::game_map; + const gamemap &map_ = *resources::game_map; unit_map::iterator u; @@ -620,7 +620,7 @@ std::pair testing_move_to_targets_phase::choose_move( void testing_move_to_targets_phase::access_points(const move_map& srcdst, const map_location& u, const map_location& dst, std::vector& out) { unit_map &units_ = *resources::units; - gamemap &map_ = *resources::game_map; + const gamemap &map_ = *resources::game_map; const unit_map::const_iterator u_it = units_.find(u); if(u_it == units_.end()) { return; @@ -711,7 +711,7 @@ map_location testing_move_to_targets_phase::form_group(const std::vector& route, const std::set& units) { unit_map &units_ = *resources::units; - gamemap &map_ = *resources::game_map; + const gamemap &map_ = *resources::game_map; const std::vector::const_iterator itor = std::find(route.begin(),route.end(),dst); if(itor == route.end()) { @@ -813,7 +813,7 @@ bool testing_move_to_targets_phase::move_group(const map_location& dst, const st double testing_move_to_targets_phase::rate_group(const std::set& group, const std::vector& battlefield) const { unit_map &units_ = *resources::units; - gamemap &map_ = *resources::game_map; + const gamemap &map_ = *resources::game_map; double strength = 0.0; for(std::set::const_iterator i = group.begin(); i != group.end(); ++i) { diff --git a/src/game_board.cpp b/src/game_board.cpp index 8b1ff2c8cd8..16613fa2f20 100644 --- a/src/game_board.cpp +++ b/src/game_board.cpp @@ -14,10 +14,20 @@ #include "config.hpp" #include "game_board.hpp" +#include "game_preferences.hpp" +#include "log.hpp" #include "unit.hpp" +#include "utils/foreach.tpp" + #include +static lg::log_domain log_engine("enginerefac"); +#define DBG_RG LOG_STREAM(debug, log_engine) +#define LOG_RG LOG_STREAM(info, log_engine) +#define WRN_RG LOG_STREAM(warn, log_engine) +#define ERR_RG LOG_STREAM(err, log_engine) + void game_board::new_turn(int player_num) { BOOST_FOREACH (unit & i, units_) { @@ -87,6 +97,91 @@ void game_board::side_change_controller(int side_num, team::CONTROLLER ctrl, con } } +bool game_board::try_add_unit_to_recall_list(const map_location& loc, const unit& u) +{ + if(teams_[u.side()-1].persistent()) { + teams_[u.side()-1].recall_list().push_back(u); + return true; + } else { + ERR_RG << "unit with id " << u.id() << ": location (" << loc.x << "," << loc.y <<") is not on the map, and player " + << u.side() << " has no recall list.\n"; + return false; + } +} + + +boost::optional game_board::replace_map(const gamemap & newmap) { + boost::optional ret = boost::optional (); + + /* Remember the locations where a village is owned by a side. */ + std::map villages; + FOREACH(const AUTO& village, map_.villages()) { + const int owner = village_owner(village); + if(owner != -1) { + villages[village] = owner; + } + } + + for (unit_map::iterator itor = units_.begin(); itor != units_.end(); ) { + if (!newmap.on_board(itor->get_location())) { + if (!try_add_unit_to_recall_list(itor->get_location(), *itor)) { + *ret = std::string("replace_map: Cannot add a unit that would become off-map to the recall list\n"); + } + units_.erase(itor++); + } else { + ++itor; + } + } + + /* Disown villages that are no longer villages. */ + FOREACH(const AUTO& village, villages) { + if(!newmap.is_village(village.first)) { + teams_[village.second].lose_village(village.first); + } + } + + map_ = newmap; + return ret; +} + + + +void game_board::overlay_map(const gamemap & mask_map, const config & cfg, map_location loc, bool border) { + map_.overlay(mask_map, cfg, loc.x, loc.y, border); +} + +bool game_board::change_terrain(const map_location &loc, const t_translation::t_terrain &t, + gamemap::tmerge_mode mode, bool replace_if_failed) +{ + /* + * When a hex changes from a village terrain to a non-village terrain, and + * a team owned that village it loses that village. When a hex changes from + * a non-village terrain to a village terrain and there is a unit on that + * hex it does not automatically capture the village. The reason for not + * capturing villages it that there are too many choices to make; should a + * unit loose its movement points, should capture events be fired. It is + * easier to do this as wanted by the author in WML. + */ + + t_translation::t_terrain + old_t = map_.get_terrain(loc), + new_t = map_.merge_terrains(old_t, t, mode, replace_if_failed); + if (new_t == t_translation::NONE_TERRAIN) return false; + preferences::encountered_terrains().insert(new_t); + + if (map_.is_village(old_t) && !map_.is_village(new_t)) { + int owner = village_owner(loc); + if (owner != -1) + teams_[owner].lose_village(loc); + } + + map_.set_terrain(loc, new_t); + + BOOST_FOREACH(const t_translation::t_terrain &ut, map_.underlying_union_terrain(loc)) { + preferences::encountered_terrains().insert(ut); + } + return true; +} void game_board::write_config(config & cfg) const { for(std::vector::const_iterator t = teams_.begin(); t != teams_.end(); ++t) { diff --git a/src/game_board.hpp b/src/game_board.hpp index c8bc2b70ea5..bff2305fefa 100644 --- a/src/game_board.hpp +++ b/src/game_board.hpp @@ -21,6 +21,7 @@ #include "team.hpp" #include "unit_map.hpp" +#include #include class config; @@ -29,6 +30,7 @@ namespace events { class mouse_handler; } + class game_board { std::vector teams_; @@ -68,6 +70,15 @@ class game_board { void side_drop_to (int side_num, team::CONTROLLER ctrl); void side_change_controller (int side_num, team::CONTROLLER ctrl, const std::string pname = ""); + // Manipulator from actionwml + + bool try_add_unit_to_recall_list(const map_location& loc, const unit& u); + boost::optional replace_map (const gamemap & r); + void overlay_map (const gamemap & o, const config & cfg, map_location loc, bool border); + + bool change_terrain(const map_location &loc, const t_translation::t_terrain &t, + gamemap::tmerge_mode mode, bool replace_if_failed); //used only by lua + // Global accessor from unit.hpp unit_map::iterator find_visible_unit(const map_location &loc, const team& current_team, bool see_all = false); diff --git a/src/game_events/action_wml.cpp b/src/game_events/action_wml.cpp index 1bd1c3db160..ab5c927c16a 100644 --- a/src/game_events/action_wml.cpp +++ b/src/game_events/action_wml.cpp @@ -288,7 +288,7 @@ namespace { // Support functions std::vector fake_unit_path(const unit& fake_unit, const std::vector& xvals, const std::vector& yvals) { - gamemap *game_map = resources::game_map; + const gamemap *game_map = resources::game_map; std::vector path; map_location src; map_location dst; @@ -532,56 +532,8 @@ namespace { // Support functions resources::screen->invalidate_all(); } - bool try_add_unit_to_recall_list(const map_location& loc, const unit& u) - { - if((*resources::teams)[u.side()-1].persistent()) { - (*resources::teams)[u.side()-1].recall_list().push_back(u); - return true; - } else { - ERR_NG << "unit with id " << u.id() << ": location (" << loc.x << "," << loc.y <<") is not on the map, and player " - << u.side() << " has no recall list.\n"; - return false; - } - } - } // end anonymous namespace (support functions) - -void change_terrain(const map_location &loc, const t_translation::t_terrain &t, - gamemap::tmerge_mode mode, bool replace_if_failed) -{ - /* - * When a hex changes from a village terrain to a non-village terrain, and - * a team owned that village it loses that village. When a hex changes from - * a non-village terrain to a village terrain and there is a unit on that - * hex it does not automatically capture the village. The reason for not - * capturing villages it that there are too many choices to make; should a - * unit loose its movement points, should capture events be fired. It is - * easier to do this as wanted by the author in WML. - */ - - gamemap *game_map = resources::game_map; - - t_translation::t_terrain - old_t = game_map->get_terrain(loc), - new_t = game_map->merge_terrains(old_t, t, mode, replace_if_failed); - if (new_t == t_translation::NONE_TERRAIN) return; - preferences::encountered_terrains().insert(new_t); - - if (game_map->is_village(old_t) && !game_map->is_village(new_t)) { - int owner = village_owner(loc); - if (owner != -1) - (*resources::teams)[owner].lose_village(loc); - } - - game_map->set_terrain(loc, new_t); - context::screen_needs_rebuild(true); - - BOOST_FOREACH(const t_translation::t_terrain &ut, game_map->underlying_union_terrain(loc)) { - preferences::encountered_terrains().insert(ut); - } -} - void handle_deprecated_message(const config& cfg) { // Note: no need to translate the string, since only used for deprecated things. @@ -1728,19 +1680,9 @@ WML_HANDLER_FUNCTION(replace_map, /*event_info*/, cfg) * easier to do this as wanted by the author in WML. */ - gamemap *game_map = resources::game_map; - + const gamemap * game_map = resources::game_map; gamemap map(*game_map); - /* Remember the locations where a village is owned by a side. */ - std::map villages; - FOREACH(const AUTO& village, map.villages()) { - const int owner = village_owner(village); - if(owner != -1) { - villages[village] = owner; - } - } - try { if (cfg["map"].empty()) { const vconfig& map_cfg = cfg.child("map"); @@ -1748,7 +1690,7 @@ WML_HANDLER_FUNCTION(replace_map, /*event_info*/, cfg) } else map.read(cfg["map"], false); } catch(incorrect_map_format_error&) { - lg::wml_error << "replace_map: Unable to load map " << cfg["map"] << "\n"; + lg::wml_error << "replace_map: Unable to load map " << cfg["map"] << std::endl; return; } catch(twml_exception& e) { e.show(*resources::screen); @@ -1757,38 +1699,24 @@ WML_HANDLER_FUNCTION(replace_map, /*event_info*/, cfg) if (map.total_width() > game_map->total_width() || map.total_height() > game_map->total_height()) { if (!cfg["expand"].to_bool()) { - lg::wml_error << "replace_map: Map dimension(s) increase but expand is not set\n"; + lg::wml_error << "replace_map: Map dimension(s) increase but expand is not set" << std::endl; return; } } if (map.total_width() < game_map->total_width() || map.total_height() < game_map->total_height()) { if (!cfg["shrink"].to_bool()) { - lg::wml_error << "replace_map: Map dimension(s) decrease but shrink is not set\n"; + lg::wml_error << "replace_map: Map dimension(s) decrease but shrink is not set" << std::endl; return; } - unit_map *units = resources::units; - unit_map::iterator itor; - for (itor = units->begin(); itor != units->end(); ) { - if (!map.on_board(itor->get_location())) { - if (!try_add_unit_to_recall_list(itor->get_location(), *itor)) { - lg::wml_error << "replace_map: Cannot add a unit that would become off-map to the recall list\n"; - } - units->erase(itor++); - } else { - ++itor; - } - } } - /* Disown villages that are no longer villages. */ - FOREACH(const AUTO& village, villages) { - if(!map.is_village(village.first)) { - (*resources::teams)[village.second].lose_village(village.first); - } + boost::optional errmsg = resources::gameboard->replace_map(map); + + if (errmsg) { + lg::wml_error << *errmsg << std::endl; } - *game_map = map; resources::screen->reload_map(); context::screen_needs_rebuild(true); ai::manager::raise_map_changed(); @@ -2475,7 +2403,7 @@ WML_HANDLER_FUNCTION(terrain_mask, /*event_info*/, cfg) return; } bool border = cfg["border"].to_bool(); - resources::game_map->overlay(mask_map, cfg.get_parsed_config(), loc.x, loc.y, border); + resources::gameboard->overlay_map(mask_map, cfg.get_parsed_config(), loc, border); context::screen_needs_rebuild(true); } diff --git a/src/map_location.cpp b/src/map_location.cpp index 399449e12d1..ffb2c2c7e3c 100644 --- a/src/map_location.cpp +++ b/src/map_location.cpp @@ -295,7 +295,7 @@ std::vector parse_location_range(const std::string &x, const std:: std::vector res; const std::vector xvals = utils::split(x); const std::vector yvals = utils::split(y); - gamemap *map = resources::game_map; + const gamemap *map = resources::game_map; assert(map); int xmin = 1, xmax = map->w(), ymin = 1, ymax = map->h(); if (with_border) { diff --git a/src/movetype.cpp b/src/movetype.cpp index 7aa776d2db8..ff838b0a7f4 100644 --- a/src/movetype.cpp +++ b/src/movetype.cpp @@ -281,7 +281,7 @@ int movetype::terrain_info::data::calc_value( return params_.default_value; } assert(resources::game_map); - gamemap & map = *resources::game_map; + const gamemap & map = *resources::game_map; // Get a list of underlying terrains. const t_translation::t_list & underlying = params_.use_move ? diff --git a/src/resources.cpp b/src/resources.cpp index da7357a1ec0..5ddee1e5e1c 100644 --- a/src/resources.cpp +++ b/src/resources.cpp @@ -21,7 +21,7 @@ namespace resources game_config_manager *config_manager = NULL; play_controller *controller = NULL; game_data *gamedata = NULL; - gamemap *game_map = NULL; + const gamemap *game_map = NULL; LuaKernel *lua_kernel = NULL; persist_manager *persist = NULL; game_display *screen = NULL; diff --git a/src/resources.hpp b/src/resources.hpp index f7230b623c1..b8103093fd2 100644 --- a/src/resources.hpp +++ b/src/resources.hpp @@ -45,7 +45,7 @@ namespace resources extern play_controller *controller; extern game_board *gameboard; extern game_data *gamedata; - extern gamemap *game_map; + extern const gamemap *game_map; extern LuaKernel *lua_kernel; // Set by game_events::manager. extern persist_manager *persist; extern game_classification *classification; diff --git a/src/scripting/lua.cpp b/src/scripting/lua.cpp index a9c6891746f..a88e66caf3f 100644 --- a/src/scripting/lua.cpp +++ b/src/scripting/lua.cpp @@ -1288,7 +1288,12 @@ static int intf_set_terrain(lua_State *L) } } - game_events::change_terrain(map_location(x - 1, y - 1), terrain, mode, replace_if_failed); + bool result = resources::gameboard->change_terrain(map_location(x - 1, y - 1), terrain, mode, replace_if_failed); + if (result) { + resources::screen->recalculate_minimap(); + resources::screen->invalidate_all(); + resources::screen->rebuild_all(); + } return 0; } @@ -1776,7 +1781,7 @@ static int intf_find_path(lua_State *L) return luaL_argerror(L, arg - 2, "invalid location"); std::vector &teams = *resources::teams; - gamemap &map = *resources::game_map; + const gamemap &map = *resources::game_map; int viewing_side = 0; bool ignore_units = false, see_all = false, ignore_teleport = false; double stop_at = 10000;