Split the editor code into different files for easier maintanace.

This commit is contained in:
Kristoffer Erlandsson 2004-04-29 20:53:56 +00:00
parent 5b07143836
commit 264844a47d
12 changed files with 1090 additions and 830 deletions

View file

@ -148,6 +148,11 @@ wesnoth_SOURCES = about.cpp \
#############################################################################
wesnoth_editor_SOURCES = editor/editor.cpp \
editor/editor_layout.cpp \
editor/map_manip.cpp \
editor/editor_palettes.cpp \
editor/editor_main.cpp \
editor/editor_dialogs.cpp \
actions.cpp \
ai.cpp \
ai_attack.cpp \
@ -202,6 +207,10 @@ wesnoth_editor_SOURCES = editor/editor.cpp \
widgets/slider.cpp \
widgets/widget.cpp \
editor/editor.hpp \
editor/editor_layout.hpp \
editor/map_manip.hpp \
editor/editor_palettes.hpp \
editor/editor_dialogs.hpp \
actions.hpp \
ai.hpp \
ai_attack.hpp \

View file

@ -13,8 +13,6 @@
#include "SDL.h"
#include "SDL_keysym.h"
#include "../actions.hpp"
#include "../ai.hpp"
#include "../config.hpp"
#include "../cursor.hpp"
#include "../dialogs.hpp"
@ -22,17 +20,13 @@
#include "../font.hpp"
#include "../game_config.hpp"
#include "../gamestatus.hpp"
#include "../image.hpp"
#include "../key.hpp"
#include "../language.hpp"
#include "../mapgen.hpp"
#include "../widgets/menu.hpp"
#include "../pathfind.hpp"
#include "../language.hpp"
#include "../playlevel.hpp"
#include "../preferences.hpp"
#include "../sdl_utils.hpp"
#include "../tooltips.hpp"
#include "../widgets/slider.hpp"
#include "../team.hpp"
#include "../unit_types.hpp"
#include "../unit.hpp"
@ -40,6 +34,9 @@
#include "../video.hpp"
#include "editor.hpp"
#include "map_manip.hpp"
#include "editor_dialogs.hpp"
#include "editor_palettes.hpp"
#include <cctype>
#include <iostream>
@ -50,7 +47,6 @@ namespace {
const unsigned int undo_limit = 1000;
// Milliseconds to sleep in every iteration of the main loop.
const unsigned int sdl_delay = 20;
const size_t default_terrain_size = 35;
void terrain_changed(gamemap &map, const gamemap::location &hex) {
// If we painted something else than a keep on a starting position,
@ -77,7 +73,7 @@ map_editor::map_editor(display &gui, gamemap &map, config &theme, config &game_c
// Set size specs.
adjust_sizes(gui_);
adjust_sizes(gui_, size_specs_, palette_.num_terrains());
tup_.set_xy(gui.mapx() + size_specs_.button_x, size_specs_.top_button_y);
tdown_.set_xy(gui.mapx() + size_specs_.button_x, size_specs_.bot_button_y);
@ -141,195 +137,20 @@ void map_editor::handle_mouse_button_event(const SDL_MouseButtonEvent &event,
}
}
std::string map_editor::new_map_dialog(display& disp)
{
const events::resize_lock prevent_resizing;
const events::event_context dialog_events_context;
int map_width(40), map_height(40);
const int width = 600;
const int height = 400;
const int xpos = disp.x()/2 - width/2;
const int ypos = disp.y()/2 - height/2;
const int horz_margin = 5;
const int vertical_margin = 20;
SDL_Rect dialog_rect = {xpos-10,ypos-10,width+20,height+20};
surface_restorer restorer(&disp.video(),dialog_rect);
gui::draw_dialog_frame(xpos,ypos,width,height,disp);
SDL_Rect title_rect = font::draw_text(NULL,disp.screen_area(),24,font::NORMAL_COLOUR,
"Create New Map",0,0);
const std::string& width_label = string_table["map_width"] + ":";
const std::string& height_label = string_table["map_height"] + ":";
SDL_Rect width_rect = font::draw_text(NULL,disp.screen_area(),14,font::NORMAL_COLOUR,width_label,0,0);
SDL_Rect height_rect = font::draw_text(NULL,disp.screen_area(),14,font::NORMAL_COLOUR,height_label,0,0);
const int text_right = xpos + horz_margin +
maximum<int>(width_rect.w,height_rect.w);
width_rect.x = text_right - width_rect.w;
height_rect.x = text_right - height_rect.w;
width_rect.y = ypos + title_rect.h + vertical_margin*2;
height_rect.y = width_rect.y + width_rect.h + vertical_margin;
gui::button new_map_button(disp,"Generate New Map With Selected Terrain");
gui::button random_map_button(disp,"Generate Random Map");
gui::button random_map_setting_button(disp,"Random Generator Setting");
gui::button cancel_button(disp,"Cancel");
new_map_button.set_x(xpos + horz_margin);
new_map_button.set_y(height_rect.y + height_rect.h + vertical_margin);
random_map_button.set_x(xpos + horz_margin);
random_map_button.set_y(ypos + height - random_map_button.height()-14*2-vertical_margin);
random_map_setting_button.set_x(random_map_button.get_x() + random_map_button.width() + horz_margin);
random_map_setting_button.set_y(ypos + height - random_map_setting_button.height()-14*2-vertical_margin);
cancel_button.set_x(xpos + width - cancel_button.width() - horz_margin);
cancel_button.set_y(ypos + height - cancel_button.height()-14);
const int right_space = 100;
const int slider_left = text_right + 10;
const int slider_right = xpos + width - horz_margin - right_space;
SDL_Rect slider_rect = { slider_left,width_rect.y,slider_right-slider_left,width_rect.h};
const int min_width = 20;
const int max_width = 200;
const int max_height = 200;
slider_rect.y = width_rect.y;
gui::slider width_slider(disp,slider_rect);
width_slider.set_min(min_width);
width_slider.set_max(max_width);
width_slider.set_value(map_width);
slider_rect.y = height_rect.y;
gui::slider height_slider(disp,slider_rect);
height_slider.set_min(min_width);
height_slider.set_max(max_height);
height_slider.set_value(map_height);
const config* const cfg = game_config_.find_child("multiplayer","id","ranmap")->child("generator");
util::scoped_ptr<map_generator> generator(NULL);
generator.assign(create_map_generator("", cfg));
for(bool draw = true;; draw = false) {
int mousex, mousey;
const int mouse_flags = SDL_GetMouseState(&mousex,&mousey);
const bool left_button = mouse_flags&SDL_BUTTON_LMASK;
if(cancel_button.process(mousex,mousey,left_button)) {
return "";
}
if(new_map_button.process(mousex,mousey,left_button)) {
if (confirm_modification_disposal(gui_, "The modification to the map will be discarded. Continue?")) {
int i;
std::stringstream str;
std::stringstream map_str;
for (i = 0; i < width_slider.value(); i++) {
str << palette_.selected_terrain();
}
str << "\n";
for (i = 0; i < height_slider.value(); i++) {
map_str << str.str();
}
return map_str.str();
}
}
if(random_map_setting_button.process(mousex,mousey,left_button)) {
if (generator.get()->allow_user_config()) {
generator.get()->user_config(gui_);
}
}
if(random_map_button.process(mousex,mousey,left_button)) {
if (confirm_modification_disposal(gui_, "The modification to the map will be discarded. Continue?")) {
const std::string map = generator.get()->create_map(std::vector<std::string>());
if (map == "") {
gui::show_dialog(gui_, NULL, "",
"Creation failed.", gui::OK_ONLY);
}
return map;
}
}
map_width = width_slider.value();
map_height = height_slider.value();
gui::draw_dialog_frame(xpos,ypos,width,height,disp);
width_slider.process();
height_slider.process();
width_slider.set_min(min_width);
height_slider.set_min(min_width);
events::raise_process_event();
events::raise_draw_event();
title_rect = font::draw_text(&disp,disp.screen_area(),24,font::NORMAL_COLOUR,
"Create New Map",xpos+(width-title_rect.w)/2,ypos+10);
font::draw_text(&disp,disp.screen_area(),14,font::NORMAL_COLOUR,
width_label,width_rect.x,width_rect.y);
font::draw_text(&disp,disp.screen_area(),14,font::NORMAL_COLOUR,
height_label,height_rect.x,height_rect.y);
std::stringstream width_str;
width_str << map_width;
font::draw_text(&disp,disp.screen_area(),14,font::NORMAL_COLOUR,width_str.str(),
slider_right+horz_margin,width_rect.y);
std::stringstream height_str;
height_str << map_height;
font::draw_text(&disp,disp.screen_area(),14,font::NORMAL_COLOUR,height_str.str(),
slider_right+horz_margin,height_rect.y);
new_map_button.draw();
random_map_button.draw();
random_map_setting_button.draw();
cancel_button.draw();
update_rect(xpos,ypos,width,height);
disp.update_display();
SDL_Delay(10);
events::pump();
}
}
void map_editor::edit_save_map() {
save_map("", true);
}
void map_editor::edit_quit() {
set_abort();
}
void map_editor::edit_new_map() {
const std::string map = new_map_dialog(gui_);
if (map != "") {
throw new_map_exception(map);
}
}
void map_editor::edit_save_as() {
std::string input_name = get_dir(get_dir(get_user_data_dir() + "/editor") + "/maps/");
int res = 0;
int overwrite = 0;
do {
res = gui::show_dialog(gui_, NULL, "", "Save As ", gui::OK_CANCEL, NULL,NULL,"",&input_name);
res = gui::show_dialog(gui_, NULL, "", "Save As ", gui::OK_CANCEL,
NULL, NULL, "", &input_name);
if (res == 0) {
if (file_exists(input_name)) {
overwrite = gui::show_dialog(gui_,NULL,"",
"Map already exists. Do you want to overwrite it?",gui::YES_NO);
overwrite = gui::show_dialog(gui_, NULL, "Overwrite?",
"Map already exists. Do you want to overwrite it?",
gui::YES_NO);
}
else
overwrite = 0;
@ -344,7 +165,8 @@ void map_editor::edit_save_as() {
void map_editor::edit_set_start_pos() {
std::string player = "1";
const int res = gui::show_dialog(gui_, NULL, "", "Which player should start here?",
const int res = gui::show_dialog(gui_, NULL, "Which Player?",
"Which player should start here?",
gui::OK_CANCEL, NULL, NULL, "", &player);
if (player != "" && res == 0) {
int int_player;
@ -377,6 +199,29 @@ void map_editor::edit_flood_fill() {
invalidate_all_and_adjacent(to_invalidate);
}
void map_editor::edit_save_map() {
save_map("", true);
}
void map_editor::edit_quit() {
set_abort();
}
void map_editor::edit_new_map() {
const std::string map = new_map_dialog(gui_, palette_.selected_terrain(),
changed_since_save(), game_config_);
if (map != "") {
throw new_map_exception(map);
}
}
void map_editor::edit_load_map() {
const std::string map = load_map_dialog(gui_, changed_since_save());
if (map != "") {
throw new_map_exception(map);
}
}
bool map_editor::can_execute_command(hotkey::HOTKEY_COMMAND command) const {
switch (command) {
case hotkey::HOTKEY_UNDO:
@ -399,30 +244,6 @@ bool map_editor::can_execute_command(hotkey::HOTKEY_COMMAND command) const {
}
}
void map_editor::adjust_sizes(const display &disp) {
const size_t button_height = 24;
const size_t button_palette_padding = 8;
size_specs_.terrain_size = default_terrain_size;
size_specs_.terrain_padding = 2;
size_specs_.terrain_space = size_specs_.terrain_size + size_specs_.terrain_padding;
size_specs_.palette_x = 40;
size_specs_.button_x = size_specs_.palette_x + size_specs_.terrain_space - 12;
size_specs_.brush_x = 25;
size_specs_.brush_y = 190;
size_specs_.top_button_y = size_specs_.brush_y + 40;
size_specs_.palette_y = size_specs_.top_button_y + button_height +
button_palette_padding;
const size_t max_bot_button_y = disp.y() - 60 - button_height;
size_t space_for_terrains = max_bot_button_y - button_palette_padding -
size_specs_.palette_y;
space_for_terrains = space_for_terrains / size_specs_.terrain_space % 2 == 0 ?
space_for_terrains : space_for_terrains - size_specs_.terrain_space;
size_specs_.nterrains = minimum((space_for_terrains / size_specs_.terrain_space) * 2,
palette_.num_terrains());
size_specs_.bot_button_y = size_specs_.palette_y +
(size_specs_.nterrains / 2) * size_specs_.terrain_space + button_palette_padding;
}
void map_editor::toggle_grid() {
preferences::set_grid(!preferences::grid());
gui_.set_grid(preferences::grid());
@ -455,6 +276,10 @@ void map_editor::redo() {
}
}
bool map_editor::changed_since_save() const {
return num_operations_since_save_ != 0;
}
void map_editor::set_starting_position(const int player, const gamemap::location loc) {
if(map_.on_board(loc)) {
map_.set_terrain(selected_hex_, gamemap::KEEP);
@ -586,33 +411,20 @@ void map_editor::middle_button_down(const int mousex, const int mousey) {
bool map_editor::confirm_exit_and_save() {
int exit_res = gui::show_dialog(gui_, NULL, "",
"Do you want to exit the map editor?", gui::YES_NO);
if (exit_res != 0) {
if (gui::show_dialog(gui_, NULL, "",
"Do you want to exit the map editor?", gui::YES_NO) != 0) {
return false;
}
if (num_operations_since_save_ != 0) {
const int save_res = gui::show_dialog(gui_, NULL, "",
"Do you want to save before exiting?",
gui::YES_NO);
if(save_res == 0) {
if (!save_map("", false)) {
return false;
}
if (changed_since_save() &&
gui::show_dialog(gui_, NULL, "",
"Do you want to save the map before exiting?", gui::YES_NO) == 0) {
if (!save_map("", false)) {
return false;
}
}
return true;
}
bool map_editor::confirm_modification_disposal(display& disp, const std::string message) {
bool ret = true;
if (num_operations_since_save_ != 0) {
const int res = gui::show_dialog(gui_, NULL, "", message,
gui::OK_CANCEL);
ret = res == 0;
}
return ret;
}
bool map_editor::save_map(const std::string fn, const bool display_confirmation) {
std::string filename = fn;
@ -780,455 +592,7 @@ void map_editor::main_loop() {
}
}
void map_editor::edit_load_map() {
const std::string system_path = game_config::path + "/data/maps/";
std::vector<std::string> files;
get_files_in_dir(system_path,&files);
files.push_back("Enter Path...");
files.push_back("Local Map...");
std::string filename;
const int res = gui::show_dialog(gui_, NULL, "",
"Choose map to edit:", gui::OK_CANCEL, &files);
if(res == int(files.size()-1)) {
std::vector<std::string> user_files;
const std::string user_path = get_user_data_dir() + "/editor/maps/";
get_files_in_dir(user_path,&user_files);
const int res = gui::show_dialog(gui_, NULL, "",
"Choose map to edit:", gui::OK_CANCEL, &user_files);
if (res < 0 || user_files.empty()) {
return;
}
filename = user_path + user_files[res];
}
else if (res == int(files.size() - 2)) {
filename = get_user_data_dir() + "/editor/maps/";
const int res = gui::show_dialog(gui_, NULL, "",
"Enter map to edit:", gui::OK_CANCEL,
NULL, NULL, "", &filename);
if (res != 0) {
return;
}
}
else if(res < 0 || files.empty()) {
return;
}
else {
filename = system_path + files[res];
}
std::string map;
bool load_successful = true;
std::string msg;
if (!file_exists(filename) || is_directory(filename)) {
load_successful = false;
msg = filename + " does not exist or can't be read as a file.";
}
else {
try {
map = read_file(filename);
}
catch (io_exception e) {
load_successful = false;
msg = e.what();
}
}
if (!load_successful) {
gui::show_dialog(gui_, NULL, "", std::string("Load failed: ") + msg, gui::OK_ONLY);
}
else {
if (! confirm_modification_disposal(gui_, "The modification to the map will be discarded. Continue?")) {
return;
}
throw new_map_exception(map);
}
}
terrain_palette::terrain_palette(display &gui, const size_specs &sizes,
const gamemap &map)
: size_specs_(sizes), gui_(gui), tstart_(0), map_(map), invalid_(true) {
terrains_ = map_.get_terrain_precedence();
terrains_.erase(std::remove_if(terrains_.begin(), terrains_.end(), is_invalid_terrain),
terrains_.end());
if(terrains_.empty()) {
std::cerr << "No terrain found.\n";
}
else {
selected_terrain_ = terrains_[0];
}
}
void terrain_palette::scroll_down() {
if(tstart_ + size_specs_.nterrains + 2 <= num_terrains()) {
tstart_ += 2;
invalid_ = true;
}
else if (tstart_ + size_specs_.nterrains + 1 <= num_terrains()) {
tstart_ += 1;
invalid_ = true;
}
}
void terrain_palette::scroll_up() {
unsigned int decrement = 2;
if (tstart_ + size_specs_.nterrains == num_terrains()
&& terrains_.size() % 2 != 0) {
decrement = 1;
}
if(tstart_ >= decrement) {
invalid_ = true;
tstart_ -= decrement;
}
}
gamemap::TERRAIN terrain_palette::selected_terrain() const {
return selected_terrain_;
}
void terrain_palette::select_terrain(gamemap::TERRAIN terrain) {
if (selected_terrain_ != terrain) {
invalid_ = true;
selected_terrain_ = terrain;
}
}
void terrain_palette::left_mouse_click(const int mousex, const int mousey) {
int tselect = tile_selected(mousex, mousey);
if(tselect >= 0) {
select_terrain(terrains_[tstart_+tselect]);
}
}
size_t terrain_palette::num_terrains() const {
return terrains_.size();
}
void terrain_palette::draw(bool force) {
if (!invalid_ && !force) {
return;
}
size_t x = gui_.mapx() + size_specs_.palette_x;
size_t y = size_specs_.palette_y;
unsigned int starting = tstart_;
unsigned int ending = starting + size_specs_.nterrains;
SDL_Rect invalid_rect;
invalid_rect.x = x;
invalid_rect.y = y;
invalid_rect.w = 0;
invalid_rect.w = size_specs_.terrain_space * 2;
invalid_rect.h = (size_specs_.nterrains / 2) * size_specs_.terrain_space;
// Everything will be redrawn even though only one little part may
// have changed, but that happens so seldom so we'll settle with
// this.
SDL_Surface* const screen = gui_.video().getSurface();
SDL_BlitSurface(surf_, NULL, screen, &invalid_rect);
surf_.assign(get_surface_portion(screen, invalid_rect));
if(ending > num_terrains()){
ending = num_terrains();
}
for(unsigned int counter = starting; counter < ending; counter++){
const gamemap::TERRAIN terrain = terrains_[counter];
const std::string filename = "terrain/" +
map_.get_terrain_info(terrain).default_image() + ".png";
scoped_sdl_surface image(image::get_image(filename, image::UNSCALED));
if(image->w != size_specs_.terrain_size || image->h != size_specs_.terrain_size) {
image.assign(scale_surface(image, size_specs_.terrain_size,
size_specs_.terrain_size));
}
if(image == NULL) {
std::cerr << "image for terrain '" << counter << "' not found\n";
return;
}
const int counter_from_zero = counter - starting;
SDL_Rect dstrect;
dstrect.x = x + (counter_from_zero % 2 != 0 ? size_specs_.terrain_space : 0);
dstrect.y = y;
dstrect.w = image->w;
dstrect.h = image->h;
SDL_BlitSurface(image, NULL, screen, &dstrect);
gui::draw_rectangle(dstrect.x, dstrect.y, image->w, image->h,
terrain == selected_terrain() ? 0xF000:0 , screen);
if (counter_from_zero % 2 != 0)
y += size_specs_.terrain_space;
}
update_rect(invalid_rect);
invalid_ = false;
}
int terrain_palette::tile_selected(const int x, const int y) const {
for(unsigned int i = 0; i != size_specs_.nterrains; i++) {
const int px = gui_.mapx() + size_specs_.palette_x +
(i % 2 != 0 ? size_specs_.terrain_space : 0);
const int py = size_specs_.palette_y + (i / 2) * size_specs_.terrain_space;
const int pw = size_specs_.terrain_space;
const int ph = size_specs_.terrain_space;
if(x > px && x < px + pw && y > py && y < py + ph) {
return i;
}
}
return -1;
}
brush_bar::brush_bar(display &gui, const size_specs &sizes)
: size_specs_(sizes), gui_(gui), selected_(0), total_brush_(3),
size_(30), invalid_(true) {}
unsigned int brush_bar::selected_brush_size() {
return selected_ + 1;
}
void brush_bar::left_mouse_click(const int mousex, const int mousey) {
int index = selected_index(mousex, mousey);
if(index >= 0) {
if (index != selected_) {
invalid_ = true;
selected_ = index;
}
}
}
void brush_bar::draw(bool force) {
if (!invalid_ && !force) {
return;
}
size_t x = gui_.mapx() + size_specs_.brush_x;
size_t y = size_specs_.brush_y;
SDL_Rect invalid_rect;
invalid_rect.x = x;
invalid_rect.y = y;
invalid_rect.w = size_ * total_brush_;
invalid_rect.h = size_;
// Everything will be redrawn even though only one little part may
// have changed, but that happens so seldom so we'll settle with
// this.
SDL_Surface* const screen = gui_.video().getSurface();
SDL_BlitSurface(surf_, NULL, screen, &invalid_rect);
surf_.assign(get_surface_portion(screen, invalid_rect));
for (int i = 1; i <= total_brush_; i++) {
std::stringstream filename;
filename << "editor/brush-" << i << ".png";
scoped_sdl_surface image(image::get_image(filename.str(), image::UNSCALED));
if (image == NULL) {
std::cerr << "Image " << filename.str() << " not found." << std::endl;
continue;
}
if (image->w != size_ || image->h != size_) {
image.assign(scale_surface(image, size_, size_));
}
SDL_Rect dstrect;
dstrect.x = x;
dstrect.y = size_specs_.brush_y;
dstrect.w = image->w;
dstrect.h = image->h;
SDL_BlitSurface(image, NULL, screen, &dstrect);
gui::draw_rectangle(dstrect.x, dstrect.y, image->w, image->h,
(i == selected_brush_size()) ? 0xF000:0 , screen);
x += image->w;
}
update_rect(invalid_rect);
invalid_ = false;
}
void drawbar(display& disp) {
SDL_Surface* const screen = disp.video().getSurface();
SDL_Rect dst = {disp.mapx(), 0, disp.x() - disp.mapx(), disp.y()};
SDL_FillRect(screen,&dst,0);
update_rect(dst);
}
int brush_bar::selected_index(const int x, const int y) const {
const int bar_x = gui_.mapx() + size_specs_.brush_x;
const int bar_y = size_specs_.brush_y;
if ((x < bar_x || x > bar_x + size_ * total_brush_)
|| (y < bar_y || y > bar_y + size_)) {
return -1;
}
for(unsigned int i = 0; i < total_brush_; i++) {
const int px = bar_x + size_ * i;
if(x >= px && x <= px + size_ && y >= bar_y && y <= bar_y + size_) {
return i;
}
}
return -1;
}
std::vector<gamemap::location> get_tiles(const gamemap &map,
const gamemap::location& a,
const unsigned int radius) {
const unsigned int distance = radius - 1;
std::vector<gamemap::location> res;
res.push_back(a);
for (int d = 1; d <= distance; d++) {
gamemap::location loc = a;
int i;
// get starting point
for (i = 1; i <= d; i++) {
loc = loc.get_direction(gamemap::location::NORTH);
}
// get all the tile clockwise with distance d
const gamemap::location::DIRECTION direction[6] =
{gamemap::location::SOUTH_EAST, gamemap::location::SOUTH, gamemap::location::SOUTH_WEST,
gamemap::location::NORTH_WEST, gamemap::location::NORTH, gamemap::location::NORTH_EAST};
for (i = 0; i < 6; i++) {
for (int j = 1; j <= d; j++) {
loc = loc.get_direction(direction[i]);
if (map.on_board(loc)) {
res.push_back(loc);
}
}
}
}
return res;
}
bool is_invalid_terrain(char c) {
return c == ' ' || c == '~';
}
void flood_fill(gamemap &map, const gamemap::location &start_loc,
const gamemap::TERRAIN fill_with, terrain_log *log) {
gamemap::TERRAIN terrain_to_fill = map.get_terrain(start_loc);
if (fill_with == terrain_to_fill) {
return;
}
std::vector<gamemap::location> to_fill;
// First push the starting location onto a stack. Then, in every
// iteration, pop one element from the stack, fill this tile and add
// all adjacent tiles that have the terrain that should be
// filled. Continue until the stack is empty.
to_fill.push_back(start_loc);
while (!to_fill.empty()) {
gamemap::location loc = to_fill.back();
to_fill.pop_back();
if (log != NULL) {
log->push_back(std::make_pair(loc, terrain_to_fill));
}
map.set_terrain(loc, fill_with);
// Find all adjacent tiles with the terrain that should be
// filled and add these to the to_fill vector.
std::vector<gamemap::location> adj = get_tiles(map, loc, 2);
for (std::vector<gamemap::location>::iterator it2 = adj.begin();
it2 != adj.end(); it2++) {
if (map.get_terrain(*it2) == terrain_to_fill && map.on_board(*it2)) {
to_fill.push_back(*it2);
}
}
// Remove duplicates.
std::sort(to_fill.begin(), to_fill.end());
std::vector<gamemap::location>::iterator end_of_unique =
std::unique(to_fill.begin(), to_fill.end());
to_fill.erase(end_of_unique, to_fill.end());
}
}
}
int main(int argc, char** argv)
{
game_config::editor = true;
if(argc > 2) {
std::cout << "usage: " << argv[0] << " [map-name]" << std::endl;
return 0;
}
CVideo video;
const font::manager font_manager;
const preferences::manager prefs_manager;
const image::manager image_manager;
std::pair<int, int> desired_resolution = preferences::resolution();
int video_flags = preferences::fullscreen() ? FULL_SCREEN : 0;
video.setMode(desired_resolution.first, desired_resolution.second,
16, video_flags);
preproc_map defines_map;
defines_map["MEDIUM"] = preproc_define();
defines_map["NORMAL"] = preproc_define();
config cfg(preprocess_file("data/game.cfg", &defines_map));
set_language("English");
std::string filename;
std::string mapdata;
if(argc == 2) {
filename = argv[1];
try {
mapdata = read_file(filename);
}
catch (io_exception) {
std::cerr << "Could not read the map file, sorry." << std::endl;
return 1;
}
}
else {
filename = "";
}
if(mapdata.empty()) {
for(int i = 0; i != 20; ++i) {
mapdata = mapdata + "gggggggggggggggggggg\n";
}
}
bool done = false;
gamestatus status(cfg, 0);
std::vector<team> teams;
// Add a dummy team so the reports will be handled properly.
teams.push_back(team(cfg));
config* theme_cfg = cfg.find_child("theme", "name", "editor");
config dummy_theme("");
if (!theme_cfg) {
std::cerr << "Editor theme could not be loaded." << std::endl;
theme_cfg = &dummy_theme;
}
std::map<gamemap::location,unit> units;
while (! done) {
try {
gamemap map(cfg, mapdata);
std::cerr << "Using theme cfg: " << std::endl << theme_cfg->write() << std::endl;
display gui(units, video, map, status, teams,
*theme_cfg, cfg);
gui.set_grid(preferences::grid());
//Draw the nice background bar
map_editor::drawbar(gui);
events::event_context ec;
map_editor::map_editor editor(gui, map, *theme_cfg, cfg);
editor.set_file_to_save_as(filename);
editor.main_loop();
done = true;
}
catch (map_editor::map_editor::new_map_exception &e) {
std::cerr << "new map " << e.new_map_ << std::endl;
mapdata = e.new_map_;
filename = "";
}
catch (gamemap::incorrect_format_exception) {
std::cerr << "The map is not in a correct format, sorry." << std::endl;
return 1;
}
}
return 0;
}

View file

@ -12,11 +12,15 @@
#ifndef EDITOR_H_INCLUDED
#define EDITOR_H_INCLUDED
#include "editor_palettes.hpp"
#include "editor_layout.hpp"
#include "../display.hpp"
#include "../events.hpp"
#include "../hotkeys.hpp"
#include <map>
#include <queue>
namespace map_editor {
@ -30,112 +34,9 @@ struct map_undo_action {
gamemap::TERRAIN new_terrain;
gamemap::location location;
};
typedef std::deque<map_undo_action> map_undo_list;
/// Size specifications for the map editor.
struct size_specs {
size_t nterrains;
size_t terrain_size;
size_t terrain_padding;
size_t terrain_space;
size_t palette_x;
size_t button_x;
size_t brush_x;
size_t brush_y;
size_t top_button_y;
size_t palette_y;
size_t bot_button_y;
};
/// How to abort the map editor.
/// DONT_ABORT is set during normal operation.
/// When ABORT_NORMALLY is set, the editor asks for confirmation and
/// if save is desired before it exits.
/// When ABORT_HARD is set, the editor exists without asking any
/// questions or saving.
enum ABORT_MODE {DONT_ABORT, ABORT_NORMALLY, ABORT_HARD};
/// A palette where the terrain to be drawn can be selected.
class terrain_palette {
public:
terrain_palette(display &gui, const size_specs &sizes,
const gamemap &map);
/// Scroll the terrain palette up one step if possible.
void scroll_up();
/// Scroll the terrain palette down one step if possible.
void scroll_down();
/// Return the currently selected terrain.
gamemap::TERRAIN selected_terrain() const;
/// Select a terrain.
void select_terrain(gamemap::TERRAIN);
/// To be called when a mouse click occurs. Check if the coordinates
/// is a terrain that may be chosen, select the terrain if that is
/// the case.
void left_mouse_click(const int mousex, const int mousey);
// Draw the palette. If force is true everything will be redrawn
// even though it is not invalidated.
void draw(bool force=false);
/// Return the number of terrains in the palette.
size_t num_terrains() const;
private:
/// Return the number of the tile that is at coordinates (x, y) in the
/// panel.
int tile_selected(const int x, const int y) const;
const size_specs &size_specs_;
scoped_sdl_surface surf_;
display &gui_;
unsigned int tstart_;
std::vector<gamemap::TERRAIN> terrains_;
gamemap::TERRAIN selected_terrain_;
const gamemap &map_;
// Set invalid_ to true if an operation that requires that the
// palette is redrawn takes place.
bool invalid_;
};
/// A bar where the brush is drawin
class brush_bar
{
public:
brush_bar(display &gui, const size_specs &sizes);
/// Return the size of currently selected brush.
unsigned int selected_brush_size();
/// To be called when a mouse click occurs. Check if the coordinates
/// is a terrain that may be chosen, select the terrain if that is
/// the case.
void left_mouse_click(const int mousex, const int mousey);
// Draw the palette. If force is true everything will be redrawn
// even though it is not invalidated.
void draw(bool force=false);
private:
/// Return the index of the brush that is at coordinates (x, y) in the
/// panel.
int selected_index(const int x, const int y) const;
const size_specs &size_specs_;
scoped_sdl_surface surf_;
display &gui_;
unsigned int selected_;
const int total_brush_;
const size_t size_;
// Set invalid_ to true if an operation that requires that the
// bar is redrawn takes place.
bool invalid_;
};
/// A map editor. Receives SDL events and can execute hotkey commands.
class map_editor : public events::handler,
@ -149,6 +50,14 @@ public:
/// Set the filename that map should be saved as.
void set_file_to_save_as(const std::string);
/// How to abort the map editor.
/// DONT_ABORT is set during normal operation.
/// When ABORT_NORMALLY is set, the editor asks for confirmation and
/// if save is desired before it exits.
/// When ABORT_HARD is set, the editor exists without asking any
/// questions or saving.
enum ABORT_MODE {DONT_ABORT, ABORT_NORMALLY, ABORT_HARD};
/// Set the abort flag, which indicates if the editor should exit in
/// some way after the current iteration of the main loop.
@ -159,22 +68,23 @@ public:
/// that shows confirmation that the map was saved is shown if
/// display_confirmation is true. Return false if the save failed.
bool save_map(const std::string filename="",
const bool display_confirmation=true);
/// Adjust the internal size specifications to fit the display.
void adjust_sizes(const display &disp);
const bool display_confirmation=true);
virtual void handle_event(const SDL_Event &event);
/// Handle a keyboard event. mousex and mousey is the current
/// position of the mouse.
void handle_keyboard_event(const SDL_KeyboardEvent &event,
const int mousex, const int mousey);
const int mousex, const int mousey);
/// Handle a mouse button event. mousex and mousey is the current
/// position of the mouse.
void handle_mouse_button_event(const SDL_MouseButtonEvent &event,
const int mousex, const int mousey);
const int mousex, const int mousey);
/// Return true if the map has changed since the last time it was
/// saved.
bool changed_since_save() const;
@ -195,7 +105,7 @@ public:
virtual bool can_execute_command(hotkey::HOTKEY_COMMAND command) const;
// exception thrown when new map is to be loaded.
// Exception thrown when new map is to be loaded.
struct new_map_exception {
new_map_exception(const std::string &new_map) : new_map_(new_map) {}
const std::string new_map_;
@ -255,14 +165,6 @@ private:
/// the operations only happen once per hex for efficiency purposes.
void invalidate_all_and_adjacent(const std::vector<gamemap::location> &hexes);
/// Shows dialog to create new map.
std::string new_map_dialog(display& disp);
/// Return true iff the map is not modified or user agreed to
/// dispose the modification.
bool confirm_modification_disposal(display& disp, const std::string message);
/// Re-set the labels for the starting positions of the
/// players. Should be called when the terrain has changed, which
/// may have changed the starting positions.
@ -294,35 +196,7 @@ private:
std::vector<gamemap::location> starting_positions_;
};
/// Display a dialog with map filenames and return the chosen
/// one. Create a temporary display to use.
std::string get_filename_from_dialog(CVideo &video, config &cfg);
void drawbar(display& disp);
bool drawterrainpalette(display& disp, int start, gamemap::TERRAIN selected,
gamemap map, size_specs specs);
bool is_invalid_terrain(char c);
typedef std::vector<std::pair<gamemap::location, gamemap::TERRAIN> > terrain_log;
std::vector<gamemap::location> get_tiles(const gamemap &map,
const gamemap::location& a,
const unsigned int radius);
/// Flood fill the map with the terrain fill_with starting from the
/// location start_loc. If log is non-null it will contain the positions
/// of the changed tiles and the terrains they had before the filling
/// started.
void flood_fill(gamemap &map, const gamemap::location &start_loc,
const gamemap::TERRAIN fill_with, terrain_log *log = NULL);
}
#endif // EDITOR_H_INCLUDED

View file

@ -0,0 +1,282 @@
/*
Copyright (C) 2003 by David White <davidnwhite@optusnet.com.au>
Part of the Battle for Wesnoth Project http://wesnoth.whitevine.net
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY.
See the COPYING file for more details.
*/
#include "SDL.h"
#include "../display.hpp"
#include "../show_dialog.hpp"
#include "../config.hpp"
#include "../game_config.hpp"
#include "../mapgen.hpp"
#include "../filesystem.hpp"
#include "../font.hpp"
#include "../events.hpp"
#include "../util.hpp"
#include "../widgets/slider.hpp"
#include "../language.hpp"
#include "../map.hpp"
#include "editor_dialogs.hpp"
namespace map_editor {
bool confirm_modification_disposal(display& disp) {
const int res = gui::show_dialog(disp, NULL, "",
"Your modifications to the map will be lost. Continue?",
gui::OK_CANCEL);
return res == 0;
}
std::string new_map_dialog(display& disp, gamemap::TERRAIN fill_terrain,
bool confirmation_needed, const config &game_config)
{
const events::resize_lock prevent_resizing;
const events::event_context dialog_events_context;
int map_width(40), map_height(40);
const int width = 600;
const int height = 400;
const int xpos = disp.x()/2 - width/2;
const int ypos = disp.y()/2 - height/2;
const int horz_margin = 5;
const int vertical_margin = 20;
SDL_Rect dialog_rect = {xpos-10,ypos-10,width+20,height+20};
surface_restorer restorer(&disp.video(),dialog_rect);
gui::draw_dialog_frame(xpos,ypos,width,height,disp);
SDL_Rect title_rect = font::draw_text(NULL,disp.screen_area(),24,font::NORMAL_COLOUR,
"Create New Map",0,0);
const std::string& width_label = string_table["map_width"] + ":";
const std::string& height_label = string_table["map_height"] + ":";
SDL_Rect width_rect = font::draw_text(NULL, disp.screen_area(), 14, font::NORMAL_COLOUR,
width_label, 0, 0);
SDL_Rect height_rect = font::draw_text(NULL, disp.screen_area(), 14, font::NORMAL_COLOUR,
height_label, 0, 0);
const int text_right = xpos + horz_margin +
maximum<int>(width_rect.w,height_rect.w);
width_rect.x = text_right - width_rect.w;
height_rect.x = text_right - height_rect.w;
width_rect.y = ypos + title_rect.h + vertical_margin*2;
height_rect.y = width_rect.y + width_rect.h + vertical_margin;
gui::button new_map_button(disp,"Generate New Map With Selected Terrain");
gui::button random_map_button(disp,"Generate Random Map");
gui::button random_map_setting_button(disp,"Random Generator Setting");
gui::button cancel_button(disp,"Cancel");
new_map_button.set_x(xpos + horz_margin);
new_map_button.set_y(height_rect.y + height_rect.h + vertical_margin);
random_map_button.set_x(xpos + horz_margin);
random_map_button.set_y(ypos + height - random_map_button.height()-14*2-vertical_margin);
random_map_setting_button.set_x(random_map_button.get_x() + random_map_button.width()
+ horz_margin);
random_map_setting_button.set_y(ypos + height - random_map_setting_button.height()
- 14*2 - vertical_margin);
cancel_button.set_x(xpos + width - cancel_button.width() - horz_margin);
cancel_button.set_y(ypos + height - cancel_button.height()-14);
const int right_space = 100;
const int slider_left = text_right + 10;
const int slider_right = xpos + width - horz_margin - right_space;
SDL_Rect slider_rect = { slider_left,width_rect.y,slider_right-slider_left,width_rect.h};
const int min_width = 20;
const int max_width = 200;
const int max_height = 200;
slider_rect.y = width_rect.y;
gui::slider width_slider(disp,slider_rect);
width_slider.set_min(min_width);
width_slider.set_max(max_width);
width_slider.set_value(map_width);
slider_rect.y = height_rect.y;
gui::slider height_slider(disp,slider_rect);
height_slider.set_min(min_width);
height_slider.set_max(max_height);
height_slider.set_value(map_height);
const config* const cfg =
game_config.find_child("multiplayer","id","ranmap")->child("generator");
util::scoped_ptr<map_generator> generator(NULL);
generator.assign(create_map_generator("", cfg));
for(bool draw = true;; draw = false) {
int mousex, mousey;
const int mouse_flags = SDL_GetMouseState(&mousex,&mousey);
const bool left_button = mouse_flags&SDL_BUTTON_LMASK;
if(cancel_button.process(mousex,mousey,left_button)) {
return "";
}
if(new_map_button.process(mousex,mousey,left_button)) {
if ((confirmation_needed &&
confirm_modification_disposal(disp))
|| !confirmation_needed) {
int i;
std::stringstream str;
std::stringstream map_str;
for (i = 0; i < width_slider.value(); i++) {
str << fill_terrain;
}
str << "\n";
for (i = 0; i < height_slider.value(); i++) {
map_str << str.str();
}
return map_str.str();
}
}
if(random_map_setting_button.process(mousex,mousey,left_button)) {
if (generator.get()->allow_user_config()) {
generator.get()->user_config(disp);
}
}
if(random_map_button.process(mousex,mousey,left_button)) {
if ((confirmation_needed
&& confirm_modification_disposal(disp))
|| !confirmation_needed) {
const std::string map = generator.get()->create_map(std::vector<std::string>());
if (map == "") {
gui::show_dialog(disp, NULL, "Creation Failed",
"Map creation failed.", gui::OK_ONLY);
}
return map;
}
}
map_width = width_slider.value();
map_height = height_slider.value();
gui::draw_dialog_frame(xpos,ypos,width,height,disp);
width_slider.process();
height_slider.process();
width_slider.set_min(min_width);
height_slider.set_min(min_width);
events::raise_process_event();
events::raise_draw_event();
title_rect = font::draw_text(&disp,disp.screen_area(),24,font::NORMAL_COLOUR,
"Create New Map",xpos+(width-title_rect.w)/2,ypos+10);
font::draw_text(&disp,disp.screen_area(),14,font::NORMAL_COLOUR,
width_label,width_rect.x,width_rect.y);
font::draw_text(&disp,disp.screen_area(),14,font::NORMAL_COLOUR,
height_label,height_rect.x,height_rect.y);
std::stringstream width_str;
width_str << map_width;
font::draw_text(&disp,disp.screen_area(),14,font::NORMAL_COLOUR,width_str.str(),
slider_right+horz_margin,width_rect.y);
std::stringstream height_str;
height_str << map_height;
font::draw_text(&disp,disp.screen_area(),14,font::NORMAL_COLOUR,height_str.str(),
slider_right+horz_margin,height_rect.y);
new_map_button.draw();
random_map_button.draw();
random_map_setting_button.draw();
cancel_button.draw();
update_rect(xpos,ypos,width,height);
disp.update_display();
SDL_Delay(10);
events::pump();
}
}
std::string load_map_dialog(display &disp, bool confirmation_needed) {
const std::string system_path = game_config::path + "/data/maps/";
std::vector<std::string> files;
get_files_in_dir(system_path,&files);
files.push_back("Enter Path...");
files.push_back("Local Map...");
std::string filename;
const int res = gui::show_dialog(disp, NULL, "",
"Choose map to edit:", gui::OK_CANCEL, &files);
if(res == int(files.size()-1)) {
std::vector<std::string> user_files;
const std::string user_path = get_user_data_dir() + "/editor/maps/";
get_files_in_dir(user_path,&user_files);
const int res = gui::show_dialog(disp, NULL, "",
"Choose map to edit:", gui::OK_CANCEL, &user_files);
if (res < 0 || user_files.empty()) {
return "";
}
filename = user_path + user_files[res];
}
else if (res == int(files.size() - 2)) {
filename = get_user_data_dir() + "/editor/maps/";
const int res = gui::show_dialog(disp, NULL, "",
"Enter map to edit:", gui::OK_CANCEL,
NULL, NULL, "", &filename);
if (res != 0) {
return "";
}
}
else if(res < 0 || files.empty()) {
return "";
}
else {
filename = system_path + files[res];
}
std::string map;
bool load_successful = true;
std::string msg;
if (!file_exists(filename) || is_directory(filename)) {
load_successful = false;
msg = filename + " does not exist or can't be read as a file.";
}
else {
try {
map = read_file(filename);
}
catch (io_exception e) {
load_successful = false;
msg = e.what();
}
}
if (!load_successful) {
gui::show_dialog(disp, NULL, "", std::string("Load failed: ") + msg, gui::OK_ONLY);
return "";
}
else {
if (confirmation_needed
&& !confirm_modification_disposal(disp)) {
return "";
}
return map;
}
}
}

View file

@ -0,0 +1,51 @@
/*
Copyright (C) 2003 by David White <davidnwhite@optusnet.com.au>
Part of the Battle for Wesnoth Project http://wesnoth.whitevine.net
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY.
See the COPYING file for more details.
*/
#include "../display.hpp"
#include "../config.hpp"
#include "../map.hpp"
#ifndef EDITOR_DIALOGS_H_INCLUDED
#define EDITOR_DIALOGS_H_INCLUDED
namespace map_editor {
/// Notify the user that the map is changed and ask if the user wants to
/// proceed. Return true if yes is answered.
bool confirm_modification_disposal(display &disp);
/// Show a dialog to create new map. If confirmation_needed is true, the
/// user will be asked if she wants to continue even though the changes
/// to the current map is lost. fill_terrain will be used to fill the
/// map if a new one is created. Return the string representation of the
/// new map, or the empty string if the operation failed or was
/// cancelled.
std::string new_map_dialog(display &disp, gamemap::TERRAIN fill_terrain,
bool confirmation_needed, const config &gconfig);
/// Show a dialog where the user may chose a map to load. If
/// confirmation_needed is true, the user will be asked if she wants to
/// continue even though the changes to the current map is lost. Return
/// the string representation of the map that is loaded, or the empty
/// string if none was.
std::string load_map_dialog(display &disp, bool confirmation_needed);
}
#endif // DIALOGS_H_INCLUDED

View file

@ -0,0 +1,48 @@
/*
Copyright (C) 2003 by David White <davidnwhite@optusnet.com.au>
Part of the Battle for Wesnoth Project http://wesnoth.whitevine.net
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY.
See the COPYING file for more details.
*/
#include "../util.hpp"
#include "editor_layout.hpp"
namespace {
const size_t default_terrain_size = 35;
}
namespace map_editor {
void adjust_sizes(const display &disp, size_specs &sizes,
const unsigned int num_terrains) {
const size_t button_height = 24;
const size_t button_palette_padding = 8;
sizes.terrain_size = default_terrain_size;
sizes.terrain_padding = 2;
sizes.terrain_space = sizes.terrain_size + sizes.terrain_padding;
sizes.palette_x = 40;
sizes.button_x = sizes.palette_x + sizes.terrain_space - 12;
sizes.brush_x = 25;
sizes.brush_y = 190;
sizes.top_button_y = sizes.brush_y + 40;
sizes.palette_y = sizes.top_button_y + button_height +
button_palette_padding;
const size_t max_bot_button_y = disp.y() - 60 - button_height;
size_t space_for_terrains = max_bot_button_y - button_palette_padding -
sizes.palette_y;
space_for_terrains = space_for_terrains / sizes.terrain_space % 2 == 0 ?
space_for_terrains : space_for_terrains - sizes.terrain_space;
sizes.nterrains = minimum((space_for_terrains / sizes.terrain_space) * 2,
num_terrains);
sizes.bot_button_y = sizes.palette_y +
(sizes.nterrains / 2) * sizes.terrain_space + button_palette_padding;
}
}

View file

@ -0,0 +1,42 @@
/*
Copyright (C) 2003 by David White <davidnwhite@optusnet.com.au>
Part of the Battle for Wesnoth Project http://wesnoth.whitevine.net
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY.
See the COPYING file for more details.
*/
#include "../display.hpp"
#ifndef EDITOR_LAYOUT_H_INCLUDED
#define EDITOR_LAYOUT_H_INCLUDED
namespace map_editor {
/// Size specifications for the map editor.
struct size_specs {
size_t nterrains;
size_t terrain_size;
size_t terrain_padding;
size_t terrain_space;
size_t palette_x;
size_t button_x;
size_t brush_x;
size_t brush_y;
size_t top_button_y;
size_t palette_y;
size_t bot_button_y;
};
/// Adjust the internal size specifications to fit the display.
void adjust_sizes(const display &disp, size_specs &sizes,
const unsigned int num_terrains);
}
#endif // EDITOR_LAYOUT_H_INCLUDED

114
src/editor/editor_main.cpp Normal file
View file

@ -0,0 +1,114 @@
/*
Copyright (C) 2003 by David White <davidnwhite@optusnet.com.au>
Part of the Battle for Wesnoth Project http://wesnoth.whitevine.net
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY.
See the COPYING file for more details.
*/
#include "editor.hpp"
#include "../config.hpp"
#include "../game_config.hpp"
#include "../font.hpp"
#include "../image.hpp"
#include "../map.hpp"
#include "../team.hpp"
#include "../preferences.hpp"
#include "../language.hpp"
#include <cctype>
#include <iostream>
#include <map>
#include <string>
int main(int argc, char** argv)
{
game_config::editor = true;
if(argc > 2) {
std::cout << "usage: " << argv[0] << " [map-name]" << std::endl;
return 0;
}
CVideo video;
const font::manager font_manager;
const preferences::manager prefs_manager;
const image::manager image_manager;
std::pair<int, int> desired_resolution = preferences::resolution();
int video_flags = preferences::fullscreen() ? FULL_SCREEN : 0;
video.setMode(desired_resolution.first, desired_resolution.second,
16, video_flags);
preproc_map defines_map;
defines_map["MEDIUM"] = preproc_define();
defines_map["NORMAL"] = preproc_define();
config cfg(preprocess_file("data/game.cfg", &defines_map));
set_language("English");
std::string filename;
std::string mapdata;
if(argc == 2) {
filename = argv[1];
try {
mapdata = read_file(filename);
}
catch (io_exception) {
std::cerr << "Could not read the map file, sorry." << std::endl;
return 1;
}
}
else {
filename = "";
}
if(mapdata.empty()) {
for(int i = 0; i != 20; ++i) {
mapdata = mapdata + "gggggggggggggggggggg\n";
}
}
bool done = false;
gamestatus status(cfg, 0);
std::vector<team> teams;
// Add a dummy team so the reports will be handled properly.
teams.push_back(team(cfg));
config* theme_cfg = cfg.find_child("theme", "name", "editor");
config dummy_theme("");
if (!theme_cfg) {
std::cerr << "Editor theme could not be loaded." << std::endl;
theme_cfg = &dummy_theme;
}
std::map<gamemap::location,unit> units;
while (! done) {
try {
gamemap map(cfg, mapdata);
std::cerr << "Using theme cfg: " << std::endl << theme_cfg->write() << std::endl;
display gui(units, video, map, status, teams,
*theme_cfg, cfg);
gui.set_grid(preferences::grid());
events::event_context ec;
map_editor::map_editor editor(gui, map, *theme_cfg, cfg);
editor.set_file_to_save_as(filename);
editor.main_loop();
done = true;
}
catch (map_editor::map_editor::new_map_exception &e) {
std::cerr << "new map " << e.new_map_ << std::endl;
mapdata = e.new_map_;
filename = "";
}
catch (gamemap::incorrect_format_exception) {
std::cerr << "The map is not in a correct format, sorry." << std::endl;
return 1;
}
}
return 0;
}

View file

@ -0,0 +1,238 @@
/*
Copyright (C) 2003 by David White <davidnwhite@optusnet.com.au>
Part of the Battle for Wesnoth Project http://wesnoth.whitevine.net
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY.
See the COPYING file for more details.
*/
#include "editor_palettes.hpp"
#include "editor_layout.hpp"
#include "../show_dialog.hpp"
#include "../image.hpp"
namespace map_editor {
bool is_invalid_terrain(char c) {
return c == ' ' || c == '~';
}
terrain_palette::terrain_palette(display &gui, const size_specs &sizes,
const gamemap &map)
: size_specs_(sizes), gui_(gui), tstart_(0), map_(map), invalid_(true) {
terrains_ = map_.get_terrain_precedence();
terrains_.erase(std::remove_if(terrains_.begin(), terrains_.end(), is_invalid_terrain),
terrains_.end());
if(terrains_.empty()) {
std::cerr << "No terrain found.\n";
}
else {
selected_terrain_ = terrains_[0];
}
}
void terrain_palette::scroll_down() {
if(tstart_ + size_specs_.nterrains + 2 <= num_terrains()) {
tstart_ += 2;
invalid_ = true;
}
else if (tstart_ + size_specs_.nterrains + 1 <= num_terrains()) {
tstart_ += 1;
invalid_ = true;
}
}
void terrain_palette::scroll_up() {
unsigned int decrement = 2;
if (tstart_ + size_specs_.nterrains == num_terrains()
&& terrains_.size() % 2 != 0) {
decrement = 1;
}
if(tstart_ >= decrement) {
invalid_ = true;
tstart_ -= decrement;
}
}
gamemap::TERRAIN terrain_palette::selected_terrain() const {
return selected_terrain_;
}
void terrain_palette::select_terrain(gamemap::TERRAIN terrain) {
if (selected_terrain_ != terrain) {
invalid_ = true;
selected_terrain_ = terrain;
}
}
void terrain_palette::left_mouse_click(const int mousex, const int mousey) {
int tselect = tile_selected(mousex, mousey);
if(tselect >= 0) {
select_terrain(terrains_[tstart_+tselect]);
}
}
size_t terrain_palette::num_terrains() const {
return terrains_.size();
}
void terrain_palette::draw(bool force) {
if (!invalid_ && !force) {
return;
}
size_t x = gui_.mapx() + size_specs_.palette_x;
size_t y = size_specs_.palette_y;
unsigned int starting = tstart_;
unsigned int ending = starting + size_specs_.nterrains;
SDL_Rect invalid_rect;
invalid_rect.x = x;
invalid_rect.y = y;
invalid_rect.w = 0;
invalid_rect.w = size_specs_.terrain_space * 2;
invalid_rect.h = (size_specs_.nterrains / 2) * size_specs_.terrain_space;
// Everything will be redrawn even though only one little part may
// have changed, but that happens so seldom so we'll settle with
// this.
SDL_Surface* const screen = gui_.video().getSurface();
SDL_BlitSurface(surf_, NULL, screen, &invalid_rect);
surf_.assign(get_surface_portion(screen, invalid_rect));
if(ending > num_terrains()){
ending = num_terrains();
}
for(unsigned int counter = starting; counter < ending; counter++){
const gamemap::TERRAIN terrain = terrains_[counter];
const std::string filename = "terrain/" +
map_.get_terrain_info(terrain).default_image() + ".png";
scoped_sdl_surface image(image::get_image(filename, image::UNSCALED));
if(image->w != size_specs_.terrain_size || image->h != size_specs_.terrain_size) {
image.assign(scale_surface(image, size_specs_.terrain_size,
size_specs_.terrain_size));
}
if(image == NULL) {
std::cerr << "image for terrain '" << counter << "' not found\n";
return;
}
const int counter_from_zero = counter - starting;
SDL_Rect dstrect;
dstrect.x = x + (counter_from_zero % 2 != 0 ? size_specs_.terrain_space : 0);
dstrect.y = y;
dstrect.w = image->w;
dstrect.h = image->h;
SDL_BlitSurface(image, NULL, screen, &dstrect);
gui::draw_rectangle(dstrect.x, dstrect.y, image->w, image->h,
terrain == selected_terrain() ? 0xF000:0 , screen);
if (counter_from_zero % 2 != 0)
y += size_specs_.terrain_space;
}
update_rect(invalid_rect);
invalid_ = false;
}
int terrain_palette::tile_selected(const int x, const int y) const {
for(unsigned int i = 0; i != size_specs_.nterrains; i++) {
const int px = gui_.mapx() + size_specs_.palette_x +
(i % 2 != 0 ? size_specs_.terrain_space : 0);
const int py = size_specs_.palette_y + (i / 2) * size_specs_.terrain_space;
const int pw = size_specs_.terrain_space;
const int ph = size_specs_.terrain_space;
if(x > px && x < px + pw && y > py && y < py + ph) {
return i;
}
}
return -1;
}
brush_bar::brush_bar(display &gui, const size_specs &sizes)
: size_specs_(sizes), gui_(gui), selected_(0), total_brush_(3),
size_(30), invalid_(true) {}
unsigned int brush_bar::selected_brush_size() {
return selected_ + 1;
}
void brush_bar::left_mouse_click(const int mousex, const int mousey) {
int index = selected_index(mousex, mousey);
if(index >= 0) {
if (index != selected_) {
invalid_ = true;
selected_ = index;
}
}
}
void brush_bar::draw(bool force) {
if (!invalid_ && !force) {
return;
}
size_t x = gui_.mapx() + size_specs_.brush_x;
size_t y = size_specs_.brush_y;
SDL_Rect invalid_rect;
invalid_rect.x = x;
invalid_rect.y = y;
invalid_rect.w = size_ * total_brush_;
invalid_rect.h = size_;
// Everything will be redrawn even though only one little part may
// have changed, but that happens so seldom so we'll settle with
// this.
SDL_Surface* const screen = gui_.video().getSurface();
SDL_BlitSurface(surf_, NULL, screen, &invalid_rect);
surf_.assign(get_surface_portion(screen, invalid_rect));
for (int i = 1; i <= total_brush_; i++) {
std::stringstream filename;
filename << "editor/brush-" << i << ".png";
scoped_sdl_surface image(image::get_image(filename.str(), image::UNSCALED));
if (image == NULL) {
std::cerr << "Image " << filename.str() << " not found." << std::endl;
continue;
}
if (image->w != size_ || image->h != size_) {
image.assign(scale_surface(image, size_, size_));
}
SDL_Rect dstrect;
dstrect.x = x;
dstrect.y = size_specs_.brush_y;
dstrect.w = image->w;
dstrect.h = image->h;
SDL_BlitSurface(image, NULL, screen, &dstrect);
gui::draw_rectangle(dstrect.x, dstrect.y, image->w, image->h,
(i == selected_brush_size()) ? 0xF000:0 , screen);
x += image->w;
}
update_rect(invalid_rect);
invalid_ = false;
}
int brush_bar::selected_index(const int x, const int y) const {
const int bar_x = gui_.mapx() + size_specs_.brush_x;
const int bar_y = size_specs_.brush_y;
if ((x < bar_x || x > bar_x + size_ * total_brush_)
|| (y < bar_y || y > bar_y + size_)) {
return -1;
}
for(unsigned int i = 0; i < total_brush_; i++) {
const int px = bar_x + size_ * i;
if(x >= px && x <= px + size_ && y >= bar_y && y <= bar_y + size_) {
return i;
}
}
return -1;
}
}

View file

@ -0,0 +1,111 @@
/*
Copyright (C) 2003 by David White <davidnwhite@optusnet.com.au>
Part of the Battle for Wesnoth Project http://wesnoth.whitevine.net
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY.
See the COPYING file for more details.
*/
#ifndef EDITOR_PALETTES_H_INCLUDED
#define EDITOR_PALETTES_H_INCLUDED
#include "SDL.h"
#include "../sdl_utils.hpp"
#include "../display.hpp"
#include "../map.hpp"
#include "editor_layout.hpp"
#include <vector>
namespace map_editor {
/// A palette where the terrain to be drawn can be selected.
class terrain_palette {
public:
terrain_palette(display &gui, const size_specs &sizes,
const gamemap &map);
/// Scroll the terrain palette up one step if possible.
void scroll_up();
/// Scroll the terrain palette down one step if possible.
void scroll_down();
/// Return the currently selected terrain.
gamemap::TERRAIN selected_terrain() const;
/// Select a terrain.
void select_terrain(gamemap::TERRAIN);
/// To be called when a mouse click occurs. Check if the coordinates
/// is a terrain that may be chosen, select the terrain if that is
/// the case.
void left_mouse_click(const int mousex, const int mousey);
// Draw the palette. If force is true everything will be redrawn
// even though it is not invalidated.
void draw(bool force=false);
/// Return the number of terrains in the palette.
size_t num_terrains() const;
private:
/// Return the number of the tile that is at coordinates (x, y) in the
/// panel.
int tile_selected(const int x, const int y) const;
const size_specs &size_specs_;
scoped_sdl_surface surf_;
display &gui_;
unsigned int tstart_;
std::vector<gamemap::TERRAIN> terrains_;
gamemap::TERRAIN selected_terrain_;
const gamemap &map_;
// Set invalid_ to true if an operation that requires that the
// palette is redrawn takes place.
bool invalid_;
};
/// A bar where the brush is drawin
class brush_bar
{
public:
brush_bar(display &gui, const size_specs &sizes);
/// Return the size of currently selected brush.
unsigned int selected_brush_size();
/// To be called when a mouse click occurs. Check if the coordinates
/// is a terrain that may be chosen, select the terrain if that is
/// the case.
void left_mouse_click(const int mousex, const int mousey);
// Draw the palette. If force is true everything will be redrawn
// even though it is not invalidated.
void draw(bool force=false);
private:
/// Return the index of the brush that is at coordinates (x, y) in the
/// panel.
int selected_index(const int x, const int y) const;
const size_specs &size_specs_;
scoped_sdl_surface surf_;
display &gui_;
unsigned int selected_;
const int total_brush_;
const size_t size_;
// Set invalid_ to true if an operation that requires that the
// bar is redrawn takes place.
bool invalid_;
};
}
#endif // EDITOR_PALETTES_H_INCLUDED

89
src/editor/map_manip.cpp Normal file
View file

@ -0,0 +1,89 @@
/*
Copyright (C) 2003 by David White <davidnwhite@optusnet.com.au>
Part of the Battle for Wesnoth Project http://wesnoth.whitevine.net
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY.
See the COPYING file for more details.
*/
#include "../map.hpp"
#include "map_manip.hpp"
#include <vector>
#include <map>
#include <algorithm>
namespace map_editor {
std::vector<gamemap::location> get_tiles(const gamemap &map,
const gamemap::location& a,
const unsigned int radius) {
const unsigned int distance = radius - 1;
std::vector<gamemap::location> res;
res.push_back(a);
for (int d = 1; d <= distance; d++) {
gamemap::location loc = a;
int i;
// Get the starting point.
for (i = 1; i <= d; i++) {
loc = loc.get_direction(gamemap::location::NORTH);
}
// Get all the tiles clockwise with distance d.
const gamemap::location::DIRECTION direction[6] =
{gamemap::location::SOUTH_EAST, gamemap::location::SOUTH, gamemap::location::SOUTH_WEST,
gamemap::location::NORTH_WEST, gamemap::location::NORTH, gamemap::location::NORTH_EAST};
for (i = 0; i < 6; i++) {
for (int j = 1; j <= d; j++) {
loc = loc.get_direction(direction[i]);
if (map.on_board(loc)) {
res.push_back(loc);
}
}
}
}
return res;
}
void flood_fill(gamemap &map, const gamemap::location &start_loc,
const gamemap::TERRAIN fill_with, terrain_log *log) {
gamemap::TERRAIN terrain_to_fill = map.get_terrain(start_loc);
if (fill_with == terrain_to_fill) {
return;
}
std::vector<gamemap::location> to_fill;
// First push the starting location onto a stack. Then, in every
// iteration, pop one element from the stack, fill this tile and add
// all adjacent tiles that have the terrain that should be
// filled. Continue until the stack is empty.
to_fill.push_back(start_loc);
while (!to_fill.empty()) {
gamemap::location loc = to_fill.back();
to_fill.pop_back();
if (log != NULL) {
log->push_back(std::make_pair(loc, terrain_to_fill));
}
map.set_terrain(loc, fill_with);
// Find all adjacent tiles with the terrain that should be
// filled and add these to the to_fill vector.
std::vector<gamemap::location> adj = get_tiles(map, loc, 2);
for (std::vector<gamemap::location>::iterator it2 = adj.begin();
it2 != adj.end(); it2++) {
if (map.get_terrain(*it2) == terrain_to_fill && map.on_board(*it2)) {
to_fill.push_back(*it2);
}
}
// Remove duplicates.
std::sort(to_fill.begin(), to_fill.end());
std::vector<gamemap::location>::iterator end_of_unique =
std::unique(to_fill.begin(), to_fill.end());
to_fill.erase(end_of_unique, to_fill.end());
}
}
}

38
src/editor/map_manip.hpp Normal file
View file

@ -0,0 +1,38 @@
/*
Copyright (C) 2003 by David White <davidnwhite@optusnet.com.au>
Part of the Battle for Wesnoth Project http://wesnoth.whitevine.net
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY.
See the COPYING file for more details.
*/
#ifndef MAP_MANIP_H_INCLUDED
#define MAP_MANIP_H_INCLUDED
#include "../map.hpp"
#include <vector>
namespace map_editor {
std::vector<gamemap::location> get_tiles(const gamemap &map,
const gamemap::location& a,
const unsigned int radius);
typedef std::vector<std::pair<gamemap::location, gamemap::TERRAIN> > terrain_log;
/// Flood fill the map with the terrain fill_with starting from the
/// location start_loc. If log is non-null it will contain the positions
/// of the changed tiles and the terrains they had before the filling
/// started.
void flood_fill(gamemap &map, const gamemap::location &start_loc,
const gamemap::TERRAIN fill_with, terrain_log *log = NULL);
}
#endif // MAP_MANIP_H_INCLUDED