Refactor the game map to permit exposing it to Lua via wesnoth.current.map
The method of accessing terrain on the map has drastically changed. - wesnoth.get_terrain and wesnoth.set_terrain are both deprecated - wesnoth.terrain_mask still works but is moved into the wesnoth.map module and now takes the map object as the first parameter - The map's terrain is now accessed exclusively via indexing on the map object, ie map[{x,y}] - You set terrain by assigning a terrain code; the position of ^ in the terrain code now determines the merge mode - The replace_if_failed option is now manifested as a function that converts any terrain code into a special value that, when assigned to a location on the map, uses the replace if failed logic. The map object has a few attributes in it: - width and height are the total size, including borders - playable_width and playable_height are the values returned from wesnoth.get_map_size, which is now deprecated - border_size is the third value from wesnoth.get_map_size - data converts the map to a string - Special locations are now part of the map object. The length operator is deprecated. - other than that, wesnoth.map is treated as if it were the metatable of the map object
This commit is contained in:
parent
51cf2621f7
commit
e6efc7de6c
15 changed files with 646 additions and 838 deletions
|
@ -64,4 +64,46 @@ if wesnoth.kernel_type() ~= "Application Lua Kernel" then
|
|||
return code
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if wesnoth.kernel_type() == "Game Lua Kernel" then
|
||||
wesnoth.terrain_mask = wesnoth.deprecate_api('wesnoth.terrain_mask', 'wesnoth.current.map:terrain_mask', 1, nil, function(...)
|
||||
wesnoth.current.map:terrain_mask(...)
|
||||
end)
|
||||
wesnoth.get_terrain = wesnoth.deprecate_api('wesnoth.get_terrain', 'wesnoth.current.map[loc]', 1, nil, function(x, y)
|
||||
local loc = wesnoth.map.read_location(x, y)
|
||||
if loc == nil then error('get_terrain: expected location') end
|
||||
return wesnoth.current.map[loc]
|
||||
end)
|
||||
wesnoth.set_terrain = wesnoth.deprecate_api('wesnoth.set_terrain', 'wesnoth.current.map[loc]=', 1, nil, function(...)
|
||||
local loc, n = wesnoth.map.read_location(...)
|
||||
if n == 0 then error('set_terrain: expected location') end
|
||||
local new_ter, mode, replace_if_failed = select(n + 1, ...)
|
||||
if new_ter == '' or type(new_ter) ~= 'string' then error('set_terrain: expected terrain string') end
|
||||
if replace_if_failed then
|
||||
mode = mode or 'both'
|
||||
new_ter = wesnoth.map.replace_if_failed(new_ter, mode, true)
|
||||
elseif mode == 'both' or mode == 'base' or mode == 'overlay' then
|
||||
new_ter = wesnoth.map['replace_' .. mode](new_ter)
|
||||
else
|
||||
error('set_terrain: invalid mode')
|
||||
end
|
||||
wesnoth.current.map[loc] = new_ter
|
||||
end)
|
||||
wesnoth.get_map_size = wesnoth.deprecate_api('wesnoth.get_map_size', 'wesnoth.current.map.playable_width,playable_height,border_size', 1, nil, function()
|
||||
local m = wesnoth.current.map
|
||||
return m.playable_width, m.playable_height, m.border_size
|
||||
end)
|
||||
wesnoth.special_locations = wesnoth.deprecate_api('wesnoth.special_locations', 'wesnoth.current.map:special_locations', 1, nil, setmetatable({}, {
|
||||
__index = function(_, k) return wesnoth.current.map.special_locations[k] end,
|
||||
__newindex = function(_, k, v) wesnoth.current.map.special_locations[k] = v end,
|
||||
__len = function(_)
|
||||
local n = 0
|
||||
for k,v in pairs(wesnoth.current.map.special_locations) do
|
||||
n = n + 1
|
||||
end
|
||||
return n
|
||||
end,
|
||||
__pairs = function(_) return pairs(wesnoth.current.map.special_locations) end,
|
||||
}), 'Note: the length operator has been removed')
|
||||
end
|
|
@ -241,7 +241,7 @@ std::unique_ptr<editor_action> editor_action_starting_position::perform(map_cont
|
|||
{
|
||||
std::unique_ptr<editor_action> undo;
|
||||
|
||||
const std::string* old_loc_id = mc.map().is_starting_position(loc_);
|
||||
const std::string* old_loc_id = mc.map().is_special_location(loc_);
|
||||
map_location old_loc = mc.map().special_location(loc_id_);
|
||||
|
||||
if(old_loc_id != nullptr) {
|
||||
|
@ -271,7 +271,7 @@ std::unique_ptr<editor_action> editor_action_starting_position::perform(map_cont
|
|||
|
||||
void editor_action_starting_position::perform_without_undo(map_context& mc) const
|
||||
{
|
||||
const std::string* old_id = mc.map().is_starting_position(loc_);
|
||||
const std::string* old_id = mc.map().is_special_location(loc_);
|
||||
if(old_id != nullptr) {
|
||||
mc.map().set_special_location(*old_id, map_location());
|
||||
}
|
||||
|
|
|
@ -106,7 +106,7 @@ std::unique_ptr<editor_action> mouse_action::key_event(
|
|||
|| event.key.keysym.sym == SDLK_DELETE) {
|
||||
int res = event.key.keysym.sym - '0';
|
||||
if (res > gamemap::MAX_PLAYERS || event.key.keysym.sym == SDLK_DELETE) res = 0;
|
||||
const std::string* old_id = disp.map().is_starting_position(previous_move_hex_);
|
||||
const std::string* old_id = disp.map().is_special_location(previous_move_hex_);
|
||||
if (res == 0 && old_id != nullptr) {
|
||||
a = std::make_unique<editor_action_starting_position>(map_location(), *old_id);
|
||||
} else if (res > 0 && (old_id == nullptr || *old_id == std::to_string(res))) {
|
||||
|
@ -402,7 +402,7 @@ std::unique_ptr<editor_action> mouse_action_starting_position::up_left(editor_di
|
|||
if (!disp.map().on_board(hex)) {
|
||||
return nullptr;
|
||||
}
|
||||
auto player_starting_at_hex = disp.map().is_starting_position(hex);
|
||||
auto player_starting_at_hex = disp.map().is_special_location(hex);
|
||||
|
||||
if (has_ctrl_modifier()) {
|
||||
if (player_starting_at_hex) {
|
||||
|
@ -437,7 +437,7 @@ std::unique_ptr<editor_action> mouse_action_starting_position::click_left(editor
|
|||
std::unique_ptr<editor_action> mouse_action_starting_position::up_right(editor_display& disp, int x, int y)
|
||||
{
|
||||
map_location hex = disp.hex_clicked_on(x, y);
|
||||
auto player_starting_at_hex = disp.map().is_starting_position(hex);
|
||||
auto player_starting_at_hex = disp.map().is_special_location(hex);
|
||||
if (player_starting_at_hex != nullptr) {
|
||||
return std::make_unique<editor_action_starting_position>(map_location(), *player_starting_at_hex);
|
||||
} else {
|
||||
|
|
|
@ -84,20 +84,20 @@ editor_map::~editor_map()
|
|||
void editor_map::sanity_check()
|
||||
{
|
||||
int errors = 0;
|
||||
if (total_width() != tiles_.w) {
|
||||
ERR_ED << "total_width is " << total_width() << " but tiles_.size() is " << tiles_.w << std::endl;
|
||||
if (total_width() != tiles().w) {
|
||||
ERR_ED << "total_width is " << total_width() << " but tiles().size() is " << tiles().w << std::endl;
|
||||
++errors;
|
||||
}
|
||||
if (total_height() != tiles_.h) {
|
||||
ERR_ED << "total_height is " << total_height() << " but tiles_[0].size() is " << tiles_.h << std::endl;
|
||||
if (total_height() != tiles().h) {
|
||||
ERR_ED << "total_height is " << total_height() << " but tiles()[0].size() is " << tiles().h << std::endl;
|
||||
++errors;
|
||||
}
|
||||
if (w() + 2 * border_size() != total_width()) {
|
||||
ERR_ED << "h is " << h_ << " and border_size is " << border_size() << " but total_width is " << total_width() << std::endl;
|
||||
ERR_ED << "h is " << h() << " and border_size is " << border_size() << " but total_width is " << total_width() << std::endl;
|
||||
++errors;
|
||||
}
|
||||
if (h() + 2 * border_size() != total_height()) {
|
||||
ERR_ED << "w is " << w_ << " and border_size is " << border_size() << " but total_height is " << total_height() << std::endl;
|
||||
ERR_ED << "w is " << w() << " and border_size is " << border_size() << " but total_height is " << total_height() << std::endl;
|
||||
++errors;
|
||||
}
|
||||
for (const map_location& loc : selection_) {
|
||||
|
@ -137,7 +137,7 @@ std::set<map_location> editor_map::set_starting_position_labels(display& disp)
|
|||
std::string label;
|
||||
|
||||
|
||||
for (const auto& pair : starting_positions_.left) {
|
||||
for (const auto& pair : special_locations().left) {
|
||||
|
||||
bool is_number = std::find_if(pair.first.begin(), pair.first.end(), [](char c) { return !std::isdigit(c); }) == pair.first.end();
|
||||
if (is_number) {
|
||||
|
@ -246,8 +246,8 @@ void editor_map::resize(int width, int height, int x_offset, int y_offset,
|
|||
|
||||
// fix the starting positions
|
||||
if(x_offset || y_offset) {
|
||||
for (auto it = starting_positions_.left.begin(); it != starting_positions_.left.end(); ++it) {
|
||||
starting_positions_.left.modify_data(it, [=](t_translation::coordinate & loc) { loc.add(-x_offset, -y_offset); });
|
||||
for (auto it = special_locations().left.begin(); it != special_locations().left.end(); ++it) {
|
||||
special_locations().left.modify_data(it, [=](t_translation::coordinate & loc) { loc.add(-x_offset, -y_offset); });
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -298,130 +298,122 @@ bool editor_map::same_size_as(const gamemap& other) const
|
|||
|
||||
void editor_map::expand_right(int count, const t_translation::terrain_code & filler)
|
||||
{
|
||||
t_translation::ter_map tiles_new(tiles_.w + count, tiles_.h);
|
||||
w_ += count;
|
||||
for (int x = 0, x_end = tiles_.w; x != x_end; ++x) {
|
||||
for (int y = 0, y_end = tiles_.h; y != y_end; ++y) {
|
||||
tiles_new.get(x, y) = tiles_.get(x, y);
|
||||
t_translation::ter_map tiles_new(tiles().w + count, tiles().h);
|
||||
for (int x = 0, x_end = tiles().w; x != x_end; ++x) {
|
||||
for (int y = 0, y_end = tiles().h; y != y_end; ++y) {
|
||||
tiles_new.get(x, y) = tiles().get(x, y);
|
||||
}
|
||||
}
|
||||
for (int x = tiles_.w, x_end = tiles_.w + count; x != x_end; ++x) {
|
||||
for (int y = 0, y_end = tiles_.h; y != y_end; ++y) {
|
||||
tiles_new.get(x, y) = filler == t_translation::NONE_TERRAIN ? tiles_.get(tiles_.w - 1, y) : filler;
|
||||
for (int x = tiles().w, x_end = tiles().w + count; x != x_end; ++x) {
|
||||
for (int y = 0, y_end = tiles().h; y != y_end; ++y) {
|
||||
tiles_new.get(x, y) = filler == t_translation::NONE_TERRAIN ? tiles().get(tiles().w - 1, y) : filler;
|
||||
}
|
||||
}
|
||||
tiles_ = std::move(tiles_new);
|
||||
tiles() = std::move(tiles_new);
|
||||
}
|
||||
|
||||
void editor_map::expand_left(int count, const t_translation::terrain_code & filler)
|
||||
{
|
||||
t_translation::ter_map tiles_new(tiles_.w + count, tiles_.h);
|
||||
w_ += count;
|
||||
for (int x = 0, x_end = tiles_.w; x != x_end; ++x) {
|
||||
for (int y = 0, y_end = tiles_.h; y != y_end; ++y) {
|
||||
tiles_new.get(x + count, y) = tiles_.get(x, y);
|
||||
t_translation::ter_map tiles_new(tiles().w + count, tiles().h);
|
||||
for (int x = 0, x_end = tiles().w; x != x_end; ++x) {
|
||||
for (int y = 0, y_end = tiles().h; y != y_end; ++y) {
|
||||
tiles_new.get(x + count, y) = tiles().get(x, y);
|
||||
}
|
||||
}
|
||||
for (int x = 0, x_end = count; x != x_end; ++x) {
|
||||
for (int y = 0, y_end = tiles_.h; y != y_end; ++y) {
|
||||
tiles_new.get(x, y) = filler == t_translation::NONE_TERRAIN ? tiles_.get(0, y) : filler;
|
||||
for (int y = 0, y_end = tiles().h; y != y_end; ++y) {
|
||||
tiles_new.get(x, y) = filler == t_translation::NONE_TERRAIN ? tiles().get(0, y) : filler;
|
||||
}
|
||||
}
|
||||
tiles_ = std::move(tiles_new);
|
||||
tiles() = std::move(tiles_new);
|
||||
}
|
||||
|
||||
void editor_map::expand_top(int count, const t_translation::terrain_code & filler)
|
||||
{
|
||||
t_translation::ter_map tiles_new(tiles_.w, tiles_.h + count);
|
||||
h_ += count;
|
||||
for (int x = 0, x_end = tiles_.w; x != x_end; ++x) {
|
||||
for (int y = 0, y_end = tiles_.h; y != y_end; ++y) {
|
||||
tiles_new.get(x, y + count) = tiles_.get(x, y);
|
||||
t_translation::ter_map tiles_new(tiles().w, tiles().h + count);
|
||||
for (int x = 0, x_end = tiles().w; x != x_end; ++x) {
|
||||
for (int y = 0, y_end = tiles().h; y != y_end; ++y) {
|
||||
tiles_new.get(x, y + count) = tiles().get(x, y);
|
||||
}
|
||||
}
|
||||
for (int x = 0, x_end = tiles_.w; x != x_end; ++x) {
|
||||
for (int x = 0, x_end = tiles().w; x != x_end; ++x) {
|
||||
for (int y = 0, y_end = count; y != y_end; ++y) {
|
||||
tiles_new.get(x, y) = filler == t_translation::NONE_TERRAIN ? tiles_.get(x, 0) : filler;
|
||||
tiles_new.get(x, y) = filler == t_translation::NONE_TERRAIN ? tiles().get(x, 0) : filler;
|
||||
}
|
||||
}
|
||||
tiles_ = std::move(tiles_new);
|
||||
tiles() = std::move(tiles_new);
|
||||
}
|
||||
|
||||
void editor_map::expand_bottom(int count, const t_translation::terrain_code & filler)
|
||||
{
|
||||
t_translation::ter_map tiles_new(tiles_.w, tiles_.h + count);
|
||||
h_ += count;
|
||||
for (int x = 0, x_end = tiles_.w; x != x_end; ++x) {
|
||||
for (int y = 0, y_end = tiles_.h; y != y_end; ++y) {
|
||||
tiles_new.get(x, y) = tiles_.get(x, y);
|
||||
t_translation::ter_map tiles_new(tiles().w, tiles().h + count);
|
||||
for (int x = 0, x_end = tiles().w; x != x_end; ++x) {
|
||||
for (int y = 0, y_end = tiles().h; y != y_end; ++y) {
|
||||
tiles_new.get(x, y) = tiles().get(x, y);
|
||||
}
|
||||
}
|
||||
for (int x = 0, x_end = tiles_.w; x != x_end; ++x) {
|
||||
for (int y = tiles_.h, y_end = tiles_.h + count; y != y_end; ++y) {
|
||||
tiles_new.get(x, y) = filler == t_translation::NONE_TERRAIN ? tiles_.get(x, tiles_.h - 1) : filler;
|
||||
for (int x = 0, x_end = tiles().w; x != x_end; ++x) {
|
||||
for (int y = tiles().h, y_end = tiles().h + count; y != y_end; ++y) {
|
||||
tiles_new.get(x, y) = filler == t_translation::NONE_TERRAIN ? tiles().get(x, tiles().h - 1) : filler;
|
||||
}
|
||||
}
|
||||
tiles_ = std::move(tiles_new);
|
||||
tiles() = std::move(tiles_new);
|
||||
}
|
||||
|
||||
void editor_map::shrink_right(int count)
|
||||
{
|
||||
if(count < 0 || count > tiles_.w) {
|
||||
if(count < 0 || count > tiles().w) {
|
||||
throw editor_map_operation_exception();
|
||||
}
|
||||
t_translation::ter_map tiles_new(tiles_.w - count, tiles_.h);
|
||||
t_translation::ter_map tiles_new(tiles().w - count, tiles().h);
|
||||
for (int x = 0, x_end = tiles_new.w; x != x_end; ++x) {
|
||||
for (int y = 0, y_end = tiles_new.h; y != y_end; ++y) {
|
||||
tiles_new.get(x, y) = tiles_.get(x, y);
|
||||
tiles_new.get(x, y) = tiles().get(x, y);
|
||||
}
|
||||
}
|
||||
w_ -= count;
|
||||
tiles_ = std::move(tiles_new);
|
||||
tiles() = std::move(tiles_new);
|
||||
}
|
||||
|
||||
void editor_map::shrink_left(int count)
|
||||
{
|
||||
if (count < 0 || count > tiles_.w) {
|
||||
if (count < 0 || count > tiles().w) {
|
||||
throw editor_map_operation_exception();
|
||||
}
|
||||
t_translation::ter_map tiles_new(tiles_.w - count, tiles_.h);
|
||||
t_translation::ter_map tiles_new(tiles().w - count, tiles().h);
|
||||
for (int x = 0, x_end = tiles_new.w; x != x_end; ++x) {
|
||||
for (int y = 0, y_end = tiles_new.h; y != y_end; ++y) {
|
||||
tiles_new.get(x, y) = tiles_.get(x + count, y);
|
||||
tiles_new.get(x, y) = tiles().get(x + count, y);
|
||||
}
|
||||
}
|
||||
w_ -= count;
|
||||
tiles_ = std::move(tiles_new);
|
||||
tiles() = std::move(tiles_new);
|
||||
}
|
||||
|
||||
void editor_map::shrink_top(int count)
|
||||
{
|
||||
if (count < 0 || count > tiles_.h) {
|
||||
if (count < 0 || count > tiles().h) {
|
||||
throw editor_map_operation_exception();
|
||||
}
|
||||
t_translation::ter_map tiles_new(tiles_.w, tiles_.h - count);
|
||||
t_translation::ter_map tiles_new(tiles().w, tiles().h - count);
|
||||
for (int x = 0, x_end = tiles_new.w; x != x_end; ++x) {
|
||||
for (int y = 0, y_end = tiles_new.h; y != y_end; ++y) {
|
||||
tiles_new.get(x, y) = tiles_.get(x, y + count);
|
||||
tiles_new.get(x, y) = tiles().get(x, y + count);
|
||||
}
|
||||
}
|
||||
h_ -= count;
|
||||
tiles_ = std::move(tiles_new);
|
||||
tiles() = std::move(tiles_new);
|
||||
}
|
||||
|
||||
void editor_map::shrink_bottom(int count)
|
||||
{
|
||||
if (count < 0 || count > tiles_.h) {
|
||||
if (count < 0 || count > tiles().h) {
|
||||
throw editor_map_operation_exception();
|
||||
}
|
||||
t_translation::ter_map tiles_new(tiles_.w, tiles_.h - count);
|
||||
t_translation::ter_map tiles_new(tiles().w, tiles().h - count);
|
||||
for (int x = 0, x_end = tiles_new.w; x != x_end; ++x) {
|
||||
for (int y = 0, y_end = tiles_new.h; y != y_end; ++y) {
|
||||
tiles_new.get(x, y) = tiles_.get(x, y);
|
||||
tiles_new.get(x, y) = tiles().get(x, y);
|
||||
}
|
||||
}
|
||||
h_ -= count;
|
||||
tiles_ = std::move(tiles_new);
|
||||
tiles() = std::move(tiles_new);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -337,7 +337,11 @@ bool game_board::change_terrain(
|
|||
} else if(mode_str == "overlay") {
|
||||
mode = terrain_type_data::OVERLAY;
|
||||
}
|
||||
|
||||
return change_terrain(loc, terrain, mode, replace_if_failed);
|
||||
}
|
||||
|
||||
bool game_board::change_terrain(const map_location &loc, const t_translation::terrain_code &terrain, terrain_type_data::merge_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
|
||||
|
|
|
@ -16,6 +16,8 @@
|
|||
|
||||
#include "display_context.hpp"
|
||||
#include "team.hpp"
|
||||
#include "terrain/translation.hpp"
|
||||
#include "terrain/type_data.hpp"
|
||||
#include "units/map.hpp"
|
||||
#include "units/id.hpp"
|
||||
#include <optional>
|
||||
|
@ -157,8 +159,8 @@ public:
|
|||
bool try_add_unit_to_recall_list(const map_location& loc, const unit_ptr u);
|
||||
std::optional<std::string> replace_map(const gamemap & r);
|
||||
|
||||
bool change_terrain(const map_location &loc, const std::string &t,
|
||||
const std::string & mode, bool replace_if_failed); //used only by lua and debug commands
|
||||
bool change_terrain(const map_location &loc, const std::string &t, const std::string & mode, bool replace_if_failed); //used only by lua and debug commands
|
||||
bool change_terrain(const map_location &loc, const t_translation::terrain_code &t, terrain_type_data::merge_mode& mode, bool replace_if_failed); //used only by lua and debug commands
|
||||
|
||||
// Global accessor from unit.hpp
|
||||
|
||||
|
|
136
src/map/map.cpp
136
src/map/map.cpp
|
@ -28,6 +28,7 @@
|
|||
#include "serialization/string_utils.hpp"
|
||||
#include "terrain/terrain.hpp"
|
||||
#include "terrain/type_data.hpp"
|
||||
#include "wml_exception.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <sstream>
|
||||
|
@ -101,12 +102,10 @@ void gamemap::write_terrain(const map_location &loc, config& cfg) const
|
|||
cfg["terrain"] = t_translation::write_terrain_code(get_terrain(loc));
|
||||
}
|
||||
|
||||
gamemap::gamemap(const std::string& data)
|
||||
: tiles_(1, 1)
|
||||
, tdata_()
|
||||
, villages_()
|
||||
, w_(-1)
|
||||
, h_(-1)
|
||||
gamemap::gamemap(const std::string& data):
|
||||
gamemap_base(1, 1),
|
||||
tdata_(),
|
||||
villages_()
|
||||
{
|
||||
if(const auto* gcm = game_config_manager::get()) {
|
||||
tdata_ = gcm->terrain_types();
|
||||
|
@ -119,19 +118,24 @@ gamemap::gamemap(const std::string& data)
|
|||
read(data);
|
||||
}
|
||||
|
||||
gamemap::~gamemap()
|
||||
gamemap_base::gamemap_base(int w, int h, terrain_code t)
|
||||
: tiles_(w, h, t)
|
||||
, starting_positions_()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
gamemap_base::~gamemap_base()
|
||||
{
|
||||
}
|
||||
|
||||
void gamemap::read(const std::string& data, const bool allow_invalid)
|
||||
{
|
||||
tiles_ = t_translation::ter_map();
|
||||
tiles() = t_translation::ter_map();
|
||||
villages_.clear();
|
||||
starting_positions_.clear();
|
||||
special_locations().clear();
|
||||
|
||||
if(data.empty()) {
|
||||
w_ = 0;
|
||||
h_ = 0;
|
||||
if(allow_invalid) return;
|
||||
}
|
||||
|
||||
|
@ -140,7 +144,7 @@ void gamemap::read(const std::string& data, const bool allow_invalid)
|
|||
const std::string& data_only = std::string(data, offset);
|
||||
|
||||
try {
|
||||
tiles_ = t_translation::read_game_map(data_only, starting_positions_, t_translation::coordinate{ border_size(), border_size() });
|
||||
tiles() = t_translation::read_game_map(data_only, special_locations(), t_translation::coordinate{ border_size(), border_size() });
|
||||
|
||||
} catch(const t_translation::error& e) {
|
||||
// We re-throw the error but as map error.
|
||||
|
@ -149,18 +153,13 @@ void gamemap::read(const std::string& data, const bool allow_invalid)
|
|||
}
|
||||
|
||||
// Post processing on the map
|
||||
w_ = total_width() - 2 * border_size();
|
||||
h_ = total_height() - 2 * border_size();
|
||||
//Disabled since there are callcases which pass along a valid map header but empty
|
||||
//map data. Still, loading (and actually applying) an empty map causes problems later on.
|
||||
//Other callcases which need to load a dummy map use completely empty data :(.
|
||||
//VALIDATE((w_ >= 1 && h_ >= 1), "A map needs at least 1 tile, the map cannot be loaded.");
|
||||
VALIDATE((total_width() >= 1 && total_height() >= 1), "A map needs at least 1 tile, the map cannot be loaded.");
|
||||
|
||||
for(int x = 0; x < total_width(); ++x) {
|
||||
for(int y = 0; y < total_height(); ++y) {
|
||||
|
||||
// Is the terrain valid?
|
||||
t_translation::terrain_code t = tiles_.get(x, y);
|
||||
t_translation::terrain_code t = tiles().get(x, y);
|
||||
if(tdata_->map().count(t) == 0) {
|
||||
if(!tdata_->is_known(t)) {
|
||||
std::stringstream ss;
|
||||
|
@ -173,7 +172,7 @@ void gamemap::read(const std::string& data, const bool allow_invalid)
|
|||
// Is it a village?
|
||||
if(x >= border_size() && y >= border_size()
|
||||
&& x < total_width()- border_size() && y < total_height()- border_size()
|
||||
&& tdata_->is_village(tiles_.get(x, y))) {
|
||||
&& tdata_->is_village(tiles().get(x, y))) {
|
||||
villages_.push_back(map_location(x - border_size(), y - border_size()));
|
||||
}
|
||||
}
|
||||
|
@ -209,40 +208,24 @@ int gamemap::read_header(const std::string& data)
|
|||
|
||||
std::string gamemap::write() const
|
||||
{
|
||||
return t_translation::write_game_map(tiles_, starting_positions_, t_translation::coordinate{ border_size(), border_size() }) + "\n";
|
||||
return t_translation::write_game_map(tiles(), special_locations(), t_translation::coordinate{ border_size(), border_size() }) + "\n";
|
||||
}
|
||||
|
||||
void gamemap::overlay(const gamemap& m, map_location loc, const std::vector<overlay_rule>& rules, bool m_is_odd, bool ignore_special_locations)
|
||||
{
|
||||
//the following line doesn't compile on all compiler without the 'this->'
|
||||
overlay_impl(tiles_, starting_positions_, m.tiles_, m.starting_positions_, [this](auto&&... arg) { this->set_terrain(std::forward<decltype(arg)>(arg)...); }, loc, rules, m_is_odd, ignore_special_locations);
|
||||
}
|
||||
|
||||
void gamemap::overlay_impl(
|
||||
// const but changed via set_terrain
|
||||
const t_translation::ter_map& m1,
|
||||
starting_positions& m1_st,
|
||||
const t_translation::ter_map& m2,
|
||||
const starting_positions& m2_st,
|
||||
std::function<void (const map_location&, const t_translation::terrain_code&, terrain_type_data::merge_mode, bool)> set_terrain,
|
||||
map_location loc,
|
||||
const std::vector<overlay_rule>& rules,
|
||||
bool m_is_odd,
|
||||
bool ignore_special_locations)
|
||||
void gamemap_base::overlay(const gamemap_base& m, map_location loc, const std::vector<overlay_rule>& rules, bool m_is_odd, bool ignore_special_locations)
|
||||
{
|
||||
int xpos = loc.wml_x();
|
||||
int ypos = loc.wml_y();
|
||||
|
||||
const int xstart = std::max<int>(0, -xpos);
|
||||
const int xend = std::min<int>(m2.w, m1.w -xpos);
|
||||
const int xend = std::min<int>(m.total_width(), total_width() - xpos);
|
||||
const int xoffset = xpos;
|
||||
|
||||
const int ystart_even = std::max<int>(0, -ypos);
|
||||
const int yend_even = std::min<int>(m2.h, m1.h - ypos);
|
||||
const int yend_even = std::min<int>(m.total_height(), total_height() - ypos);
|
||||
const int yoffset_even = ypos;
|
||||
|
||||
const int ystart_odd = std::max<int>(0, -ypos +(xpos & 1) -(m_is_odd ? 1 : 0));
|
||||
const int yend_odd = std::min<int>(m2.h, m1.h - ypos +(xpos & 1) -(m_is_odd ? 1 : 0));
|
||||
const int yend_odd = std::min<int>(m.total_height(), total_height() - ypos +(xpos & 1) -(m_is_odd ? 1 : 0));
|
||||
const int yoffset_odd = ypos -(xpos & 1) + (m_is_odd ? 1 : 0);
|
||||
|
||||
for(int x1 = xstart; x1 != xend; ++x1) {
|
||||
|
@ -257,8 +240,8 @@ void gamemap::overlay_impl(
|
|||
const int x2 = x1 + xoffset;
|
||||
const int y2 = y1 + yoffset;
|
||||
|
||||
const t_translation::terrain_code t = m2.get(x1,y1);
|
||||
const t_translation::terrain_code current = m1.get(x2, y2);
|
||||
const t_translation::terrain_code t = m.get_terrain({x1,y1, wml_loc()});
|
||||
const t_translation::terrain_code current = get_terrain({x2, y2, wml_loc()});
|
||||
|
||||
if(t == t_translation::FOGGED || t == t_translation::VOID_TERRAIN) {
|
||||
continue;
|
||||
|
@ -288,7 +271,7 @@ void gamemap::overlay_impl(
|
|||
}
|
||||
|
||||
if (!ignore_special_locations) {
|
||||
for(auto& pair : m2_st.left) {
|
||||
for(auto& pair : m.special_locations().left) {
|
||||
|
||||
int x = pair.second.wml_x();
|
||||
int y = pair.second.wml_y();
|
||||
|
@ -306,22 +289,22 @@ void gamemap::overlay_impl(
|
|||
int y_new = y + ((x & 1 ) ? yoffset_odd : yoffset_even);
|
||||
map_location pos_new = map_location(x_new, y_new, wml_loc());
|
||||
|
||||
m1_st.left.erase(pair.first);
|
||||
m1_st.insert(starting_positions::value_type(pair.first, t_translation::coordinate(pos_new.x, pos_new.y)));
|
||||
starting_positions_.left.erase(pair.first);
|
||||
starting_positions_.insert(location_map::value_type(pair.first, t_translation::coordinate(pos_new.x, pos_new.y)));
|
||||
}
|
||||
}
|
||||
}
|
||||
t_translation::terrain_code gamemap::get_terrain(const map_location& loc) const
|
||||
t_translation::terrain_code gamemap_base::get_terrain(const map_location& loc) const
|
||||
{
|
||||
|
||||
if(on_board_with_border(loc)) {
|
||||
return (*this)[loc];
|
||||
return tiles_.get(loc.x + border_size(), loc.y + border_size());
|
||||
}
|
||||
|
||||
return loc == map_location::null_location() ? t_translation::NONE_TERRAIN : t_translation::terrain_code();
|
||||
}
|
||||
|
||||
map_location gamemap::special_location(const std::string& id) const
|
||||
map_location gamemap_base::special_location(const std::string& id) const
|
||||
{
|
||||
auto it = starting_positions_.left.find(id);
|
||||
if (it != starting_positions_.left.end()) {
|
||||
|
@ -333,31 +316,46 @@ map_location gamemap::special_location(const std::string& id) const
|
|||
}
|
||||
}
|
||||
|
||||
map_location gamemap::starting_position(int n) const
|
||||
map_location gamemap_base::starting_position(int n) const
|
||||
{
|
||||
return special_location(std::to_string(n));
|
||||
}
|
||||
|
||||
int gamemap::num_valid_starting_positions() const
|
||||
namespace {
|
||||
bool is_number(const std::string& id) {
|
||||
return std::find_if(id.begin(), id.end(), [](char c) { return !std::isdigit(c); }) == id.end();
|
||||
}
|
||||
}
|
||||
|
||||
int gamemap_base::num_valid_starting_positions() const
|
||||
{
|
||||
int res = 0;
|
||||
for (auto pair : starting_positions_) {
|
||||
const std::string& id = pair.left;
|
||||
bool is_number = std::find_if(id.begin(), id.end(), [](char c) { return !std::isdigit(c); }) == id.end();
|
||||
if (is_number) {
|
||||
if (is_number(id)) {
|
||||
res = std::max(res, std::stoi(id));
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
const std::string* gamemap::is_starting_position(const map_location& loc) const
|
||||
int gamemap_base::is_starting_position(const map_location& loc) const
|
||||
{
|
||||
if(const std::string* locName = is_special_location(loc)) {
|
||||
if(is_number(*locName)) {
|
||||
return std::stoi(*locName);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
const std::string* gamemap_base::is_special_location(const map_location& loc) const
|
||||
{
|
||||
auto it = starting_positions_.right.find(loc);
|
||||
return it == starting_positions_.right.end() ? nullptr : &it->second;
|
||||
}
|
||||
|
||||
void gamemap::set_special_location(const std::string& id, const map_location& loc)
|
||||
void gamemap_base::set_special_location(const std::string& id, const map_location& loc)
|
||||
{
|
||||
bool valid = loc.valid();
|
||||
auto it_left = starting_positions_.left.find(id);
|
||||
|
@ -374,21 +372,21 @@ void gamemap::set_special_location(const std::string& id, const map_location& lo
|
|||
}
|
||||
}
|
||||
|
||||
void gamemap::set_starting_position(int side, const map_location& loc)
|
||||
void gamemap_base::set_starting_position(int side, const map_location& loc)
|
||||
{
|
||||
set_special_location(std::to_string(side), loc);
|
||||
}
|
||||
|
||||
bool gamemap::on_board(const map_location& loc) const
|
||||
bool gamemap_base::on_board(const map_location& loc) const
|
||||
{
|
||||
return loc.valid() && loc.x < w_ && loc.y < h_;
|
||||
return loc.valid() && loc.x < w() && loc.y < h();
|
||||
}
|
||||
|
||||
bool gamemap::on_board_with_border(const map_location& loc) const
|
||||
bool gamemap_base::on_board_with_border(const map_location& loc) const
|
||||
{
|
||||
return !tiles_.data.empty() && // tiles_ is not empty when initialized.
|
||||
loc.x >= -border_size() && loc.x < w_ + border_size() &&
|
||||
loc.y >= -border_size() && loc.y < h_ + border_size();
|
||||
loc.x >= -border_size() && loc.x < w() + border_size() &&
|
||||
loc.y >= -border_size() && loc.y < h() + border_size();
|
||||
}
|
||||
|
||||
void gamemap::set_terrain(const map_location& loc, const t_translation::terrain_code & terrain, const terrain_type_data::merge_mode mode, bool replace_if_failed) {
|
||||
|
@ -418,7 +416,7 @@ void gamemap::set_terrain(const map_location& loc, const t_translation::terrain_
|
|||
(*this)[loc] = new_terrain;
|
||||
}
|
||||
|
||||
std::vector<map_location> gamemap::parse_location_range(const std::string &x, const std::string &y,
|
||||
std::vector<map_location> gamemap_base::parse_location_range(const std::string &x, const std::string &y,
|
||||
bool with_border) const
|
||||
{
|
||||
std::vector<map_location> res;
|
||||
|
@ -463,3 +461,17 @@ std::vector<map_location> gamemap::parse_location_range(const std::string &x, co
|
|||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
std::string gamemap_base::to_string() const
|
||||
{
|
||||
return t_translation::write_game_map(tiles_, starting_positions_, { 1, 1 }) + "\n";
|
||||
}
|
||||
|
||||
const std::vector<map_location> gamemap_base::starting_positions() const {
|
||||
int n = num_valid_starting_positions();
|
||||
std::vector<map_location> res;
|
||||
for(int i = 1; i <= n; i++) {
|
||||
res.push_back(starting_position(i));
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
|
287
src/map/map.hpp
287
src/map/map.hpp
|
@ -23,6 +23,143 @@ class config;
|
|||
|
||||
//class terrain_type_data; Can't forward declare because of enum
|
||||
|
||||
// This could be moved to a separate file pair...
|
||||
class gamemap_base
|
||||
{
|
||||
public:
|
||||
using terrain_code = t_translation::terrain_code;
|
||||
using terrain_map = t_translation::ter_map;
|
||||
using location_map = t_translation::starting_positions;
|
||||
virtual ~gamemap_base();
|
||||
|
||||
/** The default border style for a map. */
|
||||
static const int default_border = 1;
|
||||
|
||||
/**
|
||||
* Maximum number of players supported.
|
||||
*
|
||||
* Warning: when you increase this, you need to add
|
||||
* more definitions to the team_colors.cfg file.
|
||||
*/
|
||||
static const int MAX_PLAYERS = 9;
|
||||
|
||||
std::string to_string() const;
|
||||
|
||||
/** Effective map width. */
|
||||
int w() const { return total_width() - 2 * border_size(); }
|
||||
|
||||
/** Effective map height. */
|
||||
int h() const { return total_height() - 2 * border_size(); }
|
||||
|
||||
/** Size of the map border. */
|
||||
int border_size() const { return default_border; }
|
||||
|
||||
/** Real width of the map, including borders. */
|
||||
int total_width() const { return tiles_.w; }
|
||||
|
||||
/** Real height of the map, including borders */
|
||||
int total_height() const { return tiles_.h; }
|
||||
|
||||
/** Tell if the map is of 0 size. */
|
||||
bool empty() const
|
||||
{
|
||||
return w() <= 0 || h() <= 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tell if a location is on the map.
|
||||
*/
|
||||
bool on_board(const map_location& loc) const;
|
||||
bool on_board_with_border(const map_location& loc) const;
|
||||
|
||||
/**
|
||||
* Clobbers over the terrain at location 'loc', with the given terrain.
|
||||
* Uses mode and replace_if_failed like merge_terrains().
|
||||
*/
|
||||
virtual void set_terrain(const map_location& loc, const terrain_code & terrain, const terrain_type_data::merge_mode mode = terrain_type_data::BOTH, bool replace_if_failed = false) = 0;
|
||||
|
||||
/**
|
||||
* Looks up terrain at a particular location.
|
||||
*
|
||||
* Hexes off the map may be looked up, and their 'emulated' terrain will
|
||||
* also be returned. This allows proper drawing of the edges of the map.
|
||||
*/
|
||||
terrain_code get_terrain(const map_location& loc) const;
|
||||
|
||||
location_map& special_locations() { return starting_positions_; }
|
||||
const location_map& special_locations() const { return starting_positions_; }
|
||||
const std::vector<map_location> starting_positions() const;
|
||||
|
||||
void set_special_location(const std::string& id, const map_location& loc);
|
||||
map_location special_location(const std::string& id) const;
|
||||
|
||||
/** Manipulate starting positions of the different sides. */
|
||||
void set_starting_position(int side, const map_location& loc);
|
||||
map_location starting_position(int side) const;
|
||||
|
||||
/** Counts the number of sides that have valid starting positions on this map */
|
||||
int num_valid_starting_positions() const;
|
||||
/** returns the side number of the side starting at position loc, 0 if no such side exists. */
|
||||
int is_starting_position(const map_location& loc) const;
|
||||
/** returns the name of the special location at position loc, null if no such location exists. */
|
||||
const std::string* is_special_location(const map_location& loc) const;
|
||||
|
||||
/** Parses ranges of locations into a vector of locations, using this map's dimensions as bounds. */
|
||||
std::vector<map_location> parse_location_range(const std::string& xvals, const std::string &yvals, bool with_border = false) const;
|
||||
|
||||
struct overlay_rule
|
||||
{
|
||||
t_translation::ter_list old_;
|
||||
t_translation::ter_list new_;
|
||||
terrain_type_data::merge_mode mode_;
|
||||
std::optional<t_translation::terrain_code> terrain_;
|
||||
bool use_old_;
|
||||
bool replace_if_failed_;
|
||||
|
||||
overlay_rule()
|
||||
: old_()
|
||||
, new_()
|
||||
, mode_(terrain_type_data::BOTH)
|
||||
, terrain_()
|
||||
, use_old_(false)
|
||||
, replace_if_failed_(false)
|
||||
{
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
/** Overlays another map onto this one at the given position. */
|
||||
void overlay(const gamemap_base& m, map_location loc, const std::vector<overlay_rule>& rules = std::vector<overlay_rule>(), bool is_odd = false, bool ignore_special_locations = false);
|
||||
|
||||
template<typename F>
|
||||
void for_each_loc(const F& f) const
|
||||
{
|
||||
for(int x = 0; x < total_width(); ++x) {
|
||||
for(int y = 0; y < total_height(); ++y) {
|
||||
f(map_location{x, y , wml_loc()});
|
||||
}
|
||||
}
|
||||
}
|
||||
//Doesn't include border.
|
||||
template<typename F>
|
||||
void for_each_walkable_loc(const F& f) const
|
||||
{
|
||||
for(int x = 0; x < w(); ++x) {
|
||||
for(int y = 0; y < h(); ++y) {
|
||||
f(map_location{x, y});
|
||||
}
|
||||
}
|
||||
}
|
||||
protected:
|
||||
gamemap_base() = default;
|
||||
gamemap_base(int w, int h, terrain_code default_ter = terrain_code());
|
||||
terrain_map& tiles() {return tiles_;}
|
||||
const terrain_map& tiles() const {return tiles_;}
|
||||
private:
|
||||
terrain_map tiles_;
|
||||
location_map starting_positions_;
|
||||
};
|
||||
|
||||
/**
|
||||
* Encapsulates the map of the game.
|
||||
*
|
||||
|
@ -30,7 +167,7 @@ class config;
|
|||
* Each type of terrain is represented by a multiletter terrain code.
|
||||
* @todo Update for new map-format.
|
||||
*/
|
||||
class gamemap
|
||||
class gamemap : public gamemap_base
|
||||
{
|
||||
public:
|
||||
|
||||
|
@ -75,115 +212,26 @@ public:
|
|||
*/
|
||||
gamemap(const std::string& data); // throw(incorrect_map_format_error)
|
||||
|
||||
virtual ~gamemap();
|
||||
|
||||
void read(const std::string& data, const bool allow_invalid = true);
|
||||
|
||||
std::string write() const;
|
||||
|
||||
struct overlay_rule
|
||||
{
|
||||
t_translation::ter_list old_;
|
||||
t_translation::ter_list new_;
|
||||
terrain_type_data::merge_mode mode_;
|
||||
std::optional<t_translation::terrain_code> terrain_;
|
||||
bool use_old_;
|
||||
bool replace_if_failed_;
|
||||
|
||||
overlay_rule()
|
||||
: old_()
|
||||
, new_()
|
||||
, mode_(terrain_type_data::BOTH)
|
||||
, terrain_()
|
||||
, use_old_(false)
|
||||
, replace_if_failed_(false)
|
||||
{
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
/** Overlays another map onto this one at the given position. */
|
||||
void overlay(const gamemap& m, map_location loc, const std::vector<overlay_rule>& rules = std::vector<overlay_rule>(), bool is_odd = false, bool ignore_special_locations = false);
|
||||
|
||||
static void overlay_impl(
|
||||
// const but changed via set_terrain
|
||||
const t_translation::ter_map& m1,
|
||||
t_translation::starting_positions& m1_st,
|
||||
const t_translation::ter_map& m2,
|
||||
const t_translation::starting_positions& m2_st,
|
||||
std::function<void (const map_location&, const t_translation::terrain_code&, terrain_type_data::merge_mode, bool)> set_terrain,
|
||||
map_location loc,
|
||||
const std::vector<overlay_rule>& rules,
|
||||
bool is_odd,
|
||||
bool ignore_special_locations);
|
||||
|
||||
/** Effective map width, in hexes. */
|
||||
int w() const { return w_; }
|
||||
|
||||
/** Effective map height, in hexes. */
|
||||
int h() const { return h_; }
|
||||
|
||||
/** Size of the map border. */
|
||||
int border_size() const { return default_border; }
|
||||
|
||||
/** Real width of the map, including borders. */
|
||||
int total_width() const { return tiles_.w; }
|
||||
|
||||
/** Real height of the map, including borders */
|
||||
int total_height() const { return tiles_.h; }
|
||||
|
||||
const t_translation::terrain_code operator[](const map_location& loc) const
|
||||
{
|
||||
return tiles_.get(loc.x + border_size(), loc.y + border_size());
|
||||
return tiles().get(loc.x + border_size(), loc.y + border_size());
|
||||
}
|
||||
private:
|
||||
//private method, use set_terrain instead which also updates villages_.
|
||||
t_translation::terrain_code& operator[](const map_location& loc)
|
||||
{
|
||||
return tiles_.get(loc.x + border_size(), loc.y + border_size());
|
||||
return tiles().get(loc.x + border_size(), loc.y + border_size());
|
||||
}
|
||||
public:
|
||||
|
||||
/**
|
||||
* Looks up terrain at a particular location.
|
||||
*
|
||||
* Hexes off the map may be looked up, and their 'emulated' terrain will
|
||||
* also be returned. This allows proper drawing of the edges of the map.
|
||||
*/
|
||||
t_translation::terrain_code get_terrain(const map_location& loc) const;
|
||||
void set_terrain(const map_location& loc, const terrain_code & terrain, const terrain_type_data::merge_mode mode = terrain_type_data::BOTH, bool replace_if_failed = false) override;
|
||||
|
||||
/** Writes the terrain at loc to cfg. */
|
||||
void write_terrain(const map_location &loc, config& cfg) const;
|
||||
|
||||
|
||||
/** Manipulate starting positions of the different sides. */
|
||||
void set_starting_position(int side, const map_location& loc);
|
||||
map_location starting_position(int side) const;
|
||||
|
||||
void set_special_location(const std::string& id, const map_location& loc);
|
||||
map_location special_location(const std::string& id) const;
|
||||
|
||||
|
||||
/** returns the side number of the side starting at position loc, 0 if no such side exists. */
|
||||
const std::string* is_starting_position(const map_location& loc) const;
|
||||
int num_valid_starting_positions() const;
|
||||
|
||||
|
||||
/**
|
||||
* Tell if a location is on the map.
|
||||
*
|
||||
* Should be called before indexing using [].
|
||||
* @todo inline for performance? -- Ilor
|
||||
*/
|
||||
bool on_board(const map_location& loc) const;
|
||||
bool on_board_with_border(const map_location& loc) const;
|
||||
|
||||
/** Tell if the map is of 0 size. */
|
||||
bool empty() const
|
||||
{
|
||||
return w_ == 0 || h_ == 0;
|
||||
}
|
||||
|
||||
/** Return a list of the locations of villages on the map. */
|
||||
const std::vector<map_location>& villages() const { return villages_; }
|
||||
|
||||
|
@ -193,55 +241,6 @@ public:
|
|||
/** Gets the list of terrains. */
|
||||
const t_translation::ter_list& get_terrain_list() const;
|
||||
|
||||
/**
|
||||
* Clobbers over the terrain at location 'loc', with the given terrain.
|
||||
* Uses mode and replace_if_failed like merge_terrains().
|
||||
*/
|
||||
void set_terrain(const map_location& loc, const t_translation::terrain_code & terrain, const terrain_type_data::merge_mode mode=terrain_type_data::BOTH, bool replace_if_failed = false);
|
||||
|
||||
/**
|
||||
* Maximum number of players supported.
|
||||
*
|
||||
* Warning: when you increase this, you need to add
|
||||
* more definitions to the team_colors.cfg file.
|
||||
*/
|
||||
enum { MAX_PLAYERS = 9 };
|
||||
|
||||
/** The default border style for a map. */
|
||||
static const int default_border = 1;
|
||||
|
||||
/** Parses ranges of locations into a vector of locations, using this map's dimensions as bounds. */
|
||||
std::vector<map_location> parse_location_range(const std::string& xvals,
|
||||
const std::string &yvals, bool with_border = false) const;
|
||||
|
||||
using starting_positions = t_translation::starting_positions;
|
||||
const starting_positions& special_locations() const { return starting_positions_; }
|
||||
|
||||
template<typename F>
|
||||
void for_each_loc(const F& f) const
|
||||
{
|
||||
for (int x = -border_size(); x < w() + border_size(); ++x) {
|
||||
for (int y = -border_size(); y < h() + border_size(); ++y) {
|
||||
f({ x, y });
|
||||
}
|
||||
}
|
||||
}
|
||||
//Doesn't include border.
|
||||
template<typename F>
|
||||
void for_each_walkable_loc(const F& f) const
|
||||
{
|
||||
for (int x = 0; x < w(); ++x) {
|
||||
for (int y = 0; y < h(); ++y) {
|
||||
f({ x, y });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
t_translation::ter_map tiles_;
|
||||
|
||||
starting_positions starting_positions_;
|
||||
|
||||
private:
|
||||
|
||||
/**
|
||||
|
@ -255,8 +254,4 @@ private:
|
|||
|
||||
protected:
|
||||
std::vector<map_location> villages_;
|
||||
|
||||
/** Sizes of the map area. */
|
||||
int w_;
|
||||
int h_;
|
||||
};
|
||||
|
|
|
@ -79,6 +79,7 @@
|
|||
#include "scripting/lua_pathfind_cost_calculator.hpp"
|
||||
#include "scripting/lua_race.hpp"
|
||||
#include "scripting/lua_team.hpp"
|
||||
#include "scripting/lua_terrainmap.hpp"
|
||||
#include "scripting/lua_unit_type.hpp"
|
||||
#include "scripting/push_check.hpp"
|
||||
#include "synced_commands.hpp"
|
||||
|
@ -211,83 +212,6 @@ std::vector<int> game_lua_kernel::get_sides_vector(const vconfig& cfg)
|
|||
return filter.get_teams();
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int special_locations_len(lua_State *L)
|
||||
{
|
||||
lua_pushnumber(L, lua_kernel_base::get_lua_kernel<game_lua_kernel>(L).map().special_locations().size());
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int special_locations_next(lua_State *L)
|
||||
{
|
||||
const t_translation::starting_positions::left_map& left = lua_kernel_base::get_lua_kernel<game_lua_kernel>(L).map().special_locations().left;
|
||||
|
||||
t_translation::starting_positions::left_const_iterator it;
|
||||
if (lua_isnoneornil(L, 2)) {
|
||||
it = left.begin();
|
||||
}
|
||||
else {
|
||||
it = left.find(luaL_checkstring(L, 2));
|
||||
if (it == left.end()) {
|
||||
return 0;
|
||||
}
|
||||
++it;
|
||||
}
|
||||
if (it == left.end()) {
|
||||
return 0;
|
||||
}
|
||||
lua_pushstring(L, it->first.c_str());
|
||||
luaW_pushlocation(L, it->second);
|
||||
return 2;
|
||||
}
|
||||
|
||||
static int special_locations_pairs(lua_State *L)
|
||||
{
|
||||
lua_pushcfunction(L, &special_locations_next);
|
||||
lua_pushvalue(L, -2);
|
||||
lua_pushnil(L);
|
||||
return 3;
|
||||
}
|
||||
|
||||
static int special_locations_index(lua_State *L)
|
||||
{
|
||||
const t_translation::starting_positions::left_map& left = lua_kernel_base::get_lua_kernel<game_lua_kernel>(L).map().special_locations().left;
|
||||
auto it = left.find(luaL_checkstring(L, 2));
|
||||
if (it == left.end()) {
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
luaW_pushlocation(L, it->second);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
static int special_locations_newindex(lua_State *L)
|
||||
{
|
||||
lua_pushstring(L, "special locations cannot be modified using wesnoth.special_locations");
|
||||
return lua_error(L);
|
||||
}
|
||||
|
||||
static void push_locations_table(lua_State *L)
|
||||
{
|
||||
lua_newtable(L); // The functor table
|
||||
lua_newtable(L); // The functor metatable
|
||||
lua_pushstring(L, "__len");
|
||||
lua_pushcfunction(L, &special_locations_len);
|
||||
lua_rawset(L, -3);
|
||||
lua_pushstring(L, "__index");
|
||||
lua_pushcfunction(L, &special_locations_index);
|
||||
lua_rawset(L, -3);
|
||||
lua_pushstring(L, "__newindex");
|
||||
lua_pushcfunction(L, &special_locations_newindex);
|
||||
lua_rawset(L, -3);
|
||||
lua_pushstring(L, "__pairs");
|
||||
lua_pushcfunction(L, &special_locations_pairs);
|
||||
lua_rawset(L, -3);
|
||||
lua_setmetatable(L, -2); // Apply the metatable to the functor table
|
||||
}
|
||||
|
||||
namespace {
|
||||
/**
|
||||
* Temporary entry to a queued_event stack
|
||||
|
@ -939,150 +863,6 @@ int game_lua_kernel::intf_lock_view(lua_State *L)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a terrain code.
|
||||
* - Arg 1: map location.
|
||||
* - Ret 1: string.
|
||||
*/
|
||||
int game_lua_kernel::intf_get_terrain(lua_State *L)
|
||||
{
|
||||
map_location loc = luaW_checklocation(L, 1);
|
||||
|
||||
const t_translation::terrain_code& t = board().map().
|
||||
get_terrain(loc);
|
||||
lua_pushstring(L, t_translation::write_terrain_code(t).c_str());
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a terrain code.
|
||||
* - Arg 1: map location.
|
||||
* - Arg 2: terrain code string.
|
||||
* - Arg 3: layer: (overlay|base|both, default=both)
|
||||
* - Arg 4: replace_if_failed, default = no
|
||||
*/
|
||||
int game_lua_kernel::intf_set_terrain(lua_State *L)
|
||||
{
|
||||
map_location loc = luaW_checklocation(L, 1);
|
||||
std::string t_str(luaL_checkstring(L, 2));
|
||||
|
||||
std::string mode_str = "both";
|
||||
bool replace_if_failed = false;
|
||||
if (!lua_isnone(L, 3)) {
|
||||
if (!lua_isnil(L, 3)) {
|
||||
mode_str = luaL_checkstring(L, 3);
|
||||
}
|
||||
|
||||
if(!lua_isnoneornil(L, 4)) {
|
||||
replace_if_failed = luaW_toboolean(L, 4);
|
||||
}
|
||||
}
|
||||
|
||||
bool result = board().change_terrain(loc, t_str, mode_str, replace_if_failed);
|
||||
|
||||
if (game_display_) {
|
||||
game_display_->needs_rebuild(result);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reaplces part of the map.
|
||||
* - Arg 1: map location.
|
||||
* - Arg 2: map data string.
|
||||
* - Arg 3: table for optional named arguments
|
||||
* - is_odd: boolen, if Arg2 has the odd mapo format (as if it was cut from a odd map location)
|
||||
* - ignore_special_locations: boolean
|
||||
* - rules: table of tables
|
||||
*/
|
||||
int game_lua_kernel::intf_terrain_mask(lua_State *L)
|
||||
{
|
||||
map_location loc = luaW_checklocation(L, 1);
|
||||
std::string t_str(luaL_checkstring(L, 2));
|
||||
bool is_odd = false;
|
||||
bool ignore_special_locations = false;
|
||||
std::vector<gamemap::overlay_rule> rules;
|
||||
|
||||
if(lua_istable(L, 3)) {
|
||||
if(luaW_tableget(L, 3, "is_odd")) {
|
||||
is_odd = luaW_toboolean(L, -1);
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
if(luaW_tableget(L, 3, "ignore_special_locations")) {
|
||||
ignore_special_locations = luaW_toboolean(L, -1);
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
if(luaW_tableget(L, 3, "rules")) {
|
||||
//todo: reduce code dublication by using read_rules_vector.
|
||||
if(!lua_istable(L, -1)) {
|
||||
return luaL_argerror(L, 3, "rules must be a table");
|
||||
}
|
||||
|
||||
for (int i = 1, i_end = lua_rawlen(L, -1); i <= i_end; ++i)
|
||||
{
|
||||
lua_rawgeti(L, -1, i);
|
||||
if(!lua_istable(L, -1)) {
|
||||
return luaL_argerror(L, 3, "rules must be a table of tables");
|
||||
}
|
||||
rules.push_back(gamemap::overlay_rule());
|
||||
auto& rule = rules.back();
|
||||
if(luaW_tableget(L, -1, "old")) {
|
||||
rule.old_ = t_translation::read_list(luaW_tostring(L, -1));
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
|
||||
if(luaW_tableget(L, -1, "new")) {
|
||||
rule.new_ = t_translation::read_list(luaW_tostring(L, -1));
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
|
||||
if(luaW_tableget(L, -1, "layer")) {
|
||||
auto str = luaW_tostring(L, -1);
|
||||
rule.mode_ = str == "base" ? terrain_type_data::BASE : (str == "overlay" ? terrain_type_data::OVERLAY : terrain_type_data::BOTH);
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
|
||||
if(luaW_tableget(L, -1, "terrain")) {
|
||||
const t_translation::ter_list terrain = t_translation::read_list(luaW_tostring(L, -1));
|
||||
if(!terrain.empty()) {
|
||||
rule.terrain_ = terrain[0];
|
||||
}
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
|
||||
if(luaW_tableget(L, -1, "use_old")) {
|
||||
rule.use_old_ = luaW_toboolean(L, -1);
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
|
||||
if(luaW_tableget(L, -1, "replace_if_failed")) {
|
||||
rule.replace_if_failed_ = luaW_toboolean(L, -1);
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
gamemap mask_map("");
|
||||
mask_map.read(t_str, false);
|
||||
board().map().overlay(mask_map, loc, rules, is_odd, ignore_special_locations);
|
||||
|
||||
for(team& t : board().teams()) {
|
||||
t.fix_villages(board().map());
|
||||
}
|
||||
|
||||
if (game_display_) {
|
||||
game_display_->needs_rebuild(true);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets details about a terrain.
|
||||
* - Arg 1: terrain code string.
|
||||
|
@ -1272,22 +1052,6 @@ int game_lua_kernel::intf_set_village_owner(lua_State *L)
|
|||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the map size.
|
||||
* - Ret 1: width.
|
||||
* - Ret 2: height.
|
||||
* - Ret 3: border size.
|
||||
*/
|
||||
int game_lua_kernel::intf_get_map_size(lua_State *L)
|
||||
{
|
||||
const gamemap &map = board().map();
|
||||
lua_pushinteger(L, map.w());
|
||||
lua_pushinteger(L, map.h());
|
||||
lua_pushinteger(L, map.border_size());
|
||||
return 3;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the currently overed tile.
|
||||
* - Ret 1: x.
|
||||
|
@ -1468,6 +1232,10 @@ int game_lua_kernel::impl_current_get(lua_State *L)
|
|||
return_int_attrib("turn", play_controller_.turn());
|
||||
return_string_attrib("synced_state", synced_state());
|
||||
return_bool_attrib("user_can_invoke_commands", !play_controller_.is_lingering() && play_controller_.gamestate().init_side_done() && !events::commands_disabled && gamedata().phase() == game_data::PLAY);
|
||||
|
||||
if(strcmp(m, "map") == 0) {
|
||||
return intf_terrainmap_get(L);
|
||||
}
|
||||
|
||||
if (strcmp(m, "event_context") == 0)
|
||||
{
|
||||
|
@ -4235,9 +4003,7 @@ game_lua_kernel::game_lua_kernel(game_state & gs, play_controller & pc, reports
|
|||
{ "get_all_vars", &dispatch<&game_lua_kernel::intf_get_all_vars > },
|
||||
{ "get_end_level_data", &dispatch<&game_lua_kernel::intf_get_end_level_data > },
|
||||
{ "get_locations", &dispatch<&game_lua_kernel::intf_get_locations > },
|
||||
{ "get_map_size", &dispatch<&game_lua_kernel::intf_get_map_size > },
|
||||
{ "get_sound_source", &dispatch<&game_lua_kernel::intf_get_sound_source > },
|
||||
{ "get_terrain", &dispatch<&game_lua_kernel::intf_get_terrain > },
|
||||
{ "get_terrain_info", &dispatch<&game_lua_kernel::intf_get_terrain_info > },
|
||||
{ "get_time_of_day", &dispatch<&game_lua_kernel::intf_get_time_of_day > },
|
||||
{ "get_max_liminal_bonus", &dispatch<&game_lua_kernel::intf_get_max_liminal_bonus > },
|
||||
|
@ -4266,13 +4032,11 @@ game_lua_kernel::game_lua_kernel(game_state & gs, play_controller & pc, reports
|
|||
{ "set_end_campaign_text", &dispatch<&game_lua_kernel::intf_set_end_campaign_text > },
|
||||
{ "create_side", &dispatch<&game_lua_kernel::intf_create_side > },
|
||||
{ "set_next_scenario", &dispatch<&game_lua_kernel::intf_set_next_scenario > },
|
||||
{ "set_terrain", &dispatch<&game_lua_kernel::intf_set_terrain > },
|
||||
{ "set_variable", &dispatch<&game_lua_kernel::intf_set_variable > },
|
||||
{ "set_village_owner", &dispatch<&game_lua_kernel::intf_set_village_owner > },
|
||||
{ "simulate_combat", &dispatch<&game_lua_kernel::intf_simulate_combat > },
|
||||
{ "synchronize_choice", &intf_synchronize_choice },
|
||||
{ "synchronize_choices", &intf_synchronize_choices },
|
||||
{ "terrain_mask", &dispatch<&game_lua_kernel::intf_terrain_mask > },
|
||||
{ "teleport", &dispatch<&game_lua_kernel::intf_teleport > },
|
||||
{ "place_shroud", &dispatch2<&game_lua_kernel::intf_shroud_op, true > },
|
||||
{ "remove_shroud", &dispatch2<&game_lua_kernel::intf_shroud_op, false > },
|
||||
|
@ -4317,6 +4081,9 @@ game_lua_kernel::game_lua_kernel(game_state & gs, play_controller & pc, reports
|
|||
// Create the unit_types table
|
||||
cmd_log_ << lua_unit_type::register_table(L);
|
||||
|
||||
// Create the unit_types table
|
||||
cmd_log_ << lua_terrainmap::register_metatables(L, false);
|
||||
|
||||
// Create the ai elements table.
|
||||
cmd_log_ << "Adding ai elements table...\n";
|
||||
|
||||
|
@ -4341,6 +4108,14 @@ game_lua_kernel::game_lua_kernel(game_state & gs, play_controller & pc, reports
|
|||
lua_pushcfunction(L, &lua_common::intf_tovconfig);
|
||||
lua_setfield(L, -2, "tovconfig");
|
||||
lua_pop(L, 1);
|
||||
|
||||
// Add replace_if_failed to the map module
|
||||
luaW_getglobal(L, "wesnoth", "map");
|
||||
lua_pushcfunction(L, &intf_replace_if_failed);
|
||||
lua_setfield(L, -2, "replace_if_failed");
|
||||
lua_pushcfunction(L, &intf_terrain_mask);
|
||||
lua_setfield(L, -2, "terrain_mask");
|
||||
lua_pop(L, 1);
|
||||
|
||||
// Create the units module
|
||||
cmd_log_ << "Adding units module...\n";
|
||||
|
@ -4480,8 +4255,6 @@ game_lua_kernel::game_lua_kernel(game_state & gs, play_controller & pc, reports
|
|||
lua_getglobal(L, "wesnoth");
|
||||
lua_newtable(L);
|
||||
lua_setfield(L, -2, "game_events");
|
||||
push_locations_table(L);
|
||||
lua_setfield(L, -2, "special_locations");
|
||||
lua_pop(L, 1);
|
||||
|
||||
// Create the theme_items table.
|
||||
|
|
|
@ -92,9 +92,6 @@ class game_lua_kernel : public lua_kernel_base
|
|||
int intf_unit_ability(lua_State *L);
|
||||
int intf_view_locked(lua_State *L);
|
||||
int intf_lock_view(lua_State *L);
|
||||
int intf_get_terrain(lua_State *L);
|
||||
int intf_set_terrain(lua_State *L);
|
||||
int intf_terrain_mask(lua_State *L);
|
||||
int intf_get_terrain_info(lua_State *L);
|
||||
int intf_get_time_of_day(lua_State *L);
|
||||
int intf_get_max_liminal_bonus(lua_State *L);
|
||||
|
|
|
@ -199,7 +199,7 @@ class filter_impl
|
|||
{
|
||||
public:
|
||||
filter_impl() {};
|
||||
virtual bool matches(const mapgen_gamemap& m, map_location l) = 0;
|
||||
virtual bool matches(const gamemap_base& m, map_location l) = 0;
|
||||
virtual ~filter_impl() {};
|
||||
};
|
||||
|
||||
|
@ -234,7 +234,7 @@ public:
|
|||
LOG_LMG << "created and filter\n";
|
||||
}
|
||||
|
||||
bool matches(const mapgen_gamemap& m, map_location l) override
|
||||
bool matches(const gamemap_base& m, map_location l) override
|
||||
{
|
||||
LOG_MATCHES(and);
|
||||
for(const auto& pfilter : list_) {
|
||||
|
@ -255,7 +255,7 @@ public:
|
|||
LOG_LMG << "created or filter\n";
|
||||
}
|
||||
|
||||
bool matches(const mapgen_gamemap& m, map_location l) override
|
||||
bool matches(const gamemap_base& m, map_location l) override
|
||||
{
|
||||
LOG_MATCHES(or);
|
||||
for(const auto& pfilter : list_) {
|
||||
|
@ -276,7 +276,7 @@ public:
|
|||
LOG_LMG << "created nand filter\n";
|
||||
}
|
||||
|
||||
bool matches(const mapgen_gamemap& m, map_location l) override
|
||||
bool matches(const gamemap_base& m, map_location l) override
|
||||
{
|
||||
LOG_MATCHES(nand);
|
||||
for(const auto& pfilter : list_) {
|
||||
|
@ -297,7 +297,7 @@ public:
|
|||
LOG_LMG << "created nor filter\n";
|
||||
}
|
||||
|
||||
bool matches(const mapgen_gamemap& m, map_location l) override
|
||||
bool matches(const gamemap_base& m, map_location l) override
|
||||
{
|
||||
LOG_MATCHES(nor);
|
||||
for(const auto& pfilter : list_) {
|
||||
|
@ -322,7 +322,7 @@ public:
|
|||
lua_pop(L, 1);
|
||||
}
|
||||
|
||||
bool matches(const mapgen_gamemap& m, map_location l) override
|
||||
bool matches(const gamemap_base& m, map_location l) override
|
||||
{
|
||||
LOG_MATCHES(cached);
|
||||
int cache_size = 2 * m.total_width() * m.total_height();
|
||||
|
@ -357,7 +357,7 @@ public:
|
|||
filter_ = parse_range(luaW_tostring(L, -1));
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
bool matches(const mapgen_gamemap&, map_location l) override
|
||||
bool matches(const gamemap_base&, map_location l) override
|
||||
{
|
||||
LOG_MATCHES(x);
|
||||
return l.x >= 0 && l.x < int(filter_.size()) && filter_[l.x];
|
||||
|
@ -377,7 +377,7 @@ public:
|
|||
lua_pop(L, 1);
|
||||
}
|
||||
|
||||
bool matches(const mapgen_gamemap&, map_location l) override
|
||||
bool matches(const gamemap_base&, map_location l) override
|
||||
{
|
||||
LOG_MATCHES(y);
|
||||
return l.y >= 0 && l.y < int(filter_.size()) && filter_[l.y];
|
||||
|
@ -394,10 +394,10 @@ public:
|
|||
LOG_LMG << "creating onborder filter\n";
|
||||
}
|
||||
|
||||
bool matches(const mapgen_gamemap& m, map_location l) override
|
||||
bool matches(const gamemap_base& m, map_location l) override
|
||||
{
|
||||
LOG_MATCHES(onborder);
|
||||
return !m.on_map_noborder(l);
|
||||
return !m.on_board(l);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -414,10 +414,10 @@ public:
|
|||
lua_pop(L, 1);
|
||||
}
|
||||
|
||||
bool matches(const mapgen_gamemap& m, map_location l) override
|
||||
bool matches(const gamemap_base& m, map_location l) override
|
||||
{
|
||||
LOG_MATCHES(terrain);
|
||||
const t_translation::terrain_code letter = m[l];
|
||||
const t_translation::terrain_code letter = m.get_terrain(l);
|
||||
return t_translation::terrain_matches(letter, filter_);
|
||||
}
|
||||
|
||||
|
@ -451,7 +451,7 @@ public:
|
|||
lua_pop(L, 1);
|
||||
}
|
||||
|
||||
bool matches(const mapgen_gamemap& m, map_location l) override
|
||||
bool matches(const gamemap_base& m, map_location l) override
|
||||
{
|
||||
LOG_MATCHES(adjacent);
|
||||
int count = 0;
|
||||
|
@ -459,7 +459,7 @@ public:
|
|||
offset_list_t& offsets = (l.wml_x() & 1) ? odd_offsets_ : even_offsets_;
|
||||
for(const auto& offset : offsets) {
|
||||
map_location ad = {l.x + offset.first, l.y + offset.second};
|
||||
if(m.on_map(ad) && filter_->matches(m, ad)) {
|
||||
if(m.on_board_with_border(ad) && filter_->matches(m, ad)) {
|
||||
if(accepted_counts_.size() == 0) {
|
||||
return true;
|
||||
}
|
||||
|
@ -496,7 +496,7 @@ public:
|
|||
}
|
||||
set_ = &insert_res.first->second;
|
||||
}
|
||||
bool matches(const mapgen_gamemap&, map_location l) override
|
||||
bool matches(const gamemap_base&, map_location l) override
|
||||
{
|
||||
LOG_MATCHES(findin);
|
||||
if(set_) {
|
||||
|
@ -529,14 +529,14 @@ public:
|
|||
lua_pop(L, 1);
|
||||
}
|
||||
|
||||
bool matches(const mapgen_gamemap& m, map_location l) override
|
||||
bool matches(const gamemap_base& m, map_location l) override
|
||||
{
|
||||
LOG_MATCHES(radius);
|
||||
std::set<map_location> result;
|
||||
|
||||
get_tiles_radius({{ l }}, radius_, result,
|
||||
[&](const map_location& l) {
|
||||
return m.on_map(l);
|
||||
return m.on_board_with_border(l);
|
||||
},
|
||||
[&](const map_location& l) {
|
||||
return !filter_radius_ || filter_radius_->matches(m, l);
|
||||
|
@ -573,7 +573,7 @@ public:
|
|||
ERR_LMG << "formula error" << e.what() << "\n";
|
||||
}
|
||||
}
|
||||
bool matches(const mapgen_gamemap&, map_location l) override
|
||||
bool matches(const gamemap_base&, map_location l) override
|
||||
{
|
||||
LOG_MATCHES(formula);
|
||||
try {
|
||||
|
@ -672,7 +672,7 @@ filter::filter(lua_State* L, int data_index, int res_index)
|
|||
LOG_LMG << "finished creating filter object\n";
|
||||
}
|
||||
|
||||
bool filter::matches(const mapgen_gamemap& m, map_location l)
|
||||
bool filter::matches(const gamemap_base& m, map_location l)
|
||||
{
|
||||
log_scope("filter::matches");
|
||||
return impl_->matches(m, l);
|
||||
|
@ -685,7 +685,7 @@ filter::~filter()
|
|||
|
||||
}
|
||||
|
||||
static int intf_mg_get_locations_part2(lua_State* L, mapgen_gamemap& m, lua_mapgen::filter& f)
|
||||
static int intf_mg_get_locations_part2(lua_State* L, gamemap_base& m, lua_mapgen::filter& f)
|
||||
{
|
||||
location_set res;
|
||||
LOG_LMG << "map:get_locations vaidargs\n";
|
||||
|
@ -717,7 +717,7 @@ int intf_mg_get_locations(lua_State* L)
|
|||
{
|
||||
//todo: create filter form table if needed
|
||||
LOG_LMG << "map:get_locations\n";
|
||||
mapgen_gamemap& m = luaW_checkterrainmap(L, 1);
|
||||
gamemap_base& m = luaW_checkterrainmap(L, 1);
|
||||
if(luaW_is_mgfilter(L, 2)) {
|
||||
lua_mapgen::filter& f = luaW_check_mgfilter(L, 2);
|
||||
return intf_mg_get_locations_part2(L, m, f);
|
||||
|
@ -733,14 +733,14 @@ int intf_mg_get_locations(lua_State* L)
|
|||
|
||||
int intf_mg_get_tiles_radius(lua_State* L)
|
||||
{
|
||||
mapgen_gamemap& m = luaW_checkterrainmap(L, 1);
|
||||
gamemap_base& m = luaW_checkterrainmap(L, 1);
|
||||
lua_mapgen::filter& f = luaW_check_mgfilter(L, 3);
|
||||
location_set s = luaW_to_locationset(L, 2);
|
||||
location_set res;
|
||||
int r = luaL_checkinteger(L, 4);
|
||||
get_tiles_radius(std::move(s), r, res,
|
||||
[&](const map_location& l) {
|
||||
return m.on_map(l);
|
||||
return m.on_board_with_border(l);
|
||||
},
|
||||
[&](const map_location& l) {
|
||||
return f.matches(m, l);
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#include <memory>
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include "map/map.hpp"
|
||||
|
||||
#include "scripting/lua_common.hpp"
|
||||
struct lua_State;
|
||||
|
@ -45,7 +46,7 @@ namespace lua_mapgen
|
|||
|
||||
~filter();
|
||||
|
||||
bool matches(const mapgen_gamemap& m, map_location l);
|
||||
bool matches(const gamemap_base& m, map_location l);
|
||||
//todo: add a clear cache function.
|
||||
private:
|
||||
std::map<std::string, std::set<map_location>> known_sets_;
|
||||
|
|
|
@ -22,6 +22,9 @@
|
|||
#include "scripting/lua_common.hpp"
|
||||
#include "scripting/push_check.hpp"
|
||||
#include "scripting/game_lua_kernel.hpp"
|
||||
#include "resources.hpp"
|
||||
#include "game_board.hpp"
|
||||
#include "play_controller.hpp"
|
||||
|
||||
#include "lua/lauxlib.h"
|
||||
#include "lua/lua.h"
|
||||
|
@ -30,77 +33,26 @@ static lg::log_domain log_scripting_lua("scripting/lua");
|
|||
#define LOG_LUA LOG_STREAM(info, log_scripting_lua)
|
||||
#define ERR_LUA LOG_STREAM(err, log_scripting_lua)
|
||||
|
||||
static const char terrainmapKey[] = "terrainmap";
|
||||
static const char maplocationKey[] = "special_locations";
|
||||
static const char terrainmapKey[] = "terrain map";
|
||||
static const char maplocationKey[] = "special locations";
|
||||
static const char mapReplaceIfFailedKey[] = "replace_if_failed terrain code";
|
||||
|
||||
namespace replace_if_failed_idx {
|
||||
enum {CODE = 1, MODE = 2};
|
||||
}
|
||||
|
||||
using std::string_view;
|
||||
|
||||
//////// SPECIAL LOCATION ////////
|
||||
|
||||
bool luaW_isslocs(lua_State* L, int index)
|
||||
{
|
||||
return luaL_testudata(L, index, maplocationKey) != nullptr;
|
||||
}
|
||||
|
||||
|
||||
mapgen_gamemap* luaW_toslocs(lua_State *L, int index)
|
||||
{
|
||||
if(!lua_istable(L, index)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
lua_rawgeti(L, index, 1);
|
||||
mapgen_gamemap* m = luaW_toterrainmap(L, -1);
|
||||
lua_pop(L, 1);
|
||||
return m;
|
||||
}
|
||||
|
||||
mapgen_gamemap& luaW_check_slocs(lua_State *L, int index)
|
||||
{
|
||||
if(mapgen_gamemap* m = luaW_toslocs(L, index)) {
|
||||
return *m;
|
||||
}
|
||||
luaW_type_error(L, index, "terrainmap");
|
||||
throw "luaW_type_error didn't thow.";
|
||||
}
|
||||
|
||||
void lua_slocs_setmetatable(lua_State *L)
|
||||
{
|
||||
luaL_setmetatable(L, maplocationKey);
|
||||
}
|
||||
/**
|
||||
* @a index the index of the map object.
|
||||
*/
|
||||
void luaW_pushslocs(lua_State *L, int index)
|
||||
{
|
||||
lua_pushvalue(L, index);
|
||||
//stack: map
|
||||
lua_createtable(L, 1, 0);
|
||||
//stack: map, slocs
|
||||
lua_pushvalue(L, -2);
|
||||
//stack: map, slocs, map
|
||||
lua_rawseti(L, -2, 1);
|
||||
//stack: map, slocs
|
||||
luaL_setmetatable(L, maplocationKey);
|
||||
//stack: map, slocs
|
||||
lua_remove(L, -2);
|
||||
//stack: slocs
|
||||
}
|
||||
|
||||
int impl_slocs_get(lua_State* L)
|
||||
{
|
||||
//todo: calling map.special_locations[1] will return the underlying map
|
||||
// object instead of the first starting position, because the lua
|
||||
// special locations is actually a table with the map object at
|
||||
// index 1. The probably easiest way to fix this inconsistency is
|
||||
// to just disallow all integer indices here.
|
||||
mapgen_gamemap& m = luaW_check_slocs(L, 1);
|
||||
gamemap_base& m = luaW_checkterrainmap(L, 1);
|
||||
string_view id = luaL_checkstring(L, 2);
|
||||
auto res = m.special_location(std::string(id));
|
||||
if(res.wml_x() >= 0) {
|
||||
if(res.valid()) {
|
||||
luaW_pushlocation(L, res);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
//functions with variable return numbers have been causing problem in the past
|
||||
lua_pushnil(L);
|
||||
}
|
||||
|
@ -109,7 +61,7 @@ int impl_slocs_get(lua_State* L)
|
|||
|
||||
int impl_slocs_set(lua_State* L)
|
||||
{
|
||||
mapgen_gamemap& m = luaW_check_slocs(L, 1);
|
||||
gamemap_base& m = luaW_checkterrainmap(L, 1);
|
||||
string_view id = luaL_checkstring(L, 2);
|
||||
map_location loc = luaW_checklocation(L, 3);
|
||||
|
||||
|
@ -117,119 +69,143 @@ int impl_slocs_set(lua_State* L)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int impl_slocs_next(lua_State *L)
|
||||
{
|
||||
gamemap_base& m = luaW_checkterrainmap(L, lua_upvalueindex(1));
|
||||
const t_translation::starting_positions::left_map& left = m.special_locations().left;
|
||||
|
||||
t_translation::starting_positions::left_const_iterator it;
|
||||
if (lua_isnoneornil(L, 2)) {
|
||||
it = left.begin();
|
||||
}
|
||||
else {
|
||||
it = left.find(luaL_checkstring(L, 2));
|
||||
if (it == left.end()) {
|
||||
return 0;
|
||||
}
|
||||
++it;
|
||||
}
|
||||
if (it == left.end()) {
|
||||
return 0;
|
||||
}
|
||||
lua_pushstring(L, it->first.c_str());
|
||||
luaW_pushlocation(L, it->second);
|
||||
return 2;
|
||||
}
|
||||
|
||||
int impl_slocs_iter(lua_State *L)
|
||||
{
|
||||
lua_settop(L, 1);
|
||||
lua_pushvalue(L, 1);
|
||||
lua_pushcclosure(L, &impl_slocs_next, 1);
|
||||
lua_pushvalue(L, 1);
|
||||
lua_pushnil(L);
|
||||
return 3;
|
||||
}
|
||||
|
||||
//////// MAP ////////
|
||||
|
||||
mapgen_gamemap::mapgen_gamemap(std::string_view s)
|
||||
: tiles_()
|
||||
, starting_positions_()
|
||||
{
|
||||
if(s.empty()) {
|
||||
return;
|
||||
}
|
||||
//throws t_translation::error
|
||||
//todo: make read_game_map take a string_view
|
||||
tiles_ = t_translation::read_game_map(s, starting_positions_, t_translation::coordinate{ 1, 1 });
|
||||
tiles() = t_translation::read_game_map(s, special_locations(), t_translation::coordinate{ 1, 1 });
|
||||
}
|
||||
|
||||
mapgen_gamemap::mapgen_gamemap(int w, int h, terrain_code t)
|
||||
: tiles_(w, h, t)
|
||||
, starting_positions_()
|
||||
: gamemap_base(w, h, t)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
std::string mapgen_gamemap::to_string() const
|
||||
// This can produce invalid combinations in rare case
|
||||
// where an overlay doesn't have an independent terrain definition,
|
||||
// or if you set an overlay with no base and merge mode other than OVERLAY.
|
||||
void simplemerge(t_translation::terrain_code old_t, t_translation::terrain_code& new_t, const terrain_type_data::merge_mode mode)
|
||||
{
|
||||
return t_translation::write_game_map(tiles_, starting_positions_, { 1, 1 }) + "\n";
|
||||
switch(mode) {
|
||||
case terrain_type_data::OVERLAY:
|
||||
new_t = t_translation::terrain_code(old_t.base, new_t.overlay);
|
||||
break;
|
||||
case terrain_type_data::BASE:
|
||||
new_t = t_translation::terrain_code(new_t.base, old_t.overlay);
|
||||
break;
|
||||
case terrain_type_data::BOTH:
|
||||
new_t = t_translation::terrain_code(new_t.base, new_t.overlay);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void mapgen_gamemap::set_terrain(const map_location& loc, const terrain_code & terrain, const terrain_type_data::merge_mode mode)
|
||||
void mapgen_gamemap::set_terrain(const map_location& loc, const terrain_code & terrain, const terrain_type_data::merge_mode mode, bool)
|
||||
{
|
||||
terrain_code& t = (*this)[loc];
|
||||
terrain_code old = t;
|
||||
t = terrain;
|
||||
terrain_code old = get_terrain(loc);
|
||||
terrain_code t = terrain;
|
||||
simplemerge(old, t, mode);
|
||||
|
||||
tiles().get(loc.x + border_size(), loc.y + border_size()) = t;
|
||||
}
|
||||
|
||||
void mapgen_gamemap::simplemerge(terrain_code old_t, terrain_code& new_t, const terrain_type_data::merge_mode mode)
|
||||
{
|
||||
if(mode == terrain_type_data::OVERLAY) {
|
||||
new_t = t_translation::terrain_code(old_t.base, new_t.overlay);
|
||||
}
|
||||
if(mode == terrain_type_data::BASE) {
|
||||
new_t = t_translation::terrain_code(new_t.base, old_t.overlay);
|
||||
}
|
||||
}
|
||||
struct lua_map_ref {
|
||||
virtual gamemap_base& get_map() = 0;
|
||||
virtual ~lua_map_ref() {}
|
||||
};
|
||||
|
||||
void mapgen_gamemap::set_special_location(const std::string& id, const map_location& loc)
|
||||
{
|
||||
bool valid = loc.valid();
|
||||
auto it_left = starting_positions_.left.find(id);
|
||||
if (it_left != starting_positions_.left.end()) {
|
||||
if (valid) {
|
||||
starting_positions_.left.replace_data(it_left, loc);
|
||||
}
|
||||
else {
|
||||
starting_positions_.left.erase(it_left);
|
||||
}
|
||||
// Mapgen map reference, owned by Lua
|
||||
struct lua_map_ref_gen : public lua_map_ref {
|
||||
mapgen_gamemap map;
|
||||
template<typename... T>
|
||||
lua_map_ref_gen(T&&... params) : map(std::forward<T>(params)...) {}
|
||||
gamemap_base& get_map() override {
|
||||
return map;
|
||||
}
|
||||
else {
|
||||
starting_positions_.left.insert(it_left, std::pair(id, loc));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
map_location mapgen_gamemap::special_location(const std::string& id) const
|
||||
{
|
||||
auto it = starting_positions_.left.find(id);
|
||||
if (it != starting_positions_.left.end()) {
|
||||
auto& coordinate = it->second;
|
||||
return map_location(coordinate.x, coordinate.y);
|
||||
// Main map reference, owned by the engine
|
||||
struct lua_map_ref_main : public lua_map_ref {
|
||||
gamemap& map;
|
||||
lua_map_ref_main(gamemap& ref) : map(ref) {}
|
||||
gamemap_base& get_map() override {
|
||||
return map;
|
||||
}
|
||||
else {
|
||||
return map_location();
|
||||
};
|
||||
|
||||
// Non-owning map reference to either type (used for special location userdata)
|
||||
struct lua_map_ref_locs : public lua_map_ref {
|
||||
gamemap_base& map;
|
||||
lua_map_ref_locs(gamemap_base& ref) : map(ref) {}
|
||||
gamemap_base& get_map() override {
|
||||
return map;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
bool luaW_isterrainmap(lua_State* L, int index)
|
||||
{
|
||||
return luaL_testudata(L, index, terrainmapKey) != nullptr;
|
||||
return luaL_testudata(L, index, terrainmapKey) != nullptr || luaL_testudata(L, index, maplocationKey) != nullptr;
|
||||
}
|
||||
|
||||
|
||||
mapgen_gamemap* luaW_toterrainmap(lua_State *L, int index)
|
||||
gamemap_base* luaW_toterrainmap(lua_State *L, int index)
|
||||
{
|
||||
if(luaW_isterrainmap(L, index)) {
|
||||
return static_cast<mapgen_gamemap*>(lua_touserdata(L, index));
|
||||
return &static_cast<lua_map_ref*>(lua_touserdata(L, index))->get_map();
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
mapgen_gamemap& luaW_checkterrainmap(lua_State *L, int index)
|
||||
gamemap_base& luaW_checkterrainmap(lua_State *L, int index)
|
||||
{
|
||||
if(luaW_isterrainmap(L, index)) {
|
||||
return *static_cast<mapgen_gamemap*>(lua_touserdata(L, index));
|
||||
return static_cast<lua_map_ref*>(lua_touserdata(L, index))->get_map();
|
||||
}
|
||||
luaW_type_error(L, index, "terrainmap");
|
||||
throw "luaW_type_error didn't throw";
|
||||
}
|
||||
|
||||
void lua_terrainmap_setmetatable(lua_State *L)
|
||||
{
|
||||
luaL_setmetatable(L, terrainmapKey);
|
||||
}
|
||||
|
||||
template<typename... T>
|
||||
mapgen_gamemap* luaW_pushmap(lua_State *L, T&&... params)
|
||||
{
|
||||
mapgen_gamemap* res = new(L) mapgen_gamemap(std::forward<T>(params)...);
|
||||
lua_terrainmap_setmetatable(L);
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a map.
|
||||
* - Arg 1: string describing the map data.
|
||||
* - Arg 1: string descripbing the map data.
|
||||
* - or:
|
||||
* - Arg 1: int, width
|
||||
* - Arg 2: int, height
|
||||
|
@ -241,14 +217,20 @@ int intf_terrainmap_create(lua_State *L)
|
|||
int w = lua_tonumber(L, 1);
|
||||
int h = lua_tonumber(L, 2);
|
||||
auto terrain = t_translation::read_terrain_code(luaL_checkstring(L, 3));
|
||||
luaW_pushmap(L, w, h, terrain);
|
||||
return 1;
|
||||
}
|
||||
else {
|
||||
new(L) lua_map_ref_gen(w, h, terrain);
|
||||
} else {
|
||||
string_view data_str = luaL_checkstring(L, 1);
|
||||
luaW_pushmap(L, data_str);
|
||||
return 1;
|
||||
new(L) lua_map_ref_gen(data_str);
|
||||
}
|
||||
luaL_setmetatable(L, terrainmapKey);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int intf_terrainmap_get(lua_State* L)
|
||||
{
|
||||
new(L) lua_map_ref_main(const_cast<gamemap&>(resources::gameboard->map()));
|
||||
luaL_setmetatable(L, terrainmapKey);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -256,11 +238,54 @@ int intf_terrainmap_create(lua_State *L)
|
|||
*/
|
||||
static int impl_terrainmap_collect(lua_State *L)
|
||||
{
|
||||
mapgen_gamemap *u = static_cast<mapgen_gamemap*>(lua_touserdata(L, 1));
|
||||
u->mapgen_gamemap::~mapgen_gamemap();
|
||||
lua_map_ref* m = static_cast<lua_map_ref*>(lua_touserdata(L, 1));
|
||||
m->lua_map_ref::~lua_map_ref();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void luaW_push_terrain(lua_State* L, gamemap_base& map, map_location loc)
|
||||
{
|
||||
auto t = map.get_terrain(loc);
|
||||
lua_pushstring(L, t_translation::write_terrain_code(t).c_str());
|
||||
}
|
||||
|
||||
static void impl_merge_terrain(lua_State* L, gamemap_base& map, map_location loc)
|
||||
{
|
||||
auto mode = terrain_type_data::BOTH;
|
||||
bool replace_if_failed = false;
|
||||
string_view t_str;
|
||||
if(luaL_testudata(L, 3, mapReplaceIfFailedKey)) {
|
||||
replace_if_failed = true;
|
||||
lua_getiuservalue(L, 3, replace_if_failed_idx::CODE);
|
||||
t_str = luaL_checkstring(L, -1);
|
||||
lua_getiuservalue(L, 3, replace_if_failed_idx::MODE);
|
||||
mode = terrain_type_data::merge_mode(luaL_checkinteger(L, -1));
|
||||
} else {
|
||||
t_str = luaL_checkstring(L, 3);
|
||||
if(t_str.front() == '^') {
|
||||
mode = terrain_type_data::OVERLAY;
|
||||
} else if(t_str.back() == '^') {
|
||||
mode = terrain_type_data::BASE;
|
||||
}
|
||||
}
|
||||
|
||||
auto ter = t_translation::read_terrain_code(t_str);
|
||||
|
||||
if(auto gm = dynamic_cast<gamemap*>(&map)) {
|
||||
if(resources::gameboard) {
|
||||
bool result = resources::gameboard->change_terrain(loc, ter, mode, replace_if_failed);
|
||||
|
||||
for(team& t : resources::gameboard->teams()) {
|
||||
t.fix_villages(*gm);
|
||||
}
|
||||
|
||||
if(resources::controller) {
|
||||
resources::controller->get_display().needs_rebuild(result);
|
||||
}
|
||||
}
|
||||
} else map.set_terrain(loc, ter, mode, replace_if_failed);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets some data on a map (__index metamethod).
|
||||
* - Arg 1: full userdata containing the map.
|
||||
|
@ -269,19 +294,29 @@ static int impl_terrainmap_collect(lua_State *L)
|
|||
*/
|
||||
static int impl_terrainmap_get(lua_State *L)
|
||||
{
|
||||
mapgen_gamemap& tm = luaW_checkterrainmap(L, 1);
|
||||
gamemap_base& tm = luaW_checkterrainmap(L, 1);
|
||||
map_location loc;
|
||||
if(luaW_tolocation(L, 2, loc)) {
|
||||
luaW_push_terrain(L, tm, loc);
|
||||
return 1;
|
||||
}
|
||||
|
||||
char const *m = luaL_checkstring(L, 2);
|
||||
|
||||
// Find the corresponding attribute.
|
||||
return_int_attrib("width", tm.total_width());
|
||||
return_int_attrib("height", tm.total_height());
|
||||
return_int_attrib("playable_width", tm.w());
|
||||
return_int_attrib("playable_height", tm.h());
|
||||
return_int_attrib("border_size", tm.border_size());
|
||||
return_string_attrib("data", tm.to_string());
|
||||
|
||||
if(strcmp(m, "special_locations") == 0) {
|
||||
luaW_pushslocs(L, 1);
|
||||
new(L) lua_map_ref_locs(tm);
|
||||
luaL_setmetatable(L, maplocationKey);
|
||||
return 1;
|
||||
}
|
||||
if(luaW_getmetafield(L, 1, m)) {
|
||||
if(luaW_getglobal(L, "wesnoth", "map", m)) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
|
@ -295,59 +330,21 @@ static int impl_terrainmap_get(lua_State *L)
|
|||
*/
|
||||
static int impl_terrainmap_set(lua_State *L)
|
||||
{
|
||||
mapgen_gamemap& tm = luaW_checkterrainmap(L, 1);
|
||||
UNUSED(tm);
|
||||
gamemap_base& tm = luaW_checkterrainmap(L, 1);
|
||||
map_location loc;
|
||||
// The extra check that value (arg 3) isn't a number is because without it,
|
||||
// map[4] = 5 would be interpreted as map[{4, 5}] = nil, due to the way
|
||||
// luaW_tolocation modifies the stack if it finds a pair of numbers on it.
|
||||
if(lua_type(L, 3) != LUA_TNUMBER && luaW_tolocation(L, 2, loc)) {
|
||||
impl_merge_terrain(L, tm, loc);
|
||||
return 0;
|
||||
}
|
||||
char const *m = luaL_checkstring(L, 2);
|
||||
std::string err_msg = "unknown modifiable property of map: ";
|
||||
err_msg += m;
|
||||
return luaL_argerror(L, 2, err_msg.c_str());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sets a terrain code.
|
||||
* - Arg 1: map location.
|
||||
* - Arg 2: terrain code string.
|
||||
* - Arg 3: layer: (overlay|base|both, default=both)
|
||||
*/
|
||||
static int intf_set_terrain(lua_State *L)
|
||||
{
|
||||
mapgen_gamemap& tm = luaW_checkterrainmap(L, 1);
|
||||
map_location loc = luaW_checklocation(L, 2);
|
||||
string_view t_str = luaL_checkstring(L, 3);
|
||||
|
||||
auto terrain = t_translation::read_terrain_code(t_str);
|
||||
auto mode = terrain_type_data::BOTH;
|
||||
|
||||
if(!lua_isnoneornil(L, 4)) {
|
||||
string_view mode_str = luaL_checkstring(L, 4);
|
||||
if(mode_str == "base") {
|
||||
mode = terrain_type_data::BASE;
|
||||
}
|
||||
else if(mode_str == "overlay") {
|
||||
mode = terrain_type_data::OVERLAY;
|
||||
}
|
||||
}
|
||||
|
||||
tm.set_terrain(loc, terrain, mode);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a terrain code.
|
||||
* - Arg 1: map location.
|
||||
* - Ret 1: string.
|
||||
*/
|
||||
static int intf_get_terrain(lua_State *L)
|
||||
{
|
||||
mapgen_gamemap& tm = luaW_checkterrainmap(L, 1);
|
||||
map_location loc = luaW_checklocation(L, 2);
|
||||
|
||||
auto t = tm[loc];
|
||||
lua_pushstring(L, t_translation::write_terrain_code(t).c_str());
|
||||
return 1;
|
||||
}
|
||||
|
||||
static std::vector<gamemap::overlay_rule> read_rules_vector(lua_State *L, int index)
|
||||
{
|
||||
std::vector<gamemap::overlay_rule> rules;
|
||||
|
@ -363,12 +360,13 @@ static std::vector<gamemap::overlay_rule> read_rules_vector(lua_State *L, int in
|
|||
rule.old_ = t_translation::read_list(luaW_tostring(L, -1));
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
|
||||
if(luaW_tableget(L, -1, "new")) {
|
||||
rule.new_ = t_translation::read_list(luaW_tostring(L, -1));
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
|
||||
if(luaW_tableget(L, -1, "mode")) {
|
||||
if(luaW_tableget(L, -1, "layer")) {
|
||||
auto str = luaW_tostring(L, -1);
|
||||
rule.mode_ = str == "base" ? terrain_type_data::BASE : (str == "overlay" ? terrain_type_data::OVERLAY : terrain_type_data::BOTH);
|
||||
lua_pop(L, 1);
|
||||
|
@ -405,19 +403,18 @@ static std::vector<gamemap::overlay_rule> read_rules_vector(lua_State *L, int in
|
|||
* - ignore_special_locations: boolean
|
||||
* - rules: table of tables
|
||||
*/
|
||||
int mapgen_gamemap::intf_mg_terrain_mask(lua_State *L)
|
||||
int intf_terrain_mask(lua_State *L)
|
||||
{
|
||||
mapgen_gamemap& tm1 = luaW_checkterrainmap(L, 1);
|
||||
gamemap_base& map = luaW_checkterrainmap(L, 1);
|
||||
map_location loc = luaW_checklocation(L, 2);
|
||||
mapgen_gamemap& tm2 = luaW_checkterrainmap(L, 3);
|
||||
|
||||
bool is_odd = false;
|
||||
bool ignore_special_locations = false;
|
||||
std::vector<gamemap::overlay_rule> rules;
|
||||
|
||||
if(lua_istable(L, 4)) {
|
||||
is_odd = luaW_table_get_def<bool>(L, 4, "is_odd", false);
|
||||
ignore_special_locations = luaW_table_get_def<bool>(L, 4, "ignore_special_locations", false);
|
||||
is_odd = luaW_table_get_def(L, 4, "is_odd", false);
|
||||
ignore_special_locations = luaW_table_get_def(L, 4, "ignore_special_locations", false);
|
||||
|
||||
if(luaW_tableget(L, 4, "rules")) {
|
||||
if(!lua_istable(L, -1)) {
|
||||
|
@ -427,28 +424,78 @@ int mapgen_gamemap::intf_mg_terrain_mask(lua_State *L)
|
|||
lua_pop(L, 1);
|
||||
}
|
||||
}
|
||||
|
||||
if(lua_isstring(L, 3)) {
|
||||
const std::string t_str = luaL_checkstring(L, 3);
|
||||
std::unique_ptr<gamemap_base> mask;
|
||||
if(dynamic_cast<gamemap*>(&map)) {
|
||||
auto mask_ptr = new gamemap("");
|
||||
mask_ptr->read(t_str, false);
|
||||
mask.reset(mask_ptr);
|
||||
} else {
|
||||
mask.reset(new mapgen_gamemap(t_str));
|
||||
}
|
||||
map.overlay(*mask, loc, rules, is_odd, ignore_special_locations);
|
||||
} else {
|
||||
gamemap_base& mask = luaW_checkterrainmap(L, 3);
|
||||
map.overlay(mask, loc, rules, is_odd, ignore_special_locations);
|
||||
}
|
||||
|
||||
if(resources::gameboard) {
|
||||
if(auto gmap = dynamic_cast<gamemap*>(&map)) {
|
||||
for(team& t : resources::gameboard->teams()) {
|
||||
t.fix_villages(*gmap);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
gamemap::overlay_impl(
|
||||
tm1.tiles_,
|
||||
tm1.starting_positions_,
|
||||
tm2.tiles_,
|
||||
tm2.starting_positions_,
|
||||
[&](const map_location& loc, const t_translation::terrain_code& t, terrain_type_data::merge_mode mode, bool) { tm1.set_terrain(loc, t, mode); },
|
||||
loc,
|
||||
rules,
|
||||
is_odd,
|
||||
ignore_special_locations
|
||||
);
|
||||
if(resources::controller) {
|
||||
resources::controller->get_display().needs_rebuild(true);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int intf_replace_if_failed(lua_State* L)
|
||||
{
|
||||
auto mode = terrain_type_data::BOTH;
|
||||
if(!lua_isnoneornil(L, 2)) {
|
||||
string_view mode_str = luaL_checkstring(L, 2);
|
||||
if(mode_str == "base") {
|
||||
mode = terrain_type_data::BASE;
|
||||
} else if(mode_str == "overlay") {
|
||||
mode = terrain_type_data::OVERLAY;
|
||||
} else if(mode_str != "both") {
|
||||
return luaL_argerror(L, 2, "must be one of 'base', 'overlay', or 'both'");
|
||||
}
|
||||
}
|
||||
|
||||
lua_newuserdatauv(L, 0, 2);
|
||||
lua_pushinteger(L, int(mode));
|
||||
lua_setiuservalue(L, -2, replace_if_failed_idx::MODE);
|
||||
lua_pushvalue(L, 1);
|
||||
lua_setiuservalue(L, -2, replace_if_failed_idx::CODE);
|
||||
luaL_setmetatable(L, mapReplaceIfFailedKey);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int impl_replace_if_failed_tostring(lua_State* L)
|
||||
{
|
||||
static const char* mode_strs[] = {"base", "overlay", "both"};
|
||||
lua_getiuservalue(L, 1, replace_if_failed_idx::CODE);
|
||||
string_view t_str = luaL_checkstring(L, -1);
|
||||
lua_getiuservalue(L, 1, replace_if_failed_idx::MODE);
|
||||
int mode = luaL_checkinteger(L, -1);
|
||||
lua_pushfstring(L, "replace_if_failed('%s', '%s')", t_str.data(), mode_strs[mode]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
namespace lua_terrainmap {
|
||||
std::string register_metatables(lua_State* L)
|
||||
std::string register_metatables(lua_State* L, bool use_tf)
|
||||
{
|
||||
std::ostringstream cmd_out;
|
||||
|
||||
cmd_out << "Adding terrainmap metatable...\n";
|
||||
cmd_out << "Adding terrain map metatable...\n";
|
||||
|
||||
luaL_newmetatable(L, terrainmapKey);
|
||||
lua_pushcfunction(L, impl_terrainmap_collect);
|
||||
|
@ -457,28 +504,32 @@ namespace lua_terrainmap {
|
|||
lua_setfield(L, -2, "__index");
|
||||
lua_pushcfunction(L, impl_terrainmap_set);
|
||||
lua_setfield(L, -2, "__newindex");
|
||||
lua_pushstring(L, "terrainmap");
|
||||
lua_pushstring(L, terrainmapKey);
|
||||
lua_setfield(L, -2, "__metatable");
|
||||
// terrainmap methods
|
||||
lua_pushcfunction(L, intf_set_terrain);
|
||||
lua_setfield(L, -2, "set_terrain");
|
||||
lua_pushcfunction(L, intf_get_terrain);
|
||||
lua_setfield(L, -2, "get_terrain");
|
||||
lua_pushcfunction(L, intf_mg_get_locations);
|
||||
lua_setfield(L, -2, "get_locations");
|
||||
lua_pushcfunction(L, intf_mg_get_tiles_radius);
|
||||
lua_setfield(L, -2, "get_tiles_radius");
|
||||
lua_pushcfunction(L, &mapgen_gamemap::intf_mg_terrain_mask);
|
||||
lua_setfield(L, -2, "terrain_mask");
|
||||
if(use_tf) {
|
||||
lua_pushcfunction(L, intf_mg_get_locations);
|
||||
lua_setfield(L, -2, "get_locations");
|
||||
lua_pushcfunction(L, intf_mg_get_tiles_radius);
|
||||
lua_setfield(L, -2, "get_tiles_radius");
|
||||
}
|
||||
|
||||
luaL_newmetatable(L, mapReplaceIfFailedKey);
|
||||
lua_pushcfunction(L, impl_replace_if_failed_tostring);
|
||||
lua_setfield(L, -2, "__tostring");
|
||||
lua_pushstring(L, mapReplaceIfFailedKey);
|
||||
lua_setfield(L, -2, "__metatable");
|
||||
|
||||
cmd_out << "Adding terrainmap2 metatable...\n";
|
||||
cmd_out << "Adding special locations metatable...\n";
|
||||
|
||||
luaL_newmetatable(L, maplocationKey);
|
||||
lua_pushcfunction(L, impl_slocs_get);
|
||||
lua_setfield(L, -2, "__index");
|
||||
lua_pushcfunction(L, impl_slocs_set);
|
||||
lua_setfield(L, -2, "__newindex");
|
||||
lua_pushstring(L, "special_locations");
|
||||
lua_pushcfunction(L, impl_slocs_iter);
|
||||
lua_setfield(L, -2, "__pairs");
|
||||
lua_pushstring(L, maplocationKey);
|
||||
lua_setfield(L, -2, "__metatable");
|
||||
|
||||
return cmd_out.str();
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#include <string>
|
||||
#include "scripting/lua_common.hpp"
|
||||
#include "map/location.hpp"
|
||||
#include "map/map.hpp"
|
||||
#include "terrain/translation.hpp"
|
||||
#include "terrain/type_data.hpp"
|
||||
|
||||
|
@ -24,60 +25,13 @@ struct lua_State;
|
|||
class lua_unit;
|
||||
struct map_location;
|
||||
|
||||
// this clas is similar to the orginal gamemap class but they have no 'is' rlation:
|
||||
// mapgen_gamemap, unlike gamemap offers 'raw' access to the data
|
||||
// gamemap, unlike mapgen_gamemap uses terrain type data.
|
||||
class mapgen_gamemap
|
||||
{
|
||||
// Unlike the original gamemap, this offers 'raw' access to the data.
|
||||
// The original gamemap uses terrain type data.
|
||||
class mapgen_gamemap : public gamemap_base {
|
||||
public:
|
||||
using terrain_code = t_translation::terrain_code;
|
||||
using terrain_map = t_translation::ter_map;
|
||||
using starting_positions = t_translation::starting_positions;
|
||||
explicit mapgen_gamemap(std::string_view data);
|
||||
mapgen_gamemap(int w, int h, terrain_code);
|
||||
|
||||
std::string to_string() const;
|
||||
|
||||
/** Effective map width. */
|
||||
int w() const { return total_width() - 2; }
|
||||
|
||||
/** Effective map height. */
|
||||
int h() const { return total_height() - 2; }
|
||||
|
||||
/** Real width of the map, including borders. */
|
||||
int total_width() const { return tiles_.w; }
|
||||
|
||||
/** Real height of the map, including borders */
|
||||
int total_height() const { return tiles_.h; }
|
||||
|
||||
bool on_map(const map_location& loc) const
|
||||
{
|
||||
return loc.wml_x() >= 0 && loc.wml_x() < total_width() && loc.wml_y() >= 0 && loc.wml_y() < total_height();
|
||||
}
|
||||
|
||||
bool on_map_noborder(const map_location& loc) const
|
||||
{
|
||||
return loc.wml_x() > 0 && loc.wml_x() < total_width() - 1 && loc.wml_y() > 0 && loc.wml_y() < total_height() - 1;
|
||||
}
|
||||
|
||||
terrain_code& operator[](const map_location& loc)
|
||||
{
|
||||
return tiles_.get(loc.wml_x(), loc.wml_y());
|
||||
}
|
||||
|
||||
const terrain_code& operator[](const map_location& loc) const
|
||||
{
|
||||
return tiles_.get(loc.wml_x(), loc.wml_y());
|
||||
}
|
||||
|
||||
void set_terrain(const map_location& loc, const terrain_code & terrain, const terrain_type_data::merge_mode mode);
|
||||
static void simplemerge(terrain_code old, terrain_code& t, const terrain_type_data::merge_mode mode);
|
||||
|
||||
starting_positions& special_locations() { return starting_positions_; }
|
||||
const starting_positions& special_locations() const { return starting_positions_; }
|
||||
|
||||
void set_special_location(const std::string& id, const map_location& loc);
|
||||
map_location special_location(const std::string& id) const;
|
||||
void set_terrain(const map_location& loc, const terrain_code & terrain, const terrain_type_data::merge_mode mode = terrain_type_data::BOTH, bool replace_if_failed = false) override;
|
||||
|
||||
template<typename F>
|
||||
void for_each_loc(const F& f) const
|
||||
|
@ -88,38 +42,23 @@ public:
|
|||
}
|
||||
}
|
||||
}
|
||||
static int intf_mg_terrain_mask(lua_State *L);
|
||||
private:
|
||||
t_translation::ter_map tiles_;
|
||||
starting_positions starting_positions_;
|
||||
};
|
||||
|
||||
bool luaW_isslocs(lua_State* L, int index);
|
||||
|
||||
mapgen_gamemap* luaW_toslocs(lua_State *L, int index);
|
||||
|
||||
mapgen_gamemap& luaW_check_slocs(lua_State *L, int index);
|
||||
|
||||
void lua_slocs_setmetatable(lua_State *L);
|
||||
|
||||
void luaW_pushslocs(lua_State *L, int index);
|
||||
|
||||
int impl_slocs_get(lua_State* L);
|
||||
|
||||
int impl_slocs_set(lua_State* L);
|
||||
int intf_terrain_mask(lua_State *L);
|
||||
|
||||
bool luaW_isterrainmap(lua_State* L, int index);
|
||||
|
||||
mapgen_gamemap* luaW_toterrainmap(lua_State *L, int index);
|
||||
gamemap_base* luaW_toterrainmap(lua_State *L, int index);
|
||||
|
||||
mapgen_gamemap& luaW_checkterrainmap(lua_State *L, int index);
|
||||
gamemap_base& luaW_checkterrainmap(lua_State *L, int index);
|
||||
|
||||
void lua_terrainmap_setmetatable(lua_State *L);
|
||||
|
||||
mapgen_gamemap* luaW_pushmap(lua_State *L, mapgen_gamemap&& u);
|
||||
|
||||
int intf_terrainmap_create(lua_State *L);
|
||||
int intf_terrainmap_get(lua_State *L);
|
||||
|
||||
int intf_replace_if_failed(lua_State* L);
|
||||
|
||||
namespace lua_terrainmap {
|
||||
std::string register_metatables(lua_State *L);
|
||||
std::string register_metatables(lua_State *L, bool use_tf);
|
||||
}
|
||||
|
|
|
@ -237,7 +237,7 @@ mapgen_lua_kernel::mapgen_lua_kernel(const config* vars)
|
|||
assert(lua_gettop(L) == 0);
|
||||
|
||||
|
||||
cmd_log_ << lua_terrainmap::register_metatables(L);
|
||||
cmd_log_ << lua_terrainmap::register_metatables(L, true);
|
||||
cmd_log_ << lua_terrainfilter::register_metatables(L);
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue