Skip to content
This repository
Fetching contributors…

Octocat-spinner-32-eaf2f5

Cannot retrieve contributors at this time

file 357 lines (261 sloc) 10.451 kb
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356
#ifndef EDITOR_HPP_INCLUDED
#define EDITOR_HPP_INCLUDED
#ifndef NO_EDITOR

#include <boost/function.hpp>
#include <boost/scoped_ptr.hpp>
#include <stack>
#include <vector>

#include "external_text_editor.hpp"
#include "geometry.hpp"
#include "key.hpp"
#include "level.hpp"
#include "level_object.hpp"
#include "preferences.hpp"
#include "stats.hpp"

static const int EDITOR_MENUBAR_HEIGHT = 40;
static const int EDITOR_SIDEBAR_WIDTH = 220;

namespace gui {
class dialog;
}

namespace editor_dialogs {
class character_editor_dialog;
class editor_layers_dialog;
class property_editor_dialog;
class segment_editor_dialog;
class tileset_editor_dialog;
class custom_object_dialog;
class hex_tileset_editor_dialog;
}

class code_editor_dialog;

class editor_menu_dialog;
class editor_mode_dialog;

class editor
{
public:
//A manager which should be scoped around creation of editors.
struct manager {
~manager();
};

static editor* get_editor(const char* level_cfg);
static void edit(const char* level_cfg, int xpos=-1, int ypos=-1);
static std::string last_edited_level();

static int sidebar_width();
static int codebar_height();

editor(const char* level_cfg);
~editor();

void setup_for_editing();
void edit_level();

void process();
bool handle_event(const SDL_Event& event, bool swallowed);
void handle_scrolling();

int xpos() const { return xpos_; }
int ypos() const { return ypos_; }

int xres() const { return xres_; }
int yres() const { return yres_; }

void set_pos(int x, int y);

typedef boost::intrusive_ptr<level> level_ptr;
void set_playing_level(level_ptr lvl);
void toggle_active_level();

void load_stats();
void show_stats();
void download_stats();

struct tileset {
static void init(variant node);
explicit tileset(variant node);
std::string category;
std::string type;
int zorder;
int x_speed;
int y_speed;
bool sloped;
variant node_info;

boost::shared_ptr<tile_map> preview() const;
private:
mutable boost::shared_ptr<tile_map> preview_;
};

struct enemy_type {
enemy_type(const std::string& type, const std::string& category, variant frame_info);
variant node;
std::string category;
std::string help;

const entity_ptr& preview_object() const;
const boost::shared_ptr<const frame>& preview_frame() const;

private:
mutable entity_ptr preview_object_;
mutable boost::shared_ptr<const frame> preview_frame_;
variant frame_info_;
};

struct tile_selection {
bool empty() const { return tiles.empty(); }
std::vector<point> tiles;
};

const tile_selection& selection() const { return tile_selection_; }

const std::vector<tileset>& all_tilesets() const;
int get_tileset() const { return cur_tileset_; }
void set_tileset(int index);

int get_hex_tileset() const { return cur_hex_tileset_; }
void set_hex_tileset(int index);

std::vector<enemy_type>& all_characters() const;

int get_object() const { return cur_object_; }
void set_object(int index);

enum EDIT_TOOL { TOOL_ADD_RECT, TOOL_SELECT_RECT, TOOL_MAGIC_WAND, TOOL_PENCIL, TOOL_PICKER, TOOL_ADD_OBJECT, TOOL_SELECT_OBJECT, TOOL_EDIT_SEGMENTS, TOOL_EDIT_HEXES, NUM_TOOLS };
EDIT_TOOL tool() const;
void change_tool(EDIT_TOOL tool);

level& get_level() { return *lvl_; }
const level& get_level() const { return *lvl_; }

std::vector<level_ptr> get_level_list() const { return levels_; }

void save_level();
void save_level_as(const std::string& filename);
void quit();
bool confirm_quit(bool allow_cancel=true);
void zoom_in();
void zoom_out();
int zoom() const { return zoom_; }

void undo_command();
void redo_command();

void close() { done_ = true; }

void edit_level_properties();
void create_new_module();
void edit_module_properties();
void create_new_object();
void edit_shaders();

//make the selected objects part of a group
void group_selection();

bool face_right() const { return face_right_; }

//switch the current facing.
void toggle_facing();

void toggle_upside_down();

void duplicate_selected_objects();

void run_script(const std::string& id);

//function which gets the expected layer at which a certain tile id appears.
int get_tile_zorder(const std::string& tile_id) const;
void add_tile_rect(int zorder, const std::string& tile_id, int x1, int y1, int x2, int y2);

enum EXECUTABLE_COMMAND_TYPE { COMMAND_TYPE_DEFAULT, COMMAND_TYPE_DRAG_OBJECT };

//function to execute a command which will go into the undo/redo list.
//normally any time the editor mutates the level, it should be done
//through this function
void execute_command(boost::function<void()> command, boost::function<void()> undo, EXECUTABLE_COMMAND_TYPE type=COMMAND_TYPE_DEFAULT);

//functions to begin and end a group of commands. This is used when we
//are going to execute a bunch of commands, and from the point of view of
//undoing, they should be viewed as a single operation.
//When end_command_group() is called, all calls to execute_command since
//the corresponding call to begin_command_group() will be rolled up
//into a single command.
//
//These functions are re-entrant.
void begin_command_group();
void end_command_group();

void draw_gui() const;

//We are currently playing a level we are editing, and we want
//to reset it to its initial state.
void reset_playing_level(bool keep_player=true);

void toggle_pause() const;
void toggle_code();

bool has_keyboard_focus() const;

void start_adding_points(const std::string& field_name);
const std::string& adding_points() const { return adding_points_; }

int level_state_id() const { return level_changed_; }

void mutate_object_value(level_ptr lvl, entity_ptr e, const std::string& value, variant new_value);

bool done() const { return done_; }

private:
editor(const editor&);
void operator=(const editor&);

//Are we editing a level that is actually being played and in motion?
bool editing_level_being_played() const;

void reset_dialog_positions();

void handle_mouse_button_down(const SDL_MouseButtonEvent& event);
void handle_mouse_button_up(const SDL_MouseButtonEvent& event);
void handle_key_press(const SDL_KeyboardEvent& key);

void handle_object_dragging(int mousex, int mousey);
void handle_drawing_rect(int mousex, int mousey);

void process_ghost_objects();
void remove_ghost_objects();
void draw() const;
void draw_selection(int xoffset, int yoffset) const;

void add_hex_tile_rect(int x1, int y1, int x2, int y2);
void remove_hex_tile_rect(int x1, int y1, int x2, int y2);

void add_tile_rect(int x1, int y1, int x2, int y2);
void remove_tile_rect(int x1, int y1, int x2, int y2);
void select_tile_rect(int x1, int y1, int x2, int y2);
void select_magic_wand(int xpos, int ypos);

void set_selection(const tile_selection& s);

void execute_shift_object(entity_ptr e, int dx, int dy);

void move_object(level_ptr lvl, entity_ptr e, int delta_x, int delta_y);

bool editing_objects() const { return tool_ == TOOL_ADD_OBJECT || tool_ == TOOL_SELECT_OBJECT; }
bool editing_tiles() const { return !editing_objects(); }

//functions which add and remove an object from a level, as well as
//sending the object appropriate events.
void add_multi_object_to_level(level_ptr lvl, entity_ptr e);
void add_object_to_level(level_ptr lvl, entity_ptr e);
void remove_object_from_level(level_ptr lvl, entity_ptr e);

void generate_mutate_commands(entity_ptr e, const std::string& attr, variant new_value,
std::vector<boost::function<void()> >& undo,
std::vector<boost::function<void()> >& redo);

void generate_remove_commands(entity_ptr e, std::vector<boost::function<void()> >& undo, std::vector<boost::function<void()> >& redo);

CKey key_;

level_ptr lvl_;

std::vector<level_ptr> levels_;
int zoom_;
int xpos_, ypos_;
int anchorx_, anchory_;

// X and Y resolution of the editor, 0 means use default.
int xres_, yres_;

//if we are dragging an entity around, this marks the position from
//which the entity started the drag.
int selected_entity_startx_, selected_entity_starty_;
std::string filename_;

//If we are currently adding points to an object, this is non-empty
//and has the name of the field we're adding points to. The object
//being edited will always be lvl.editor_highlight()
std::string adding_points_;

EDIT_TOOL tool_;
bool done_;
bool face_right_;
bool upside_down_;
int cur_tileset_;
int cur_hex_tileset_;

int cur_object_;

tile_selection tile_selection_;

boost::scoped_ptr<editor_menu_dialog> editor_menu_dialog_;
boost::scoped_ptr<editor_mode_dialog> editor_mode_dialog_;
boost::scoped_ptr<editor_dialogs::character_editor_dialog> character_dialog_;
boost::scoped_ptr<editor_dialogs::editor_layers_dialog> layers_dialog_;
boost::scoped_ptr<editor_dialogs::property_editor_dialog> property_dialog_;
boost::scoped_ptr<editor_dialogs::tileset_editor_dialog> tileset_dialog_;
boost::scoped_ptr<editor_dialogs::hex_tileset_editor_dialog> hex_tileset_dialog_;

boost::scoped_ptr<editor_dialogs::segment_editor_dialog> segment_dialog_;

boost::scoped_ptr<code_editor_dialog> code_dialog_;

external_text_editor_ptr external_code_editor_;

void set_code_file();

gui::dialog* current_dialog_;

//if the mouse is currently down, drawing a rect.
bool drawing_rect_, dragging_;

struct executable_command {
boost::function<void()> redo_command;
boost::function<void()> undo_command;
EXECUTABLE_COMMAND_TYPE type;
};

std::vector<executable_command> undo_, redo_;

//a temporary undo which is used for when we execute commands on
//a temporary basis -- e.g. for a preview -- so we can later undo them.
boost::scoped_ptr<executable_command> tmp_undo_;

//indexes into undo_ which records the beginning of the current 'group'
//of commands. When begin_command_group() is called, a value is added
//set to the size of undo_. When end_command_group() is called, all
//commands with index > the top value are aggregated into a single command,
//and the top value is popped.
std::stack<int> undo_commands_groups_;

std::vector<entity_ptr> ghost_objects_;

int level_changed_;
int selected_segment_;

int prev_mousex_, prev_mousey_;
};

struct editor_resolution_manager : private preferences::editor_screen_size_scope
{
static bool is_active();
explicit editor_resolution_manager(int xres, int yres);
~editor_resolution_manager();

int original_width_, original_height_;
};

#endif // !NO_EDITOR
#endif
Something went wrong with that request. Please try again.