470 lines
9.6 KiB
C++
470 lines
9.6 KiB
C++
/*
|
||
* Copyright (C) 2002,2003,2004 Daniel Heck
|
||
*
|
||
* This program is free software; you can redistribute it and/or
|
||
* modify it under the terms of the GNU General Public License
|
||
* as published by the Free Software Foundation; either version 2
|
||
* of the License, or (at your option) any later version.
|
||
*
|
||
* This program is distributed in the hope that it will be useful,
|
||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
* GNU General Public License for more details.
|
||
*
|
||
* You should have received a copy of the GNU General Public License along
|
||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||
*
|
||
*/
|
||
#include "editor.hh"
|
||
|
||
#include "ecl_sdl.hh"
|
||
#include "ecl_video.hh" // set_color, line
|
||
#include "ecl_util.hh" // set_flags
|
||
|
||
#include "main.hh"
|
||
#include "world.hh"
|
||
#include "lua.hh"
|
||
#include "video.hh"
|
||
#include "gui/widgets.hh"
|
||
#include "display_internal.hh" // WorldArea
|
||
|
||
#include <iostream>
|
||
#include <cassert>
|
||
|
||
#include "display_internal.hh"
|
||
#include "d_engine.hh"
|
||
|
||
#ifndef CXXLUA
|
||
extern "C" {
|
||
#include "lualib.h"
|
||
#include "tolua++.h"
|
||
}
|
||
#else
|
||
#include "lualib.h"
|
||
#include "tolua++.h"
|
||
#endif
|
||
|
||
#include "lua-editor.hh"
|
||
|
||
using namespace std;
|
||
using namespace enigma;
|
||
using namespace editor;
|
||
using namespace ecl;
|
||
|
||
using display::ScreenArea;
|
||
using display::DisplayEngine;
|
||
using display::Model;
|
||
//using world::ObjectTraits;
|
||
|
||
using world::ItemID;
|
||
|
||
#include "editor_impl.hh"
|
||
|
||
|
||
/* -------------------- Editor state -------------------- */
|
||
|
||
EditorState::EditorState()
|
||
{
|
||
}
|
||
|
||
|
||
EditorState::~EditorState()
|
||
{
|
||
}
|
||
|
||
|
||
void EditorState::save( std::ostream & /*os*/ )
|
||
{
|
||
}
|
||
|
||
void EditorState::load( std::istream & /*is*/ )
|
||
{
|
||
}
|
||
|
||
|
||
|
||
/* -------------------- Editor display engine -------------------- */
|
||
|
||
EditorDisplay::EditorDisplay()
|
||
{
|
||
DisplayEngine *engine = get_engine();
|
||
engine->set_screen_area( video::GetInfo()->gamearea );
|
||
engine->add_layer( new DL_Editor );
|
||
}
|
||
|
||
void
|
||
EditorDisplay::redraw()
|
||
{
|
||
display::CommonDisplay::redraw();
|
||
}
|
||
|
||
|
||
/* -------------------- Editor tools -------------------- */
|
||
|
||
void
|
||
GridObjectTool::advance_in_group( int offset )
|
||
{
|
||
int newidx = m_objectidx + offset;
|
||
if( newidx >= 0 && newidx < (int)m_groups[ m_groupidx ].entries.size() ) {
|
||
m_objectidx = newidx;
|
||
}
|
||
}
|
||
|
||
void
|
||
GridObjectTool::advance_group( int offset )
|
||
{
|
||
int newidx = m_groupidx + offset;
|
||
if( newidx >= 0 && newidx < (int)m_groups.size() ) {
|
||
m_groupidx = newidx;
|
||
m_objectidx = 0;
|
||
}
|
||
}
|
||
|
||
void
|
||
GridObjectTool::on_mousebutton( const SDL_Event &e, V2 worldpos )
|
||
{
|
||
Editor *ed = Editor::get_instance();
|
||
string obj = current_object();
|
||
|
||
round_coordinates( &worldpos );
|
||
int x = (int)worldpos[ 0 ];
|
||
int y = (int)worldpos[ 1 ];
|
||
|
||
if( e.button.type == SDL_MOUSEBUTTONDOWN ) {
|
||
if( e.button.button == 1 ) {
|
||
// left mb -> set object
|
||
switch( m_layer ) {
|
||
case GRID_FLOOR: ed->set_floor( x, y, obj ); break;
|
||
case GRID_ITEMS: ed->set_item( x, y, obj ); break;
|
||
case GRID_STONES: ed->set_stone( x, y, obj ); break;
|
||
default: break;
|
||
}
|
||
}
|
||
else if( e.button.button == 3 ) {
|
||
// right mb
|
||
}
|
||
}
|
||
}
|
||
|
||
void
|
||
GridObjectTool::object_menu()
|
||
{
|
||
}
|
||
|
||
void
|
||
ActorTool::on_mousebutton( const SDL_Event &e, V2 worldpos )
|
||
{
|
||
Editor *ed = Editor::get_instance();
|
||
string obj = current_object();
|
||
|
||
if( e.button.type == SDL_MOUSEBUTTONDOWN ) {
|
||
if( e.button.button == 1 ) {
|
||
// left mb -> set object
|
||
ed->set_actor( worldpos[0], worldpos[1], obj );
|
||
}
|
||
else if( e.button.button == 3 ) {
|
||
// right mb
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
/* -------------------- The Editor -------------------- */
|
||
|
||
Editor *Editor::m_instance = 0;
|
||
|
||
Editor::Editor()
|
||
: m_editarea( 0,0,640,13*32 )
|
||
, m_iconarea( 0,13*32,640,64 )
|
||
, m_display()
|
||
, m_iconbar( m_iconarea, 2, 640/32 )
|
||
, m_quit_editor( false )
|
||
, m_cursor()
|
||
, m_lua( luaL_newstate() )
|
||
, m_editmode( MODE_FLOOR )
|
||
, m_tools()
|
||
{
|
||
luaL_openlibs(m_lua);
|
||
tolua_open( m_lua );
|
||
tolua_editor_open( m_lua );
|
||
}
|
||
|
||
Editor::~Editor()
|
||
{
|
||
lua_close( m_lua );
|
||
}
|
||
|
||
void
|
||
Editor::init()
|
||
{
|
||
delete_sequence( m_tools.begin(), m_tools.end() );
|
||
m_tools.clear();
|
||
m_tools.resize( MODE_COUNT, NULL );
|
||
m_tools[ MODE_FLOOR ] = m_floortool = new FloorTool;
|
||
m_tools[ MODE_ITEMS ] = m_itemtool = new ItemTool;
|
||
m_tools[ MODE_STONES ] = m_stonetool = new StoneTool;
|
||
m_tools[ MODE_ACTORS ] = m_actortool = new ActorTool;
|
||
|
||
new_world( 20, 13 );
|
||
|
||
// TODO - just printing a message is not enough - the app will crash on missing editor.lua
|
||
if (lua::DoSysFile(m_lua, "compat.lua") != lua::NO_LUAERROR) {
|
||
std::string message = "While processing 'compat.lua':\n" +lua::LastError(m_lua);
|
||
fprintf( stderr, message.c_str() );
|
||
}
|
||
if (lua::DoSysFile(m_lua, "editor.lua") != lua::NO_LUAERROR) {
|
||
std::string message = "Error loading 'editor.lua'\n" +lua::LastError(m_lua);
|
||
fprintf( stderr, message.c_str() );
|
||
}
|
||
}
|
||
|
||
void
|
||
Editor::run()
|
||
{
|
||
m_quit_editor = false;
|
||
while( !m_quit_editor ) {
|
||
video::HideMouse();
|
||
m_display.redraw();
|
||
video::ShowMouse();
|
||
video::GetScreen()->flush_updates();
|
||
|
||
SDL_Event e;
|
||
if( SDL_PollEvent( &e ) ) {
|
||
dispatch_event (e);
|
||
}
|
||
|
||
SDL_Delay( 10 );
|
||
}
|
||
}
|
||
|
||
void Editor::set_mode( EditMode m )
|
||
{
|
||
m_editmode = m;
|
||
update_cursor();
|
||
}
|
||
|
||
void Editor::update_cursor()
|
||
{
|
||
// set proper position
|
||
int mx;
|
||
int my;
|
||
SDL_GetMouseState( &mx, &my );
|
||
DisplayEngine *engine = m_display.get_engine();
|
||
V2 worldpos = engine->to_world( V2( mx, my ) );
|
||
current_tool()->round_coordinates( &worldpos );
|
||
m_cursor.move( worldpos );
|
||
|
||
// set proper face
|
||
set_cursor( current_tool()->current_object() );
|
||
}
|
||
|
||
Tool *Editor::current_tool()
|
||
{
|
||
if( Tool *tool = m_tools[ m_editmode ] ) {
|
||
return tool;
|
||
}
|
||
else {
|
||
fprintf( stderr, "undefined tool\n" );
|
||
assert( m_stonetool != NULL );
|
||
return m_stonetool;
|
||
}
|
||
}
|
||
|
||
|
||
void
|
||
Editor::set_floor( int x, int y, std::string const& name )
|
||
{
|
||
m_display.set_floor( x, y, display::MakeModel( name ) );
|
||
}
|
||
|
||
void
|
||
Editor::set_item( int x, int y, std::string const& name )
|
||
{
|
||
m_display.set_item( x, y, display::MakeModel( name ) );
|
||
}
|
||
|
||
void
|
||
Editor::set_stone( int x, int y, std::string const& name )
|
||
{
|
||
m_display.set_stone( x, y, display::MakeModel( name ) );
|
||
}
|
||
|
||
void
|
||
Editor::set_actor( double x, double y, std::string const& name )
|
||
{
|
||
m_display.add_sprite( V2( x, y ), display::MakeModel( name ) );
|
||
}
|
||
|
||
|
||
void
|
||
Editor::new_world( int w, int h )
|
||
{
|
||
m_display.new_world( w, h );
|
||
for( int x=0; x<w; ++x ) {
|
||
for( int y=0; y<h; ++y ) {
|
||
set_floor (x, y, "fl-normal");
|
||
}
|
||
}
|
||
m_cursor = m_display.add_effect( V2(), display::MakeModel( "it-hammer" ) );
|
||
}
|
||
|
||
void
|
||
Editor::set_cursor( const string &name )
|
||
{
|
||
m_cursor.replace_model( display::MakeModel( name ) );
|
||
}
|
||
|
||
|
||
void
|
||
Editor::scroll( double xoff, double yoff )
|
||
{
|
||
DisplayEngine *engine = m_display.get_engine();
|
||
V2 newoffset = engine->get_offset() + V2( xoff, yoff );
|
||
video::HideMouse();
|
||
engine->move_offset( newoffset );
|
||
video::ShowMouse();
|
||
}
|
||
|
||
void
|
||
Editor::scroll_abs( double x, double y )
|
||
{
|
||
DisplayEngine *engine = m_display.get_engine();
|
||
video::HideMouse();
|
||
engine->move_offset( V2( x, y ) );
|
||
video::ShowMouse();
|
||
}
|
||
|
||
bool
|
||
Editor::on_mousemotion( SDL_Event &e )
|
||
{
|
||
DisplayEngine *engine = m_display.get_engine();
|
||
V2 worldpos = engine->to_world( V2( e.motion.x, e.motion.y ) );
|
||
current_tool()->round_coordinates( &worldpos );
|
||
m_cursor.move( worldpos );
|
||
return true;
|
||
}
|
||
|
||
bool
|
||
Editor::on_mousebutton( SDL_Event &e )
|
||
{
|
||
DisplayEngine *engine = m_display.get_engine();
|
||
V2 worldpos = engine->to_world( V2( e.motion.x, e.motion.y ) );
|
||
|
||
if( Tool *tool = current_tool() ) {
|
||
tool->on_mousebutton( e, worldpos );
|
||
}
|
||
return true;
|
||
}
|
||
|
||
bool
|
||
Editor::on_keydown( SDL_Event &e )
|
||
{
|
||
bool ctrl_pressed = e.key.keysym.mod & KMOD_CTRL;
|
||
bool shift_pressed = e.key.keysym.mod & KMOD_SHIFT;
|
||
int hoff = 19;
|
||
int voff = 12;
|
||
|
||
Tool *tool = current_tool();
|
||
|
||
switch( e.key.keysym.sym ) {
|
||
case SDLK_ESCAPE:
|
||
m_quit_editor = true;
|
||
break;
|
||
case SDLK_LEFT: scroll( ctrl_pressed ? -hoff : -1, 0 ); break;
|
||
case SDLK_RIGHT: scroll( ctrl_pressed ? +hoff : +1, 0 ); break;
|
||
case SDLK_DOWN: scroll( 0, ctrl_pressed ? +voff : +1 ); break;
|
||
case SDLK_UP: scroll( 0, ctrl_pressed ? -voff : -1 ); break;
|
||
case SDLK_HOME: scroll_abs( 0, 0 ); break;
|
||
|
||
case SDLK_PAGEUP:
|
||
tool->advance_group( -1 );
|
||
update_cursor();
|
||
break;
|
||
case SDLK_PAGEDOWN:
|
||
tool->advance_group( +1 );
|
||
update_cursor();
|
||
break;
|
||
|
||
case SDLK_PLUS:
|
||
case SDLK_KP_PLUS:
|
||
tool->advance_in_group( +1 );
|
||
update_cursor();
|
||
break;
|
||
|
||
case SDLK_MINUS:
|
||
case SDLK_KP_MINUS:
|
||
tool->advance_in_group( -1 );
|
||
update_cursor();
|
||
break;
|
||
|
||
case SDLK_a:
|
||
if( shift_pressed )
|
||
;
|
||
set_mode( MODE_ACTORS );
|
||
break;
|
||
|
||
case SDLK_f:
|
||
if( shift_pressed )
|
||
;
|
||
set_mode( MODE_FLOOR );
|
||
break;
|
||
|
||
case SDLK_i:
|
||
if( shift_pressed )
|
||
;
|
||
set_mode( MODE_ITEMS );
|
||
break;
|
||
|
||
case SDLK_s:
|
||
set_mode( MODE_STONES );
|
||
if( shift_pressed ) {
|
||
tool = current_tool();
|
||
tool->object_menu();
|
||
}
|
||
break;
|
||
|
||
default:
|
||
return false;
|
||
}
|
||
return true;
|
||
}
|
||
|
||
void editor::DefineFloorGroup( char const* name, char const* descr,
|
||
int nentries, char ** entries )
|
||
{
|
||
Editor *ed = Editor::get_instance();
|
||
|
||
vector<string> entryvec(entries, entries+nentries);
|
||
ObjectGroup group(name, descr, entryvec);
|
||
ed->add_floor_group (group);
|
||
}
|
||
|
||
void editor::DefineItemGroup( const char *name, const char *descr,
|
||
int nentries, char **entries )
|
||
{
|
||
Editor *ed = Editor::get_instance();
|
||
|
||
vector<string> entryvec( entries, entries + nentries );
|
||
ObjectGroup group( name, descr, entryvec );
|
||
ed->add_item_group( group );
|
||
}
|
||
|
||
void editor::DefineStoneGroup( const char *name, const char *descr,
|
||
int nentries, char **entries )
|
||
{
|
||
Editor *ed = Editor::get_instance();
|
||
|
||
vector<string> entryvec( entries, entries+nentries );
|
||
ObjectGroup group( name, descr, entryvec );
|
||
ed->add_stone_group( group );
|
||
}
|
||
|
||
|
||
void editor::Run()
|
||
{
|
||
Editor *ed = Editor::get_instance();
|
||
ed->init();
|
||
ed->run();
|
||
}
|