Skip to content

Commit

Permalink
allow to special apceisl locations in the map_data
Browse files Browse the repository at this point in the history
it is now possible to specify locations in the editor that can then be
read with wml (without the create scenario editor mode). These special
locations can be placed like starting positions, and can them be used in
the wml code like:
'location_id=<id>' in standard location filters or 'placement=<id>' in
[unit], i also intend to add a lua interface wesnoth.special_locations
later.

It's currently not possible to have multiple special  locations in the
same hex, the main reason is that i'm unsure about how to integrate that
in the editor ui.
  • Loading branch information
gfgtdf committed Jun 17, 2016
1 parent a0ce7dc commit 42d9323
Show file tree
Hide file tree
Showing 15 changed files with 130 additions and 94 deletions.
3 changes: 3 additions & 0 deletions src/actions/unit_creator.cpp
Expand Up @@ -134,6 +134,9 @@ map_location unit_creator::find_location(const config &cfg, const unit* pass_che
else if ( place == "map" || place.compare(0, 4, "map_") == 0 ) {
loc = map_location(cfg, resources::gamedata);
}
else {
loc = board_->map().special_location(place);
}

if(loc.valid() && board_->map().on_board(loc)) {
const bool pass((place == "leader_passable") || (place == "map_passable"));
Expand Down
29 changes: 14 additions & 15 deletions src/editor/action/action.cpp
Expand Up @@ -221,32 +221,31 @@ editor_action_starting_position* editor_action_starting_position::clone() const
editor_action* editor_action_starting_position::perform(map_context& mc) const
{
util::unique_ptr<editor_action> undo;
int old_player = mc.get_map().is_starting_position(loc_);
map_location old_loc = mc.get_map().starting_position(player_);
LOG_ED << "ssp perform, player_" << player_ << ", loc_ " << loc_ << ", old_player " << old_player << ", old_loc " << old_loc << "\n";
if (old_player != -1) {
const std::string* old_loc_id = mc.get_map().is_starting_position(loc_);
map_location old_loc = mc.get_map().special_location(loc_id_);
if (old_loc_id != nullptr) {
// If another player was starting at the location, we actually perform two actions, so the undo is an action_chain.
editor_action_chain* undo_chain = new editor_action_chain();
undo_chain->append_action(new editor_action_starting_position(loc_, old_player));
undo_chain->append_action(new editor_action_starting_position(old_loc, player_));
undo_chain->append_action(new editor_action_starting_position(loc_, *old_loc_id));
undo_chain->append_action(new editor_action_starting_position(old_loc, loc_id_));
undo.reset(undo_chain);
LOG_ED << "ssp actual: " << old_player << " to " << map_location() << "\n";
mc.get_map().set_starting_position(old_player, map_location());
LOG_ED << "ssp actual: " << *old_loc_id << " to " << map_location() << "\n";
mc.get_map().set_special_location(*old_loc_id, map_location());
} else {
undo.reset(new editor_action_starting_position(old_loc, player_));
undo.reset(new editor_action_starting_position(old_loc, loc_id_));
}
LOG_ED << "ssp actual: " << player_ << " to " << loc_ << "\n";
mc.get_map().set_starting_position(player_, loc_);
LOG_ED << "ssp actual: " << loc_id_ << " to " << loc_ << "\n";
mc.get_map().set_special_location(loc_id_, loc_);
mc.set_needs_labels_reset();
return undo.release();
}
void editor_action_starting_position::perform_without_undo(map_context& mc) const
{
int old_player = mc.get_map().is_starting_position(loc_) - 1;
if (old_player != -1) {
mc.get_map().set_starting_position(old_player - 1, map_location());
const std::string* old_id = mc.get_map().is_starting_position(loc_);
if (old_id != nullptr) {
mc.get_map().set_special_location(*old_id, map_location());
}
mc.get_map().set_starting_position(player_, loc_);
mc.get_map().set_special_location(loc_id_, loc_);
mc.set_needs_labels_reset();
}

Expand Down
6 changes: 3 additions & 3 deletions src/editor/action/action.hpp
Expand Up @@ -283,16 +283,16 @@ class editor_action_fill : public editor_action_location_terrain
class editor_action_starting_position : public editor_action_location
{
public:
editor_action_starting_position(map_location loc, int player)
: editor_action_location(loc), player_(player)
editor_action_starting_position(map_location loc, std::string loc_id)
: editor_action_location(loc), loc_id_(loc_id)
{
}
editor_action_starting_position* clone() const;
editor_action* perform(map_context& mc) const;
void perform_without_undo(map_context& mc) const;
const char* get_name() const { return "starting_pos"; }
protected:
int player_;
std::string loc_id_;
};


Expand Down
24 changes: 12 additions & 12 deletions src/editor/action/mouse/mouse_action.cpp
Expand Up @@ -107,11 +107,11 @@ 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;
int player_starting_at_hex = disp.map().is_starting_position(previous_move_hex_);
if (res == 0 && player_starting_at_hex != -1) {
a = new editor_action_starting_position(map_location(), player_starting_at_hex);
} else if (res > 0 && res != player_starting_at_hex) {
a = new editor_action_starting_position(previous_move_hex_, res);
const std::string* old_id = disp.map().is_starting_position(previous_move_hex_);
if (res == 0 && old_id != nullptr) {
a = new editor_action_starting_position(map_location(), *old_id);
} else if (res > 0 && (old_id == nullptr || *old_id == std::to_string(res))) {
a = new editor_action_starting_position(previous_move_hex_, std::to_string(res));
}
}
return a;
Expand Down Expand Up @@ -399,20 +399,20 @@ editor_action* mouse_action_starting_position::up_left(editor_display& disp, int
return nullptr;
}

const unsigned player_starting_at_hex = disp.map().is_starting_position(hex);
auto player_starting_at_hex = disp.map().is_starting_position(hex);

std::vector<map_location> starting_positions;

unsigned new_player_at_hex = std::stoi(location_palette_.selected_item());
std::string new_player_at_hex = location_palette_.selected_item();
editor_action* a = nullptr;

if(new_player_at_hex != player_starting_at_hex) {
if(!player_starting_at_hex || new_player_at_hex != *player_starting_at_hex) {
// Set a starting position
a = new editor_action_starting_position(hex, new_player_at_hex);
}
else {
// Erase current starting position
a = new editor_action_starting_position(map_location(), player_starting_at_hex);
a = new editor_action_starting_position(map_location(), *player_starting_at_hex);
}

update_brush_highlights(disp, hex);
Expand All @@ -429,9 +429,9 @@ editor_action* mouse_action_starting_position::click_left(editor_display& /*disp
editor_action* mouse_action_starting_position::up_right(editor_display& disp, int x, int y)
{
map_location hex = disp.hex_clicked_on(x, y);
int player_starting_at_hex = disp.map().is_starting_position(hex);
if (player_starting_at_hex != -1) {
return new editor_action_starting_position(map_location(), player_starting_at_hex);
auto player_starting_at_hex = disp.map().is_starting_position(hex);
if (player_starting_at_hex != nullptr) {
return new editor_action_starting_position(map_location(), *player_starting_at_hex);
} else {
return nullptr;
}
Expand Down
2 changes: 1 addition & 1 deletion src/editor/controller/editor_controller.cpp
Expand Up @@ -984,7 +984,7 @@ bool editor_controller::execute_command(const hotkey::hotkey_command& cmd, int i
case HOTKEY_EDITOR_REMOVE_LOCATION: {
location_palette* lp = dynamic_cast<location_palette*>(&toolkit_->get_palette_manager()->active_palette());
if (lp) {
perform_delete(new editor_action_starting_position(map_location(), std::stoi(lp->selected_item())));
perform_delete(new editor_action_starting_position(map_location(), lp->selected_item()));
}
return true;
}
Expand Down
17 changes: 14 additions & 3 deletions src/editor/map/editor_map.cpp
Expand Up @@ -18,6 +18,7 @@
#include "formula/string_utils.hpp"

#include "display.hpp"
#include "formula/string_utils.hpp"
#include "gettext.hpp"
#include "map/exception.hpp"
#include "map/label.hpp"
Expand Down Expand Up @@ -148,10 +149,20 @@ std::set<map_location> editor_map::get_contiguous_terrain_tiles(const map_locati
std::set<map_location> editor_map::set_starting_position_labels(display& disp)
{
std::set<map_location> label_locs;
std::string label = _("Player");
label += " ";
std::string label;


for (const auto& pair : starting_positions_.left) {
disp.labels().set_label(map_location(pair.second.x, pair.second.y), label + std::to_string(pair.first));

bool is_number = std::find_if(pair.first.begin(), pair.first.end(), [](char c) { return !std::isdigit(c); }) == pair.first.end();
if (is_number) {
label = vgettext("Player $side_num", utils::string_map{ { "side_num", pair.first } });
}
else {
label = pair.first;
}

disp.labels().set_label(map_location(pair.second.x, pair.second.y), label);
label_locs.insert(map_location(pair.second.x, pair.second.y));
}
return label_locs;
Expand Down
23 changes: 18 additions & 5 deletions src/editor/palette/location_palette.cpp
Expand Up @@ -21,6 +21,7 @@
#include "tooltips.hpp"

#include "editor/action/mouse/mouse_action.hpp"
#include "gui/dialogs/edit_text.hpp"

#include "wml_separators.hpp"
#include "formula/string_utils.hpp"
Expand Down Expand Up @@ -71,7 +72,10 @@ class location_palette_item : public gui::widget
parent_.select_item(id_);
}
if (e.button == SDL_BUTTON_RIGHT) {
//TODO: implement 'jump to item' or 'delete item' here.
//TODO: add a context menu with the follwing options:
// 1) 'copy it to clipboard'
// 2) 'jump to item'
// 3) 'delete item'.
}
}

Expand Down Expand Up @@ -223,23 +227,32 @@ void location_palette::adjust_size(const SDL_Rect& target)
palette_x_ = target.x;
palette_y_ = target.y;
const int button_height = 30;
int bottom = target.y + target.h - button_height;
int bottom = target.y + target.h;


button_add_.reset();
button_delete_.reset();
button_goto_.reset();

button_goto_.reset(new location_palette_button(video(), SDL_Rect{ target.x , bottom, target.w - 10, button_height }, _("Go To"), [this]() {
button_goto_.reset(new location_palette_button(video(), SDL_Rect{ target.x , bottom -= button_height, target.w - 10, button_height }, _("Go To"), [this]() {
//static_cast<mouse_action_starting_position&>(**active_mouse_action_).
map_location pos = disp_.get_map().starting_position(std::stoi(selected_item_));
if (pos.valid()) {
disp_.scroll_to_tile(pos, display::WARP);
}
}));
button_add_.reset(new location_palette_button(video(), SDL_Rect{ target.x , bottom -= button_height, target.w - 10, button_height }, _("Add"), [this]() {
std::string newid;
if (gui2::tedit_text::execute(_("New Location Identifer"), "", newid, video())) {
items_.push_back(newid);
adjust_size(location());
}
}));
button_delete_.reset(new location_palette_button(video(), SDL_Rect{ target.x , bottom -= button_height, target.w - 10, button_height }, _("Delete"), nullptr));
const size_t space_for_items = bottom - target.x;
const unsigned items_fitting = static_cast<unsigned> (space_for_items / item_space_);


const size_t space_for_items = bottom - target.y;
const int items_fitting = static_cast<unsigned> (space_for_items / item_space_);
nitems_ = std::min<int>(items_fitting, items_.size());
if (buttons_.size() != nitems_) {
buttons_.resize(nitems_, &location_palette_item(gui_.video(), *this));
Expand Down
2 changes: 1 addition & 1 deletion src/generators/cave_map_generator.cpp
Expand Up @@ -345,7 +345,7 @@ void cave_map_generator::cave_map_generator_job::place_castle(int starting_posit
t_translation::coordinate coord(
loc.x + gamemap::default_border
, loc.y + gamemap::default_border);
starting_positions_.insert(t_translation::tstarting_positions::value_type(starting_position, coord));
starting_positions_.insert(t_translation::tstarting_positions::value_type(std::to_string(starting_position), coord));
}

map_location adj[6];
Expand Down
2 changes: 1 addition & 1 deletion src/generators/default_map_generator_job.cpp
Expand Up @@ -1202,7 +1202,7 @@ std::string default_map_generator_job::default_generate_map(size_t width, size_t
const int y = c->y;
const int player = c - castles.begin() + 1;
const struct t_translation::coordinate coord(x, y);
starting_positions.insert(t_translation::tstarting_positions::value_type(player, coord));
starting_positions.insert(t_translation::tstarting_positions::value_type(std::to_string(player), coord));
terrain[x][y] = t_translation::HUMAN_KEEP;

const int castles[13][2] = {
Expand Down
1 change: 1 addition & 0 deletions src/gui/dialogs/edit_text.cpp
Expand Up @@ -39,6 +39,7 @@ namespace gui2

REGISTER_DIALOG(edit_text)

//TODO: add a way to disallow certain chracters (like spaces or ")
tedit_text::tedit_text(const std::string& title,
const std::string& label,
std::string& text)
Expand Down
64 changes: 33 additions & 31 deletions src/map/map.cpp
Expand Up @@ -158,7 +158,6 @@ void gamemap::read(const std::string& data, const bool allow_invalid, int border
tiles_.clear();
villages_.clear();
starting_positions_.clear();
std::map<int, t_translation::coordinate> starting_positions;

if(data.empty()) {
w_ = 0;
Expand All @@ -181,23 +180,6 @@ void gamemap::read(const std::string& data, const bool allow_invalid, int border
throw incorrect_map_format_error(e.message);
}

// Convert the starting positions to the array
int max_stating_pos = 0;
for(const auto& pair : starting_positions) {
// Check for valid position,
// the first valid position is 1,
// so the offset 0 in the array is never used.
if(pair.first < 1 || pair.first >= MAX_PLAYERS+1) {
std::stringstream ss;
ss << "Starting position " << pair.first << " out of range\n";
ERR_CF << ss.str();
ss << "The map cannot be loaded.";
throw incorrect_map_format_error(ss.str().c_str());
}

// Add to the starting position array
max_stating_pos = std::max<int>(max_stating_pos, pair.first);
}
// Post processing on the map
total_width_ = tiles_.size();
total_height_ = total_width_ > 0 ? tiles_[0].size() : 0;
Expand Down Expand Up @@ -424,9 +406,9 @@ t_translation::t_terrain gamemap::get_terrain(const map_location& loc) const

}

map_location gamemap::starting_position(int n) const
map_location gamemap::special_location(const std::string& id) const
{
auto it = starting_positions_.left.find(n);
auto it = starting_positions_.left.find(id);
if (it != starting_positions_.left.end()) {
auto& coordinate = it->second;
return map_location(coordinate.x, coordinate.y);
Expand All @@ -436,32 +418,52 @@ map_location gamemap::starting_position(int n) const
}
}

map_location gamemap::starting_position(int n) const
{
return special_location(std::to_string(n));
}

int gamemap::num_valid_starting_positions() const
{
const int res = is_starting_position(map_location());
if(res == 0)
return num_starting_positions();
else
return res;
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) {
res = std::max(res, std::stoi(id));
}
}
return res;
}

int gamemap::is_starting_position(const map_location& loc) const
const std::string* gamemap::is_starting_position(const map_location& loc) const
{
auto it = starting_positions_.right.find(t_translation::coordinate(loc.x, loc.y));
return it == starting_positions_.right.end() ? 0 : it->second;
return it == starting_positions_.right.end() ? nullptr : &it->second;
}

void gamemap::set_starting_position(int side, const map_location& loc)
void gamemap::set_special_location(const std::string& id, const map_location& loc)
{
auto it_left = starting_positions_.left.find(side);
bool valid = loc.valid();
auto it_left = starting_positions_.left.find(id);
if (it_left != starting_positions_.left.end()) {
starting_positions_.left.replace_data(it_left, t_translation::coordinate(loc.x, loc.y));
if (valid) {
starting_positions_.left.replace_data(it_left, t_translation::coordinate(loc.x, loc.y));
}
else {
starting_positions_.left.erase(it_left);
}
}
else {
starting_positions_.left.insert(it_left, std::make_pair(side, t_translation::coordinate(loc.x, loc.y)));
starting_positions_.left.insert(it_left, std::make_pair(id, t_translation::coordinate(loc.x, loc.y)));
}
}

void gamemap::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
{
return loc.valid() && loc.x < w_ && loc.y < h_;
Expand Down
12 changes: 7 additions & 5 deletions src/map/map.hpp
Expand Up @@ -132,12 +132,17 @@ class gamemap


/** 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.
int is_starting_position(const map_location& loc) const;
const std::string* is_starting_position(const map_location& loc) const;
int num_valid_starting_positions() const;

void set_starting_position(int side, const map_location& loc);

/**
* Tell if a location is on the map.
Expand Down Expand Up @@ -224,9 +229,6 @@ class gamemap
*/
int read_header(const std::string& data);

int num_starting_positions() const
{ return starting_positions_.size(); }

/** Allows lookup of terrain at a particular location. */
//const t_translation::t_list operator[](int index) const
// { return tiles_[index + border_size_]; }
Expand Down

0 comments on commit 42d9323

Please sign in to comment.