24 |
#include "gui.hh" |
#include "gui.hh" |
25 |
#include "objects.hh" |
#include "objects.hh" |
26 |
#include "px/sdl.hh" |
#include "px/sdl.hh" |
27 |
|
#include "px/tools.hh" |
28 |
//#include "px/windows.hh" |
//#include "px/windows.hh" |
29 |
#include <iostream> |
#include <iostream> |
30 |
|
|
31 |
#include "display.hh" |
#include "display.hh" |
32 |
#include "d_engine.hh" |
#include "d_engine.hh" |
33 |
|
|
34 |
|
extern "C" { |
35 |
|
#include "lualib.h" |
36 |
|
#include "tolua.h" |
37 |
|
} |
38 |
|
#include "editor-lua.hh" |
39 |
|
|
40 |
using namespace std; |
using namespace std; |
41 |
using namespace enigma; |
using namespace enigma; |
42 |
using namespace enigma::editor; |
using namespace editor; |
43 |
using namespace px; |
using namespace px; |
44 |
|
|
45 |
using display::ScreenArea; |
using display::ScreenArea; |
46 |
using display::DisplayEngine; |
using display::DisplayEngine; |
47 |
using display::Model; |
using display::Model; |
48 |
using world::ObjectTraits; |
//using world::ObjectTraits; |
|
|
|
|
namespace |
|
|
{ |
|
|
class EditorDisplay : public display::CommonDisplay { |
|
|
public: |
|
|
EditorDisplay(const ScreenArea &a); |
|
|
~EditorDisplay() {} |
|
|
|
|
|
void tick(double /*dtime*/) {} |
|
|
|
|
|
Model *make_model (const std::string &name); |
|
|
private: |
|
|
|
|
|
}; |
|
|
|
|
|
class IconBar : public gui::Container { |
|
|
public: |
|
|
IconBar (const ScreenArea &a, int rows, int cols) |
|
|
: m_area (a), m_rows (rows), m_cols(cols), |
|
|
m_bgcolor (150,150,150) |
|
|
{} |
|
|
|
|
|
~IconBar() {} |
|
|
|
|
|
ScreenArea get_area() const { return m_area; } |
|
|
|
|
|
// Widget interface. |
|
|
void draw (px::GC &gc, const px::Rect &area_) { |
|
|
set_color (gc, m_bgcolor); |
|
|
box (gc, area_); |
|
|
} |
|
|
|
|
|
private: |
|
|
// Variables. |
|
|
ScreenArea m_area; |
|
|
int m_rows, m_cols; |
|
|
px::RGB m_bgcolor; |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
enum EditMode { |
|
|
MODE_FLOOR, |
|
|
MODE_ITEMS, |
|
|
MODE_STONES, |
|
|
MODE_ACTORS |
|
|
}; |
|
|
|
|
|
class Level { |
|
|
public: |
|
|
Level (); |
|
|
|
|
|
|
|
|
private: |
|
|
/* |
|
|
** Variables. |
|
|
*/ |
|
|
|
|
|
}; |
|
|
|
|
|
class LevelReader { |
|
|
public: |
|
|
virtual ~LevelReader() {} |
|
|
virtual Level *load_level () = 0; |
|
|
}; |
|
|
|
|
|
class LevelWriter { |
|
|
public: |
|
|
virtual ~LevelWriter() {} |
|
|
virtual void write_level (Level *l) = 0; |
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
class Action { |
|
|
public: |
|
|
void perform() { on_perform(); } |
|
|
void undo() { on_undo(); } |
|
|
private: |
|
|
virtual void on_perform() = 0; |
|
|
virtual void on_undo() = 0; |
|
|
}; |
|
|
|
|
|
class Tool { |
|
|
public: |
|
|
virtual ~Tool() {} |
|
|
|
|
|
}; |
|
|
|
|
|
class ItemTool : public Tool { |
|
|
public: |
|
|
}; |
|
|
|
|
|
class FloorTool : public Tool { |
|
|
public: |
|
|
}; |
|
|
|
|
|
class StoneTool : public Tool { |
|
|
public: |
|
|
}; |
|
|
|
|
|
class ActorTool : public Tool { |
|
|
public: |
|
|
}; |
|
|
|
|
|
class SignalTool : public Tool { |
|
|
public: |
|
|
}; |
|
|
|
|
|
|
|
|
class Editor : sdl::EventHandler { |
|
|
public: |
|
|
Editor(); |
|
|
~Editor(); |
|
|
|
|
|
void run(); |
|
|
|
|
|
void set_cursor (const string &name); |
|
|
|
|
|
private: |
|
|
// Private methods. |
|
|
void set_floor (int x, int y, const string &name); |
|
|
void set_item (int x, int y, const string &name); |
|
|
void set_stone (int x, int y, const string &name); |
|
|
|
|
|
void set_mode (EditMode m); |
|
|
|
|
|
void new_world (int w, int h); |
|
|
|
|
|
void scroll (double xoff, double yoff); |
|
|
void scroll_abs (double x, double y); |
|
|
|
|
|
// EventHandler interface. |
|
|
bool on_mousemotion (SDL_Event &e); |
|
|
bool on_mousebutton (SDL_Event &e); |
|
|
bool on_keydown (SDL_Event &e); |
|
|
|
|
|
// Variables. |
|
|
ScreenArea m_editarea; |
|
|
ScreenArea m_iconarea; |
|
|
EditorDisplay m_display; |
|
|
IconBar m_iconbar; |
|
|
bool m_quit_editor; |
|
|
display::SpriteHandle m_cursor; |
|
|
|
|
|
EditMode m_editmode; |
|
|
|
|
|
// AvailableObjects m_avail_objects; |
|
|
}; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------- |
|
|
// Level representation inside the level editor |
|
|
//---------------------------------------------------------------------- |
|
|
|
|
|
Level::Level () |
|
|
{ |
|
|
} |
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------- |
|
|
// Icon bar |
|
|
//---------------------------------------------------------------------- |
|
49 |
|
|
50 |
|
#include "editor_impl.hh" |
51 |
|
|
52 |
|
|
53 |
//---------------------------------------------------------------------- |
//---------------------------------------------------------------------- |
59 |
{} |
{} |
60 |
|
|
61 |
//---------------------------------------------------------------------- |
//---------------------------------------------------------------------- |
62 |
// Data structure containing information on the available object types |
// Editor tools |
63 |
//---------------------------------------------------------------------- |
//---------------------------------------------------------------------- |
64 |
namespace |
void |
65 |
|
GridObjectTool::advance_in_group (int offset) |
66 |
{ |
{ |
67 |
enum ObjectFlags { |
int newidx = m_objectidx + offset; |
68 |
OBJFLAG_None = 0, |
if (newidx >= 0 && newidx < (int)m_groups[m_groupidx].entries.size()) |
69 |
OBJFLAG_SignalEmitter = 0x1, |
m_objectidx = newidx; |
70 |
OBJFLAG_SignalRecipient = 0x2, |
} |
|
}; |
|
|
|
|
|
const char *signal_names[] = { |
|
|
"trigger", |
|
|
"open", |
|
|
"close", |
|
|
"open / close", |
|
|
"on", |
|
|
"off", |
|
|
"on / off" |
|
|
}; |
|
|
|
|
|
|
|
|
class AvailableObjects { |
|
|
public: |
|
|
AvailableObjects(); |
|
|
vector<ObjectTraits> floors; |
|
|
vector<ObjectTraits> items; |
|
|
vector<ObjectTraits> stones; |
|
|
private: |
|
71 |
|
|
72 |
}; |
void |
73 |
|
GridObjectTool::advance_group (int offset) |
74 |
|
{ |
75 |
|
int newidx = m_groupidx + offset; |
76 |
|
if (newidx >= 0 && newidx < (int)m_groups.size()) { |
77 |
|
m_groupidx = newidx; |
78 |
|
m_objectidx = 0; |
79 |
|
} |
80 |
|
} |
81 |
|
|
82 |
|
|
83 |
|
void |
84 |
|
GridObjectTool::on_mousebutton (const SDL_Event &e, V2 worldpos) |
85 |
|
{ |
86 |
|
Editor *ed = Editor::get_instance(); |
87 |
|
string obj = current_object(); |
88 |
|
int x = static_cast<int>(worldpos[0]); |
89 |
|
int y = static_cast<int>(worldpos[1]); |
90 |
|
|
91 |
|
if (e.button.type == SDL_MOUSEBUTTONDOWN) { |
92 |
|
if (e.button.button == 1) { |
93 |
|
// left mb -> set object |
94 |
|
switch (m_layer) { |
95 |
|
case GRID_FLOOR: ed->set_floor (x, y, obj); break; |
96 |
|
case GRID_ITEMS: ed->set_item (x, y, obj); break; |
97 |
|
case GRID_STONES: ed->set_stone (x, y, obj); break; |
98 |
|
default: break; |
99 |
|
} |
100 |
|
} else if (e.button.button == 3) { |
101 |
|
// right mb |
102 |
|
} |
103 |
|
} |
104 |
} |
} |
105 |
AvailableObjects::AvailableObjects() |
|
106 |
|
void |
107 |
|
GridObjectTool::object_menu() |
108 |
{ |
{ |
|
floors.push_back (ObjectTraits ("fl-metal", world::OBJTYPE_Floor)); |
|
109 |
} |
} |
110 |
|
|
111 |
|
|
112 |
|
|
113 |
|
|
114 |
//====================================================================== |
//====================================================================== |
115 |
// THE EDITOR |
// THE EDITOR |
116 |
//====================================================================== |
//====================================================================== |
117 |
|
|
118 |
|
Editor *Editor::m_instance = 0; |
119 |
|
|
120 |
Editor::Editor() |
Editor::Editor() |
121 |
: m_editarea (0,0,640,13*32), |
: m_editarea (0,0,640,13*32), |
122 |
m_iconarea (0,13*32,640,64), |
m_iconarea (0,13*32,640,64), |
124 |
m_iconbar (m_iconarea, 2, 640/32), |
m_iconbar (m_iconarea, 2, 640/32), |
125 |
m_quit_editor (false), |
m_quit_editor (false), |
126 |
m_cursor(), |
m_cursor(), |
127 |
|
m_lua (lua_open(0)), |
128 |
m_editmode (MODE_FLOOR) |
m_editmode (MODE_FLOOR) |
129 |
{ |
{ |
130 |
|
lua_baselibopen (m_lua); |
131 |
|
lua_strlibopen(m_lua); |
132 |
|
tolua_open (m_lua); |
133 |
|
tolua_editor_open (m_lua); |
134 |
} |
} |
135 |
|
|
136 |
Editor::~Editor() |
Editor::~Editor() |
137 |
{} |
{ |
138 |
|
lua_close (m_lua); |
139 |
|
} |
140 |
|
|
141 |
void |
void Editor::init() |
|
Editor::run() |
|
142 |
{ |
{ |
143 |
// video::HideMouse(); |
delete_sequence (m_tools.begin(), m_tools.end()); |
144 |
cout << "Editor is up and running...\n"; |
m_tools.clear(); |
145 |
|
m_tools.resize (MODE_COUNT, (Tool*) 0); |
146 |
|
m_tools[MODE_FLOOR] = m_floortool = new FloorTool; |
147 |
|
m_tools[MODE_ITEMS] = m_itemtool = new ItemTool; |
148 |
|
m_tools[MODE_STONES] = m_stonetool = new StoneTool; |
149 |
|
|
150 |
new_world (20, 13); |
new_world (20, 13); |
151 |
|
|
152 |
|
string fname = enigma::FindDataFile ("editor.lua"); |
153 |
|
if (lua_dofile (m_lua, fname.c_str()) != 0) { |
154 |
|
fprintf (stderr, "Error loading 'editor.lua'\n"); |
155 |
|
} |
156 |
|
} |
157 |
|
|
158 |
|
void Editor::run() |
159 |
|
{ |
160 |
|
m_quit_editor = false; |
161 |
while (!m_quit_editor) { |
while (!m_quit_editor) { |
162 |
video::HideMouse(); |
video::HideMouse(); |
163 |
m_display.redraw(); |
m_display.redraw(); |
172 |
} |
} |
173 |
} |
} |
174 |
|
|
175 |
void |
void Editor::set_mode (EditMode m) |
|
Editor::set_mode (EditMode m) |
|
176 |
{ |
{ |
177 |
m_editmode = m; |
m_editmode = m; |
178 |
|
update_cursor(); |
179 |
|
} |
180 |
|
|
181 |
|
void Editor::update_cursor() |
182 |
|
{ |
183 |
|
set_cursor (current_tool()->current_object()); |
184 |
} |
} |
185 |
|
|
186 |
|
Tool *Editor::current_tool() |
187 |
|
{ |
188 |
|
if (Tool *tool = m_tools[m_editmode]) |
189 |
|
return tool; |
190 |
|
else { |
191 |
|
fprintf (stderr, "undefined tool\n"); |
192 |
|
return m_stonetool; |
193 |
|
} |
194 |
|
} |
195 |
|
|
196 |
|
|
197 |
void |
void |
198 |
Editor::set_floor (int x, int y, const std::string &name) |
Editor::set_floor (int x, int y, const std::string &name) |
199 |
{ |
{ |
263 |
bool |
bool |
264 |
Editor::on_mousebutton (SDL_Event &e) |
Editor::on_mousebutton (SDL_Event &e) |
265 |
{ |
{ |
266 |
if (e.button.type == SDL_MOUSEBUTTONDOWN) |
DisplayEngine *engine = m_display.get_engine(); |
267 |
{ |
V2 worldpos = engine->to_world (V2(e.motion.x, e.motion.y)); |
268 |
DisplayEngine *engine = m_display.get_engine(); |
|
269 |
V2 worldpos = engine->to_world (V2(e.motion.x, e.motion.y)); |
if (Tool *tool = current_tool()) |
270 |
int x = int(worldpos[0]); |
tool->on_mousebutton (e, worldpos); |
271 |
int y = int(worldpos[1]); |
return true; |
|
|
|
|
switch (m_editmode) { |
|
|
case MODE_FLOOR: |
|
|
set_floor (x, y, "fl-hay"); |
|
|
break; |
|
|
case MODE_ITEMS: |
|
|
set_item (x, y, "it-umbrella"); |
|
|
break; |
|
|
case MODE_STONES: |
|
|
set_stone (x, y, "st-brownie"); |
|
|
break; |
|
|
case MODE_ACTORS: |
|
|
break; |
|
|
} |
|
|
return true; |
|
|
} |
|
|
return false; |
|
272 |
} |
} |
273 |
|
|
274 |
bool |
bool |
275 |
Editor::on_keydown(SDL_Event &e) |
Editor::on_keydown(SDL_Event &e) |
276 |
{ |
{ |
277 |
|
bool ctrl_pressed = e.key.keysym.mod & KMOD_CTRL; |
278 |
|
bool shift_pressed = e.key.keysym.mod & KMOD_SHIFT; |
279 |
|
int hoff = 19; |
280 |
|
int voff = 12; |
281 |
|
|
282 |
|
Tool *tool = current_tool(); |
283 |
|
|
284 |
switch (e.key.keysym.sym) { |
switch (e.key.keysym.sym) { |
285 |
case SDLK_ESCAPE: |
case SDLK_ESCAPE: |
286 |
m_quit_editor = true; |
m_quit_editor = true; |
287 |
break; |
break; |
288 |
case SDLK_LEFT: |
case SDLK_LEFT: scroll (ctrl_pressed ? -hoff : -1, 0); break; |
289 |
if (e.key.keysym.mod & KMOD_CTRL) |
case SDLK_RIGHT: scroll (ctrl_pressed ? +hoff : +1, 0); break; |
290 |
scroll (-19, 0); |
case SDLK_DOWN: scroll (0, ctrl_pressed ? +voff : +1); break; |
291 |
else |
case SDLK_UP: scroll (0, ctrl_pressed ? -voff : -1); break; |
292 |
scroll (-1, 0); |
case SDLK_HOME: scroll_abs (0,0); break; |
293 |
|
|
294 |
|
case SDLK_PAGEUP: |
295 |
|
tool->advance_group (-1); |
296 |
|
update_cursor(); |
297 |
break; |
break; |
298 |
case SDLK_RIGHT: |
case SDLK_PAGEDOWN: |
299 |
if (e.key.keysym.mod & KMOD_CTRL) |
tool->advance_group (+1); |
300 |
scroll (+19, 0); |
update_cursor(); |
|
else |
|
|
scroll (+1, 0); |
|
301 |
break; |
break; |
302 |
case SDLK_DOWN: |
|
303 |
if (e.key.keysym.mod & KMOD_CTRL) |
case SDLK_PLUS: |
304 |
scroll (0, +12); |
tool->advance_in_group (+1); |
305 |
else |
update_cursor(); |
|
scroll (0, +1); |
|
|
break; |
|
|
case SDLK_UP: |
|
|
if (e.key.keysym.mod & KMOD_CTRL) |
|
|
scroll (0, -12); |
|
|
else |
|
|
scroll (0, -1); |
|
306 |
break; |
break; |
307 |
case SDLK_HOME: |
case SDLK_MINUS: |
308 |
scroll_abs (0,0); |
tool->advance_in_group (-1); |
309 |
|
update_cursor(); |
310 |
break; |
break; |
311 |
|
|
312 |
case SDLK_a: |
case SDLK_a: |
313 |
if (e.key.keysym.mod & KMOD_SHIFT) |
if (shift_pressed) |
314 |
; |
; |
315 |
else |
set_mode(MODE_ACTORS); |
|
set_mode(MODE_ACTORS); |
|
316 |
break; |
break; |
317 |
case SDLK_f: |
case SDLK_f: |
318 |
if (e.key.keysym.mod & KMOD_SHIFT) |
if (shift_pressed) |
319 |
; |
; |
320 |
else |
set_mode(MODE_FLOOR); |
|
set_mode(MODE_FLOOR); |
|
321 |
break; |
break; |
322 |
case SDLK_i: |
case SDLK_i: |
323 |
if (e.key.keysym.mod & KMOD_SHIFT) |
if (shift_pressed) |
324 |
; |
; |
325 |
else |
set_mode(MODE_ITEMS); |
|
set_mode(MODE_ITEMS); |
|
326 |
break; |
break; |
327 |
case SDLK_s: |
case SDLK_s: |
328 |
if (e.key.keysym.mod & KMOD_SHIFT) |
set_mode (MODE_STONES); |
329 |
; |
if (shift_pressed) { |
330 |
else |
tool = current_tool(); |
331 |
set_mode (MODE_STONES); |
tool->object_menu(); |
332 |
|
} |
333 |
break; |
break; |
334 |
|
|
335 |
default: |
default: |
338 |
return true; |
return true; |
339 |
} |
} |
340 |
|
|
341 |
|
void editor::DefineFloorGroup (const char *name, const char *descr, |
342 |
|
int nentries, const char **entries) |
343 |
|
{ |
344 |
|
Editor *ed = Editor::get_instance(); |
345 |
|
|
346 |
|
vector<string> entryvec(entries, entries+nentries); |
347 |
|
ObjectGroup group(name, descr, entryvec); |
348 |
|
ed->add_floor_group (group); |
349 |
|
} |
350 |
|
|
351 |
void |
void editor::DefineItemGroup (const char *name, const char *descr, |
352 |
editor::Run() |
int nentries, const char **entries) |
353 |
|
{ |
354 |
|
Editor *ed = Editor::get_instance(); |
355 |
|
|
356 |
|
vector<string> entryvec(entries, entries+nentries); |
357 |
|
ObjectGroup group(name, descr, entryvec); |
358 |
|
ed->add_item_group (group); |
359 |
|
} |
360 |
|
|
361 |
|
void editor::DefineStoneGroup (const char *name, const char *descr, |
362 |
|
int nentries, const char **entries) |
363 |
|
{ |
364 |
|
Editor *ed = Editor::get_instance(); |
365 |
|
|
366 |
|
vector<string> entryvec(entries, entries+nentries); |
367 |
|
ObjectGroup group(name, descr, entryvec); |
368 |
|
ed->add_stone_group (group); |
369 |
|
} |
370 |
|
|
371 |
|
|
372 |
|
void editor::Run() |
373 |
{ |
{ |
374 |
// lua::Dofile("editor.lua"); |
Editor *ed = Editor::get_instance(); |
375 |
Editor().run(); |
ed->init(); |
376 |
|
ed->run(); |
377 |
} |
} |