home *** CD-ROM | disk | FTP | other *** search
/ Maximum CD 2009 February / maximum-cd-2009-02.iso / DiscContents / SMC_1.6_win32.exe / src / core / editor.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2008-09-04  |  44.1 KB  |  1,718 lines

  1. /***************************************************************************
  2.  * editor.cpp  -  class for the basic editor
  3.  *
  4.  * Copyright (C) 2006 - 2008 Florian Richter
  5.  ***************************************************************************/
  6. /*
  7.    This program is free software; you can redistribute it and/or modify
  8.    it under the terms of the GNU General Public License as published by
  9.    the Free Software Foundation; either version 3 of the License, or
  10.    (at your option) any later version.
  11.    
  12.    You should have received a copy of the GNU General Public License
  13.    along with this program.  If not, see <http://www.gnu.org/licenses/>.
  14. */
  15.  
  16. #include "../core/editor.h"
  17. #include "../core/game_core.h"
  18. #include "../core/obj_manager.h"
  19. #include "../core/camera.h"
  20. #include "../core/framerate.h"
  21. #include "../audio/audio.h"
  22. #include "../video/font.h"
  23. #include "../video/animation.h"
  24. #include "../input/keyboard.h"
  25. #include "../input/mouse.h"
  26. #include "../input/joystick.h"
  27. #include "../user/preferences.h"
  28. #include "../level/level.h"
  29. #include "../player/player.h"
  30. #include "../overworld/world_manager.h"
  31. #include "../video/renderer.h"
  32. #include "../video/gl_surface.h"
  33. #include "../core/sprite_manager.h"
  34. #include "../overworld/overworld.h"
  35. #include "../core/i18n.h"
  36. // boost filesystem
  37. #include "boost/filesystem/convenience.hpp"
  38. namespace fs = boost::filesystem;
  39.  
  40. /* *** *** *** *** *** *** *** *** cEditor_Item_Object *** *** *** *** *** *** *** *** *** */
  41.  
  42. cEditor_Item_Object :: cEditor_Item_Object( string text )
  43. : ListboxItem( "" )
  44. {
  45.     list_text = new CEGUI::ListboxTextItem( reinterpret_cast<const CEGUI::utf8*>(text.c_str()) );
  46.  
  47.     sprite_obj = NULL;
  48.     preview_scale = 1;
  49. }
  50.  
  51. cEditor_Item_Object :: ~cEditor_Item_Object( void )
  52. {
  53.     delete list_text;
  54.  
  55.     if( sprite_obj )
  56.     {
  57.         delete sprite_obj;
  58.     }
  59. }
  60.  
  61. void cEditor_Item_Object :: Init( void )
  62. {
  63.     // CEGUI settings
  64.     list_text->setTextColours( Get_Massive_Type_Color( sprite_obj->massivetype ).Get_cegui_Color() );
  65.     list_text->setSelectionColours( CEGUI::colour( 0.33f, 0.33f, 0.33f ) );
  66.     list_text->setSelectionBrushImage( "TaharezLook", "ListboxSelectionBrush" );
  67.  
  68.     // image dimension text
  69.     // string size_text = int_to_string( static_cast<int>(image->w) ) + "x" + int_to_string( static_cast<int>(image->h) );
  70.  
  71.     // get scale
  72.     preview_scale = pVideo->Get_Scale( sprite_obj->start_image, 100, 50 );
  73.  
  74.     // check if name is fitting
  75.     if( sprite_obj->name.length() > 25 )
  76.     {
  77.         sprite_obj->name.erase( 25 );
  78.         sprite_obj->name += "|";
  79.     }
  80.  
  81.     // set position
  82.     sprite_obj->Set_Pos_X( 20, 1 );
  83.  
  84.     /* Don't set sprite settings which could get copied
  85.      * into the level if selected like shadow and z position
  86.     */
  87. }
  88.  
  89. CEGUI::Size cEditor_Item_Object :: getPixelSize( void ) const
  90. {
  91.     CEGUI::Size tmp = list_text->getPixelSize();
  92.     tmp.d_height += 60 * global_upscaley;
  93.  
  94.     return tmp;
  95. }
  96.  
  97. void cEditor_Item_Object :: draw( const CEGUI::Vector3 &position, float alpha, const CEGUI::Rect &clipper ) const
  98. {
  99.     // draw text
  100.     list_text->draw( position, alpha, clipper );
  101. }
  102.  
  103. void cEditor_Item_Object :: draw( CEGUI::RenderCache &cache, const CEGUI::Rect &targetRect, float zBase, float alpha, const CEGUI::Rect *clipper ) const
  104. {
  105.     // draw text
  106.     list_text->draw( cache, targetRect, zBase, alpha, clipper );
  107. }
  108.  
  109. void cEditor_Item_Object :: Draw_Image( void )
  110. {
  111.     // no image available to blit
  112.     if( !sprite_obj->start_image )
  113.     {
  114.         return;
  115.     }
  116.  
  117.     const CEGUI::Listbox *owner = static_cast<const CEGUI::Listbox *>( getOwnerWindow() );
  118.  
  119.     // if item is not visible
  120.     if( !owner->isVisible() )
  121.     {
  122.         return;
  123.     }
  124.  
  125.     // force valid draw
  126.     sprite_obj->valid_draw = 1;
  127.  
  128.     // create request
  129.     cSurfaceRequest *request = new cSurfaceRequest();
  130.  
  131.     // scale
  132.     sprite_obj->start_scalex = preview_scale;
  133.     sprite_obj->start_scaley = preview_scale;
  134.     // draw image
  135.     sprite_obj->Draw_Image( request );
  136.     // reset scale
  137.     sprite_obj->start_scalex = 1;
  138.     sprite_obj->start_scaley = 1;
  139.  
  140.     // ignore camera
  141.     request->no_camera = 1;
  142.     // position z
  143.     request->pos_z = 0.9f;
  144.  
  145.     // set shadow
  146.     request->shadow_color = blackalpha128;
  147.     request->shadow_pos = 2;
  148.  
  149.     // add request
  150.     pRenderer_GUI->Add( request );
  151. }
  152.  
  153. /* *** *** *** *** *** *** *** *** cEditor_Menu_Object *** *** *** *** *** *** *** *** *** */
  154.  
  155. cEditor_Menu_Object :: cEditor_Menu_Object( string text )
  156. : ListboxTextItem( text.c_str() )
  157. {
  158.     bfunction = 0;
  159.     header = 0;
  160. }
  161.  
  162. cEditor_Menu_Object :: ~cEditor_Menu_Object( void )
  163. {
  164.  
  165. }
  166.  
  167. void cEditor_Menu_Object :: Init( void )
  168. {
  169.     setSelectionColours( CEGUI::colour( 0.33f, 0.33f, 0.33f ) );
  170.     setSelectionBrushImage( "TaharezLook", "ListboxSelectionBrush" );
  171. }
  172.  
  173. /* *** *** *** *** *** *** *** cEditor *** *** *** *** *** *** *** *** *** *** */
  174.  
  175. cEditor :: cEditor( void )
  176. {
  177.     enabled = 0;
  178.  
  179.     camera_speed = 35;
  180.     menu_timer = 0;
  181.     show_editor_help = 0;
  182.     editor_window = NULL;
  183. }
  184.  
  185. cEditor :: ~cEditor( void )
  186. {
  187.     cEditor::Unload();
  188. }
  189.  
  190. void cEditor :: Init( void )
  191. {
  192.     // already loaded
  193.     if( editor_window )
  194.     {
  195.         return;
  196.     }
  197.  
  198.     // Create Editor CEGUI Window
  199.     editor_window = CEGUI::WindowManager::getSingleton().loadWindowLayout( "editor.layout" );
  200.     pGuiSystem->getGUISheet()->addChildWindow( editor_window );
  201.  
  202.     // Get TabControl
  203.     CEGUI::TabControl *tabcontrol_menu = static_cast<CEGUI::TabControl *>(CEGUI::WindowManager::getSingleton().getWindow( "tabcontrol_editor" ));
  204.     // TabControl Menu Tab Events
  205.     tabcontrol_menu->getTabContents( "editor_tab_menu" )->subscribeEvent( CEGUI::Window::EventMouseEnters, CEGUI::Event::Subscriber( &cEditor::Editor_Mouse_Enter, this ) );
  206.     // TabControl Items Tab Events
  207.     tabcontrol_menu->getTabContents( "editor_tab_items" )->subscribeEvent( CEGUI::Window::EventMouseEnters, CEGUI::Event::Subscriber( &cEditor::Editor_Mouse_Enter, this ) );
  208.  
  209.     // Get Menu Listbox
  210.     CEGUI::Listbox *listbox_menu = static_cast<CEGUI::Listbox *>(CEGUI::WindowManager::getSingleton().getWindow( "editor_menu" ));
  211.     // Menu Listbox events
  212.     listbox_menu->subscribeEvent( CEGUI::Listbox::EventSelectionChanged, CEGUI::Event::Subscriber( &cEditor::Menu_Select, this ) );
  213.     // Get Items Listbox
  214.     CEGUI::Listbox *listbox_items = static_cast<CEGUI::Listbox *>(CEGUI::WindowManager::getSingleton().getWindow( "editor_items" ));
  215.     // Items Listbox events
  216.     listbox_items->subscribeEvent( CEGUI::Listbox::EventSelectionChanged, CEGUI::Event::Subscriber( &cEditor::Item_Select, this ) );
  217.  
  218.     // Get Items
  219.     if( !File_Exists( items_filename ) )
  220.     {
  221.         printf( "Error : Editor Loading : No Item file found : %s\n", items_filename.c_str() );
  222.         return;
  223.     }
  224.     // Parse Items
  225.     CEGUI::System::getSingleton().getXMLParser()->parseXMLFile( *this, items_filename.c_str(), DATA_DIR "/" GAME_SCHEMA_DIR "/Editor_Items.xsd", "" );
  226.  
  227.     // Get all image items
  228.     Load_Image_Items( DATA_DIR "/" GAME_PIXMAPS_DIR );
  229.  
  230.     // Get Menu
  231.     if( !File_Exists( menu_filename ) )
  232.     {
  233.         printf( "Error : Editor Loading : No Menu file found : %s\n", menu_filename.c_str() );
  234.         return;
  235.     }
  236.     // Parse Menu
  237.     CEGUI::System::getSingleton().getXMLParser()->parseXMLFile( *this, menu_filename.c_str(), DATA_DIR "/" GAME_SCHEMA_DIR "/Editor_Menu.xsd", "" );
  238. }
  239.  
  240. void cEditor :: Unload( void )
  241. {
  242.     // Unload Items
  243.     Unload_Item_Menu();
  244.  
  245.     // if editor window is loaded
  246.     if( editor_window )
  247.     {
  248.         pGuiSystem->getGUISheet()->removeChildWindow( editor_window );
  249.         CEGUI::WindowManager::getSingleton().destroyWindow( editor_window );
  250.         editor_window = NULL;
  251.     }
  252.  
  253.     // Tagged Items
  254.     for( TaggedItemObjectsList::iterator itr = tagged_item_objects.begin(), itr_end = tagged_item_objects.end(); itr != itr_end; ++itr )
  255.     {
  256.         delete *itr;
  257.     }
  258.  
  259.     tagged_item_objects.clear();
  260.  
  261.     // Tagged Image Settings
  262.     for( TaggedItemImageSettingsList::iterator itr = tagged_item_images.begin(), itr_end = tagged_item_images.end(); itr != itr_end; ++itr )
  263.     {
  264.         delete *itr;
  265.     }
  266.  
  267.     tagged_item_images.clear();
  268.  
  269.  
  270.     // Help Sprites
  271.     for( HudSpriteList::iterator itr = help_sprites.begin(), itr_end = help_sprites.end(); itr != itr_end; ++itr )
  272.     {
  273.         delete *itr;
  274.     }
  275.  
  276.     help_sprites.clear();
  277. }
  278.  
  279. void cEditor :: Toggle( void )
  280. {
  281.     // enable
  282.     if( !enabled )
  283.     {
  284.         Enable();
  285.     }
  286.     // disable
  287.     else
  288.     {
  289.         Disable();
  290.     }
  291. }
  292.  
  293. void cEditor :: Enable( void )
  294. {
  295.     // already enabled
  296.     if( enabled )
  297.     {
  298.         return;
  299.     }
  300.  
  301.     // Draw Loading Text
  302.     Draw_Static_Text( _("Loading"), &orange, NULL, 0 );
  303.  
  304.     // Basic Initialize
  305.     Init();
  306.  
  307.     pAudio->Play_Sound( "editor/enter.ogg" );
  308.     debugdisplay->Set_Text( _("Editor enabled") );
  309.     pAnimation_Manager->Delete_All();
  310.  
  311.     pMouseCursor->visible = 1;
  312.  
  313.     // update player position rect
  314.     pActive_Player->Update_Position_Rect();
  315.     // update sprite manager position rect
  316.     for( SpriteList::iterator itr = pActive_Sprite_Manager->objects.begin(), itr_end = pActive_Sprite_Manager->objects.end(); itr != itr_end; ++itr )
  317.     {
  318.         (*itr)->Update_Position_Rect();
  319.     }
  320.  
  321.     pActive_Camera->Update_Position();
  322.     enabled = 1;
  323. }
  324.  
  325. void cEditor :: Disable( bool native_mode /* = 1 */ )
  326. {
  327.     // already disabled
  328.     if( !enabled )
  329.     {
  330.         return;
  331.     }
  332.  
  333.     Unload();
  334.  
  335.     enabled = 0;
  336.     // disable help screen
  337.     show_editor_help = 0;
  338.  
  339.     if( native_mode )
  340.     {
  341.         pAudio->Play_Sound( "editor/leave.ogg" );
  342.  
  343.         // player
  344.         pActive_Player->Update_Position_Rect();
  345.         // sprite manager
  346.         for( SpriteList::iterator itr = pActive_Sprite_Manager->objects.begin(), itr_end = pActive_Sprite_Manager->objects.end(); itr != itr_end; ++itr )
  347.         {
  348.             (*itr)->Update_Position_Rect();
  349.         }
  350.  
  351.         pActive_Camera->Center();
  352.         pMouseCursor->Reset( 0 );
  353.  
  354.         // ask if editor should save
  355.         Function_Save( 1 );
  356.         
  357.         pMouseCursor->Set_Visible( 0 );
  358.     }
  359. }
  360.  
  361. void cEditor :: Update( void )
  362. {
  363.     if( !enabled )
  364.     {
  365.         return;
  366.     }
  367.  
  368.     // if timed out
  369.     if( menu_timer >= speedfactor_fps * 2 )
  370.     {
  371.         // fade out
  372.         if( editor_window->getAlpha() > 0 )
  373.         {
  374.             float new_alpha = editor_window->getAlpha() - pFramerate->speedfactor * 0.05f;
  375.  
  376.             if( new_alpha <= 0 )
  377.             {
  378.                 new_alpha = 1;
  379.                 // hide editor window
  380.                 editor_window->setXPosition( CEGUI::UDim( -0.19f, 0 ) );
  381.                 // Hide Listbox
  382.                 CEGUI::Listbox *listbox = static_cast<CEGUI::Listbox *>(CEGUI::WindowManager::getSingleton().getWindow( "editor_menu" ));
  383.                 listbox->hide();
  384.                 listbox = static_cast<CEGUI::Listbox *>(CEGUI::WindowManager::getSingleton().getWindow( "editor_items" ));
  385.                 listbox->hide();
  386.                 menu_timer = 0;
  387.             }
  388.  
  389.             editor_window->setAlpha( new_alpha );
  390.         }
  391.     }
  392.     // active
  393.     else
  394.     {
  395.         // fade in
  396.         if( editor_window->getAlpha() < 1 )
  397.         {
  398.             float new_alpha = editor_window->getAlpha() + pFramerate->speedfactor * 0.1f;
  399.  
  400.             if( new_alpha > 1 )
  401.             {
  402.                 new_alpha = 1;
  403.             }
  404.  
  405.             editor_window->setAlpha( new_alpha );
  406.         }
  407.         // inactive counter
  408.         else if( editor_window->getXPosition().asRelative( 1 ) == 0 )
  409.         {
  410.             // if mouse is over the window
  411.             if( CEGUI::MouseCursor::getSingletonPtr()->getDisplayIndependantPosition().d_x < editor_window->getXPosition().asRelative( 1 ) + 0.2f )
  412.             {
  413.                 menu_timer = 0;
  414.             }
  415.             // inactive
  416.             else
  417.             {
  418.                 menu_timer += pFramerate->speedfactor;
  419.             }
  420.         }
  421.     }
  422.  
  423.     pMouseCursor->Editor_Update();
  424. }
  425.  
  426. void cEditor :: Draw( void )
  427. {
  428.     if( !enabled )
  429.     {
  430.         return;
  431.     }
  432.  
  433.     Color color = static_cast<Uint8>(0);
  434.  
  435.     // Camera limit bottom line
  436.     if( pActive_Camera->y > pActive_Camera->limit_rect.y && pActive_Camera->y + pActive_Camera->limit_rect.y < game_res_h )
  437.     {
  438.         int start_x = 0;
  439.  
  440.         if( pActive_Camera->x < 0 )
  441.         {
  442.             start_x = -static_cast<int>(pActive_Camera->x);
  443.         }
  444.  
  445.         Color color = Color( static_cast<Uint8>(0), 0, 100, 192 );
  446.         pVideo->Draw_Line( static_cast<float>(start_x), static_cast<float>(game_res_h - static_cast<int>(pActive_Camera->y)), static_cast<float>(game_res_w), static_cast<float>( game_res_h - static_cast<int>(pActive_Camera->y) ), 0.124f, &color );
  447.     }
  448.     // Camera limit top line
  449.     if( pActive_Camera->y + game_res_h > pActive_Camera->limit_rect.y + pActive_Camera->limit_rect.h && pActive_Camera->y < pActive_Camera->limit_rect.y + pActive_Camera->limit_rect.h )
  450.     {
  451.         int start_x = 0;
  452.  
  453.         if( pActive_Camera->x < pActive_Camera->limit_rect.x )
  454.         {
  455.             start_x = -static_cast<int>(pActive_Camera->x);
  456.         }
  457.  
  458.         Color color = Color( static_cast<Uint8>(20), 20, 150, 192 );
  459.         pVideo->Draw_Line( static_cast<float>(start_x), ( pActive_Camera->limit_rect.y + pActive_Camera->limit_rect.h ) - pActive_Camera->y, static_cast<float>(game_res_w), ( pActive_Camera->limit_rect.y + pActive_Camera->limit_rect.h ) - pActive_Camera->y, 0.124f, &color );
  460.     }
  461.  
  462.     // Camera limit left line
  463.     if( pActive_Camera->x < 0 && pActive_Camera->x > -game_res_w )
  464.     {
  465.         int start_y = game_res_h;
  466.  
  467.         if( pActive_Camera->y < game_res_h )
  468.         {
  469.             start_y = game_res_h - static_cast<int>(pActive_Camera->y);
  470.         }
  471.  
  472.         Color color = Color( static_cast<Uint8>(0), 100, 0, 192 );
  473.         pVideo->Draw_Line( static_cast<float>( 0 - pActive_Camera->x ), static_cast<float>(start_y), static_cast<float>( -pActive_Camera->x ), 0, 0.124f, &color );
  474.     }
  475.     // Camera limit right line
  476.     if( pActive_Camera->x < pActive_Camera->limit_rect.x + pActive_Camera->limit_rect.w && pActive_Camera->x > -game_res_w + pActive_Camera->limit_rect.x + pActive_Camera->limit_rect.w )
  477.     {
  478.         int start_y = game_res_h;
  479.  
  480.         if( pActive_Camera->y < game_res_h )
  481.         {
  482.             start_y = game_res_h - static_cast<int>(pActive_Camera->y);
  483.         }
  484.  
  485.         Color color = Color( static_cast<Uint8>(20), 150, 20, 192 );
  486.         pVideo->Draw_Line( static_cast<float>( pActive_Camera->limit_rect.x + pActive_Camera->limit_rect.w - pActive_Camera->x ), static_cast<float>(start_y), static_cast<float>( pActive_Camera->limit_rect.x + pActive_Camera->limit_rect.w - pActive_Camera->x ), 0, 0.124f, &color );
  487.     }
  488.  
  489.     // Get Items Listbox
  490.     CEGUI::Listbox *listbox_items = static_cast<CEGUI::Listbox *>(CEGUI::WindowManager::getSingleton().getWindow( "editor_items" ));
  491.  
  492.     // if editor window is active
  493.     if( editor_window->getXPosition().asRelative( 1 ) >= 0 )
  494.     {
  495.         // Listbox dimension
  496.         float list_posy = listbox_items->getUnclippedPixelRect().d_top * global_downscaley;
  497.         float list_height = listbox_items->getUnclippedPixelRect().getHeight() * global_downscaley;
  498.         // Vertical ScrollBar Position
  499.         float scroll_pos = listbox_items->getVertScrollbar()->getScrollPosition() * global_downscaley;
  500.         // font height
  501.         float font_height = CEGUI::FontManager::getSingleton().getFont( "bluebold_medium" )->getFontHeight() * global_downscaley;
  502.  
  503.         // draw items
  504.         for( unsigned int i = 0; i < listbox_items->getItemCount(); i++ )
  505.         {
  506.             // Get item
  507.             cEditor_Item_Object *item = static_cast<cEditor_Item_Object *>( listbox_items->getListboxItemFromIndex( i ) );
  508.             // Item height
  509.             float item_height = item->getPixelSize().d_height * global_downscaley;
  510.             // Item position
  511.             float item_posy = list_posy + ( item_height * i );
  512.             float item_image_posy = item_posy + ( font_height * 2 );
  513.  
  514.             // not visible
  515.             if( item_posy + item_height > list_posy + list_height + scroll_pos || item_image_posy < list_posy + scroll_pos )
  516.             {
  517.                 continue;
  518.             }
  519.  
  520.             item->sprite_obj->Set_Pos_Y( item_image_posy - scroll_pos, 1 );
  521.             item->Draw_Image();
  522.         }
  523.     }
  524.  
  525.     if( show_editor_help )
  526.     {
  527.         Draw_Editor_Help();
  528.     }
  529. }
  530.  
  531. void cEditor :: Process_Input( void )
  532. {
  533.     if( !enabled )
  534.     {
  535.         return;
  536.     }
  537.  
  538.     // Drag Delete
  539.     if( ( pKeyboard->keys[SDLK_RCTRL] || pKeyboard->keys[SDLK_LCTRL] ) && pMouseCursor->right && pMouseCursor->Editor_Collsion_Check() )
  540.     {
  541.         pMouseCursor->Delete( pMouseCursor->mouse_object->obj );
  542.     }
  543.  
  544.     // Camera Movement
  545.     if( pKeyboard->keys[SDLK_RIGHT] || pJoystick->right )
  546.     {
  547.         if( pKeyboard->keys[SDLK_RSHIFT] || pKeyboard->keys[SDLK_LSHIFT] )
  548.         {
  549.             pActive_Camera->Move( camera_speed * pFramerate->speedfactor * 3 * pPreferences->scroll_speed, 0 );
  550.         }
  551.         else
  552.         {
  553.             pActive_Camera->Move( camera_speed * pFramerate->speedfactor * pPreferences->scroll_speed, 0 );
  554.         }
  555.     }
  556.     else if( pKeyboard->keys[SDLK_LEFT] || pJoystick->left )
  557.     {
  558.         if( pKeyboard->keys[SDLK_RSHIFT] || pKeyboard->keys[SDLK_LSHIFT] )
  559.         {
  560.             pActive_Camera->Move( -( camera_speed * pFramerate->speedfactor * 3 * pPreferences->scroll_speed ), 0 );
  561.         }
  562.         else
  563.         {
  564.             pActive_Camera->Move( -( camera_speed * pFramerate->speedfactor * pPreferences->scroll_speed ), 0 );
  565.         }
  566.     }
  567.     if( pKeyboard->keys[SDLK_UP] || pJoystick->up )
  568.     {
  569.         if( pKeyboard->keys[SDLK_RSHIFT] || pKeyboard->keys[SDLK_LSHIFT] )
  570.         {
  571.             pActive_Camera->Move( 0, -( camera_speed * pFramerate->speedfactor * 3 * pPreferences->scroll_speed ) );
  572.         }
  573.         else
  574.         {
  575.             pActive_Camera->Move( 0, -( camera_speed * pFramerate->speedfactor * pPreferences->scroll_speed ) );
  576.         }
  577.     }
  578.     else if( pKeyboard->keys[SDLK_DOWN] || pJoystick->down )
  579.     {
  580.         if( pKeyboard->keys[SDLK_RSHIFT] || pKeyboard->keys[SDLK_LSHIFT] )
  581.         {
  582.             pActive_Camera->Move( 0, camera_speed * pFramerate->speedfactor * 3 * pPreferences->scroll_speed );
  583.         }
  584.         else
  585.         {
  586.             pActive_Camera->Move( 0, camera_speed * pFramerate->speedfactor * pPreferences->scroll_speed );
  587.         }
  588.     }
  589. }
  590.  
  591. bool cEditor :: Handle_Event( SDL_Event *ev )
  592. {
  593.     if( !enabled )
  594.     {
  595.         return 0;
  596.     }
  597.  
  598.     switch( ev->type )
  599.     {
  600.     case SDL_MOUSEMOTION:
  601.     {
  602.         if( pMouseCursor->mover_mode )
  603.         {
  604.             pMouseCursor->Mover_Update( input_event.motion.xrel, input_event.motion.yrel );
  605.         }
  606.  
  607.         break;
  608.     }
  609.     default: // other events
  610.     {
  611.         break;
  612.     }
  613.     }
  614.  
  615.     return 0;
  616. }
  617.  
  618. bool cEditor :: Key_Down( SDLKey key )
  619. {
  620.     if( !enabled )
  621.     {
  622.         return 0;
  623.     }
  624.  
  625.     if( key == SDLK_F1 )
  626.     {
  627.         show_editor_help = !show_editor_help;
  628.     }
  629.     // focus level start
  630.     else if( key == SDLK_HOME )
  631.     {
  632.         pActive_Camera->Set_Pos( 0, 0 );
  633.     }
  634.     // move the screen size to the right
  635.     else if( key == SDLK_n )
  636.     {
  637.         pActive_Camera->Move( static_cast<float>(game_res_w), 0 );
  638.     }
  639.     // move the screen size to the left
  640.     else if( key == SDLK_p )
  641.     {
  642.         pActive_Camera->Move( -static_cast<float>(game_res_w), 0 );
  643.     }
  644.     // push selected objects into the front
  645.     else if( key == SDLK_KP_PLUS )
  646.     {
  647.         for( SelectedObjectList::iterator itr = pMouseCursor->selected_objects.begin(), itr_end = pMouseCursor->selected_objects.end(); itr != itr_end; ++itr )
  648.         {
  649.             cSelectedObject *sel_obj = (*itr);
  650.  
  651.             Change_Draw_Position( sel_obj->obj, 0 );
  652.         }
  653.     }
  654.     // push selected objects into the back
  655.     else if( key == SDLK_KP_MINUS )
  656.     {
  657.         for( SelectedObjectList::iterator itr = pMouseCursor->selected_objects.begin(), itr_end = pMouseCursor->selected_objects.end(); itr != itr_end; ++itr )
  658.         {
  659.             cSelectedObject *sel_obj = (*itr);
  660.  
  661.             Change_Draw_Position( sel_obj->obj, 1 );
  662.         }
  663.     }
  664.     // ## only with mouse_object functions
  665.     // Precise Pixel-Positioning or copy into direction
  666.     if( ( key == SDLK_KP2 || key == SDLK_KP4 || key == SDLK_KP6 || key == SDLK_KP8 ) && pMouseCursor->mouse_object->obj )
  667.     {
  668.         if( pMouseCursor->mode_fastcopy )
  669.         {
  670.             ObjectDirection dir = DIR_UNDEFINED;
  671.  
  672.             // down
  673.             if( key == SDLK_KP2 )
  674.             {
  675.                 dir = DIR_DOWN;
  676.             }
  677.             // left
  678.             else if( key == SDLK_KP4 )
  679.             {
  680.                 dir = DIR_LEFT;
  681.             }
  682.             // right
  683.             else if( key == SDLK_KP6 )
  684.             {
  685.                 dir = DIR_RIGHT;
  686.             }
  687.             // up
  688.             else if( key == SDLK_KP8 )
  689.             {
  690.                 dir = DIR_UP;
  691.             }
  692.  
  693.             // get currently selected objects
  694.             SpriteList objects = pMouseCursor->Get_Selected_Objects();
  695.             // copy objects
  696.             SpriteList new_objects = Copy_Direction( objects, dir );
  697.  
  698.             // add new objects
  699.             for( SpriteList::iterator itr = new_objects.begin(), itr_end = new_objects.end(); itr != itr_end; ++itr )
  700.             {
  701.                 cSprite *obj = (*itr);
  702.  
  703.                 pMouseCursor->Add_Selected_Object( obj, 1 );
  704.             }
  705.             
  706.             // deselect old objects
  707.             for( SpriteList::iterator itr = objects.begin(), itr_end = objects.end(); itr != itr_end; ++itr )
  708.             {
  709.                 cSprite *obj = (*itr);
  710.  
  711.                 pMouseCursor->Remove_Selected_Object( obj );
  712.             }
  713.         }
  714.         else
  715.         {
  716.             // down
  717.             if( key == SDLK_KP2 )
  718.             {
  719.                 pActive_Camera->Move( 0, 1 );
  720.             }
  721.             // left
  722.             else if( key == SDLK_KP4 )
  723.             {
  724.                 pActive_Camera->Move( -1, 0 );
  725.             }
  726.             // right
  727.             else if( key == SDLK_KP6 )
  728.             {
  729.                 pActive_Camera->Move( 1, 0 );
  730.             }
  731.             // up
  732.             else if( key == SDLK_KP8 )
  733.             {
  734.                 pActive_Camera->Move( 0, -1 );
  735.             }
  736.         }
  737.     }
  738.     // select all Sprites
  739.     else if( key == SDLK_a && ( input_event.key.keysym.mod & KMOD_LCTRL || input_event.key.keysym.mod & KMOD_RCTRL ) )
  740.     {
  741.         pMouseCursor->Clear_Selected_Objects();
  742.  
  743.         // player
  744.         pMouseCursor->Add_Selected_Object( pActive_Player, 1 );
  745.         // sprite manager
  746.         for( SpriteList::iterator itr = pActive_Sprite_Manager->objects.begin(), itr_end = pActive_Sprite_Manager->objects.end(); itr != itr_end; ++itr )
  747.         {
  748.             cSprite *obj = (*itr);
  749.  
  750.             pMouseCursor->Add_Selected_Object( obj, 1 );
  751.         }
  752.     }
  753.     // Paste copy buffer objects
  754.     else if( key == SDLK_INSERT || ( key == SDLK_v && ( input_event.key.keysym.mod & KMOD_LCTRL || input_event.key.keysym.mod & KMOD_RCTRL ) ) )
  755.     {
  756.         pMouseCursor->Paste_Copy_Objects( static_cast<float>(static_cast<int>(pMouseCursor->posx)), static_cast<float>(static_cast<int>(pMouseCursor->posy)) );
  757.     }
  758.     // Cut selected Sprites to the copy buffer
  759.     else if( key == SDLK_x && ( input_event.key.keysym.mod & KMOD_LCTRL || input_event.key.keysym.mod & KMOD_RCTRL ) )
  760.     {
  761.         pMouseCursor->Clear_Copy_Objects();
  762.  
  763.         for( SelectedObjectList::iterator itr = pMouseCursor->selected_objects.begin(), itr_end = pMouseCursor->selected_objects.end(); itr != itr_end; ++itr )
  764.         {
  765.             cSelectedObject *sel_obj = (*itr);
  766.  
  767.             pMouseCursor->Add_Copy_Object( sel_obj->obj );
  768.         }
  769.  
  770.         pMouseCursor->Delete_Selected_Objects();
  771.     }
  772.     // Add selected Sprites to the copy buffer
  773.     else if( key == SDLK_c && ( input_event.key.keysym.mod & KMOD_LCTRL || input_event.key.keysym.mod & KMOD_RCTRL ) )
  774.     {
  775.         pMouseCursor->Clear_Copy_Objects();
  776.  
  777.         for( SelectedObjectList::iterator itr = pMouseCursor->selected_objects.begin(), itr_end = pMouseCursor->selected_objects.end(); itr != itr_end; ++itr )
  778.         {
  779.             cSelectedObject *sel_obj = (*itr);
  780.  
  781.             pMouseCursor->Add_Copy_Object( sel_obj->obj );
  782.         }
  783.     }
  784.     // Delete mouse object
  785.     else if( key == SDLK_DELETE && pMouseCursor->mouse_object->obj )
  786.     {
  787.         pMouseCursor->Delete( pMouseCursor->mouse_object->obj );
  788.     }
  789.     // if shift got pressed remove mouse object for possible mouse selection
  790.     else if( ( key == SDLK_RSHIFT || key == SDLK_LSHIFT ) && pMouseCursor->mouse_object->obj )
  791.     {
  792.         pMouseCursor->Clear_Mouse_Object();
  793.     }
  794.     // Delete selected objects
  795.     else if( key == SDLK_DELETE )
  796.     {
  797.         pMouseCursor->Delete_Selected_Objects();
  798.     }
  799.     else
  800.     {
  801.         // not processed
  802.         return 0;
  803.     }
  804.  
  805.     // key got processed
  806.     return 1;
  807. }
  808.  
  809. bool cEditor :: Mouse_Down( Uint8 button )
  810. {
  811.     if( !enabled )
  812.     {
  813.         return 0;
  814.     }
  815.  
  816.     // left
  817.     if( button == SDL_BUTTON_LEFT )
  818.     {
  819.         pMouseCursor->Click();
  820.         
  821.         // auto hide if enabled
  822.         if( pMouseCursor->mouse_object->obj && pPreferences->editor_mouse_auto_hide )
  823.         {
  824.             pMouseCursor->Set_Visible( 0 );
  825.         }
  826.     }
  827.     // middle
  828.     else if( button == SDL_BUTTON_MIDDLE )
  829.     {
  830.         // Activate fast copy mode
  831.         if( pMouseCursor->mouse_object->obj )
  832.         {
  833.             pMouseCursor->mode_fastcopy = 1;
  834.             return 1;
  835.         }
  836.         // Mover mode
  837.         else
  838.         {
  839.             pMouseCursor->Toggle_Mover_Mode();
  840.             return 1;
  841.         }
  842.     }
  843.     // right
  844.     else if( button == SDL_BUTTON_RIGHT )
  845.     {
  846.         if( !pMouseCursor->left )
  847.         {
  848.             pMouseCursor->Delete( pMouseCursor->mouse_object->obj );
  849.             return 1;
  850.         }
  851.     }
  852.     else
  853.     {
  854.         // not processed
  855.         return 0;
  856.     }
  857.  
  858.     // button got processed
  859.     return 1;
  860. }
  861.  
  862. bool cEditor :: Mouse_Up( Uint8 button )
  863. {
  864.     if( !enabled )
  865.     {
  866.         return 0;
  867.     }
  868.  
  869.     // left
  870.     if( button == SDL_BUTTON_LEFT )
  871.     {
  872.         pMouseCursor->End_Selection();
  873.  
  874.         // unhide
  875.         if( pPreferences->editor_mouse_auto_hide )
  876.         {
  877.             pMouseCursor->Set_Visible( 1 );
  878.         }
  879.     }
  880.     // middle
  881.     else if( button == SDL_BUTTON_MIDDLE )
  882.     {
  883.         pMouseCursor->mode_fastcopy = 0;
  884.     }
  885.     else
  886.     {
  887.         // not processed
  888.         return 0;
  889.     }
  890.  
  891.     // button got processed
  892.     return 1;
  893. }
  894.  
  895. void cEditor :: Add_Menu_Object( string name, string tags, CEGUI::colour normal_color /* = CEGUI::colour( 1, 1, 1 ) */ )
  896. {
  897.     // Create Menu Object
  898.     cEditor_Menu_Object *new_menu = new cEditor_Menu_Object( name );
  899.  
  900.     // if function
  901.     if( tags.find( "function:" ) == 0 )
  902.     {
  903.         new_menu->bfunction = 1;
  904.         // cut out the function identifier
  905.         tags.erase( 0, 9 );
  906.     }
  907.  
  908.     // if header
  909.     if( tags.find( "header" ) == 0 )
  910.     {
  911.         new_menu->header = 1;
  912.         // cut out the function identifier
  913.         tags.erase( 0, 6 );
  914.  
  915.         // header color rect
  916.         new_menu->setTextColours( normal_color, normal_color, CEGUI::colour( 0.5f, 0.5f, 0.5f ), CEGUI::colour( 0.5f, 0.5f, 0.5f ) );
  917.         // not selectable
  918.         new_menu->setDisabled( 1 );
  919.         // set tooltip
  920.         new_menu->setTooltipText( "Header " + name );
  921.     }
  922.     // if not a header
  923.     else
  924.     {
  925.         new_menu->setTextColours( normal_color );
  926.     }
  927.  
  928.     // if default items menu
  929.     if( !new_menu->bfunction && !new_menu->header )
  930.     {
  931.         // set tooltip
  932.         new_menu->setTooltipText( "Tags used " + tags );
  933.     }
  934.  
  935.     new_menu->tags = tags;
  936.     new_menu->Init();
  937.  
  938.     // Get Listbox
  939.     CEGUI::Listbox *listbox_editor_menu = static_cast<CEGUI::Listbox *>(CEGUI::WindowManager::getSingleton().getWindow( "editor_menu" ));
  940.     // Add Listbox item
  941.     listbox_editor_menu->addItem( new_menu );
  942. }
  943.  
  944. void cEditor :: Activate_Menu( cEditor_Menu_Object *entry )
  945. {
  946.     // Function
  947.     if( entry->bfunction )
  948.     {
  949.         if( entry->tags.compare( "exit" ) == 0 )
  950.         {
  951.             Function_Exit();
  952.         }
  953.         else
  954.         {
  955.             printf( "Unknown Function %s\n", entry->tags.c_str() );
  956.         }
  957.     }
  958.     // Header
  959.     else if( entry->header )
  960.     {
  961.         return;
  962.     }
  963.     // Item Menu
  964.     else
  965.     {
  966.         if( Load_Item_Menu( entry->tags ) )
  967.         {
  968.             // Get TabControl
  969.             CEGUI::TabControl *tabcontrol_menu = static_cast<CEGUI::TabControl *>(CEGUI::WindowManager::getSingleton().getWindow( "tabcontrol_editor" ));
  970.             // Select Items Tab
  971.             tabcontrol_menu->setSelectedTab( "editor_tab_items" );
  972.         }
  973.         // failed
  974.         else
  975.         {
  976.             printf( "Unknown Menu Type %s\n", entry->tags.c_str() );
  977.         }
  978.     }
  979. }
  980.  
  981. bool cEditor :: Load_Item_Menu( string item_tags )
  982. {
  983.     if( item_tags.empty() )
  984.     {
  985.         return 0;
  986.     }
  987.  
  988.     Unload_Item_Menu();
  989.  
  990.     // Convert to Array Tags
  991.     vector<string> array_tags;
  992.  
  993.     // Convert
  994.     while( item_tags.length() )
  995.     {
  996.         std::string::size_type pos = item_tags.find( ";" );
  997.  
  998.         // last item
  999.         if( pos == string::npos )
  1000.         {
  1001.             array_tags.push_back( item_tags );
  1002.             item_tags.clear();
  1003.             break;
  1004.         }
  1005.  
  1006.         // add tag
  1007.         array_tags.push_back( item_tags.substr( 0, pos ) );
  1008.         // remove tag
  1009.         item_tags.erase( 0, pos + 1 );
  1010.     }
  1011.  
  1012.     unsigned int tag_pos = 0;
  1013.  
  1014.     // Get all Images with the Tags
  1015.     for( TaggedItemImageSettingsList::iterator itr = tagged_item_images.begin(), itr_end = tagged_item_images.end(); itr != itr_end; ++itr )
  1016.     {
  1017.         cImage_settings_data *settings = (*itr);
  1018.  
  1019.         // search
  1020.         while( Is_Tag_Available( settings->m_editor_tags, array_tags[tag_pos] ) )
  1021.         {
  1022.             tag_pos++;
  1023.  
  1024.             // found all tags
  1025.             if( tag_pos >= array_tags.size() )
  1026.             {
  1027.                 GL_Surface *image = pVideo->Get_Surface( settings->m_base );
  1028.                 // Create sprite
  1029.                 cSprite *new_sprite = new cSprite( image );
  1030.                 // default massivetype
  1031.                 new_sprite->Set_Sprite_Type( static_cast<SpriteType>(image->type) );
  1032.                 // Add new Sprite
  1033.                 Add_Item_Object( new_sprite );
  1034.  
  1035.                 break;
  1036.             }
  1037.         }
  1038.  
  1039.         tag_pos = 0;
  1040.     }
  1041.  
  1042.     // Get all Objects with the Tags
  1043.     for( TaggedItemObjectsList::iterator itr = tagged_item_objects.begin(), itr_end = tagged_item_objects.end(); itr != itr_end; ++itr )
  1044.     {
  1045.         cSprite *object = (*itr);
  1046.  
  1047.         // search
  1048.         while( Is_Tag_Available( object->editor_tags, array_tags[tag_pos] ) )
  1049.         {
  1050.             tag_pos++;
  1051.  
  1052.             // found all tags
  1053.             if( tag_pos >= array_tags.size() )
  1054.             {
  1055.                 // Add Objects
  1056.                 Add_Item_Object( object->Copy() );
  1057.  
  1058.                 break;
  1059.             }
  1060.         }
  1061.  
  1062.         tag_pos = 0;
  1063.     }
  1064.  
  1065.     return 1;
  1066. }
  1067.  
  1068. void cEditor :: Unload_Item_Menu( void )
  1069. {
  1070.     // already unloaded
  1071.     if( !CEGUI::WindowManager::getSingleton().isWindowPresent( "editor_items" ) )
  1072.     {
  1073.         return;
  1074.     }
  1075.  
  1076.     // Get Items Listbox
  1077.     CEGUI::Listbox *listbox_items = static_cast<CEGUI::Listbox *>(CEGUI::WindowManager::getSingleton().getWindow( "editor_items" ));
  1078.     // Clear Listbox
  1079.     listbox_items->resetList();
  1080. }
  1081.  
  1082.  
  1083. void cEditor :: Add_Item_Object( cSprite *sprite, string new_name /* = "" */, GL_Surface *image /* = NULL */ )
  1084. {
  1085.     // if invalid
  1086.     if( !sprite )
  1087.     {
  1088.         printf( "Warning : Invalid Editor Item\n" );
  1089.         return;
  1090.     }
  1091.  
  1092.     // set correct array if not given
  1093.     if( sprite->sprite_array == ARRAY_UNDEFINED )
  1094.     {
  1095.         printf( "Warning : Editor sprite %s array not set\n", sprite->name.c_str() );
  1096.  
  1097.         if( sprite->massivetype == MASS_PASSIVE )
  1098.         {
  1099.             sprite->sprite_array = ARRAY_PASSIVE;
  1100.         }
  1101.         else if( sprite->massivetype == MASS_MASSIVE )
  1102.         {
  1103.             sprite->sprite_array = ARRAY_MASSIVE;
  1104.         }
  1105.         else if( sprite->massivetype == MASS_HALFMASSIVE )
  1106.         {
  1107.             sprite->sprite_array = ARRAY_ACTIVE;
  1108.         }
  1109.     }
  1110.  
  1111.     // set correct type if not given
  1112.     if( sprite->type == TYPE_UNDEFINED )
  1113.     {
  1114.         printf( "Warning : Editor sprite %s type not set\n", sprite->name.c_str() );
  1115.  
  1116.         if( sprite->massivetype == MASS_PASSIVE )
  1117.         {
  1118.             sprite->type = TYPE_PASSIVE;
  1119.         }
  1120.         else if( sprite->massivetype == MASS_MASSIVE )
  1121.         {
  1122.             sprite->type = TYPE_MASSIVE;
  1123.         }
  1124.         else if( sprite->massivetype == MASS_HALFMASSIVE )
  1125.         {
  1126.             sprite->type = TYPE_HALFMASSIVE;
  1127.         }
  1128.         else if( sprite->massivetype == MASS_CLIMBABLE )
  1129.         {
  1130.             sprite->type = TYPE_CLIMBABLE;
  1131.         }
  1132.     }
  1133.  
  1134.     // if no image is given use the sprite start image
  1135.     if( !image )
  1136.     {
  1137.         // special object
  1138.         if( sprite->type == TYPE_ENEMY_STOPPER || sprite->type == TYPE_LEVEL_EXIT || sprite->type == TYPE_LEVEL_ENTRY || sprite->type == TYPE_SOUND || sprite->type == TYPE_ANIMATION )
  1139.         {
  1140.             sprite->image = pVideo->Get_Surface( "game/editor/special.png" );
  1141.             sprite->start_image = sprite->image;
  1142.         }
  1143.  
  1144.         image = sprite->start_image;
  1145.     }
  1146.  
  1147.     // set object name
  1148.     string obj_name;
  1149.  
  1150.     if( new_name.length() )
  1151.     {
  1152.         obj_name = new_name;
  1153.     }
  1154.     else if( sprite->name.length() )
  1155.     {
  1156.         obj_name = sprite->name;
  1157.     }
  1158.     // no object name available
  1159.     else
  1160.     {
  1161.         if( image )
  1162.         {
  1163.             obj_name = image->Get_Filename( 0, 0 );
  1164.         }
  1165.  
  1166.         // Warn if using filename
  1167.         printf( "Warning : editor object %s with no name given\n", obj_name.c_str() );
  1168.     }
  1169.  
  1170.     cEditor_Item_Object *new_item = new cEditor_Item_Object( obj_name );
  1171.  
  1172.     // object pointer
  1173.     new_item->sprite_obj = sprite;
  1174.  
  1175.     // Initialize
  1176.     new_item->Init();
  1177.  
  1178.     // Get Items Listbox
  1179.     CEGUI::Listbox *listbox_items = static_cast<CEGUI::Listbox *>(CEGUI::WindowManager::getSingleton().getWindow( "editor_items" ));
  1180.     // Add Item
  1181.     listbox_items->addItem( new_item );
  1182. }
  1183.  
  1184. void cEditor :: Load_Image_Items( string dir )
  1185. {
  1186.     vector<string> image_files = Get_Directory_Files( dir, ".settings" );
  1187.  
  1188.     // load all available objects
  1189.     for( vector<string>::iterator itr = image_files.begin(), itr_end = image_files.end(); itr != itr_end; ++itr )
  1190.     {
  1191.         // get filename
  1192.         string filename = (*itr);
  1193.  
  1194.         // load settings
  1195.         cImage_settings_data *settings = pSettingsParser->Get( filename );
  1196.  
  1197.         // if settings are available
  1198.         if( settings )
  1199.         {
  1200.             // if required editor tag is available
  1201.             if( settings->m_editor_tags.find( editor_item_tag ) != string::npos )
  1202.             {
  1203.                 // set base to the filename
  1204.                 settings->m_base = filename;
  1205.                 // add real image
  1206.                 tagged_item_images.push_back( settings );
  1207.             }
  1208.         }
  1209.     }
  1210. }
  1211.  
  1212. void cEditor :: Activate_Item( cEditor_Item_Object *entry )
  1213. {
  1214.     // invalid
  1215.     if( !entry )
  1216.     {
  1217.         printf( "Error : Invalid Editor Item\n" );
  1218.         return;
  1219.     }
  1220.  
  1221.     // create copy from editor item
  1222.     cSprite *new_sprite = entry->sprite_obj->Copy();
  1223.  
  1224.     // if copying failed
  1225.     if( !new_sprite )
  1226.     {
  1227.         printf( "Error : Editor Sprite %s copy failed\n", entry->sprite_obj->name.c_str() );
  1228.         return;
  1229.     }
  1230.     
  1231.     new_sprite->Set_Pos( pMouseCursor->posx, pMouseCursor->posy, 1 );
  1232.  
  1233.     // hide editor window
  1234.     editor_window->setXPosition( CEGUI::UDim( -0.19f, 0 ) );
  1235.     // Hide Listbox
  1236.     CEGUI::Listbox *listbox = static_cast<CEGUI::Listbox *>(CEGUI::WindowManager::getSingleton().getWindow( "editor_menu" ));
  1237.     listbox->hide();
  1238.     listbox = static_cast<CEGUI::Listbox *>(CEGUI::WindowManager::getSingleton().getWindow( "editor_items" ));
  1239.     listbox->hide();
  1240.  
  1241.     // add item
  1242.     pActive_Sprite_Manager->Add( new_sprite );
  1243.  
  1244.     // Set Mouse Objects
  1245.     pMouseCursor->left = 1;
  1246.     pMouseCursor->mouse_object->mouse_h = static_cast<int>( new_sprite->col_rect.h / 2 );
  1247.     pMouseCursor->mouse_object->mouse_w = static_cast<int>( new_sprite->col_rect.w / 2 );
  1248.     pMouseCursor->Set_Mouse_Object( new_sprite );
  1249. }
  1250.  
  1251. bool cEditor :: Is_Tag_Available( string str, string tag, unsigned int search_pos /* = 0 */ )
  1252. {
  1253.     // found tag position
  1254.     std::string::size_type pos = str.find( tag, search_pos );
  1255.  
  1256.     // not found
  1257.     if( pos == string::npos )
  1258.     {
  1259.         return 0;
  1260.     }
  1261.  
  1262.     // tag end position
  1263.     std::string::size_type end_pos = pos + tag.length();
  1264.  
  1265.     // if tag starting position is valid
  1266.     if( pos == 0 || str.substr( pos - 1, 1 ).compare( ";" ) == 0  )
  1267.     {
  1268.         // if tag ending position is valid
  1269.         if( end_pos == str.length() || str.substr( end_pos, 1 ).compare( ";" ) == 0  )
  1270.         {
  1271.             return 1;
  1272.         }
  1273.     }
  1274.  
  1275.     // not valid - continue search
  1276.     return Is_Tag_Available( str, tag, end_pos );
  1277. }
  1278.  
  1279. void cEditor :: Draw_Editor_Help( void )
  1280. {
  1281.     // Help Window Background Rect
  1282.     pVideo->Draw_Rect( 50, 5, 700, 550, 0.58f, &blackalpha192 );
  1283.  
  1284.     // no help text set
  1285.     if( !help_sprites.size() )
  1286.     {
  1287.         // Add/Create the Help Text
  1288.         // todo : create a CEGUI help box with tabs and translate with gettext then
  1289.         Add_Help_Line( "Editor Help", "", 5, 300 );
  1290.         Add_Help_Line( "F1", "Toggle this Help Window" );
  1291.         Add_Help_Line( "F8", "Open / Close the Level editor" );
  1292.         Add_Help_Line( "F10", "Toggle sound effects" );
  1293.         Add_Help_Line( "F11", "Toggle music play" );
  1294.         Add_Help_Line( "Home", "Focus level start" );
  1295.         Add_Help_Line( "End", "Focus last level exit" );
  1296.         Add_Help_Line( "L", "Load a Level" );
  1297.         Add_Help_Line( "W", "Load an Overworld" );
  1298.         Add_Help_Line( "N", "Step one screen to the right ( Next Screen )" );
  1299.         Add_Help_Line( "P", "Step one screen to the left ( Previous Screen )" );
  1300.         Add_Help_Line( "M", "Cycle through massive types (use for object groups)" );
  1301.         Add_Help_Line( "Massive types (color):" );
  1302.         Add_Help_Line( "Massive(red) ->   Halfmassive(orange) ->   Climbable(lila) ->   Passive(green) ->   Front Passive(green)", "" , 0, 80 );
  1303.         Add_Help_Line( "Ctrl + S", "Quicksave current Level" );
  1304.         Add_Help_Line( "Ctrl + D", "Toggle debug mode" );
  1305.         Add_Help_Line( "Ctrl + A", "Select all objects" );
  1306.         Add_Help_Line( "Ctrl + X", "Cut currently selected objects" );
  1307.         Add_Help_Line( "Ctrl + C", "Copy currently selected objects" );
  1308.         Add_Help_Line( "Ctrl + V", "Paste current copied / cutted objects" );
  1309.         Add_Help_Line( "Insert", "Paste current copied / cutted objects" );
  1310.         Add_Help_Line( "Del", "If Mouse is over an object: Delete current object" );
  1311.         Add_Help_Line( "Del", "If Mouse has nothing selected: Delete selected objects" );
  1312.         Add_Help_Line( "Numpad:" );
  1313.         Add_Help_Line( " +", "Bring object to front" );
  1314.         Add_Help_Line( " -", "Send object to back" );
  1315.         Add_Help_Line( " 2/4/6/8", "Move selected tile in direction ( 1 Pixel )" );
  1316.         Add_Help_Line( "Mouse:" );
  1317.         Add_Help_Line( " Left (Hold)", "Drag objects" );
  1318.         Add_Help_Line( " Left (Click)", "With shift to select / deselect single objects" );
  1319.         Add_Help_Line( " Right", "Delete intersecting Object" );
  1320.         Add_Help_Line( " Middle", "Switch to Mover Mode" );
  1321.         Add_Help_Line( "Arrow keys:" );
  1322.         Add_Help_Line( " Use arrow keys to move around. Press shift for faster movement" );
  1323.     }
  1324.  
  1325.     // draw
  1326.     for( HudSpriteList::iterator itr = help_sprites.begin(), itr_end = help_sprites.end(); itr != itr_end; ++itr )
  1327.     {
  1328.         (*itr)->Draw();
  1329.     }
  1330. }
  1331.  
  1332. void cEditor :: Add_Help_Line( string key_text, string text /* = "" */, float spacing /* = 0 */, float pos_x /* = 60 */ )
  1333. {
  1334.     // create help sprites
  1335.     cHudSprite *help_sprite_key_text = new cHudSprite();
  1336.     cHudSprite *help_sprite_text = new cHudSprite();
  1337.     // with shadow
  1338.     help_sprite_key_text->Set_Shadow( black, 0.5f );
  1339.     help_sprite_text->Set_Shadow( black, 0.5f );
  1340.     // position in front
  1341.     help_sprite_key_text->posz = 0.591f;
  1342.     help_sprite_text->posz = 0.59f;
  1343.  
  1344.     // Set Y position
  1345.     float pos_y = spacing;
  1346.     // if not the first help sprite use the last position
  1347.     if( help_sprites.size() )
  1348.     {
  1349.         // get last help sprite
  1350.         cHudSprite *last_hud_sprite = help_sprites[ help_sprites.size() - 1 ];
  1351.         // set correct position
  1352.         pos_y += last_hud_sprite->posy + last_hud_sprite->rect.h;
  1353.     }
  1354.     // first item
  1355.     else
  1356.     {
  1357.         pos_y += 5;
  1358.     }
  1359.  
  1360.     // text must be filled with something to get created by Render_Text
  1361.     if( key_text.empty() )
  1362.     {
  1363.         key_text = " ";
  1364.     }
  1365.     if( text.empty() )
  1366.     {
  1367.         text = " ";
  1368.     }
  1369.  
  1370.     // set key text
  1371.     help_sprite_key_text->Set_Image( pFont->Render_Text( pFont->font_very_small, key_text, lightorange ), 0, 1 );
  1372.     help_sprite_key_text->Set_Pos( pos_x, pos_y, 1 );
  1373.     // set text
  1374.     help_sprite_text->Set_Image( pFont->Render_Text( pFont->font_very_small, text, white ), 0, 1 );
  1375.     help_sprite_text->Set_Pos( pos_x + 90, pos_y, 1 );
  1376.  
  1377.     // add to array
  1378.     help_sprites.push_back( help_sprite_key_text );
  1379.     help_sprites.push_back( help_sprite_text );
  1380. }
  1381.  
  1382. void cEditor :: Change_Draw_Position( cSprite *obj, bool push_back )
  1383. {
  1384.     // empty object
  1385.     if( !obj )
  1386.     {
  1387.         return;
  1388.     }
  1389.  
  1390.     // check if valid object
  1391.     if( !( obj->sprite_array == ARRAY_MASSIVE || obj->sprite_array == ARRAY_PASSIVE || obj->sprite_array == ARRAY_FRONT_PASSIVE || obj->sprite_array == ARRAY_ACTIVE ) )
  1392.     {
  1393.         return;
  1394.     }
  1395.  
  1396.     cSprite *temp = NULL;
  1397.  
  1398.     // push front
  1399.     if( !push_back )
  1400.     {
  1401.         temp = pActive_Sprite_Manager->objects.back();
  1402.  
  1403.         // if already in front
  1404.         if( obj == temp )
  1405.         {
  1406.             return;
  1407.         }
  1408.  
  1409.         pActive_Sprite_Manager->Delete( obj, 0 );
  1410.         pActive_Sprite_Manager->objects.back() = obj;
  1411.         pActive_Sprite_Manager->objects.insert( pActive_Sprite_Manager->objects.end() - 1, temp );
  1412.  
  1413.         obj->posz = pActive_Sprite_Manager->Get_Last( obj->type )->posz + 0.000001f;
  1414.     }
  1415.     // push back
  1416.     else
  1417.     {
  1418.         temp = pActive_Sprite_Manager->objects.front();
  1419.  
  1420.         // if already in back
  1421.         if( obj == temp )
  1422.         {
  1423.             return;
  1424.         }
  1425.  
  1426.         pActive_Sprite_Manager->Delete( obj, 0 );
  1427.         pActive_Sprite_Manager->objects.front() = obj;
  1428.         pActive_Sprite_Manager->objects.insert( pActive_Sprite_Manager->objects.begin() + 1, temp );
  1429.  
  1430.         obj->posz = pActive_Sprite_Manager->Get_First( obj->type )->posz - 0.000001f;
  1431.     }
  1432. }
  1433.  
  1434. SpriteList cEditor :: Copy_Direction( SpriteList objects, ObjectDirection dir )
  1435. {
  1436.     // additional direction objects offset
  1437.     unsigned int offset = 0;
  1438.  
  1439.     // get the objects difference offset
  1440.     if( dir == DIR_LEFT || dir == DIR_RIGHT )
  1441.     {
  1442.         // first object
  1443.         cSprite *first = objects[0];
  1444.  
  1445.         for( unsigned int i = 1; i < objects.size(); i++ )
  1446.         {
  1447.             if( objects[i]->startposx < first->startposx )
  1448.             {
  1449.                 first = objects[i];
  1450.             }
  1451.         }
  1452.  
  1453.         // last object
  1454.         cSprite *last = objects[0];
  1455.  
  1456.         for( unsigned int i = 1; i < objects.size(); i++ )
  1457.         {
  1458.             if( objects[i]->startposx + objects[i]->start_rect.w > last->startposx + last->start_rect.w )
  1459.             {
  1460.                 last = objects[i];
  1461.             }
  1462.         }
  1463.  
  1464.         // Set X offset
  1465.         offset = static_cast<int>( last->startposx - first->startposx + last->start_rect.w );
  1466.     }
  1467.     else if( dir == DIR_UP || dir == DIR_DOWN )
  1468.     {
  1469.         // first object
  1470.         cSprite *first = objects[0];
  1471.  
  1472.         for( unsigned int i = 1; i < objects.size(); i++ )
  1473.         {
  1474.             if( objects[i]->startposy < first->startposy )
  1475.             {
  1476.                 first = objects[i];
  1477.             }
  1478.         }
  1479.  
  1480.         // last object
  1481.         cSprite *last = objects[0];
  1482.  
  1483.         for( unsigned int i = 1; i < objects.size(); i++ )
  1484.         {
  1485.             if( objects[i]->startposy + objects[i]->start_rect.h > last->startposy + last->start_rect.h )
  1486.             {
  1487.                 last = objects[i];
  1488.             }
  1489.         }
  1490.  
  1491.         // Set Y offset
  1492.         offset = static_cast<int>( last->startposy - first->startposy + last->start_rect.h );
  1493.     }
  1494.  
  1495.     // new copied objects
  1496.     SpriteList new_objects;
  1497.  
  1498.     for( SpriteList::iterator itr = objects.begin(), itr_end = objects.end(); itr != itr_end; ++itr )
  1499.     {
  1500.         cSprite *obj = (*itr);
  1501.  
  1502.         new_objects.push_back( Copy_Direction( obj, dir, offset ) );
  1503.     }
  1504.  
  1505.     // return only new objects
  1506.     return new_objects;
  1507. }
  1508.  
  1509. cSprite *cEditor :: Copy_Direction( cSprite *obj, ObjectDirection dir, int offset /* = 0 */ )
  1510. {
  1511.     float w = 0, h = 0;
  1512.  
  1513.     if( dir == DIR_LEFT )
  1514.     {
  1515.         if( offset )
  1516.         {
  1517.             w = -static_cast<float>(offset);
  1518.         }
  1519.         else
  1520.         {
  1521.             w = -obj->start_rect.w;
  1522.         }
  1523.     }
  1524.     else if( dir == DIR_RIGHT )
  1525.     {
  1526.         if( offset )
  1527.         {
  1528.             w = static_cast<float>(offset);
  1529.         }
  1530.         else
  1531.         {
  1532.             w = obj->start_rect.w;
  1533.         }
  1534.     }
  1535.     else if( dir == DIR_UP )
  1536.     {
  1537.         if( offset )
  1538.         {
  1539.             h = -static_cast<float>(offset);
  1540.         }
  1541.         else
  1542.         {
  1543.             h = -obj->start_rect.h;
  1544.         }
  1545.     }
  1546.     else if( dir == DIR_DOWN )
  1547.     {
  1548.         if( offset )
  1549.         {
  1550.             h = static_cast<float>(offset);
  1551.         }
  1552.         else
  1553.         {
  1554.             h = obj->start_rect.h;
  1555.         }
  1556.     }
  1557.  
  1558.     // only move camera if obj is the mouse object
  1559.     if( pMouseCursor->mouse_object->obj == obj )
  1560.     {
  1561.         pActive_Camera->Move( w, h );
  1562.     }
  1563.  
  1564.     return pMouseCursor->Copy( obj, obj->startposx + w, obj->startposy + h );
  1565. }
  1566.  
  1567. bool cEditor :: Editor_Mouse_Enter( const CEGUI::EventArgs &event )
  1568. {
  1569.     // ignore if a button is pressed
  1570.     if( pMouseCursor->left || pMouseCursor->middle || pMouseCursor->right )
  1571.     {
  1572.         return 1;
  1573.     }
  1574.  
  1575.     // if not active fade in
  1576.     if( editor_window->getXPosition().asRelative( 1 ) != 0 )
  1577.     {
  1578.         editor_window->setXPosition( CEGUI::UDim( 0, 0 ) );
  1579.         editor_window->setAlpha( 0 );
  1580.  
  1581.         // Show Listbox
  1582.         CEGUI::Listbox *listbox = static_cast<CEGUI::Listbox *>(CEGUI::WindowManager::getSingleton().getWindow( "editor_menu" ));
  1583.         listbox->show();
  1584.         listbox = static_cast<CEGUI::Listbox *>(CEGUI::WindowManager::getSingleton().getWindow( "editor_items" ));
  1585.         listbox->show();
  1586.     }
  1587.     // if active but fading out
  1588.     else if( editor_window->getAlpha() < 1 )
  1589.     {
  1590.         editor_window->setAlpha( 1 );
  1591.         menu_timer = 0;
  1592.     }
  1593.  
  1594.     return 1;
  1595. }
  1596.  
  1597. bool cEditor :: Menu_Select( const CEGUI::EventArgs &event )
  1598. {
  1599.     const CEGUI::WindowEventArgs &windowEventArgs = static_cast<const CEGUI::WindowEventArgs&>( event );
  1600.     CEGUI::ListboxItem *item = static_cast<CEGUI::Listbox *>( windowEventArgs.window )->getFirstSelectedItem();
  1601.  
  1602.     // set item
  1603.     if( item )
  1604.     {
  1605.         Activate_Menu( static_cast<cEditor_Menu_Object *>(item) );
  1606.     }
  1607.     // clear ?
  1608.     else
  1609.     {
  1610.         // todo : clear
  1611.     }
  1612.  
  1613.     return 1;
  1614. }
  1615.  
  1616. bool cEditor :: Item_Select( const CEGUI::EventArgs &event )
  1617. {
  1618.     const CEGUI::WindowEventArgs &windowEventArgs = static_cast<const CEGUI::WindowEventArgs&>( event );
  1619.     CEGUI::ListboxItem *item = static_cast<CEGUI::Listbox *>( windowEventArgs.window )->getFirstSelectedItem();
  1620.  
  1621.     // activate item
  1622.     if( item )
  1623.     {
  1624.         Activate_Item( static_cast<cEditor_Item_Object *>(item) );
  1625.     }
  1626.  
  1627.     return 1;
  1628. }
  1629.  
  1630. void cEditor :: Function_Exit( void )
  1631. {
  1632.     pKeyboard->Key_Down( SDLK_F8 );
  1633. }
  1634.  
  1635. // XML element start
  1636. void cEditor :: elementStart( const CEGUI::String &element, const CEGUI::XMLAttributes &attributes )
  1637. {
  1638.     // Property/Item/Tag of an Element
  1639.     if( element == "Property" )
  1640.     {
  1641.         xml_attributes.add( attributes.getValueAsString( "Name" ), attributes.getValueAsString( "Value" ) );
  1642.     }
  1643. }
  1644.  
  1645. // XML element end
  1646. void cEditor :: elementEnd( const CEGUI::String &element )
  1647. {
  1648.     if( element != "Property" )
  1649.     {
  1650.         if( element == "Item" )
  1651.         {
  1652.             // Menu Item
  1653.             if( xml_attributes.getValueAsString( "tags" ).length() )
  1654.             {
  1655.                 Handle_Menu( xml_attributes );
  1656.             }
  1657.             // Items Item
  1658.             else
  1659.             {
  1660.                 Handle_Item( xml_attributes );
  1661.             }
  1662.         }
  1663.         else if( element == "Items" || element == "Menu" )
  1664.         {
  1665.             // ignore
  1666.         }
  1667.         else if( element.length() )
  1668.         {
  1669.             printf( "Warning : Editor Unknown Item Element : %s\n", element.c_str() );
  1670.         }
  1671.  
  1672.         // clear
  1673.         xml_attributes = CEGUI::XMLAttributes();
  1674.     }
  1675. }
  1676.  
  1677. void cEditor :: Handle_Item( const CEGUI::XMLAttributes &attributes )
  1678. {
  1679.     // element name must be given
  1680.     CEGUI::String name = xml_attributes.getValueAsString( "object_name" );
  1681.     CEGUI::String tags = xml_attributes.getValueAsString( "object_tags" );
  1682.  
  1683.     // create
  1684.     cSprite *object = NULL;
  1685.  
  1686.     // Level object
  1687.     if( editor_level_enabled )
  1688.     {
  1689.         object = Get_Level_Object( name, xml_attributes );
  1690.     }
  1691.     // Overworld object
  1692.     else
  1693.     {
  1694.         object = Get_World_Object( name, xml_attributes );
  1695.     }
  1696.  
  1697.  
  1698.     // if creation failed
  1699.     if( !object )
  1700.     {
  1701.         return;
  1702.     }
  1703.  
  1704.     // set editor tags
  1705.     object->editor_tags = tags.c_str();
  1706.  
  1707.     // Add Item Object
  1708.     tagged_item_objects.push_back( object );
  1709. }
  1710.  
  1711. void cEditor :: Handle_Menu( const CEGUI::XMLAttributes &attributes )
  1712. {
  1713.     string name = xml_attributes.getValueAsString( "name" ).c_str();
  1714.     string tags = xml_attributes.getValueAsString( "tags" ).c_str();
  1715.  
  1716.     Add_Menu_Object( name, tags, CEGUI::PropertyHelper::stringToColour( xml_attributes.getValueAsString( "color", "FFFFFFFF" ) ) );
  1717. }
  1718.