Explorar o código

By hand/manual merge of Akaris changes - expect bugs from this :) WriteTriangleVertex and WriteGlyph calls have been removed, will be restored in next change

Paul %!s(int64=11) %!d(string=hai) anos
pai
achega
fb774d93bc
Modificáronse 42 ficheiros con 3243 adicións e 768 borrados
  1. 6 0
      QGearsMain/CMakeLists.txt
  2. 119 0
      QGearsMain/include/core/DialogsManager.h
  3. 2 0
      QGearsMain/include/core/EntityManager.h
  4. 2 0
      QGearsMain/include/core/Event.h
  5. 21 14
      QGearsMain/include/core/InputManager.h
  6. 55 14
      QGearsMain/include/core/InputManagerCommands.h
  7. 40 1
      QGearsMain/include/core/ScriptManagerBinds.h
  8. 49 0
      QGearsMain/include/core/TextManager.h
  9. 36 0
      QGearsMain/include/core/TextManagerCommands.h
  10. 6 1
      QGearsMain/include/core/Timer.h
  11. 13 0
      QGearsMain/include/core/UiAnimation.h
  12. 3 1
      QGearsMain/include/core/UiFont.h
  13. 0 10
      QGearsMain/include/core/UiManager.h
  14. 87 15
      QGearsMain/include/core/UiTextArea.h
  15. 21 7
      QGearsMain/include/core/UiWidget.h
  16. 23 0
      QGearsMain/include/core/Utilites.h
  17. 0 1
      QGearsMain/include/core/XmlScreenFile.h
  18. 1 1
      QGearsMain/include/core/XmlTextFile.h
  19. 3 3
      QGearsMain/include/core/XmlTextsFile.h
  20. 8 6
      QGearsMain/src/Main.cpp
  21. 9 9
      QGearsMain/src/core/Console.cpp
  22. 78 14
      QGearsMain/src/core/DebugDraw.cpp
  23. 525 0
      QGearsMain/src/core/DialogsManager.cpp
  24. 98 8
      QGearsMain/src/core/EntityManager.cpp
  25. 3 0
      QGearsMain/src/core/GameFrameListner.cpp
  26. 155 50
      QGearsMain/src/core/InputManager.cpp
  27. 2 2
      QGearsMain/src/core/ScriptManager.cpp
  28. 121 0
      QGearsMain/src/core/TextManager.cpp
  29. 28 2
      QGearsMain/src/core/Timer.cpp
  30. 158 173
      QGearsMain/src/core/UiAnimation.cpp
  31. 18 1
      QGearsMain/src/core/UiFont.cpp
  32. 45 80
      QGearsMain/src/core/UiManager.cpp
  33. 783 146
      QGearsMain/src/core/UiTextArea.cpp
  34. 202 80
      QGearsMain/src/core/UiWidget.cpp
  35. 254 1
      QGearsMain/src/core/Utilites.cpp
  36. 2 1
      QGearsMain/src/core/XmlFontFile.cpp
  37. 161 73
      QGearsMain/src/core/XmlScreenFile.cpp
  38. 16 3
      QGearsMain/src/core/XmlScreensFile.cpp
  39. 11 4
      QGearsMain/src/core/XmlTextFile.cpp
  40. 41 14
      QGearsMain/src/core/XmlTextsFile.cpp
  41. 27 22
      utilities/ffvii_field_dat_dumper/src/DatFile.cpp
  42. 11 11
      utilities/ffvii_font_exporter/src/FontFile.cpp

+ 6 - 0
QGearsMain/CMakeLists.txt

@@ -98,6 +98,10 @@ set(HEADER_FILES
   include/core/XmlScriptsFile.h
   include/core/XmlTextFile.h
   include/core/XmlTextsFile.h
+  include/core/DialogsManager.h
+  include/core/ScriptManagerBinds.h
+  include/core/TextManager.h
+  include/core/TextManagerCommands.h
   #include/viewer/ViewerModule.h
   include/data/QGearsXMLSerializer.h
 )
@@ -270,6 +274,8 @@ set(SOURCE_FILES
   src/core/XmlScriptsFile.cpp
   src/core/XmlTextFile.cpp
   src/core/XmlTextsFile.cpp
+  src/core/DialogsManager.cpp
+  src/core/TextManager.cpp
   src/map/QGearsBackground2DFile.cpp
   src/map/QGearsBackground2DFileManager.cpp
   src/map/QGearsBackground2DFileXMLSerializer.cpp

+ 119 - 0
QGearsMain/include/core/DialogsManager.h

@@ -0,0 +1,119 @@
+#ifndef DIALOGS_MANAGER_h
+#define DIALOGS_MANAGER_h
+
+#include <OgreSingleton.h>
+
+#include "UiManager.h"
+#include "UiTextArea.h"
+
+
+
+enum MessageState
+{
+    MS_CLOSED,
+    MS_SHOW_WINDOW,
+    MS_SHOW_TEXT,
+    MS_OPENED,
+    MS_HIDE_WINDOW
+};
+
+
+
+enum MessageStyle
+{
+    MSL_SOLID,
+    MSL_TRANSPARENT,
+    MSL_NONE
+};
+
+
+
+struct MessageData
+{
+    MessageData():
+        widget( NULL ),
+        window( NULL ),
+        scissor( NULL ),
+        text_area( NULL ),
+        cursor( NULL ),
+
+        state( MS_CLOSED ),
+
+        clickable( true ),
+        show_window( true ),
+        show_cursor( false ),
+        auto_close( false ),
+
+        cursor_percent_y( 0 ),
+        cursor_y( 0 ),
+        cursor_row_selected( 0 ),
+        cursor_row_current( 0 ),
+        cursor_row_first( 0 ),
+        cursor_row_last( 0 )
+    {
+    }
+
+    UiWidget* widget;
+    UiWidget* window;
+    UiWidget* scissor;
+    UiTextArea* text_area;
+    UiWidget* cursor;
+
+    MessageState state;
+
+    std::vector< ScriptId > sync;
+
+    bool clickable;
+    bool show_window;
+    bool show_cursor;
+    bool auto_close;
+
+    float cursor_percent_y;
+    float cursor_y;
+    int cursor_row_selected;
+    int cursor_row_current;
+    int cursor_row_first;
+    int cursor_row_last;
+};
+
+
+
+class DialogsManager : public Ogre::Singleton< DialogsManager >
+{
+public:
+    DialogsManager();
+    virtual ~DialogsManager();
+
+    void Initialise();
+    void Input( const QGears::Event& event );
+    void Update();
+    void Clear();
+
+    void ShowDialog( const char* d_name, const char* name, const int x, const int y );
+    void ShowText( const char* d_name, const char* text, const int x, const int y, const int width, const int height );
+    int Sync( const char* d_name );
+    void SetVariable( const char* d_name, const char* name, const char* value );
+    void Hide( const char* d_name );
+    void SetClickable( const char* d_name, const bool clickable );
+    void SetCursor( const char* d_name, const int first_row, const int last_row );
+    int GetCursor( const char* d_name ) const;
+
+private:
+    void ShowMessage( const int id, const int x, const int y, const int width, const int height );
+    void HideMessage( const int id );
+    int GetMessageId( const char* d_name ) const;
+    bool AutoCloseCheck( const unsigned int id );
+
+private:
+    UiWidget* m_LimitArea;
+    std::vector< MessageData* > m_Messages;
+
+    bool m_NextPressed;
+    bool m_NextRepeated;
+    bool m_UpPressed;
+    bool m_DownPressed;
+};
+
+
+
+#endif // DIALOGS_MANAGER_H

+ 2 - 0
QGearsMain/include/core/EntityManager.h

@@ -54,6 +54,7 @@ private:
     bool CheckSolidCollisions( Entity* entity, Ogre::Vector3& position );
     void SetEntityDirectionByVector( Entity* entity, const Ogre::Vector2& vector );
     void CheckTriggers( Entity* entity, Ogre::Vector3& position );
+    void CheckEntityInteract();
 
     void SetNextOffsetStep( Entity* entity );
     void SetNextTurnStep( Entity* entity );
@@ -73,6 +74,7 @@ private:
     Ogre::Vector3                 m_PlayerMove;
     Ogre::Radian                  m_PlayerMoveRotation;
     bool                          m_PlayerLock;
+    bool                          m_PlayerRun;
 
     std::vector< EntityTrigger* > m_EntityTriggers;
     std::vector< EntityPoint* >   m_EntityPoints;

+ 2 - 0
QGearsMain/include/core/Event.h

@@ -11,6 +11,7 @@ namespace QGears
         ET_NULL = 0,
         ET_KEY_PRESS,
         ET_KEY_REPEAT,
+		ET_KEY_REPEAT_WAIT,
         ET_KEY_IMPULSE,
         ET_KEY_RELEASE,
         ET_MOUSE_PRESS,
@@ -47,5 +48,6 @@ namespace QGears
         EventType type;
         float param1;
         float param2;
+        Ogre::String event;
     };
 }

+ 21 - 14
QGearsMain/include/core/InputManager.h

@@ -13,7 +13,7 @@
 typedef std::vector< QGears::Event > InputEventArray;
 typedef std::vector< int > ButtonList;
 
-
+class ConfigCmd;
 
 class InputManager : public Ogre::Singleton< InputManager >
 {
@@ -34,21 +34,12 @@ public:
 
     // binds
     void                InitCmd();
-    void                BindCommand( const Ogre::String& cmd, const ButtonList& buttons );
-    void                ActivateBinds( int button );
+    void                BindCommand( ConfigCmd* cmd, const Ogre::StringVector& params, const ButtonList& buttons );
+    void                BindGameEvent( const Ogre::String& event, const ButtonList& buttons );
+    void                ActivateBinds( const int button );
+    void                AddGameEvents( const int button, const QGears::EventType type );
 
 private:
-    struct BindInfo
-    {
-        BindInfo( const Ogre::String& _cmd, const ButtonList& _key_set ):
-            cmd( _cmd ),
-            key_set( _key_set )
-        {}
-
-        ButtonList      key_set;
-        Ogre::String    cmd;
-    };
-
     bool                    m_ButtonState[ 256 ];
     char                    m_ButtonText[ 256 ];
 
@@ -58,7 +49,23 @@ private:
     InputEventArray         m_EventQueue;
 
     // binds
+    struct BindInfo
+    {
+        BindInfo():
+            cmd( NULL )
+        {}
+
+        ConfigCmd* cmd;
+        Ogre::StringVector params;
+        ButtonList buttons;
+    };
     std::vector< BindInfo > m_Binds;
+    struct BindGameEventInfo
+    {
+        Ogre::String event;
+        ButtonList buttons;
+    };
+    std::vector< BindGameEventInfo > m_BindGameEvents;
 };
 
 

+ 55 - 14
QGearsMain/include/core/InputManagerCommands.h

@@ -8,37 +8,77 @@
 
 
 
+bool
+ParseKeys( const Ogre::String& string, ButtonList& key_codes )
+{
+    Ogre::StringVector keys = Ogre::StringUtil::split( string, "+" );
+
+    for( unsigned int i = 0; i < keys.size(); ++i )
+    {
+        key_codes.push_back( StringToKey( keys[ i ] ) );
+    }
+
+    bool fail = false;
+    for( unsigned int i = 0; i < key_codes.size(); ++i )
+    {
+        if( key_codes[ i ] == OIS::KC_UNASSIGNED )
+        {
+            LOG_ERROR( "Failed to parse key string \"" + string + "\". Can't recognize key " + Ogre::StringConverter::toString( i ) );
+            fail = true;
+        }
+    }
+
+    return fail;
+}
+
+
+
 void
 CmdBind( const Ogre::StringVector& params )
 {
-    if( params.size() < 3 || params.size() > 4 )
+    if( params.size() != 3 )
     {
         Console::getSingleton().AddTextToOutput( "Usage: /bind <key1>+[key2]+[key3] \"<command line>\"" );
         return;
     }
 
-    Ogre::StringVector keys = Ogre::StringUtil::split( params[ 1 ], "+" );
     ButtonList key_codes;
 
-    for( size_t i = 0; i < keys.size(); ++i )
+    if( ParseKeys( params[ 1 ], key_codes ) == false )
     {
-        key_codes.push_back( StringToKey( keys[ i ] ) );
-    }
+        Ogre::StringVector params_cmd = StringTokenise( params[ 2 ] );
 
-    bool fail = false;
-    for( size_t i = 0; i < key_codes.size(); ++i )
-    {
-        if( key_codes[ i ] == OIS::KC_UNASSIGNED )
+        // handle command
+        ConfigCmd* cmd = ConfigCmdManager::getSingleton().Find( params_cmd[ 0 ] );
+        if( cmd != NULL )
         {
-            LOG_ERROR( "Failed to bind \"" + params[ 1 ] + "\" to command \"" + params[ 2 ] + "\". Can't recognize key " + Ogre::StringConverter::toString( i ) );
-            fail = true;
+            InputManager::getSingleton().BindCommand( cmd, params_cmd, key_codes );
+            LOG_TRIVIAL( "Bind \"" + params[ 1 ] + "\" to command \"" + params[ 2 ] + "\"." );
         }
+        else
+        {
+            LOG_ERROR( "Can't find command \"" + params_cmd[ 0 ] + "\" in bind command \"" + params[ 2 ] + "\"." );
+        }
+    }
+}
+
+
+
+void
+CmdBindGameEvent( const Ogre::StringVector& params )
+{
+    if( params.size() != 3 )
+    {
+        Console::getSingleton().AddTextToOutput( "Usage: /game_bind <key1>+[key2]+[key3] \"<game event>\"" );
+        return;
     }
 
-    if( fail == false )
+    ButtonList key_codes;
+
+    if( ParseKeys( params[ 1 ], key_codes ) == false )
     {
-        InputManager::getSingleton().BindCommand( params[ 2 ], key_codes );
-        LOG_TRIVIAL( "Bind \"" + params[ 1 ] + "\" to command \"" + params[ 2 ] + "\"." );
+        InputManager::getSingleton().BindGameEvent( params[ 2 ], key_codes );
+        LOG_TRIVIAL( "Bind \"" + params[ 1 ] + "\" to game event \"" + params[ 2 ] + "\"." );
     }
 }
 
@@ -48,4 +88,5 @@ void
 InputManager::InitCmd()
 {
     ConfigCmdManager::getSingleton().AddCommand( "bind", "Bind command to keys", "", CmdBind, NULL );
+    ConfigCmdManager::getSingleton().AddCommand( "bind_game_event", "Bind game event to keys", "", CmdBindGameEvent, NULL );
 }

+ 40 - 1
QGearsMain/include/core/ScriptManagerBinds.h

@@ -7,7 +7,7 @@
 #include "UiWidget.h"
 #include "XmlMapFile.h"
 #include "XmlMapsFile.h"
-
+#include "DialogsManager.h"
 
 #include "modules/worldmap/WorldMapModule.h"
 
@@ -66,6 +66,10 @@ ScriptManager::InitBinds()
             .def( "is_solid", ( bool( Entity::* )() ) &Entity::IsSolid )
             .def( "set_talk_radius", ( void( Entity::* )( const float ) ) &Entity::SetTalkRadius )
             .def( "get_talk_radius", ( float( Entity::* )() ) &Entity::GetTalkRadius )
+            
+            // Some old test script use this, its just an alias for SetTalkable
+            .def("set_interactable", (void(Entity::*)(const bool)) &Entity::SetTalkable)
+
             .def( "set_talkable", ( void( Entity::* )( const bool ) ) &Entity::SetTalkable )
             .def( "is_talkable", ( bool( Entity::* )() ) &Entity::IsTalkable )
             .def( "set_visible", ( void( Entity::* )( const bool ) ) &Entity::SetVisible )
@@ -153,6 +157,33 @@ ScriptManager::InitBinds()
             ]
     ];
 
+    // walkmesh access
+    luabind::module( m_LuaState )
+    [
+        luabind::class_< Walkmesh >( "Walkmesh" )
+            .def( "lock_walkmesh", ( void( Walkmesh ::* )( unsigned int, bool ) ) &Walkmesh ::LockWalkmesh)
+            .def( "is_locked", ( bool( Walkmesh ::* )( unsigned int ) ) &Walkmesh ::IsLocked)
+    ];
+
+    luabind::module( m_LuaState )
+    [
+        luabind::class_< DialogsManager >( "Dialog" )
+            .def( "show_dialog", ( void( DialogsManager::* )( const char*, const char*, const int, const int ) ) &DialogsManager::ShowDialog )
+            .def( "show_text", ( void( DialogsManager::* )( const char*, const char*, const int, const int, const int, const int ) ) &DialogsManager::ShowText )
+            .def( "sync", ( int( DialogsManager::* )( const char* ) ) &DialogsManager::Sync, luabind::yield )
+            .def( "set_variable", ( void( DialogsManager::* )( const char*, const char*, const char* ) ) &DialogsManager::SetVariable )
+            .def( "hide", ( void( DialogsManager::* )( const char* ) ) &DialogsManager::Hide )
+            .def( "set_clickable", ( void( DialogsManager::* )( const char*, const bool ) ) &DialogsManager::SetClickable )
+            .def( "set_cursor", ( void( DialogsManager::* )( const char*, const int, const int ) ) &DialogsManager::SetCursor )
+            .def( "get_cursor", ( int( DialogsManager::* )( const char* ) ) &DialogsManager::GetCursor )
+
+            .enum_("constants")
+            [
+                luabind::value("SOLID", MSL_SOLID),
+                luabind::value("TRANSPARENT", MSL_TRANSPARENT),
+                luabind::value("NONE", MSL_NONE)
+            ]
+    ];
     // ui widget access
     luabind::module( m_LuaState )
     [
@@ -167,7 +198,11 @@ ScriptManager::InitBinds()
             .def( "animation_sync", ( int( UiWidget::* )() ) &UiWidget::ScriptAnimationSync, luabind::yield )
             .def( "set_colour", ( void( UiWidget::* )( const float, const float, const float ) ) &UiWidget::SetColour )
             .def( "set_alpha", ( void( UiWidget::* )( const float ) ) &UiWidget::SetAlpha )
+            .def( "set_x", ( void( UiWidget::* )( const float, const float ) ) &UiWidget::SetX )
+            .def( "set_y", ( void( UiWidget::* )( const float, const float ) ) &UiWidget::SetY )
             .def( "set_z", ( void( UiWidget::* )( const float ) ) &UiWidget::SetZ )
+            .def( "set_width", ( void( UiWidget::* )( const float, const float ) ) &UiWidget::SetWidth )
+            .def( "set_height", ( void( UiWidget::* )( const float, const float ) ) &UiWidget::SetHeight )
     ];
 
     // ui access
@@ -182,6 +217,8 @@ ScriptManager::InitBinds()
     [
         luabind::class_< Timer >( "Timer" )
             .def( "get_game_time_total", ( float( Timer::* )() ) &Timer::GetGameTimeTotal )
+            .def( "set_timer", ( float( Timer::* )( const float ) ) &Timer::SetGameTimer )
+            .def( "get_timer", ( int( Timer::* )() ) &Timer::GetGameTimer )
     ];
 
     // script access
@@ -208,6 +245,8 @@ ScriptManager::InitBinds()
 
     luabind::globals( m_LuaState )[ "entity_manager" ] = boost::ref( *( EntityManager::getSingletonPtr() ) );
     luabind::globals( m_LuaState )[ "background2d" ] = boost::ref( *( EntityManager::getSingletonPtr()->GetBackground2D() ) );
+    luabind::globals( m_LuaState )[ "walkmesh" ] = boost::ref( *( EntityManager::getSingletonPtr()->GetWalkmesh() ) );
+    luabind::globals( m_LuaState )[ "message" ] = boost::ref( *( DialogsManager::getSingletonPtr() ) );
     luabind::globals( m_LuaState )[ "ui_manager" ] = boost::ref( *( UiManager::getSingletonPtr() ) );
     luabind::globals( m_LuaState )[ "world_map_module" ] = boost::ref( *( QGears::WorldMapModule::getSingletonPtr() ) );
     luabind::globals( m_LuaState )[ "timer" ] = boost::ref( *( Timer::getSingletonPtr() ) );

+ 49 - 0
QGearsMain/include/core/TextManager.h

@@ -0,0 +1,49 @@
+#ifndef TEXT_MANAGER_H
+#define TEXT_MANAGER_H
+
+#include <OgreString.h>
+#include <OgreSingleton.h>
+
+#include "tinyxml/tinyxml.h"
+
+
+
+class TextManager : public Ogre::Singleton< TextManager >
+{
+public:
+    TextManager();
+    virtual ~TextManager();
+
+    void InitCmd();
+
+    void SetLanguage( const Ogre::String& language );
+    const Ogre::String& GetLanguage();
+    void AddText( const Ogre::String& name, TiXmlNode* node );
+    void AddDialog( const Ogre::String& name, TiXmlNode* node, const float width, const float height );
+    TiXmlNode* GetText( const Ogre::String& name ) const;
+    TiXmlNode* GetDialog( const Ogre::String& name, float &width, float& height ) const;
+    void UnloadTexts();
+
+private:
+    Ogre::String m_Language;
+
+    struct Text
+    {
+        Ogre::String name;
+        TiXmlNode* node;
+    };
+    std::vector< Text > m_Texts;
+
+    struct Dialog
+    {
+        Ogre::String name;
+        TiXmlNode* node;
+        float width;
+        float height;
+    };
+     std::vector< Dialog > m_Dialogs;
+};
+
+
+
+#endif // TEXT_MANAGER_H

+ 36 - 0
QGearsMain/include/core/TextManagerCommands.h

@@ -0,0 +1,36 @@
+#include "ConfigCmdManager.h"
+#include "Console.h"
+#include "Logger.h"
+#include "XmlTextsFile.h"
+
+
+
+void
+CmdSetLanguage( const Ogre::StringVector& params )
+{
+    if( params.size() < 2 )
+    {
+        Console::getSingleton().AddTextToOutput( "Usage: /set_language <language>" );
+        return;
+    }
+
+    TextManager::getSingleton().SetLanguage( params[ 1 ] );
+    LOG_TRIVIAL( "Set game language to \"" + params[ 1 ] + "\"." );
+}
+
+
+
+void
+CmdSetLanguageCompletition( Ogre::StringVector& complete_params )
+{
+    XmlTextsFile texts( "./data/texts.xml" );
+    texts.GetAvailableLanguages( complete_params );
+}
+
+
+
+void
+TextManager::InitCmd()
+{
+    ConfigCmdManager::getSingleton().AddCommand( "set_language", "Change language of texts and dialogs", "", CmdSetLanguage, CmdSetLanguageCompletition );
+}

+ 6 - 1
QGearsMain/include/core/Timer.h

@@ -15,13 +15,18 @@ public:
     float GetGameTimeTotal();
     float GetGameTimeDelta();
 
-    void AddTime( float time );
+    void AddTime( const float time );
+
+    void SetGameTimer( const float timer );
+    int GetGameTimer() const;
 
 private:
     float m_SystemTimeTotal;
     float m_SystemTimeDelta;
     float m_GameTimeTotal;
     float m_GameTimeDelta;
+
+    float m_GameTimer;
 };
 
 

+ 13 - 0
QGearsMain/include/core/UiAnimation.h

@@ -50,12 +50,18 @@ public:
     void AddScaleKeyFrame( const UiKeyFrameVector2& key_frame );
     void AddXKeyFrame( const UiKeyFrameVector2& key_frame );
     void AddYKeyFrame( const UiKeyFrameVector2& key_frame );
+    void AddWidthKeyFrame( const UiKeyFrameVector2& key_frame );
+    void AddHeightKeyFrame( const UiKeyFrameVector2& key_frame );
     void AddRotationKeyFrame( const UiKeyFrameFloat& key_frame );
     void AddAlphaKeyFrame( const UiKeyFrameFloat& key_frame );
+    void AddScissorKeyFrame( const UiKeyFrameVector2& x1, const UiKeyFrameVector2& y1, const UiKeyFrameVector2& x2, const UiKeyFrameVector2& y2 );
 
 private:
     UiAnimation();
 
+    float KeyFrameGetValue( std::vector< UiKeyFrameFloat >& data );
+    Ogre::Vector2 KeyFrameGetValue( std::vector< UiKeyFrameVector2 >& data );
+
     Ogre::String m_Name;
     UiWidget*    m_Widget;
 
@@ -65,8 +71,15 @@ private:
     std::vector< UiKeyFrameVector2 > m_Scale;
     std::vector< UiKeyFrameVector2 > m_X;
     std::vector< UiKeyFrameVector2 > m_Y;
+    std::vector< UiKeyFrameVector2 > m_Width;
+    std::vector< UiKeyFrameVector2 > m_Height;
     std::vector< UiKeyFrameFloat >   m_Rotation;
     std::vector< UiKeyFrameFloat >   m_Alpha;
+
+    std::vector< UiKeyFrameVector2 > m_ScissorXTop;
+    std::vector< UiKeyFrameVector2 > m_ScissorYLeft;
+    std::vector< UiKeyFrameVector2 > m_ScissorXBottom;
+    std::vector< UiKeyFrameVector2 > m_ScissorYRight;
 };
 
 

+ 3 - 1
QGearsMain/include/core/UiFont.h

@@ -21,10 +21,11 @@ struct UiCharData
 class UiFont
 {
 public:
-    UiFont( const Ogre::String& name );
+    UiFont( const Ogre::String& name, const Ogre::String& language );
     virtual ~UiFont();
 
     const Ogre::String& GetName() const;
+    const Ogre::String& GetLanguage() const;
 
     void SetImage( const Ogre::String& image, const int width, const int height );
     const Ogre::String& GetImageName() const;
@@ -39,6 +40,7 @@ public:
 
 private:
     Ogre::String              m_Name;
+    Ogre::String              m_Language;
 
     Ogre::String              m_ImageName;
     int                       m_ImageWidth;

+ 0 - 10
QGearsMain/include/core/UiManager.h

@@ -21,10 +21,6 @@ public:
     void Update();
     void OnResize();
 
-    void SetLanguage( const Ogre::String& language );
-    void AddText( const Ogre::String& name, TiXmlNode* text );
-    void UnloadTexts();
-    TiXmlNode* GetText( const Ogre::String& name ) const;
 
     void AddFont( UiFont* font );
     UiFont* GetFont( const Ogre::String& name );
@@ -39,12 +35,6 @@ public:
     void renderQueueStarted( Ogre::uint8 queueGroupId, const Ogre::String& invocation, bool& skipThisInvocation );
 
 private:
-    struct UiText
-    {
-        Ogre::String name;
-        TiXmlNode* node;
-    };
-    std::vector< UiText > m_Texts;
     std::vector< UiFont* > m_Fonts;
     struct UiPrototype
     {

+ 87 - 15
QGearsMain/include/core/UiTextArea.h

@@ -10,20 +10,55 @@
 #include "UiFont.h"
 #include "UiWidget.h"
 
+class UiSprite;
+
+enum TextState
+{
+    TS_SHOW_TEXT,
+    TS_SCROLL_TEXT,
+    TS_PAUSE_OK,
+    TS_PAUSE_TIME,
+    TS_DONE,
+    TS_OVERFLOW,
+    TS_NEXT_PAGE,
+};
+
 
 
-struct TextStyle
+struct TextChar
 {
+    TextChar():
+        char_code( 0 ),
+        colour( Ogre::ColourValue::White ),
+        skip( false ),
+        variable( "" ),
+        variable_len( 0 ),
+        pause_ok( false ),
+        pause_time( 0.0f ),
+        next_page( false ),
+        sprite( NULL ),
+        sprite_y( 0 )
+    {
+    }
+
+    int char_code;
     Ogre::ColourValue colour;
+    bool skip;
+    Ogre::String variable;
+    unsigned int variable_len;
+    bool pause_ok;
+    float pause_time;
+    bool next_page;
+    UiSprite* sprite;
+    float sprite_y;
 };
 
 
 
-struct TextBlockData
+struct TextVariable
 {
-    float local_x1;
-    float local_y1;
-    int position;
+    Ogre::String name;
+    Ogre::UTFString value;
 };
 
 
@@ -40,6 +75,11 @@ public:
     virtual void Render();
     virtual void UpdateTransformation();
 
+    void UpdateGeometry();
+
+    void InputPressed();
+    void InputRepeated();
+
     enum TextAlign
     {
         LEFT,
@@ -47,16 +87,27 @@ public:
         CENTER
     };
     void SetTextAlign( const TextAlign align );
+    void SetPadding( const float top, const float right, const float bottom, const float left );
     void SetText( const Ogre::UTFString& text );
     void SetText( TiXmlNode* text );
+    void TextClear();
+    void RemoveSpritesFromText( const unsigned int end );
     void SetFont( const Ogre::String& font );
-    void UpdateGeometry();
-    float GetTextLengthFromNode( TiXmlNode* node ) const;
-    float GetTextLength( const Ogre::UTFString& text ) const;
-    void SetTextGeometryFromNode( TiXmlNode* node, TextBlockData& data, const TextStyle& style );
-    void SetTextGeometry( const Ogre::UTFString& text, TextBlockData& data, const TextStyle& style );
+    const UiFont* GetFont() const;
+    void SetTextPrintSpeed( const float speed );
+    void SetTextScrollTime( const float time );
+    void SetVariable( const Ogre::String& name, const Ogre::UTFString& value );
+    Ogre::UTFString GetVariable( const Ogre::String& name ) const;
+    TextState GetTextState() const;
+    float GetTextLimit() const;
+    unsigned int GetTextSize() const;
+    float GetPauseTime() const;
 
 private:
+    float GetTextWidth() const;
+    void PrepareTextFromNode( TiXmlNode* node, const Ogre::ColourValue& colour );
+    void PrepareTextFromText( const Ogre::UTFString& text, const Ogre::ColourValue& colour );
+
     UiTextArea();
     void CreateVertexBuffer();
     void DestroyVertexBuffer();
@@ -72,13 +123,34 @@ private:
 
     UiFont*                             m_Font;
     TextAlign                           m_TextAlign;
-    Ogre::UTFString                     m_Text;
-    TiXmlNode*                          m_TextNode;
-};
 
+    std::vector< TextChar >             m_Text;
+    float                               m_TextLimit;
+    float                               m_TextPrintSpeed;
+    float                               m_TextPrintSpeedMod;
+    TextState                           m_TextState;
+    std::vector< TextVariable >         m_TextVariable;
+
+    float                               m_TextScrollTime;
+    float                               m_TextYOffset;
+    float                               m_TextYOffsetTarget;
+    float                               m_PauseTime;
+    unsigned int                        m_NextPageStart;
+
+    bool                                m_NextPressed;
+    bool                                m_NextRepeated;
+
+    float                               m_PaddingTop;
+    float                               m_PaddingRight;
+    float                               m_PaddingBottom;
+    float                               m_PaddingLeft;
+
+    bool                                m_Timer;
+    int                                 m_TimerTime;
+};
 inline
 void WriteTriangleVertex(float *&writeIterator, const Ogre::Vector3 &coord,
-                const Ogre::ColourValue &colour, const float u, const float v)
+const Ogre::ColourValue &colour, const float u, const float v)
 {
     *writeIterator++ = coord.x;
     *writeIterator++ = coord.y;
@@ -93,7 +165,7 @@ void WriteTriangleVertex(float *&writeIterator, const Ogre::Vector3 &coord,
 
 inline void
 WriteGlyph(float *&writeIterator, const Ogre::Vector3 coords[],
-           const Ogre::ColourValue &colour, const Ogre::FloatRect &texture)
+const Ogre::ColourValue &colour, const Ogre::FloatRect &texture)
 {
     // draw two triangles with a colour and texture.
     WriteTriangleVertex(writeIterator, coords[0], colour, texture.left, texture.top);

+ 21 - 7
QGearsMain/include/core/UiWidget.h

@@ -30,11 +30,14 @@ public:
 
     void AddChild( UiWidget* widget );
     UiWidget* GetChild( const Ogre::String& name );
+    UiWidget* GetChild( const unsigned int id );
+    unsigned int GetNumberOfChildren();
     void RemoveAllChildren();
 
     // animation related
     void AddAnimation( UiAnimation* animation );
     const Ogre::String& GetCurrentAnimationName() const;
+    UiAnimation::State GetAnimationState() const;
     void PlayAnimation( const Ogre::String& animation, UiAnimation::State state, const float start, const float end );
     void ScriptPlayAnimation( const char* name );
     void ScriptPlayAnimationStop( const char* name );
@@ -43,6 +46,7 @@ public:
     void ScriptSetDefaultAnimation( const char* animation );
     int ScriptAnimationSync();
 
+    void SetUpdateTransformation();
     virtual void UpdateTransformation();
 
     enum Align
@@ -65,24 +69,24 @@ public:
     Ogre::Vector2 GetFinalTranslate() const;
     Ogre::Vector2 GetFinalSize() const;
     Ogre::Vector2 GetFinalScale() const;
+    Ogre::Vector4 GetFinalScissor( bool& scissor ) const;
     float GetFinalRotation() const;
 
     void SetOriginX( const float percent, const float x );
     void SetOriginY( const float percent, const float y );
     void SetX( const float percent, const float x );
+    void GetX( float& percent, float& x );
     void SetY( const float percent, const float y );
+    void GetY( float& percent, float& y );
     void SetZ( const float z );
     void SetWidth( const float percent, const float width );
+    void GetWidth( float& percent, float& width );
     void SetHeight( const float percent, const float height );
+    void GetHeight( float& percent, float& height );
     void SetScale( const Ogre::Vector2& scale );
     void SetRotation( const float degree );
-
-    void SetScissor( bool scissor );
-    int GetScissorTop() const;
-    int GetScissorBottom() const;
-    int GetScissorLeft() const;
-    int GetScissorRight() const;
-
+    void SetScissorArea( const float percent_x1, const float x1, const float percent_y1, const float y1, const float percent_x2, const float x2, const float percent_y2, const float y2 );
+    void SetGlobalScissor( const bool global );
     void SetColour( const float r, const float g, const float b );
     void SetColours( const float r1, const float g1, const float b1, const float r2, const float g2, const float b2, const float r3, const float g3, const float b3, const float r4, const float g4, const float b4 );
     void SetAlpha( const float a );
@@ -135,10 +139,20 @@ protected:
     float                    m_Rotation;
 
     bool                     m_Scissor;
+    bool                     m_LocalScissor;
+    bool                     m_GlobalScissor;
     int                      m_ScissorTop;
+    float                    m_ScissorXPercentTop;
+    float                    m_ScissorXTop;
     int                      m_ScissorBottom;
+    float                    m_ScissorXPercentBottom;
+    float                    m_ScissorXBottom;
     int                      m_ScissorLeft;
+    float                    m_ScissorYPercentLeft;
+    float                    m_ScissorYLeft;
     int                      m_ScissorRight;
+    float                    m_ScissorYPercentRight;
+    float                    m_ScissorYRight;
 
     UiAnimation*                m_AnimationCurrent;
     std::vector< ScriptId >     m_AnimationSync;

+ 23 - 0
QGearsMain/include/core/Utilites.h

@@ -1,10 +1,33 @@
 #ifndef UTILITES_H
 #define UTILITES_H
 
+#include <OgreColourValue.h>
+#include <OgreMatrix4.h>
 #include <OgreString.h>
 #include <OgreStringVector.h>
+#include <OgreVector2.h>
+#include <OgreVector3.h>
+#include <OgreVector4.h>
+#include <OgreUTFString.h>
 #include <OIS.h>
 
+#include <tinyxml/tinyxml.h>
+
+bool                      GetBool( TiXmlNode* node, const Ogre::String& tag, bool def = false );
+int                       GetInt( TiXmlNode* node, const Ogre::String& tag, int def = 0 );
+float                     GetFloat( TiXmlNode* node, const Ogre::String& tag, float def = 0.0f );
+const Ogre::String        GetString( TiXmlNode* node, const Ogre::String& tag, const Ogre::String& def = "" );
+const Ogre::UTFString     GetUTFString( TiXmlNode* node, const Ogre::String& tag, const Ogre::UTFString& def = "" );
+const Ogre::Vector2       GetVector2( TiXmlNode* node, const Ogre::String& tag, const Ogre::Vector2& def = Ogre::Vector2::ZERO );
+const Ogre::Vector3       GetVector3( TiXmlNode* node, const Ogre::String& tag, const Ogre::Vector3& def = Ogre::Vector3::ZERO );
+const Ogre::Vector4       GetVector4( TiXmlNode* node, const Ogre::String& tag, const Ogre::Vector4& def = Ogre::Vector4::ZERO );
+const Ogre::Matrix4       GetMatrix4( TiXmlNode* node, const Ogre::String& tag, const Ogre::Matrix4& def = Ogre::Matrix4::IDENTITY );
+const Ogre::Quaternion    GetQuaternion( TiXmlNode* node, const Ogre::String& tag, const Ogre::Quaternion& def = Ogre::Quaternion::IDENTITY );
+const Ogre::ColourValue   GetColourValue( TiXmlNode* node, const Ogre::String& tag, const Ogre::ColourValue& def = Ogre::ColourValue::ZERO );
+
+void                      ParsePersent( float& value_percent, float& value, const Ogre::String& string );
+float                     ParseKeyFrameTime( const float length, const Ogre::String& string );
+
 
 
 const Ogre::String

+ 0 - 1
QGearsMain/include/core/XmlScreenFile.h

@@ -14,7 +14,6 @@ public:
 
     void LoadScreen();
     void LoadScreenRecursive( TiXmlNode* node, const Ogre::String& base_name, UiWidget* widget );
-    void ParsePersent( float& value_percent, float& value, const Ogre::String& string );
 };
 
 

+ 1 - 1
QGearsMain/include/core/XmlTextFile.h

@@ -11,7 +11,7 @@ public:
     XmlTextFile( const Ogre::String& file );
     virtual ~XmlTextFile();
 
-    void LoadText();
+    void LoadTexts();
 };
 
 

+ 3 - 3
QGearsMain/include/core/XmlTextsFile.h

@@ -3,6 +3,7 @@
 
 #include "XmlFile.h"
 
+#include <OgreStringVector.h>
 
 
 class XmlTextsFile : public XmlFile
@@ -11,9 +12,8 @@ public:
     XmlTextsFile( const Ogre::String& file );
     virtual ~XmlTextsFile();
 
-    void LoadTexts( const Ogre::String& language );
+    void GetAvailableLanguages( Ogre::StringVector& languages );
+    void LoadTexts();
 };
 
-
-
 #endif // XML_TEXTS_FILE_H

+ 8 - 6
QGearsMain/src/Main.cpp

@@ -22,7 +22,8 @@
 #include "core/Timer.h"
 #include "core/UiManager.h"
 #include "core/particles/ParticleSystemManager.h"
-
+#include "core/TextManager.h"
+#include "core/DialogsManager.h"
 #include "data/QGearsLZSFLevelFileManager.h"
 #include "common/make_unique.h"
 #include <OgreFontManager.h>
@@ -89,16 +90,16 @@ main(int argc, char *argv[])
 
         // create This earlier than DisplayFrameListener cause it can fire event there
         auto camera_manager = std::make_unique<CameraManager>();
+        auto text_manager = std::make_unique<TextManager>();
 
-        auto console = std::make_unique<Console>();
-
-
-        auto entity_manager = std::make_unique<EntityManager>();
         auto ui_manager = std::make_unique<UiManager>();
+        auto dialogs_manager = std::make_unique<DialogsManager>();
+        auto entity_manager = std::make_unique<EntityManager>();
+
+        auto console = std::make_unique<Console>();
 
         auto worldMapModule = std::make_unique<QGears::WorldMapModule>();
 
-        ui_manager->SetLanguage("English");
 
         // init after game managers because it attach them to script
         auto script_manager = std::make_unique<ScriptManager>();
@@ -118,6 +119,7 @@ main(int argc, char *argv[])
 
         // init ui and run it scripts
         ui_manager->Initialise();
+    dialogs_manager->Initialise();
 
 
         // run application cycle

+ 9 - 9
QGearsMain/src/core/Console.cpp

@@ -157,7 +157,7 @@ Console::Input(const QGears::Event& event)
         SetToHide();
     }
     // history up
-    else if ((event.type == QGears::ET_KEY_PRESS || event.type == QGears::ET_KEY_REPEAT) && event.param1 == OIS::KC_UP)
+    else if ((event.type == QGears::ET_KEY_PRESS || event.type == QGears::ET_KEY_REPEAT_WAIT) && event.param1 == OIS::KC_UP)
     {
         if(m_HistoryLineCycleIndex < (int)m_History.size() - 1)
         {
@@ -166,7 +166,7 @@ Console::Input(const QGears::Event& event)
         }
     }
     // history down
-    else if ((event.type == QGears::ET_KEY_PRESS || event.type == QGears::ET_KEY_REPEAT) && event.param1 == OIS::KC_DOWN)
+    else if ((event.type == QGears::ET_KEY_PRESS || event.type == QGears::ET_KEY_REPEAT_WAIT) && event.param1 == OIS::KC_DOWN)
     {
         if(m_HistoryLineCycleIndex > 0)
         {
@@ -192,7 +192,7 @@ Console::Input(const QGears::Event& event)
 
     }
     // scroll display to previous row
-    else if ((event.type == QGears::ET_KEY_PRESS || event.type == QGears::ET_KEY_REPEAT) && event.param1 == OIS::KC_PGUP)
+    else if ((event.type == QGears::ET_KEY_PRESS || event.type == QGears::ET_KEY_REPEAT_WAIT) && event.param1 == OIS::KC_PGUP)
     {
         if(m_DisplayLine > 0)
         {
@@ -200,7 +200,7 @@ Console::Input(const QGears::Event& event)
         }
     }
     // scroll display to next row
-    else if ((event.type == QGears::ET_KEY_PRESS || event.type == QGears::ET_KEY_REPEAT) && event.param1 == OIS::KC_PGDOWN)
+    else if ((event.type == QGears::ET_KEY_PRESS || event.type == QGears::ET_KEY_REPEAT_WAIT) && event.param1 == OIS::KC_PGDOWN)
     {
         if(m_DisplayLine < m_OutputLine.size())
         {
@@ -208,7 +208,7 @@ Console::Input(const QGears::Event& event)
         }
     }
     // delete character after cursor
-    else if ((event.type == QGears::ET_KEY_PRESS || event.type == QGears::ET_KEY_REPEAT) && event.param1 == OIS::KC_DELETE)
+    else if ((event.type == QGears::ET_KEY_PRESS || event.type == QGears::ET_KEY_REPEAT_WAIT) && event.param1 == OIS::KC_DELETE)
     {
         if(m_AutoCompletition.size() > 0)
         {
@@ -223,7 +223,7 @@ Console::Input(const QGears::Event& event)
         }
     }
     // delete character before cursor
-    else if ((event.type == QGears::ET_KEY_PRESS || event.type == QGears::ET_KEY_REPEAT) && event.param1 == OIS::KC_BACK)
+    else if ((event.type == QGears::ET_KEY_PRESS || event.type == QGears::ET_KEY_REPEAT_WAIT) && event.param1 == OIS::KC_BACK)
     {
         if(m_AutoCompletition.size() > 0)
         {
@@ -239,7 +239,7 @@ Console::Input(const QGears::Event& event)
         }
     }
     // move cursor to left
-    else if ((event.type == QGears::ET_KEY_PRESS || event.type == QGears::ET_KEY_REPEAT) && event.param1 == OIS::KC_LEFT)
+    else if ((event.type == QGears::ET_KEY_PRESS || event.type == QGears::ET_KEY_REPEAT_WAIT) && event.param1 == OIS::KC_LEFT)
     {
         if(m_AutoCompletition.size() > 0)
         {
@@ -253,7 +253,7 @@ Console::Input(const QGears::Event& event)
         }
     }
     // move cursor to right
-    else if ((event.type == QGears::ET_KEY_PRESS || event.type == QGears::ET_KEY_REPEAT) && event.param1 == OIS::KC_RIGHT)
+    else if ((event.type == QGears::ET_KEY_PRESS || event.type == QGears::ET_KEY_REPEAT_WAIT) && event.param1 == OIS::KC_RIGHT)
     {
         if(m_AutoCompletition.size() > 0)
         {
@@ -295,7 +295,7 @@ Console::Input(const QGears::Event& event)
         m_CursorPosition = m_InputLine.size();
     }
     // input ascii character
-    else if ((event.type == QGears::ET_KEY_PRESS || event.type == QGears::ET_KEY_REPEAT) && m_InputLine.size() < m_LineWidth)
+    else if ((event.type == QGears::ET_KEY_PRESS || event.type == QGears::ET_KEY_REPEAT_WAIT) && m_InputLine.size() < m_LineWidth)
     {
         char legalchars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890~!@#$%^&*()-_=+?{[]}|\\;:'\"<>,./? ";
         char txt = TranslateNumpad(event);

+ 78 - 14
QGearsMain/src/core/DebugDraw.cpp

@@ -357,22 +357,86 @@ DebugDraw::Text(const float x, const float y, const Ogre::String& text)
     float current_y =  (m_ScreenSpace == true) ? -(((int) y / height) * 2 - 1) : y;
     float char_height = -(m_FontHeight / height) * 2;
 
-    for(auto &c : text)
+    for( unsigned int i = 0; i < text.size(); ++i )
     {
-        // for each character, compute the size of the glyph.
-        // create a square from 2 triangles for the glyph and
-        // set x, y, color and texture location
-        float char_width = ((m_Font->getGlyphAspectRatio(c) * m_FontHeight) / width) * 2;
-
-        Ogre::Vector3 coords[4] = {
-            Ogre::Vector3(current_x, current_y, m_Z),
-            Ogre::Vector3(current_x + char_width, current_y, m_Z),
-            Ogre::Vector3(current_x + char_width, current_y + char_height, m_Z),
-            Ogre::Vector3(current_x, current_y + char_height, m_Z),
-        };
+        float char_width = ( ( m_Font->getGlyphAspectRatio( text[ i ] ) * m_FontHeight ) / width ) * 2;
+
+        float new_x1 = current_x;
+        float new_y1 = current_y;
+
+        float new_x2 = current_x + char_width;
+        float new_y2 = current_y;
+
+        float new_x3 = current_x + char_width;
+        float new_y3 = current_y + char_height;
+
+        float new_x4 = current_x;
+        float new_y4 = current_y + char_height;
+
         current_x += char_width;
-        const Ogre::Font::UVRect& uv = m_Font->getGlyphTexCoords(c);
-        WriteGlyph(writeIterator, coords, m_Colour, m_Font->getGlyphTexCoords(c));
+
+        const Ogre::Font::UVRect& uv = m_Font->getGlyphTexCoords( text[ i ] );
+
+        *writeIterator++ = new_x1;
+        *writeIterator++ = new_y1;
+        *writeIterator++ = m_Z;
+        *writeIterator++ = m_Colour.r;
+        *writeIterator++ = m_Colour.g;
+        *writeIterator++ = m_Colour.b;
+        *writeIterator++ = m_Colour.a;
+        *writeIterator++ = uv.left;
+        *writeIterator++ = uv.top;
+
+        *writeIterator++ = new_x2;
+        *writeIterator++ = new_y2;
+        *writeIterator++ = m_Z;
+        *writeIterator++ = m_Colour.r;
+        *writeIterator++ = m_Colour.g;
+        *writeIterator++ = m_Colour.b;
+        *writeIterator++ = m_Colour.a;
+        *writeIterator++ = uv.right;
+        *writeIterator++ = uv.top;
+
+        *writeIterator++ = new_x3;
+        *writeIterator++ = new_y3;
+        *writeIterator++ = m_Z;
+        *writeIterator++ = m_Colour.r;
+        *writeIterator++ = m_Colour.g;
+        *writeIterator++ = m_Colour.b;
+        *writeIterator++ = m_Colour.a;
+        *writeIterator++ = uv.right;
+        *writeIterator++ = uv.bottom;
+
+        *writeIterator++ = new_x1;
+        *writeIterator++ = new_y1;
+        *writeIterator++ = m_Z;
+        *writeIterator++ = m_Colour.r;
+        *writeIterator++ = m_Colour.g;
+        *writeIterator++ = m_Colour.b;
+        *writeIterator++ = m_Colour.a;
+        *writeIterator++ = uv.left;
+        *writeIterator++ = uv.top;
+
+        *writeIterator++ = new_x3;
+        *writeIterator++ = new_y3;
+        *writeIterator++ = m_Z;
+        *writeIterator++ = m_Colour.r;
+        *writeIterator++ = m_Colour.g;
+        *writeIterator++ = m_Colour.b;
+        *writeIterator++ = m_Colour.a;
+        *writeIterator++ = uv.right;
+        *writeIterator++ = uv.bottom;
+
+        *writeIterator++ = new_x4;
+        *writeIterator++ = new_y4;
+        *writeIterator++ = m_Z;
+        *writeIterator++ = m_Colour.r;
+        *writeIterator++ = m_Colour.g;
+        *writeIterator++ = m_Colour.b;
+        *writeIterator++ = m_Colour.a;
+        *writeIterator++ = uv.left;
+        *writeIterator++ = uv.bottom;
+
         m_TextRenderOp.vertexData->vertexCount += 6;
     }
 

+ 525 - 0
QGearsMain/src/core/DialogsManager.cpp

@@ -0,0 +1,525 @@
+#include "core/DialogsManager.h"
+
+#include "core/ConfigVar.h"
+#include "core/DebugDraw.h"
+#include "core/Logger.h"
+#include "core/TextManager.h"
+
+
+
+template<>DialogsManager *Ogre::Singleton< DialogsManager >::msSingleton = NULL;
+
+
+
+ConfigVar cv_debug_message( "debug_message", "Draw message debug", "false" );
+
+Ogre::String message_state_string[ 5 ] = {"Closed", "Show Window", "Show Text", "Opened", "Hide Window"};
+
+
+
+DialogsManager::DialogsManager():
+    m_NextPressed( false ),
+    m_NextRepeated( false ),
+    m_UpPressed( false ),
+    m_DownPressed( false ),
+
+    m_LimitArea( NULL )
+{
+    LOG_TRIVIAL( "DialogsManager created." );
+}
+
+
+
+DialogsManager::~DialogsManager()
+{
+    for( unsigned int i = 0; i < m_Messages.size(); ++i )
+    {
+        delete m_Messages[ i ];
+    }
+
+    LOG_TRIVIAL( "DialogsManager destroyed." );
+}
+
+
+
+void
+DialogsManager::Initialise()
+{
+    UiWidget* g_widget = UiManager::getSingletonPtr()->GetWidget( "Dialog" );
+    if( g_widget == NULL )
+    {
+        LOG_ERROR( "Can't create DialogsManager because Widget \"Dialog\" not founded." );
+        return;
+    }
+    m_LimitArea = g_widget->GetChild( "LimitArea" );
+    if( m_LimitArea == NULL )
+    {
+        LOG_ERROR( "Can't create DialogsManager because Widget \"LimitArea\" not founded in Widget \"Dialog\"." );
+        return;
+    }
+
+    unsigned int num = m_LimitArea->GetNumberOfChildren();
+
+    for( unsigned int i = 0; i < num; ++i )
+    {
+        UiWidget* widget = m_LimitArea->GetChild( i );
+        UiTextArea* text_area = (UiTextArea*) widget->GetChild( "TextArea" );
+        if( text_area == NULL )
+        {
+            LOG_ERROR( "Can't create dialog \"" +widget->GetName() + "\" because because text_area with name \"TextArea\" missing." );
+            continue;
+        }
+
+        MessageData* data = new MessageData();
+        data->widget = widget;
+        data->window = widget->GetChild( "Window" );
+        data->text_area = text_area;
+        data->text_area->SetTextPrintSpeed( 256 );
+        data->text_area->SetTextScrollTime( 0.267f );
+        data->cursor = widget->GetChild( "Cursor" );
+        if( data->cursor != NULL )
+        {
+            data->cursor->GetY( data->cursor_percent_y, data->cursor_y );
+        }
+        m_Messages.push_back( data );
+    }
+
+    LOG_TRIVIAL( "DialogsManager initialized." );
+}
+
+
+
+void
+DialogsManager::Input( const QGears::Event& input )
+{
+    if ((input.type == QGears::ET_KEY_PRESS) && (input.event == "message_ok"))
+    {
+        m_NextPressed = true;
+    }
+    else if ((input.type == QGears::ET_KEY_REPEAT) && (input.event == "message_ok"))
+    {
+        m_NextRepeated = true;
+    }
+    else if ((input.type == QGears::ET_KEY_PRESS) && (input.event == "message_up"))
+    {
+        m_UpPressed = true;
+    }
+    else if ((input.type == QGears::ET_KEY_PRESS) && (input.event == "message_down"))
+    {
+        m_DownPressed = true;
+    }
+}
+
+
+
+void
+DialogsManager::Update()
+{
+    for( unsigned int i = 0; i < m_Messages.size(); ++i )
+    {
+        switch( m_Messages[ i ]->state )
+        {
+            case MS_SHOW_WINDOW:
+            {
+                if( ( m_Messages[ i ]->window == NULL ) || (m_Messages[ i ]->window->GetCurrentAnimationName() == Ogre::StringUtil::BLANK ) )
+                {
+                    m_Messages[ i ]->text_area->PlayAnimation( "Show", UiAnimation::ONCE, 0, -1 );
+                    m_Messages[ i ]->text_area->SetVisible( true );
+                    m_Messages[ i ]->state = MS_SHOW_TEXT;
+                }
+            }
+            break;
+
+            case MS_SHOW_TEXT:
+            {
+                if( AutoCloseCheck( i ) == true )
+                {
+                    break;
+                }
+
+                if( m_Messages[ i ]->clickable == true )
+                {
+                    if( m_NextPressed == true )
+                    {
+                        m_Messages[ i ]->text_area->InputPressed();
+                    }
+                    if( m_NextRepeated == true )
+                    {
+                        m_Messages[ i ]->text_area->InputRepeated();
+                    }
+                }
+
+                if( m_Messages[ i ]->text_area->GetTextState() == TS_DONE )
+                {
+                    m_Messages[ i ]->state = MS_OPENED;
+
+                    if( ( m_Messages[ i ]->cursor != NULL ) && ( m_Messages[ i ]->show_cursor == true ) )
+                    {
+                        m_Messages[ i ]->cursor->SetY( m_Messages[ i ]->cursor_percent_y, m_Messages[ i ]->cursor_y + m_Messages[ i ]->cursor_row_current * m_Messages[ i ]->text_area->GetFont()->GetHeight() );
+                        m_Messages[ i ]->cursor->SetVisible( true );
+                    }
+                }
+            }
+            break;
+
+            case MS_OPENED:
+            {
+                if( m_Messages[ i ]->clickable == true && m_NextPressed == true )
+                {
+                    m_Messages[ i ]->auto_close = true;
+
+                    if( ( m_Messages[ i ]->cursor != NULL ) && ( m_Messages[ i ]->show_cursor == true ) )
+                    {
+                        m_Messages[ i ]->show_cursor = false;
+                        m_Messages[ i ]->cursor_row_selected = m_Messages[ i ]->cursor_row_current;
+                        m_Messages[ i ]->cursor->SetVisible( false );
+                    }
+                }
+
+                if( AutoCloseCheck( i ) == true )
+                {
+                    break;
+                }
+
+                if( ( m_Messages[ i ]->cursor != NULL ) && ( m_Messages[ i ]->show_cursor == true ) && ( m_Messages[ i ]->clickable == true ) )
+                {
+                    if( m_UpPressed == true )
+                    {
+                        m_Messages[ i ]->cursor_row_current -= 1;
+                    }
+                    else if( m_DownPressed == true )
+                    {
+                        m_Messages[ i ]->cursor_row_current += 1;
+                    }
+
+                    m_Messages[ i ]->cursor_row_current = ( m_Messages[ i ]->cursor_row_current < m_Messages[ i ]->cursor_row_first ) ? m_Messages[ i ]->cursor_row_last : m_Messages[ i ]->cursor_row_current;
+                    m_Messages[ i ]->cursor_row_current = ( m_Messages[ i ]->cursor_row_current > m_Messages[ i ]->cursor_row_last ) ? m_Messages[ i ]->cursor_row_first : m_Messages[ i ]->cursor_row_current;
+
+                    m_Messages[ i ]->cursor->SetY( m_Messages[ i ]->cursor_percent_y, m_Messages[ i ]->cursor_y + m_Messages[ i ]->cursor_row_current * m_Messages[ i ]->text_area->GetFont()->GetHeight() );
+                }
+            }
+            break;
+
+            case MS_HIDE_WINDOW:
+            {
+                if( ( m_Messages[ i ]->window == NULL ) || (m_Messages[ i ]->window->GetCurrentAnimationName() == Ogre::StringUtil::BLANK ) )
+                {
+                    HideMessage( i );
+                }
+            }
+            break;
+        }
+    }
+
+
+
+    if( cv_debug_message.GetB() == true )
+    {
+        DEBUG_DRAW.SetColour( Ogre::ColourValue::White );
+        DEBUG_DRAW.SetTextAlignment( DEBUG_DRAW.LEFT );
+        DEBUG_DRAW.SetScreenSpace( true );
+        int y = 34;
+
+        for( unsigned int i = 0; i < m_Messages.size(); ++i )
+        {
+            Ogre::String caption;
+            caption += "Message " + Ogre::StringConverter::toString( i ) + ": " + message_state_string[ m_Messages[ i ]->state ];
+
+            if( m_Messages[ i ]->state == MS_SHOW_TEXT )
+            {
+                caption += " (" + Ogre::StringConverter::toString( int( m_Messages[ i ]->text_area->GetTextLimit() ) ) + "/" + Ogre::StringConverter::toString( m_Messages[ i ]->text_area->GetTextSize() );
+
+                switch( m_Messages[ i ]->text_area->GetTextState() )
+                {
+                    case TS_PAUSE_OK: caption += " pause ok"; break;
+                    case TS_PAUSE_TIME: caption += " pause time " + Ogre::StringConverter::toString( int( m_Messages[ i ]->text_area->GetPauseTime() ) ); break;
+                    case TS_OVERFLOW: caption += " overflow"; break;
+                    case TS_NEXT_PAGE: caption += " next page"; break;
+                    case TS_SCROLL_TEXT: caption += " scroll"; break;
+                }
+
+                caption += ")";
+            }
+
+            DEBUG_DRAW.Text( 10, y, caption );
+            y += 16;
+        }
+    }
+
+
+
+    m_NextPressed = false;
+    m_NextRepeated = false;
+    m_UpPressed = false;
+    m_DownPressed = false;
+}
+
+
+
+void
+DialogsManager::Clear()
+{
+    for( unsigned int i = 0; i < m_Messages.size(); ++i )
+    {
+        HideMessage( i );
+    }
+}
+
+
+
+void
+DialogsManager::ShowDialog( const char* d_name, const char* name, const int x, const int y )
+{
+    int id = GetMessageId( d_name );
+    if( id == -1 )
+    {
+        LOG_TRIVIAL( "[SCRIPT] show_dialog: dialog \"" + Ogre::String( d_name ) + "\" doesn't exist." );
+        return;
+    }
+
+    if( m_Messages[ id ]->state != MS_CLOSED )
+    {
+        LOG_TRIVIAL( "[SCRIPT] show_dialog: dialog \"" + Ogre::String( d_name ) + " already shown. Close it first." );
+        return;
+    }
+
+    float width, height;
+    TiXmlNode* text = TextManager::getSingleton().GetDialog( name, width, height );
+    if( text != NULL )
+    {
+        m_Messages[ id ]->text_area->SetText( text );
+        ShowMessage( id, x, y, width, height );
+    }
+    else
+    {
+        LOG_TRIVIAL( "[SCRIPT] show_dialog: dialog text \"" + Ogre::String( name ) + "\" doesn't exist." );
+    }
+}
+
+
+
+void
+DialogsManager::ShowText( const char* d_name, const char* text, const int x, const int y, const int width, const int height )
+{
+    int id = GetMessageId( d_name );
+    if( id == -1 )
+    {
+        LOG_TRIVIAL( "[SCRIPT] show_text: dialog \"" + Ogre::String( d_name ) + "\" doesn't exist." );
+        return;
+    }
+
+    if( m_Messages[ id ]->state != MS_CLOSED )
+    {
+        LOG_TRIVIAL( "[SCRIPT] show_dialog: dialog \"" + Ogre::String( d_name ) + " already shown. Close it first." );
+        return;
+    }
+
+    m_Messages[ id ]->text_area->SetText( text );
+    ShowMessage( id, x, y, width, height );
+}
+
+
+
+int
+DialogsManager::Sync( const char* d_name )
+{
+    int id = GetMessageId( d_name );
+    if( id == -1 )
+    {
+        LOG_TRIVIAL( "[SCRIPT] sync: dialog \"" + Ogre::String( d_name ) + "\" doesn't exist." );
+        return 1;
+    }
+
+    ScriptId script = ScriptManager::getSingleton().GetCurrentScriptId();
+    m_Messages[ id ]->sync.push_back( script );
+    return -1;
+}
+
+
+
+void
+DialogsManager::SetVariable( const char* d_name, const char* name, const char* value )
+{
+    int id = GetMessageId( d_name );
+    if( id == -1 )
+    {
+        LOG_TRIVIAL( "[SCRIPT] set_variable: dialog \"" + Ogre::String( d_name ) + "\" doesn't exist." );
+        return;
+    }
+
+    m_Messages[ id ]->text_area->SetVariable( name, value );
+}
+
+
+
+void
+DialogsManager::Hide( const char* d_name )
+{
+    int id = GetMessageId( d_name );
+    if( id == -1 )
+    {
+        LOG_TRIVIAL( "[SCRIPT] hide: dialog \"" + Ogre::String( d_name ) + "\" doesn't exist." );
+        return;
+    }
+
+    if( m_Messages[ id ]->state == MS_CLOSED )
+    {
+        LOG_TRIVIAL( "[SCRIPT ERROR] hide: dialog \"" + Ogre::String( d_name ) + "\" already closed. Open it first." );
+        return;
+    }
+
+    m_Messages[ id ]->auto_close = true;
+}
+
+
+
+void
+DialogsManager::SetClickable( const char* d_name, const bool clickable )
+{
+    int id = GetMessageId( d_name );
+    if( id == -1 )
+    {
+        LOG_TRIVIAL( "[SCRIPT] set_clickable: dialog \"" + Ogre::String( d_name ) + "\" doesn't exist." );
+        return;
+    }
+
+    m_Messages[ id ]->clickable = clickable;
+}
+
+
+
+void
+DialogsManager::SetCursor( const char* d_name, const int first_row, const int last_row )
+{
+    int id = GetMessageId( d_name );
+    if( id == -1 )
+    {
+        LOG_TRIVIAL( "[SCRIPT] set_cursor: dialog \"" + Ogre::String( d_name ) + "\" doesn't exist." );
+        return;
+    }
+
+    if( m_Messages[ id ]->state != MS_CLOSED )
+    {
+        LOG_TRIVIAL( "[SCRIPT] set_cursor: dialog \"" + Ogre::String( d_name ) + "\" already shown. Close it first." );
+        return;
+    }
+
+    m_Messages[ id ]->show_cursor = true;
+    m_Messages[ id ]->cursor_row_current = first_row;
+    m_Messages[ id ]->cursor_row_first = first_row;
+    m_Messages[ id ]->cursor_row_last = last_row;
+}
+
+
+
+int
+DialogsManager::GetCursor( const char* d_name ) const
+{
+    int id = GetMessageId( d_name );
+    if( id == -1 )
+    {
+        LOG_TRIVIAL( "[SCRIPT] get_cursor: dialog \"" + Ogre::String( d_name ) + "\" doesn't exist." );
+        return 0;
+    }
+
+    return m_Messages[ id ]->cursor_row_selected;
+}
+
+
+
+void
+DialogsManager::ShowMessage( const int id, const int x, const int y, const int width, const int height )
+{
+    // handle error when dialog wingow cross border of limit area
+    float la_percent_width, la_width;
+    m_LimitArea->GetWidth( la_percent_width, la_width );
+    float move_back_x = 0;
+    if( x + width > la_width )
+    {
+        move_back_x = x + width - la_width;
+    }
+    float la_percent_height, la_height;
+    m_LimitArea->GetWidth( la_percent_height, la_height );
+    float move_back_y = 0;
+    if( y + height > la_height )
+    {
+        move_back_y = y + height - la_height;
+    }
+
+    m_Messages[ id ]->widget->SetX( 0, x - move_back_x );
+    m_Messages[ id ]->widget->SetY( 0, y - move_back_y );
+    m_Messages[ id ]->widget->SetWidth( 0, width );
+    m_Messages[ id ]->widget->SetHeight( 0, height );
+    m_Messages[ id ]->widget->SetVisible( true );
+
+    m_Messages[ id ]->auto_close = false;
+
+    if( ( m_Messages[ id ]->window != NULL ) && ( m_Messages[ id ]->show_window == true ) )
+    {
+        m_Messages[ id ]->window->SetVisible( true );
+        m_Messages[ id ]->window->PlayAnimation( "Show", UiAnimation::ONCE, 0, -1 );
+    }
+
+    m_Messages[ id ]->state = MS_SHOW_WINDOW;
+}
+
+
+
+void
+DialogsManager::HideMessage( const int id )
+{
+    m_Messages[ id ]->auto_close = false;
+    m_Messages[ id ]->state = MS_CLOSED;
+
+    if( m_Messages[ id ]->window != NULL )
+    {
+        m_Messages[ id ]->window->SetVisible( false );
+    }
+    if( m_Messages[ id ]->cursor != NULL )
+    {
+        m_Messages[ id ]->cursor->SetVisible( false );
+    }
+    m_Messages[ id ]->text_area->SetVisible( false );
+    m_Messages[ id ]->widget->SetVisible( false );
+
+    for( unsigned int i = 0; i < m_Messages[ id ]->sync.size(); ++i )
+    {
+        ScriptManager::getSingleton().ContinueScriptExecution( m_Messages[ id ]->sync[ i ] );
+    }
+    m_Messages[ id ]->sync.clear();
+}
+
+
+
+int
+DialogsManager::GetMessageId( const char* d_name ) const
+{
+    for( unsigned int i = 0; i < m_Messages.size(); ++i )
+    {
+        if( m_Messages[ i ]->widget->GetName() == Ogre::String( d_name ) )
+        {
+            return i;
+        }
+    }
+
+    return -1;
+}
+
+
+
+bool
+DialogsManager::AutoCloseCheck( const unsigned int id )
+{
+    if( m_Messages[ id ]->auto_close == true )
+    {
+        m_Messages[ id ]->text_area->PlayAnimation( "Hide", UiAnimation::ONCE, 0, -1 );
+        if( m_Messages[ id ]->window != NULL )
+        {
+            m_Messages[ id ]->window->PlayAnimation( "Hide", UiAnimation::ONCE, 0, -1 );
+        }
+        m_Messages[ id ]->state = MS_HIDE_WINDOW;
+        return true;
+    }
+
+    return false;
+}

+ 98 - 8
QGearsMain/src/core/EntityManager.cpp

@@ -10,6 +10,7 @@
 #include "core/Logger.h"
 #include "core/ScriptManager.h"
 #include "core/Timer.h"
+#include "core/DialogsManager.h"
 
 
 template<>EntityManager *Ogre::Singleton<EntityManager>::msSingleton = nullptr;
@@ -76,7 +77,8 @@ EntityManager::EntityManager():
     m_PlayerEntity(nullptr),
     m_PlayerMove(Ogre::Vector3::ZERO),
     m_PlayerMoveRotation(0),
-    m_PlayerLock(false)
+    m_PlayerLock( false ),
+    m_PlayerRun( false )
 {
     LOG_TRIVIAL("EntityManager created.");
 
@@ -118,27 +120,48 @@ EntityManager::Input(const QGears::Event& event)
         return;
     }
 
-    if(m_PlayerEntity != nullptr && m_PlayerLock == false)
+    if( m_PlayerEntity != NULL && m_PlayerLock == false )
     {
-        if ((event.type == QGears::ET_KEY_IMPULSE) && (event.param1 == OIS::KC_LEFT))
+        if ((event.type == QGears::ET_KEY_REPEAT) && (event.event == "walk_left"))
         {
             m_PlayerMove.x = -1;
         }
-        else if ((event.type == QGears::ET_KEY_IMPULSE) && (event.param1 == OIS::KC_RIGHT))
+        else if ((event.type == QGears::ET_KEY_REPEAT) && (event.event == "walk_right"))
         {
             m_PlayerMove.x = 1;
         }
 
-        if ((event.type == QGears::ET_KEY_IMPULSE) && (event.param1 == OIS::KC_DOWN))
+        if ((event.type == QGears::ET_KEY_REPEAT) && (event.event == "walk_down"))
         {
             m_PlayerMove.y = -1;
         }
-
-        if ((event.type == QGears::ET_KEY_IMPULSE) && (event.param1 == OIS::KC_UP))
+        else if ((event.type == QGears::ET_KEY_REPEAT) && (event.event == "walk_up"))
         {
             m_PlayerMove.y = 1;
         }
 
+        if ((event.type == QGears::ET_KEY_REPEAT) && (event.event == "run"))
+        {
+            m_PlayerRun = true;
+        }
+
+        if ((event.type == QGears::ET_KEY_PRESS) && (event.event == "interact"))
+        {
+            CheckEntityInteract();
+
+            for( unsigned int i = 0; i < m_EntityTriggers.size(); ++i )
+            {
+                if( m_EntityTriggers[ i ]->IsEnabled() == true && m_EntityTriggers[ i ]->IsActivator( m_PlayerEntity ) == true )
+                {
+                    ScriptEntity* scr_entity = ScriptManager::getSingleton().GetScriptEntityByName( ScriptManager::ENTITY, m_EntityTriggers[ i ]->GetName() );
+                    bool added = ScriptManager::getSingleton().ScriptRequest( scr_entity, "on_interact", 1, "", "", false, false );
+                    if( added == false )
+                    {
+                        LOG_WARNING( "Script \"on_interact\" for entity \"" +  m_EntityTriggers[ i ]->GetName() + "\" doesn't exist." );
+                    }
+                }
+            }
+        }
         //rotate move vector to field move rotation
         Ogre::Quaternion q1;
         q1.FromAngleAxis(m_PlayerMoveRotation, Ogre::Vector3::UNIT_Z);
@@ -234,7 +257,7 @@ EntityManager::Update()
                     {
                         speed = m_Entity[i]->GetMoveWalkSpeed();
 
-                        if(InputManager::getSingleton().IsButtonPressed(OIS::KC_LCONTROL) == true)
+                        if( m_PlayerRun == true )
                         {
                             speed *= 4;
                         }
@@ -293,6 +316,7 @@ EntityManager::Update()
 
     // reset player move. It already must be handled in update
     m_PlayerMove = Ogre::Vector3::ZERO;
+    m_PlayerRun = false;
 
     if(m_Background2D.GetScrollType() != Background2D::NONE)
     {
@@ -340,6 +364,7 @@ EntityManager::Clear()
 {
     m_Walkmesh.Clear();
     m_Background2D.Clear();
+    DialogsManager::getSingleton().Clear();
 
     for(unsigned int i = 0; i < m_Entity.size(); ++i)
     {
@@ -1105,6 +1130,71 @@ EntityManager::CheckTriggers(Entity* entity, Ogre::Vector3& position)
 }
 
 
+
+void
+EntityManager::CheckEntityInteract()
+{
+    if( m_PlayerEntity == NULL || m_PlayerLock == true || m_PlayerEntity->IsSolid() == false )
+    {
+        return;
+    }
+
+    Ogre::Degree angle_pc = m_PlayerEntity->GetRotation();
+    Entity* entity_to_interact = NULL;
+    Ogre::Degree less_angle( 90 );
+
+    for( unsigned int i = 0; i < m_Entity.size(); ++i )
+    {
+        if( m_Entity[ i ]->IsTalkable() == false )
+        {
+            continue;
+        }
+
+        if( m_Entity[ i ] == m_PlayerEntity )
+        {
+            continue;
+        }
+
+        Ogre::Vector3 pos1 =  m_Entity[ i ]->GetPosition();
+        float interact_range =  m_Entity[ i ]->GetTalkRadius();
+        Ogre::Vector3 pos2 = m_PlayerEntity->GetPosition();
+        float solid_range = m_PlayerEntity->GetSolidRadius();
+
+        int height = ( pos1.z < pos2.z ) ?  m_Entity[ i ]->GetHeight() : m_PlayerEntity->GetHeight();
+
+        if( ( ( pos1.z - pos2.z + height ) < ( height * 2 ) ) && ( ( pos1.z - pos2.z + height ) >= 0 ) )
+        {
+            interact_range = ( interact_range + solid_range ) * ( interact_range + solid_range );
+            float distance = ( pos1.x - pos2.x ) * ( pos1.x - pos2.x ) + ( pos1.y - pos2.y ) * ( pos1.y - pos2.y );
+
+            if( distance < interact_range + solid_range )
+            {
+                Ogre::Degree angle_to_model = GetDirectionToPoint( pos2, pos1 );
+                Ogre::Degree angle = angle_pc - angle_to_model;
+                angle = ( angle < Ogre::Degree( 0 ) ) ? -angle : angle;
+                angle = ( angle >= Ogre::Degree( 180 ) ) ? Ogre::Degree( 360 ) - angle : angle;
+
+                if( angle < less_angle )
+                {
+                    angle = less_angle;
+                    entity_to_interact = m_Entity[ i ];
+                }
+            }
+        }
+    }
+
+    if( entity_to_interact != NULL )
+    {
+        Ogre::String name = entity_to_interact->GetName();
+        ScriptEntity* scr_entity = ScriptManager::getSingleton().GetScriptEntityByName( ScriptManager::ENTITY, name );
+        bool added = ScriptManager::getSingleton().ScriptRequest( scr_entity, "on_interact", 1, "", "", false, false );
+        if( added == false )
+        {
+            LOG_WARNING( "Script \"on_interact\" for entity \"" +  name + "\" doesn't exist." );
+        }
+    }
+}
+
 void
 EntityManager::SetNextOffsetStep(Entity* entity)
 {

+ 3 - 0
QGearsMain/src/core/GameFrameListner.cpp

@@ -12,6 +12,7 @@
 #include "core/ScriptManager.h"
 #include "core/Timer.h"
 #include "core/UiManager.h"
+#include "core/DialogsManager.h"
 
 
 ConfigVar cv_debug_fps("debug_fps", "Debug FPS", "false");
@@ -103,6 +104,7 @@ GameFrameListener::frameStarted(const Ogre::FrameEvent& evt)
         if(console_active != true)
         {
             EntityManager::getSingleton().Input(input_event_array[ i ]);
+            DialogsManager::getSingleton().Input( input_event_array[ i ] );
             ScriptManager::getSingleton().Input(input_event_array[ i ]);
             CameraManager::getSingleton().Input(input_event_array[ i ], evt.timeSinceLastFrame);
         }
@@ -114,6 +116,7 @@ GameFrameListener::frameStarted(const Ogre::FrameEvent& evt)
     UiManager::getSingleton().Update();
     CameraManager::getSingleton().Update();
     EntityManager::getSingleton().Update();
+    DialogsManager::getSingleton().Update();
 
     return true;
 }

+ 155 - 50
QGearsMain/src/core/InputManager.cpp

@@ -37,57 +37,92 @@ InputManager::Reset()
 void
 InputManager::ButtonPressed(int button, char text, bool down)
 {
-    if(m_ButtonState[button] != down)
+    if( m_ButtonState[ button ] != down )
     {
-        m_ButtonState[button] = down;
-        m_ButtonText[button] = text;
+        m_ButtonState[ button ] = down;
+        m_ButtonText[ button ] = text;
 
-        m_EventQueue.push_back(QGears::Event((down == true) ? QGears::ET_KEY_PRESS : QGears::ET_KEY_RELEASE, static_cast<float>(button), static_cast<float>(text)));
+        QGears::Event event;
+        event.type = (down == true) ? QGears::ET_KEY_PRESS : QGears::ET_KEY_RELEASE;
+        event.param1 = button;
+        event.param2 = text;
+        m_EventQueue.push_back( event );
 
         m_RepeatFirstWait = true;
         m_RepeatTimer = 0;
     }
 
-    if(down == true && Console::getSingleton().IsVisible() != true)
+    if( Console::getSingleton().IsVisible() != true )
     {
-        ActivateBinds(button);
+        if( down == true )
+        {
+            ActivateBinds( button );
+            AddGameEvents(button, QGears::ET_KEY_PRESS);
+        }
+        else
+        {
+            AddGameEvents(button, QGears::ET_KEY_RELEASE);
+        }
     }
 }
 
 
+
 void
-InputManager::MousePressed(int button, bool down)
+InputManager::MousePressed( int button, bool down )
 {
-    m_EventQueue.push_back(QGears::Event((down == true) ? QGears::ET_MOUSE_PRESS : QGears::ET_MOUSE_RELEASE, static_cast<float>(button), 0.0f));
+    QGears::Event event;
+    event.type = (down == true) ? QGears::ET_KEY_PRESS : QGears::ET_KEY_RELEASE;
+    event.param1 = button;
+    m_EventQueue.push_back( event );
 }
 
 
+
 void
-InputManager::MouseMoved(int x, int y)
+InputManager::MouseMoved( int x, int y )
 {
-    m_EventQueue.push_back(QGears::Event(QGears::ET_MOUSE_MOVE, static_cast<float>(x), static_cast<float>(y)));
+    QGears::Event event;
+    event.type = QGears::ET_MOUSE_MOVE;
+    event.param1 = x;
+    event.param2 = y;
+    m_EventQueue.push_back( event );
 }
 
 
+
 void
-InputManager::MouseScrolled(int value)
+InputManager::MouseScrolled( int value )
 {
-    m_EventQueue.push_back(QGears::Event(QGears::ET_MOUSE_SCROLL, static_cast<float>(value), 0.0f));
+    QGears::Event event;
+    event.type = QGears::ET_MOUSE_SCROLL;
+    event.param1 = value;
+    m_EventQueue.push_back( event );
 }
 
 
+
 void
 InputManager::Update()
 {
     m_RepeatTimer += Timer::getSingleton().GetSystemTimeDelta();
 
-    if((m_RepeatFirstWait == true && m_RepeatTimer >= 0.5) || (m_RepeatFirstWait == false && m_RepeatTimer >= 0.05))
+    if( ( m_RepeatFirstWait == true && m_RepeatTimer >= 0.5 ) || ( m_RepeatFirstWait == false && m_RepeatTimer >= 0.05 ) )
     {
-        for(int button = 0; button < 256; ++button)
+        for( int button = 0; button < 256; ++button )
         {
-            if(m_ButtonState[button] == true)
+            if( m_ButtonState[ button ] == true )
             {
-                m_EventQueue.push_back(QGears::Event(QGears::ET_KEY_REPEAT, static_cast<float>(button), static_cast<float>(m_ButtonText[button])));
+                QGears::Event event;
+                event.type = QGears::ET_KEY_REPEAT_WAIT;
+                event.param1 = button;
+                event.param2 = m_ButtonText[ button ];
+                m_EventQueue.push_back( event );
+
+                if( Console::getSingleton().IsVisible() != true )
+                {
+                    AddGameEvents(button, QGears::ET_KEY_REPEAT_WAIT);
+                }
             }
         }
 
@@ -95,96 +130,166 @@ InputManager::Update()
         m_RepeatTimer = 0;
     }
 
-    // send impulses
-    for(int button = 0; button < 256; ++button)
+    for( int button = 0; button < 256; ++button )
     {
-        if(m_ButtonState[button] == true)
+        if( m_ButtonState[ button ] == true )
         {
-            m_EventQueue.push_back(QGears::Event(QGears::ET_KEY_IMPULSE, static_cast<float>(button), static_cast<float>(m_ButtonText[button])));
+            QGears::Event event;
+            event.type = QGears::ET_KEY_REPEAT;
+            event.param1 = button;
+            event.param2 = m_ButtonText[ button ];
+            m_EventQueue.push_back( event );
+
+            if( Console::getSingleton().IsVisible() != true )
+            {
+                AddGameEvents(button, QGears::ET_KEY_REPEAT);
+            }
         }
     }
 }
 
 
+
 bool
-InputManager::IsButtonPressed(int button) const
+InputManager::IsButtonPressed( int button ) const
 {
-    return m_ButtonState[button];
+    return m_ButtonState[ button ];
 }
 
 
+
 void
-InputManager::GetInputEvents(InputEventArray& input_events)
+InputManager::GetInputEvents( InputEventArray& input_events )
 {
     input_events = m_EventQueue;
-
     m_EventQueue.clear();
 }
 
 
+
 void
-InputManager::BindCommand(const Ogre::String& cmd, const ButtonList& buttons)
+InputManager::BindCommand( ConfigCmd* cmd, const Ogre::StringVector& params, const ButtonList& buttons )
 {
-    BindInfo info = BindInfo(cmd, buttons);
-    m_Binds.push_back(info);
+    BindInfo info;
+    info.cmd = cmd;
+    info.params = params;
+    info.buttons = buttons;
+    m_Binds.push_back( info );
 }
 
 
+
+void
+InputManager::BindGameEvent( const Ogre::String& event, const ButtonList& buttons )
+{
+    BindGameEventInfo info;
+    info.event = event;
+    info.buttons = buttons;
+    m_BindGameEvents.push_back( info );
+}
+
+
+
 void
-InputManager::ActivateBinds(int button)
+InputManager::ActivateBinds( const int button )
 {
     std::vector< int > binds_indexes;
-    for(size_t i = 0; i < m_Binds.size(); ++i)
+    for( unsigned int i = 0; i < m_Binds.size(); ++i )
     {
         // if we found pressed button in this bind
-        if(std::find(m_Binds[i].key_set.begin(), m_Binds[i].key_set.end(), button) != m_Binds[i].key_set.end())
+        if( std::find( m_Binds[ i ].buttons.begin(), m_Binds[ i ].buttons.end(), button ) != m_Binds[ i ].buttons.end() )
         {
-            size_t j = 0;
-            for(; j < m_Binds[i].key_set.size(); ++j)
+            unsigned int j = 0;
+            for( ; j < m_Binds[ i ].buttons.size(); ++j )
             {
-                if(IsButtonPressed(m_Binds[i].key_set[j]) == false)
+                if( IsButtonPressed( m_Binds[ i ].buttons[ j ] ) == false )
                 {
                     break;
                 }
             }
 
-            if(j >= m_Binds[i].key_set.size())
+            if( j >= m_Binds[ i ].buttons.size() )
             {
-                binds_indexes.push_back(i);
+                binds_indexes.push_back( i );
             }
         }
     }
 
     std::vector< int > binds_to_activate;
-    size_t max_size = 0;
-    for(size_t i = 0; i < binds_indexes.size(); ++i)
+    unsigned int max_size = 0;
+    for( unsigned int i = 0; i < binds_indexes.size(); ++i )
     {
-        if(max_size < m_Binds[binds_indexes[i]].key_set.size())
+        if( max_size < m_Binds[ binds_indexes[ i ] ].buttons.size() )
         {
-            max_size = m_Binds[binds_indexes[i]].key_set.size();
+            max_size = m_Binds[ binds_indexes[ i ] ].buttons.size();
 
             binds_to_activate.clear();
-            binds_to_activate.push_back(binds_indexes[i]);
+            binds_to_activate.push_back( binds_indexes[ i ] );
         }
-        else if(max_size == m_Binds[binds_indexes[i]].key_set.size())
+        else if( max_size == m_Binds[ binds_indexes[ i ] ].buttons.size() )
         {
-            binds_to_activate.push_back(binds_indexes[i]);
+            binds_to_activate.push_back( binds_indexes[ i ] );
         }
     }
 
-    for(size_t i = 0; i < binds_to_activate.size(); ++i)
+    for( unsigned int i = 0; i < binds_to_activate.size(); ++i )
     {
-        Ogre::StringVector params = StringTokenise(m_Binds[binds_to_activate[i]].cmd);
+         m_Binds[ binds_to_activate[ i ] ].cmd->GetHandler()( m_Binds[ binds_to_activate[ i ] ].params );
+    }
+}
+
+
 
-        // handle command
-        ConfigCmd* cmd = ConfigCmdManager::getSingleton().Find(params[0]);
-        if(cmd != nullptr)
+void
+InputManager::AddGameEvents(const int button, const QGears::EventType type)
+{
+    std::vector< int > binds_indexes;
+    for( unsigned int i = 0; i < m_BindGameEvents.size(); ++i )
+    {
+        // if we found button in this bind
+        if( std::find( m_BindGameEvents[ i ].buttons.begin(), m_BindGameEvents[ i ].buttons.end(), button ) != m_BindGameEvents[ i ].buttons.end() )
         {
-            cmd->GetHandler()(params);
+            unsigned int j = 0;
+            for( ; j < m_BindGameEvents[ i ].buttons.size(); ++j )
+            {
+                if( m_BindGameEvents[ i ].buttons[ j ] != button )
+                {
+                    if( IsButtonPressed( m_BindGameEvents[ i ].buttons[ j ] ) == false )
+                    {
+                        break;
+                    }
+                }
+            }
+
+            if( j >= m_BindGameEvents[ i ].buttons.size() )
+            {
+                binds_indexes.push_back( i );
+            }
         }
-        else
+    }
+
+    std::vector< int > binds_to_activate;
+    unsigned int max_size = 0;
+    for( unsigned int i = 0; i < binds_indexes.size(); ++i )
+    {
+        if( max_size < m_BindGameEvents[ binds_indexes[ i ] ].buttons.size() )
         {
-            LOG_ERROR("Can't find command \"" + params[0] + "\" in bind command \"" + m_Binds[i].cmd + "\".");
+            max_size = m_BindGameEvents[ binds_indexes[ i ] ].buttons.size();
+
+            binds_to_activate.clear();
+            binds_to_activate.push_back( binds_indexes[ i ] );
+        }
+        else if( max_size == m_BindGameEvents[ binds_indexes[ i ] ].buttons.size() )
+        {
+            binds_to_activate.push_back( binds_indexes[ i ] );
         }
     }
+
+    for( unsigned int i = 0; i < binds_to_activate.size(); ++i )
+    {
+        QGears::Event event;
+        event.type = type;
+        event.event = m_BindGameEvents[ binds_to_activate[ i ] ].event;
+        m_EventQueue.push_back( event );
+    }
 }

+ 2 - 2
QGearsMain/src/core/ScriptManager.cpp

@@ -57,7 +57,7 @@ ScriptManager::~ScriptManager()
 void
 ScriptManager::Input(const QGears::Event& event)
 {
-    if ((event.type == QGears::ET_KEY_PRESS || event.type == QGears::ET_KEY_REPEAT) &&
+    if ((event.type == QGears::ET_KEY_PRESS || event.type == QGears::ET_KEY_REPEAT_WAIT) &&
                                       (
                                         event.param1 == OIS::KC_RETURN ||
                                         event.param1 == OIS::KC_ESCAPE ||
@@ -76,7 +76,7 @@ ScriptManager::Input(const QGears::Event& event)
             {
                 argument2 = "Press";
             }
-            else if (event.type == QGears::ET_KEY_REPEAT)
+            else if (event.type == QGears::ET_KEY_REPEAT_WAIT)
             {
                 argument2 = "Repeat";
             }

+ 121 - 0
QGearsMain/src/core/TextManager.cpp

@@ -0,0 +1,121 @@
+#include "core\TextManager.h"
+#include "core\TextManagerCommands.h"
+#include "core\XmlTextsFile.h"
+
+
+
+template<>TextManager* Ogre::Singleton< TextManager >::msSingleton = NULL;
+
+
+
+TextManager::TextManager():
+    m_Language( "" )
+{
+    InitCmd();
+}
+
+
+
+TextManager::~TextManager()
+{
+    UnloadTexts();
+}
+
+
+
+void
+TextManager::SetLanguage( const Ogre::String& language )
+{
+    m_Language = language;
+
+    UnloadTexts();
+
+    XmlTextsFile texts( "./data/texts.xml" );
+    texts.LoadTexts();
+}
+
+
+
+const Ogre::String&
+TextManager::GetLanguage()
+{
+    return m_Language;
+}
+
+
+
+void
+TextManager::AddText( const Ogre::String& name, TiXmlNode* node )
+{
+    Text text;
+    text.name = name;
+    text.node = node;
+    m_Texts.push_back( text );
+}
+
+
+
+void
+TextManager::AddDialog( const Ogre::String& name, TiXmlNode* node, const float width, const float height )
+{
+    Dialog dialog;
+    dialog.name = name;
+    dialog.node = node;
+    dialog.width = width;
+    dialog.height = height;
+    m_Dialogs.push_back( dialog );
+}
+
+
+
+TiXmlNode*
+TextManager::GetText( const Ogre::String& name ) const
+{
+    for( unsigned int i = 0; i < m_Texts.size(); ++i )
+    {
+        if( m_Texts[ i ].name == name )
+        {
+            return m_Texts[ i ].node;
+        }
+    }
+
+    LOG_WARNING( "Can't find text \"" + name + "\"." );
+
+    return NULL;
+}
+
+
+
+TiXmlNode*
+TextManager::GetDialog( const Ogre::String& name, float &width, float& height ) const
+{
+    for( unsigned int i = 0; i < m_Dialogs.size(); ++i )
+    {
+        if( m_Dialogs[ i ].name == name )
+        {
+            width = m_Dialogs[ i ].width;
+            height = m_Dialogs[ i ].height;
+            return m_Dialogs[ i ].node;
+        }
+    }
+
+    return NULL;
+}
+
+
+
+void
+TextManager::UnloadTexts()
+{
+    for( unsigned int i = 0; i < m_Texts.size(); ++i )
+    {
+        delete m_Texts[ i ].node;
+    }
+    m_Texts.clear();
+
+    for( unsigned int i = 0; i < m_Dialogs.size(); ++i )
+    {
+        delete m_Dialogs[ i ].node;
+    }
+    m_Dialogs.clear();
+}

+ 28 - 2
QGearsMain/src/core/Timer.cpp

@@ -10,7 +10,8 @@ Timer::Timer():
     m_SystemTimeTotal(0),
     m_SystemTimeDelta(0),
     m_GameTimeTotal(0),
-    m_GameTimeDelta(0)
+    m_GameTimeDelta( 0 ),
+    m_GameTimer( 0 )
 {
 }
 
@@ -44,11 +45,36 @@ Timer::GetGameTimeDelta()
 
 
 void
-Timer::AddTime(float time)
+Timer::AddTime( const float time )
 {
     m_SystemTimeDelta = time;
     m_SystemTimeTotal += m_SystemTimeDelta;
 
     m_GameTimeDelta = time * cv_timer_scale_game.GetF();
     m_GameTimeTotal += m_GameTimeDelta;
+
+    if( m_GameTimer > 0 )
+    {
+        m_GameTimer -= time;
+        if( m_GameTimer < 0 )
+        {
+            m_GameTimer = 0;
+        }
+    }
+}
+
+
+
+void
+Timer::SetGameTimer( const float timer )
+{
+    m_GameTimer = timer;
+}
+
+
+
+int
+Timer::GetGameTimer() const
+{
+    return (int) m_GameTimer;
 }

+ 158 - 173
QGearsMain/src/core/UiAnimation.cpp

@@ -27,189 +27,60 @@ UiAnimation::AddTime(const float time)
         m_Time = m_Length;
     }
 
-    // update all
-    if(m_Scale.size() > 0)
-    {
-        Ogre::Vector2 min_value = m_Scale[0].value;
-        Ogre::Vector2 max_value = min_value;
-        float min = 0;
-        float max = m_Length;
-
-        for(size_t i = 0; i < m_Scale.size(); ++i)
-        {
-            if(m_Scale[i].time < m_Time && m_Scale[i].time > min)
-            {
-                min_value = m_Scale[i].value;
-                min = m_Scale[i].time;
-            }
-
-            if(m_Scale[i].time >= m_Time && m_Scale[i].time <= max)
-            {
-                max_value = m_Scale[i].value;
-                max = m_Scale[i].time;
-            }
-        }
 
-        Ogre::Vector2 value;
-
-        if(m_Time == 0)
-        {
-            value = min_value;
-        }
-        else
-        {
-            value = min_value + (max_value - min_value) * ((m_Time - min) / (max - min));
-        }
 
-        m_Widget->SetScale(value);
+    if( m_Scale.size() > 0 )
+    {
+        m_Widget->SetScale( KeyFrameGetValue( m_Scale ) );
     }
 
-    if(m_X.size() > 0)
+    if( m_X.size() > 0 )
     {
-        Ogre::Vector2 min_value = m_X[0].value;
-        Ogre::Vector2 max_value = min_value;
-        float min = 0;
-        float max = m_Length;
-
-        for(size_t i = 0; i < m_X.size(); ++i)
-        {
-            if(m_X[i].time < m_Time && m_X[i].time > min)
-            {
-                min_value = m_X[i].value;
-                min = m_X[i].time;
-            }
-
-            if(m_X[i].time >= m_Time && m_X[i].time <= max)
-            {
-                max_value = m_X[i].value;
-                max = m_X[i].time;
-            }
-        }
-
-        Ogre::Vector2 value;
-
-        if(m_Time == 0)
-        {
-            value = min_value;
-        }
-        else
-        {
-            value = min_value + (max_value - min_value) * ((m_Time - min) / (max - min));
-        }
-
-        m_Widget->SetX(value.x, value.y);
+        Ogre::Vector2 value = KeyFrameGetValue( m_X );
+        m_Widget->SetX( value.x, value.y );
     }
 
-    if(m_Y.size() > 0)
+    if( m_Y.size() > 0 )
     {
-        Ogre::Vector2 min_value = m_Y[0].value;
-        Ogre::Vector2 max_value = min_value;
-        float min = 0;
-        float max = m_Length;
-
-        for(size_t i = 0; i < m_Y.size(); ++i)
-        {
-            if(m_Y[i].time < m_Time && m_Y[i].time > min)
-            {
-                min_value = m_Y[i].value;
-                min = m_Y[i].time;
-            }
-
-            if(m_Y[i].time >= m_Time && m_Y[i].time <= max)
-            {
-                max_value = m_Y[i].value;
-                max = m_Y[i].time;
-            }
-        }
-
-        Ogre::Vector2 value;
-
-        if(m_Time == 0)
-        {
-            value = min_value;
-        }
-        else
-        {
-            value = min_value + (max_value - min_value) * ((m_Time - min) / (max - min));
-        }
-
-        m_Widget->SetY(value.x, value.y);
+        Ogre::Vector2 value = KeyFrameGetValue( m_Y );
+        m_Widget->SetY( value.x, value.y );
     }
 
-    if(m_Rotation.size() > 0)
+    if( m_Width.size() > 0 )
     {
-        float min_value = m_Rotation[0].value;
-        float max_value = min_value;
-        float min = 0;
-        float max = m_Length;
-
-        for(size_t i = 0; i < m_Rotation.size(); ++i)
-        {
-            if(m_Rotation[i].time < m_Time && m_Rotation[i].time > min)
-            {
-                min_value = m_Rotation[i].value;
-                min = m_Rotation[i].time;
-            }
-
-            if(m_Rotation[i].time >= m_Time && m_Rotation[i].time <= max)
-            {
-                max_value = m_Rotation[i].value;
-                max = m_Rotation[i].time;
-            }
-        }
-
-        float value;
-
-        if(m_Time == 0)
-        {
-            value = min_value;
-        }
-        else
-        {
-            value = min_value + (max_value - min_value) * ((m_Time - min) / (max - min));
-        }
-
-        m_Widget->SetRotation(value);
+        Ogre::Vector2 value = KeyFrameGetValue( m_Width );
+        m_Widget->SetWidth( value.x, value.y );
     }
 
-    if(m_Alpha.size() > 0)
+    if( m_Height.size() > 0 )
     {
-        float min_value = m_Alpha[0].value;
-        float max_value = min_value;
-        float min = 0;
-        float max = m_Length;
+        Ogre::Vector2 value = KeyFrameGetValue( m_Height );
+        m_Widget->SetHeight( value.x, value.y );
+    }
 
-        for(size_t i = 0; i < m_Alpha.size(); ++i)
-        {
-            if(m_Alpha[i].time < m_Time && m_Alpha[i].time > min)
-            {
-                min_value = m_Alpha[i].value;
-                min = m_Alpha[i].time;
-            }
-
-            if(m_Alpha[i].time >= m_Time && m_Alpha[i].time <= max)
-            {
-                max_value = m_Alpha[i].value;
-                max = m_Alpha[i].time;
-            }
-        }
+    if( m_Rotation.size() > 0 )
+    {
+        m_Widget->SetRotation( KeyFrameGetValue( m_Rotation ) );
+    }
 
-        float value;
+    if( m_Alpha.size() > 0 )
+    {
+        m_Widget->SetAlpha( KeyFrameGetValue( m_Alpha ) );
+    }
 
-        if(m_Time == 0)
-        {
-            value = min_value;
-        }
-        else
-        {
-            value = min_value + (max_value - min_value) * ((m_Time - min) / (max - min));
-        }
+    if( m_ScissorXTop.size() > 0 )
+    {
+        Ogre::Vector2 value1 =  KeyFrameGetValue( m_ScissorXTop );
+        Ogre::Vector2 value2 =  KeyFrameGetValue( m_ScissorYLeft );
+        Ogre::Vector2 value3 =  KeyFrameGetValue( m_ScissorXBottom );
+        Ogre::Vector2 value4 =  KeyFrameGetValue( m_ScissorYRight );
 
-        m_Widget->SetAlpha(value);
+        m_Widget->SetScissorArea( value1.x, value1.y, value2.x, value2.y, value3.x, value3.y, value4.x, value4.y );
     }
 }
 
 
+
 const Ogre::String&
 UiAnimation::GetName() const
 {
@@ -217,13 +88,15 @@ UiAnimation::GetName() const
 }
 
 
+
 void
-UiAnimation::SetTime(const float time)
+UiAnimation::SetTime( const float time )
 {
     m_Time = time;
 }
 
 
+
 float
 UiAnimation::GetTime() const
 {
@@ -231,13 +104,15 @@ UiAnimation::GetTime() const
 }
 
 
+
 void
-UiAnimation::SetLength(const float time)
+UiAnimation::SetLength( const float time )
 {
     m_Length = time;
 }
 
 
+
 float
 UiAnimation::GetLength() const
 {
@@ -245,36 +120,146 @@ UiAnimation::GetLength() const
 }
 
 
+
 void
-UiAnimation::AddScaleKeyFrame(const UiKeyFrameVector2& key_frame)
+UiAnimation::AddScaleKeyFrame( const UiKeyFrameVector2& key_frame )
 {
-    m_Scale.push_back(key_frame);
+    m_Scale.push_back( key_frame );
 }
 
 
+
 void
-UiAnimation::AddXKeyFrame(const UiKeyFrameVector2& key_frame)
+UiAnimation::AddXKeyFrame( const UiKeyFrameVector2& key_frame )
 {
-    m_X.push_back(key_frame);
+    m_X.push_back( key_frame );
 }
 
 
+
 void
-UiAnimation::AddYKeyFrame(const UiKeyFrameVector2& key_frame)
+UiAnimation::AddYKeyFrame( const UiKeyFrameVector2& key_frame )
 {
-    m_Y.push_back(key_frame);
+    m_Y.push_back( key_frame );
 }
 
 
+
 void
-UiAnimation::AddRotationKeyFrame(const UiKeyFrameFloat& key_frame)
+UiAnimation::AddWidthKeyFrame( const UiKeyFrameVector2& key_frame )
 {
-    m_Rotation.push_back(key_frame);
+    m_Width.push_back( key_frame );
 }
 
 
+
+void
+UiAnimation::AddHeightKeyFrame( const UiKeyFrameVector2& key_frame )
+{
+    m_Height.push_back( key_frame );
+}
+
+
+
+void
+UiAnimation::AddRotationKeyFrame( const UiKeyFrameFloat& key_frame )
+{
+    m_Rotation.push_back( key_frame );
+}
+
+
+
+void
+UiAnimation::AddAlphaKeyFrame( const UiKeyFrameFloat& key_frame )
+{
+    m_Alpha.push_back( key_frame );
+}
+
+
+
 void
-UiAnimation::AddAlphaKeyFrame(const UiKeyFrameFloat& key_frame)
+UiAnimation::AddScissorKeyFrame( const UiKeyFrameVector2& x1, const UiKeyFrameVector2& y1, const UiKeyFrameVector2& x2, const UiKeyFrameVector2& y2 )
+{
+    m_ScissorXTop.push_back( x1 );
+    m_ScissorYLeft.push_back( y1 );
+    m_ScissorXBottom.push_back( x2 );
+    m_ScissorYRight.push_back( y2 );
+}
+
+
+
+float
+UiAnimation::KeyFrameGetValue( std::vector< UiKeyFrameFloat >& data )
+{
+    float min_value = data[ 0 ].value;
+    float max_value = min_value;
+    float min = 0;
+    float max = m_Length;
+
+    for( unsigned int i = 0; i < data.size(); ++i )
+    {
+        if( data[ i ].time < m_Time && data[ i ].time > min )
+        {
+            min_value = data[ i ].value;
+            min = data[ i ].time;
+        }
+
+        if( data[ i ].time >= m_Time && data[ i ].time <= max )
+        {
+            max_value = data[ i ].value;
+            max = data[ i ].time;
+        }
+    }
+
+    float value;
+
+    if( m_Time == 0 )
+    {
+        value = min_value;
+    }
+    else
+    {
+        value = min_value + ( max_value - min_value ) * ( ( m_Time - min ) / ( max - min ) );
+    }
+
+    return value;
+}
+
+
+
+Ogre::Vector2
+UiAnimation::KeyFrameGetValue( std::vector< UiKeyFrameVector2 >& data )
 {
-    m_Alpha.push_back(key_frame);
+    Ogre::Vector2 min_value = data[ 0 ].value;
+    Ogre::Vector2 max_value = min_value;
+    float min = 0;
+    float max = m_Length;
+
+    for( unsigned int i = 0; i < data.size(); ++i )
+    {
+        if( data[ i ].time < m_Time && data[ i ].time > min )
+        {
+            min_value = data[ i ].value;
+            min = data[ i ].time;
+        }
+
+        if( data[ i ].time >= m_Time && data[ i ].time <= max )
+        {
+            max_value = data[ i ].value;
+            max = data[ i ].time;
+        }
+    }
+
+    Ogre::Vector2 value;
+
+    if( m_Time == 0 )
+    {
+        value = min_value;
+    }
+    else
+    {
+        value = min_value + ( max_value - min_value ) * ( ( m_Time - min ) / ( max - min ) );
+    }
+
+    return value;
 }

+ 18 - 1
QGearsMain/src/core/UiFont.cpp

@@ -2,13 +2,24 @@
 #include "core/UiFont.h"
 
 
-UiFont::UiFont(const Ogre::String& name):
+UiFont::UiFont( const Ogre::String& name, const Ogre::String& language ):
     m_Name(name),
+    m_Language( language ),
     m_ImageName(""),
     m_ImageWidth(0),
     m_ImageHeight(0),
     m_Height(0)
 {
+    // Insets special symbol of next row
+    UiCharData data;
+    data.char_code = 10;
+    data.x = 0;
+    data.y = 0;
+    data.width = 0;
+    data.height = 0;
+    data.pre = 0;
+    data.post = 0;
+    m_CharData.push_back( data );
 }
 
 
@@ -24,6 +35,12 @@ UiFont::GetName() const
 }
 
 
+
+const Ogre::String&
+UiFont::GetLanguage() const
+{
+    return m_Language;
+}
 void
 UiFont::SetImage(const Ogre::String& image, const int width, const int height)
 {

+ 45 - 80
QGearsMain/src/core/UiManager.cpp

@@ -9,7 +9,7 @@
 #include "core/XmlPrototypesFile.h"
 #include "core/XmlScreensFile.h"
 #include "core/XmlTextsFile.h"
-
+#include "core/TextManager.h"
 
 template<>UiManager *Ogre::Singleton<UiManager>::msSingleton = nullptr;
 
@@ -24,7 +24,6 @@ UiManager::~UiManager()
 {
     Ogre::Root::getSingleton().getSceneManager("Scene")->removeRenderQueueListener(this);
 
-    UnloadTexts();
 
     for(size_t i = 0; i < m_Fonts.size(); ++i)
     {
@@ -44,8 +43,6 @@ UiManager::Initialise()
     XmlFontsFile fonts("./data/fonts.xml");
     fonts.LoadFonts();
 
-    XmlPrototypesFile prototypes("./data/screens/prototypes.xml");
-    prototypes.LoadPrototypes();
 
     XmlScreensFile screens("./data/screens.xml");
     screens.LoadScreens();
@@ -74,124 +71,90 @@ UiManager::OnResize()
 }
 
 
-void
-UiManager::SetLanguage(const Ogre::String& language)
-{
-    UnloadTexts();
-
-    XmlTextsFile texts("./data/texts.xml");
-    texts.LoadTexts(language);
-}
-
-
-void
-UiManager::AddText(const Ogre::String& name, TiXmlNode* text)
-{
-    UiText ui_text;
-    ui_text.name = name;
-    ui_text.node = text;
-    m_Texts.push_back(ui_text);
-}
-
 
 void
-UiManager::UnloadTexts()
-{
-    for(unsigned int i = 0; i < m_Texts.size(); ++i)
-    {
-        delete m_Texts[i].node;
-    }
-    m_Texts.clear();
-}
-
-
-TiXmlNode*
-UiManager::GetText(const Ogre::String& name) const
+UiManager::AddFont( UiFont* font )
 {
-    for(unsigned int i = 0; i < m_Texts.size(); ++i)
-    {
-        if(m_Texts[i].name == name)
-        {
-            return m_Texts[i].node;
-        }
-    }
-
-    return nullptr;
+    m_Fonts.push_back( font );
 }
 
 
-void
-UiManager::AddFont(UiFont* font)
-{
-    m_Fonts.push_back(font);
-}
-
 
 UiFont*
-UiManager::GetFont(const Ogre::String& name)
+UiManager::GetFont( const Ogre::String& name )
 {
-    for(unsigned int i = 0; i < m_Fonts.size(); ++i)
+    Ogre::String language = TextManager::getSingleton().GetLanguage();
+
+    for( unsigned int i = 0; i < m_Fonts.size(); ++i )
     {
-        if(m_Fonts[i]->GetName() == name)
+        if( m_Fonts[ i ]->GetName() == name )
         {
-            return m_Fonts[i];
+            Ogre::String f_lang = m_Fonts[ i ]->GetLanguage();
+            if( ( f_lang == "" ) || ( f_lang == language ) )
+            {
+                return m_Fonts[ i ];
+            }
         }
     }
 
-    return nullptr;
+    return NULL;
 }
 
 
+
 void
-UiManager::AddPrototype(const Ogre::String& name, TiXmlNode* prototype)
+UiManager::AddPrototype( const Ogre::String& name, TiXmlNode* prototype )
 {
     UiPrototype ui_prototype;
     ui_prototype.name = name;
     ui_prototype.node = prototype;
-    m_Prototypes.push_back(ui_prototype);
+    m_Prototypes.push_back( ui_prototype );
 }
 
 
+
 TiXmlNode*
-UiManager::GetPrototype(const Ogre::String& name) const
+UiManager::GetPrototype( const Ogre::String& name ) const
 {
-    for(unsigned int i = 0; i < m_Prototypes.size(); ++i)
+    for( unsigned int i = 0; i < m_Prototypes.size(); ++i )
     {
-        if(m_Prototypes[i].name == name)
+        if( m_Prototypes[ i ].name == name )
         {
-            return m_Prototypes[i].node;
+            return m_Prototypes[ i ].node;
         }
     }
 
-    return nullptr;
+    return NULL;
 }
 
 
+
 void
-UiManager::AddWidget(UiWidget* widget)
+UiManager::AddWidget( UiWidget* widget )
 {
-    m_Widgets.push_back(widget);
+    m_Widgets.push_back( widget );
 }
 
 
+
 UiWidget*
-UiManager::GetWidget(const Ogre::String& name)
+UiManager::GetWidget( const Ogre::String& name )
 {
     // get real table by name
-    Ogre::StringVector table_path = StringTokenise(name, ".");
-    UiWidget* widget = nullptr;
+    Ogre::StringVector table_path = StringTokenise( name, "." );
+    UiWidget* widget = NULL;
 
-    if(table_path.size() > 0)
+    if( table_path.size() > 0 )
     {
-        for(unsigned int i = 0; i < m_Widgets.size(); ++i)
+        for( unsigned int i = 0; i < m_Widgets.size(); ++i )
         {
-            if(m_Widgets[i]->GetName() == table_path[0])
+            if( m_Widgets[ i ]->GetName() == table_path[ 0 ] )
             {
-                widget = m_Widgets[i];
+                widget = m_Widgets[ i ];
 
-                for(unsigned int j = 1; (j < table_path.size()) && (widget != nullptr); ++j)
+                for( unsigned int j = 1; ( j < table_path.size() ) && ( widget != NULL ); ++j )
                 {
-                    widget = widget->GetChild(table_path[j]);
+                    widget = widget->GetChild( table_path[ j ] );
                 }
             }
         }
@@ -201,23 +164,25 @@ UiManager::GetWidget(const Ogre::String& name)
 }
 
 
+
 UiWidget*
-UiManager::ScriptGetWidget(const char* name)
+UiManager::ScriptGetWidget( const char* name )
 {
-    return GetWidget(Ogre::String(name));
+    return GetWidget( Ogre::String( name ) );
 }
 
 
+
 void
-UiManager::renderQueueStarted(Ogre::uint8 queueGroupId, const Ogre::String& invocation, bool& skipThisInvocation)
+UiManager::renderQueueStarted( Ogre::uint8 queueGroupId, const Ogre::String& invocation, bool& skipThisInvocation )
 {
-    if(queueGroupId == Ogre::RENDER_QUEUE_OVERLAY)
+    if( queueGroupId == Ogre::RENDER_QUEUE_OVERLAY )
     {
-        Ogre::Root::getSingletonPtr()->getRenderSystem()->clearFrameBuffer(Ogre::FBT_DEPTH);
+        Ogre::Root::getSingletonPtr()->getRenderSystem()->clearFrameBuffer( Ogre::FBT_DEPTH );
 
-        for(unsigned int i = 0; i < m_Widgets.size(); ++i)
+        for( unsigned int i = 0; i < m_Widgets.size(); ++i)
         {
-            m_Widgets[i]->Render();
+            m_Widgets[ i ]->Render();
         }
     }
 }

+ 783 - 146
QGearsMain/src/core/UiTextArea.cpp

@@ -5,7 +5,10 @@
 #include "core/Logger.h"
 #include "core/UiManager.h"
 #include "core/UiTextArea.h"
-
+#include "core/TextManager.h"
+#include "core/Timer.h"
+#include "core/UiSprite.h"
+#include "core/Utilites.h"
 
 UiTextArea::UiTextArea(const Ogre::String& name):
     UiWidget(name)
@@ -33,9 +36,30 @@ UiTextArea::Initialise()
     m_Font = nullptr;
     m_MaxLetters = 0;
     m_TextAlign = UiTextArea::LEFT;
-    m_Text = "";
-    m_TextNode = nullptr;
-
+    m_TextLimit = 0;
+    m_TextPrintSpeed = -1; // -1 instant
+    m_TextPrintSpeedMod = 1;
+    m_TextState = TS_DONE;
+    m_TextYOffset = 0;
+    m_TextYOffsetTarget = 0;
+    m_PauseTime = 0;
+    m_NextPageStart = 0;
+
+    m_PaddingTop = 0;
+    m_PaddingRight = 0;
+    m_PaddingBottom = 0;
+    m_PaddingLeft = 0;
+
+    m_NextPressed = false;
+    m_NextRepeated = false;
+
+    m_Timer = false;
+    m_TimerTime = 0;
+
+    TextVariable var;
+    var.name = "UITextAreaTimer";
+    var.value = "00:00";
+    m_TextVariable.push_back( var );
     m_SceneManager = Ogre::Root::getSingleton().getSceneManager("Scene");
     m_RenderSystem = Ogre::Root::getSingletonPtr()->getRenderSystem();
 
@@ -46,6 +70,139 @@ UiTextArea::Initialise()
 void
 UiTextArea::Update()
 {
+    if( m_Visible == true )
+    {
+        if( m_Timer == true )
+        {
+            int time = Timer::getSingleton().GetGameTimer();
+            if( time > 5999 ) // 99:59
+            {
+                time = 5999;
+            }
+
+            if( time != m_TimerTime )
+            {
+                m_TimerTime = time;
+
+                Ogre::String time_string = "";
+                time_string += Ogre::StringConverter::toString( m_TimerTime / 60, 2, '0' );
+                time_string += ( m_TimerTime & 1 ) ? ":" : ";";
+                time_string += Ogre::StringConverter::toString( m_TimerTime % 60, 2, '0' );
+                SetVariable( "UITextAreaTimer", time_string );
+            }
+        }
+
+
+
+        switch( m_TextState )
+        {
+            case TS_SHOW_TEXT:
+            {
+                if( m_TextPrintSpeed == -1 )
+                {
+                    m_TextLimit = m_MaxLetters;
+                }
+                else
+                {
+                    float time = Timer::getSingleton().GetGameTimeDelta() * 30;
+                    float addition, limit;
+
+                    if( m_NextPressed == true || m_NextRepeated == true )
+                    {
+                        m_TextPrintSpeedMod += ( m_TextPrintSpeedMod >= 128 ) ? 0 : 1.0f * time;
+                    }
+                    else
+                    {
+                        m_TextPrintSpeedMod -= ( m_TextPrintSpeedMod <= 1) ? 0 : 1.0f * time;
+                    }
+
+                    if( m_TextPrintSpeed < 128 )
+                    {
+                        addition = ( ( 128 - m_TextPrintSpeed ) / 32 ) + 2;
+                        limit = 1;
+                    }
+                    else
+                    {
+                        addition = 2;
+                        limit = ( ( m_TextPrintSpeed - 128 ) / 32 ) + 1;
+                    }
+
+                    float char_to_add = ( limit * m_TextPrintSpeedMod / 16 + addition ) / limit;
+                    m_TextLimit += time * char_to_add;
+                }
+
+                m_UpdateTransformation = true;
+            }
+            break;
+
+            case TS_SCROLL_TEXT:
+            {
+                m_TextYOffset -= m_Font->GetHeight() *  Timer::getSingleton().GetGameTimeDelta() / m_TextScrollTime;
+                if( m_TextYOffset <= m_TextYOffsetTarget )
+                {
+                    m_TextYOffset = m_TextYOffsetTarget;
+                    m_TextPrintSpeedMod = 1;
+                    m_TextState = TS_SHOW_TEXT;
+                }
+
+                m_UpdateTransformation = true;
+            }
+            break;
+
+            case TS_PAUSE_OK:
+            {
+                if( m_NextPressed == true )
+                {
+                    m_TextPrintSpeedMod = 1;
+                    m_TextState = TS_SHOW_TEXT;
+                }
+            }
+            break;
+
+            case TS_PAUSE_TIME:
+            {
+                m_PauseTime -= Timer::getSingleton().GetGameTimeDelta();
+
+                if( m_PauseTime <= 0 )
+                {
+                    m_TextPrintSpeedMod = 1;
+                    m_TextState = TS_SHOW_TEXT;
+                }
+            }
+            break;
+
+            case TS_OVERFLOW:
+            {
+                if( m_NextPressed == true )
+                {
+                    m_TextYOffsetTarget = m_TextYOffset - m_Font->GetHeight();
+                    m_TextState = TS_SCROLL_TEXT;
+                }
+            }
+            break;
+
+            case TS_NEXT_PAGE:
+            {
+                if( m_NextPressed == true )
+                {
+                    RemoveSpritesFromText( m_NextPageStart );
+                    m_Text.erase( m_Text.begin(), m_Text.begin() + m_NextPageStart );
+
+                    m_TextLimit = 0;
+                    m_TextPrintSpeedMod = 1;
+                    m_TextYOffset = 0;
+                    m_TextYOffsetTarget = 0;
+                    m_TextState = TS_SHOW_TEXT;
+                }
+            }
+            break;
+        }
+    }
+
+
+
+    m_NextPressed = false;
+    m_NextRepeated = false;
     UiWidget::Update();
 }
 
@@ -53,7 +210,7 @@ UiTextArea::Update()
 void
 UiTextArea::Render()
 {
-    if(m_Visible == true)
+    if( m_UpdateTransformation == false && m_Visible == true )
     {
         if(m_RenderOp.vertexData->vertexCount != 0)
         {
@@ -81,27 +238,128 @@ UiTextArea::UpdateTransformation()
 }
 
 
+
+void
+UiTextArea::InputPressed()
+{
+    m_NextPressed = true;
+}
+
+
+
+void
+UiTextArea::InputRepeated()
+{
+    m_NextRepeated = true;
+}
+
+
+
 void
-UiTextArea::SetTextAlign(const TextAlign align)
+UiTextArea::SetTextAlign( const TextAlign align )
 {
     m_TextAlign = align;
+    m_UpdateTransformation = true;
 }
 
 
+
+void
+UiTextArea::SetPadding( const float top, const float right, const float bottom, const float left )
+{
+    m_PaddingTop = top;
+    m_PaddingRight = right;
+    m_PaddingBottom = bottom;
+    m_PaddingLeft = left;
+}
+
+
+
+void
+UiTextArea::SetText( const Ogre::UTFString& text )
+{
+    TiXmlDocument doc;
+    Ogre::UTFString xml_text = "<container>" + text + "</container>";
+    doc.Parse( xml_text.asUTF8_c_str(), 0, TIXML_ENCODING_UTF8 );
+    if( doc.Error() == true )
+    {
+        LOG_ERROR( "Can't parse text \"" + text + "\". TinyXml Error: " + doc.ErrorDesc() );
+        return;
+    }
+    SetText( doc.RootElement() );
+}
+
+
+
 void
-UiTextArea::SetText(const Ogre::UTFString& text)
+UiTextArea::SetText( TiXmlNode* text )
 {
-    m_Text = text;
+    if( text == NULL )
+    {
+        LOG_ERROR( "Text pointer is NULL." );
+        return;
+    }
+
+    // reload font if language was changed
+    if( m_Font != NULL )
+    {
+        Ogre::String language = m_Font->GetLanguage();
+        if( language != "" )
+        {
+            if( TextManager::getSingleton().GetLanguage() != language )
+            {
+                SetFont( m_Font->GetName() );
+            }
+        }
+    }
+
+    TextClear();
+
+    PrepareTextFromNode( text, m_Colour1 );
+    m_TextState = TS_SHOW_TEXT;
+    m_UpdateTransformation = true;
+
+    if( m_Text.size() > m_MaxLetters )
+    {
+        m_Text.clear();
+        LOG_ERROR( "Max number of text reached in \"" + m_PathName + "\". Can't render text from node. Max number of letters is " + Ogre::StringConverter::toString( m_MaxLetters ) + "." );
+    }
 }
 
 
+
 void
-UiTextArea::SetText(TiXmlNode* text)
+UiTextArea::TextClear()
 {
-    m_TextNode = text;
+    RemoveSpritesFromText( m_Text.size() );
+    m_Text.clear();
+    m_TextLimit = 0;
+    m_TextPrintSpeedMod = 1;
+    m_TextYOffset = 0;
+    m_TextYOffsetTarget = 0;
 }
 
 
+void
+UiTextArea::RemoveSpritesFromText( const unsigned int end )
+{
+    for( unsigned int i = 0; i < end; ++i )
+    {
+        if( m_Text[ i ].sprite != NULL )
+        {
+            for( unsigned int j = 0; j < m_Children.size(); ++j )
+            {
+                if( m_Text[ i ].sprite == m_Children[ j ] )
+                {
+                    delete m_Children[ j ];
+                    m_Children.erase( m_Children.begin() + j, m_Children.begin() + j + 1 );
+                    break;
+                }
+            }
+        }
+    }
+}
+
 void
 UiTextArea::SetFont(const Ogre::String& font)
 {
@@ -128,138 +386,583 @@ UiTextArea::SetFont(const Ogre::String& font)
     tex->setTextureName(m_Font->GetImageName());
     tex->setNumMipmaps(-1);
     tex->setTextureFiltering(Ogre::TFO_NONE);
+    m_UpdateTransformation = true;
 }
 
 
+
+const UiFont*
+UiTextArea::GetFont() const
+{
+    return m_Font;
+}
+
 void
-UiTextArea::UpdateGeometry()
+UiTextArea::SetTextPrintSpeed( const float speed )
 {
-    if(m_Font == nullptr)
-    {
-        LOG_ERROR("Font for \"" + m_PathName + "\" if not set.");
-        return;
-    }
+    m_TextPrintSpeed = speed;
+}
 
-    if(m_Text.size() > m_MaxLetters)
+
+
+void
+UiTextArea::SetTextScrollTime( const float time )
+{
+    m_TextScrollTime = time;
+}
+
+
+
+void
+UiTextArea::SetVariable( const Ogre::String& name, const Ogre::UTFString& value )
+{
+    if( name == "" )
     {
-        LOG_ERROR("Max number of text reached in \"" + m_PathName + "\". Can't render text \"" + m_Text + "\". Max number of letters is " + Ogre::StringConverter::toString(m_MaxLetters) + ".");
         return;
     }
 
-    float length = 0;
-    if(m_TextAlign != LEFT)
+    bool update = false;
+
+    for( unsigned int i = 0; i < m_TextVariable.size(); ++i )
     {
-        if(m_TextNode != nullptr)
+        if( m_TextVariable[ i ].name == name )
         {
-            length = GetTextLengthFromNode(m_TextNode);
+            m_TextVariable[ i ].value = value;
+            update = true;
+
+            for( unsigned int j = 0; j < m_Text.size(); ++j )
+            {
+                if( m_Text[ j ].variable == name )
+                {
+                    m_Text.erase( m_Text.begin() + j + 1, m_Text.begin() + j + 1 + m_Text[ j ].variable_len );
+                }
+            }
         }
-        else
+    }
+
+    if( update == false )
+    {
+        TextVariable var;
+        var.name = name;
+        var.value = value;
+        m_TextVariable.push_back( var );
+    }
+
+    for( unsigned int i = 0; i < m_Text.size(); ++i )
+    {
+        if( m_Text[ i ].variable == name )
         {
-            length = GetTextLength(m_Text);
+            m_Text[ i ].variable_len = value.size();
+            unsigned int j = 0;
+            for( ; j < m_Text[ i ].variable_len; ++j )
+            {
+                TextChar text_char;
+                text_char.char_code = value[ j ];
+                text_char.colour = m_Text[ i ].colour;
+                m_Text.insert( m_Text.begin() + i + 1 + j, text_char );
+            }
+
+            i += j;
         }
+    }
 
-        if(m_TextAlign == CENTER)
+    m_UpdateTransformation = true;
+}
+
+
+
+Ogre::UTFString
+UiTextArea::GetVariable( const Ogre::String& name ) const
+{
+    for( unsigned int i = 0; i < m_TextVariable.size(); ++i )
+    {
+        if( m_TextVariable[ i ].name == name )
         {
-            length /= 2;
+            return m_TextVariable[ i ].value;
         }
     }
 
-    TextBlockData data;
-    data.local_x1 = -m_FinalOrigin.x - length;
-    data.local_y1 = -m_FinalOrigin.y;
-    data.position = 0;
+    return "";
+}
+
+
+
+TextState
+UiTextArea::GetTextState() const
+{
+    return m_TextState;
+}
+
+
+
+float
+UiTextArea::GetTextLimit() const
+{
+    return m_TextLimit;
+}
+
+
+
+unsigned int
+UiTextArea::GetTextSize() const
+{
+    return m_Text.size();
+}
+
+
+
+float
+UiTextArea::GetPauseTime() const
+{
+    return m_PauseTime;
+}
 
-    TextStyle style;
-    style.colour = m_Colour1;
 
-    if(m_TextNode != nullptr)
+void
+UiTextArea::UpdateGeometry()
+{
+    if( m_Font == NULL )
     {
-        SetTextGeometryFromNode(m_TextNode, data, style);
+        LOG_ERROR( "Font for \"" + m_PathName + "\" if not set." );
+        return;
     }
-    else
+
+    float width = 0;
+    if( m_TextAlign != LEFT )
     {
-        SetTextGeometry(m_Text, data, style);
+        width = GetTextWidth();
+
+        if( m_TextAlign == CENTER )
+        {
+            width /= 2;
+        }
     }
-}
 
+    //LOG_ERROR( "1) m_FinalOrigin.y = " + Ogre::StringConverter::toString( m_FinalOrigin.y ) + ", m_TextYOffset = " + Ogre::StringConverter::toString( m_TextYOffset ) );
 
-float
-UiTextArea::GetTextLengthFromNode(TiXmlNode* node) const
-{
-    float length = 0;
+    float* writeIterator = ( float* ) m_VertexBuffer->lock( Ogre::HardwareBuffer::HBL_NORMAL );
+    m_RenderOp.vertexData->vertexCount = 0;
 
-    while(node != nullptr)
+    float local_x_start = -m_FinalOrigin.x - ( width - m_PaddingLeft ) * m_FinalScale.x * m_ScreenHeight / 720.0f;
+    float local_x1 = local_x_start;
+    float local_y1 = -m_FinalOrigin.y + ( ( m_TextYOffset + m_PaddingTop ) * m_FinalScale.y * m_ScreenHeight / 720.0f );
+    float local_x2;
+    float local_y2;
+    float x = m_FinalTranslate.x;
+    float y = m_FinalTranslate.y;
+
+    unsigned int i = 0;
+    for( ; ( i < m_TextLimit ) && ( i < m_Text.size() ); ++i )
     {
-        switch(node->Type())
+        if( m_Text[ i ].skip == true )
         {
-            case TiXmlNode::TINYXML_TEXT:
-            {
-                TiXmlText* childText = node->ToText();
-                if(childText)
-                {
-                    length += GetTextLength(childText->Value());
-                }
-            }
+            continue;
+        }
+        else if( m_Text[ i ].pause_ok == true )
+        {
+            m_Text[ i ].skip = true;
+            m_TextState = TS_PAUSE_OK;
+            break;
+        }
+        else if( m_Text[ i ].pause_time != 0 )
+        {
+            m_Text[ i ].skip = true;
+            m_PauseTime = m_Text[ i ].pause_time;
+            m_TextState = TS_PAUSE_TIME;
             break;
+        }
+        else if( m_Text[ i ].next_page == true )
+        {
+            m_Text[ i ].skip = true;
+            m_NextPageStart = i + 1;
+            m_TextState = TS_NEXT_PAGE;
+            break;
+        }
+        else if( m_Text[ i ].sprite != NULL )
+        {
+            float width_percent = 0;
+            float width = 0;
+            m_Text[ i ].sprite->GetWidth( width_percent, width );
+            m_Text[ i ].sprite->SetX( 0, local_x1 / ( m_FinalScale.x * m_ScreenHeight / 720.0f ) );
+            local_x1 += width * m_FinalScale.x * m_ScreenHeight / 720.0f;
+            float height_percent = 0;
+            float height = 0;
+            m_Text[ i ].sprite->GetHeight( height_percent, height );
+            m_Text[ i ].sprite->SetY( 0, m_Text[ i ].sprite_y + ( local_y1 / ( m_FinalScale.y * m_ScreenHeight / 720.0f ) ) );
+            m_Text[ i ].sprite->SetVisible( true );
+            m_Text[ i ].sprite->UpdateGeometry();
+            continue;
+        }
 
-            case TiXmlNode::TINYXML_ELEMENT:
+
+
+        UiCharData char_data = m_Font->GetCharData( m_Text[ i ].char_code );
+        Ogre::ColourValue colour = m_Text[ i ].colour;
+
+        if( char_data.char_code == 10 )
+        {
+            local_x1 = local_x_start;
+            local_y1 += m_Font->GetHeight() * m_FinalScale.y * m_ScreenHeight / 720.0f;
+            continue;
+        }
+
+        local_x1 += char_data.pre * m_FinalScale.x * m_ScreenHeight / 720.0f;
+        local_x2 = local_x1 + char_data.width * m_FinalScale.x * m_ScreenHeight / 720.0f;
+        local_y2 = local_y1 + char_data.height * m_FinalScale.y * m_ScreenHeight / 720.0f;
+
+        if( local_x2 + char_data.post * m_FinalScale.x * m_ScreenHeight / 720.0f > m_FinalSize.x - m_PaddingRight * m_FinalScale.x * m_ScreenHeight / 720.0f )
+        {
+            local_x1 = local_x_start;
+            local_x2 = local_x1 + char_data.width * m_FinalScale.x * m_ScreenHeight / 720.0f;
+            local_y1 += m_Font->GetHeight() * m_FinalScale.y * m_ScreenHeight / 720.0f;
+            local_y2 = local_y1 + char_data.height * m_FinalScale.y * m_ScreenHeight / 720.0f;
+        }
+
+        // if we cross lower border of textarea - generate event and stop rendering
+        if( local_y2 > m_FinalSize.y - m_PaddingBottom * m_FinalScale.y * m_ScreenHeight / 720.0f )
+        {
+            if( m_TextState != TS_SCROLL_TEXT )
             {
-                length +=GetTextLengthFromNode(node->FirstChild());
+                m_TextState = TS_OVERFLOW;
             }
+
             break;
         }
 
-        node = node->NextSibling();
+
+        int x1, y1, x2, y2, x3, y3, x4, y4;
+
+        //LOG_ERROR( m_Name );
+        //LOG_ERROR( "local_x1 = " + Ogre::StringConverter::toString( local_x1 ) + ", local_y1 = " + Ogre::StringConverter::toString( local_y1 ) );
+        //LOG_ERROR( "local_x2 = " + Ogre::StringConverter::toString( local_x2 ) + ", local_y2 = " + Ogre::StringConverter::toString( local_y2 ) );
+
+        if( m_FinalRotation != 0 )
+        {
+            float cos = Ogre::Math::Cos( Ogre::Radian( Ogre::Degree( m_FinalRotation ) ) );
+            float sin = Ogre::Math::Sin( Ogre::Radian( Ogre::Degree( m_FinalRotation ) ) );
+
+            x1 = local_x1 * cos - local_y1 * sin + x;
+            y1 = local_x1 * sin + local_y1 * cos + y;
+            x2 = local_x2 * cos - local_y1 * sin + x;
+            y2 = local_x2 * sin + local_y1 * cos + y;
+            x3 = local_x2 * cos - local_y2 * sin + x;
+            y3 = local_x2 * sin + local_y2 * cos + y;
+            x4 = local_x1 * cos - local_y2 * sin + x;
+            y4 = local_x1 * sin + local_y2 * cos + y;
+        }
+        else
+        {
+            x1 = local_x1 + x;
+            y1 = local_y1 + y;
+            x2 = local_x2 + x;
+            y2 = local_y1 + y;
+            x3 = local_x2 + x;
+            y3 = local_y2 + y;
+            x4 = local_x1 + x;
+            y4 = local_y2 + y;
+        }
+
+        //LOG_ERROR( "x1 = " + Ogre::StringConverter::toString( x1 ) + ", y1 = " + Ogre::StringConverter::toString( y1 ) );
+        //LOG_ERROR( "x2 = " + Ogre::StringConverter::toString( x2 ) + ", y2 = " + Ogre::StringConverter::toString( y2 ) );
+        //LOG_ERROR( "x3 = " + Ogre::StringConverter::toString( x3 ) + ", y3 = " + Ogre::StringConverter::toString( y3 ) );
+        //LOG_ERROR( "x4 = " + Ogre::StringConverter::toString( x4 ) + ", y4 = " + Ogre::StringConverter::toString( y4 ) );
+
+        float new_x1 = ( x1 / m_ScreenWidth ) * 2 - 1;
+        float new_y1 = -( ( y1 / m_ScreenHeight ) * 2 - 1 );
+        float new_x2 = ( x2 / m_ScreenWidth ) * 2 - 1;
+        float new_y2 = -( ( y2 / m_ScreenHeight ) * 2 - 1 );
+        float new_x3 = ( x3 / m_ScreenWidth ) * 2 - 1;
+        float new_y3 = -( ( y3 / m_ScreenHeight ) * 2 - 1 );
+        float new_x4 = ( x4 / m_ScreenWidth ) * 2 - 1;
+        float new_y4 = -( ( y4 / m_ScreenHeight ) * 2 - 1 );
+
+        local_x1 += ( char_data.width + char_data.post ) * m_FinalScale.x * m_ScreenHeight / 720.0f;
+
+        float width = m_Font->GetImageWidth();
+        float height = m_Font->GetImageHeight();
+        float left = ( float )char_data.x / width;
+        float right = ( float )( char_data.x + char_data.width ) / width;
+        float top = ( float )char_data.y / height;
+        float bottom = ( float )( char_data.y + char_data.height ) / height;
+
+        //LOG_ERROR( "width = " + Ogre::StringConverter::toString( width ) + "." );
+        //LOG_ERROR( "height = " + Ogre::StringConverter::toString( height ) + "." );
+        //LOG_ERROR( "char_data.x = " + Ogre::StringConverter::toString( char_data.x ) + "." );
+        //LOG_ERROR( "char_data.y = " + Ogre::StringConverter::toString( char_data.y ) + "." );
+        //LOG_ERROR( "char_data.width = " + Ogre::StringConverter::toString( char_data.width ) + "." );
+        //LOG_ERROR( "char_data.height = " + Ogre::StringConverter::toString( char_data.height ) + "." );
+        //LOG_ERROR( "left = " + Ogre::StringConverter::toString( left ) + "." );
+        //LOG_ERROR( "right = " + Ogre::StringConverter::toString( right ) + "." );
+        //LOG_ERROR( "top = " + Ogre::StringConverter::toString( top ) + "." );
+        //LOG_ERROR( "bottom = " + Ogre::StringConverter::toString( bottom ) + "." );
+
+        *writeIterator++ = new_x1;
+        *writeIterator++ = new_y1;
+        *writeIterator++ = m_FinalZ;
+        *writeIterator++ = colour.r;
+        *writeIterator++ = colour.g;
+        *writeIterator++ = colour.b;
+        *writeIterator++ = colour.a;
+        *writeIterator++ = left;
+        *writeIterator++ = top;
+
+        *writeIterator++ = new_x2;
+        *writeIterator++ = new_y2;
+        *writeIterator++ = m_FinalZ;
+        *writeIterator++ = colour.r;
+        *writeIterator++ = colour.g;
+        *writeIterator++ = colour.b;
+        *writeIterator++ = colour.a;
+        *writeIterator++ = right;
+        *writeIterator++ = top;
+
+        *writeIterator++ = new_x3;
+        *writeIterator++ = new_y3;
+        *writeIterator++ = m_FinalZ;
+        *writeIterator++ = colour.r;
+        *writeIterator++ = colour.g;
+        *writeIterator++ = colour.b;
+        *writeIterator++ = colour.a;
+        *writeIterator++ = right;
+        *writeIterator++ = bottom;
+
+        *writeIterator++ = new_x1;
+        *writeIterator++ = new_y1;
+        *writeIterator++ = m_FinalZ;
+        *writeIterator++ = colour.r;
+        *writeIterator++ = colour.g;
+        *writeIterator++ = colour.b;
+        *writeIterator++ = colour.a;
+        *writeIterator++ = left;
+        *writeIterator++ = top;
+
+        *writeIterator++ = new_x3;
+        *writeIterator++ = new_y3;
+        *writeIterator++ = m_FinalZ;
+        *writeIterator++ = colour.r;
+        *writeIterator++ = colour.g;
+        *writeIterator++ = colour.b;
+        *writeIterator++ = colour.a;
+        *writeIterator++ = right;
+        *writeIterator++ = bottom;
+
+        *writeIterator++ = new_x4;
+        *writeIterator++ = new_y4;
+        *writeIterator++ = m_FinalZ;
+        *writeIterator++ = colour.r;
+        *writeIterator++ = colour.g;
+        *writeIterator++ = colour.b;
+        *writeIterator++ = colour.a;
+        *writeIterator++ = left;
+        *writeIterator++ = bottom;
+
+        m_RenderOp.vertexData->vertexCount += 6;
     }
 
-    return length;
+    m_VertexBuffer->unlock();
+
+    if( i == m_Text.size() )
+    {
+        m_TextState = TS_DONE;
+    }
 }
 
 
 float
-UiTextArea::GetTextLength(const Ogre::UTFString& text) const
+UiTextArea::GetTextWidth() const
 {
-    float length = 0;
-    for(size_t i = 0; i < text.size(); ++i)
+    float width = 0;
+    float width_max = 0;
+
+    for( unsigned int i = 0; i < m_Text.size(); ++i )
     {
-        UiCharData char_data = m_Font->GetCharData(text[i]);
-        length += (char_data.pre + char_data.width + char_data.post) * m_FinalScale.x * m_ScreenHeight / 720.0f;
+        UiCharData char_data = m_Font->GetCharData( m_Text[ i ].char_code );
+
+        // if we go to next row store max previous row width
+        if( char_data.char_code == 10 )
+        {
+            width_max = ( width > width_max ) ? width : width_max;
+            width = 0;
+        }
+        else
+        {
+            width += char_data.pre + char_data.width + char_data.post;
+        }
     }
 
-    return length;
+    return ( width > width_max ) ? width : width_max;
 }
 
 
 void
-UiTextArea::SetTextGeometryFromNode(TiXmlNode* node, TextBlockData& data, const TextStyle& style)
+UiTextArea::PrepareTextFromNode( TiXmlNode* node, const Ogre::ColourValue& colour )
 {
-    while(node != nullptr)
+    while( node != NULL )
     {
-        switch(node->Type())
+        switch( node->Type() )
         {
             case TiXmlNode::TINYXML_TEXT:
             {
                 TiXmlText* childText = node->ToText();
-                if(childText)
+                if( childText )
                 {
-                    SetTextGeometry(childText->Value(), data, style);
+                    PrepareTextFromText( childText->Value(), colour );
                 }
             }
             break;
 
             case TiXmlNode::TINYXML_ELEMENT:
             {
-                TextStyle style_child;
-                style_child.colour = style.colour;
+                Ogre::ColourValue colour_child = colour;
 
                 Ogre::String name = node->ValueStr();
-                if(name == "colour")
+                if( name == "colour" )
+                {
+                    colour_child = Ogre::StringConverter::parseColourValue( node->ToElement()->Attribute( "value" ) );
+                }
+                else if( name == "pause_ok" )
+                {
+                    TextChar new_char;
+                    new_char.pause_ok = true;
+                    m_Text.push_back( new_char );
+                }
+                else if( name == "pause" )
+                {
+                    const std::string* string = node->ToElement()->Attribute( Ogre::String( "time" ) );
+                    if( string != NULL )
+                    {
+                        TextChar new_char;
+                        new_char.pause_time = Ogre::StringConverter::parseReal( *string );
+                        m_Text.push_back( new_char );
+                    }
+                }
+                else if( name == "next_page" )
+                {
+                    TextChar new_char;
+                    new_char.next_page = true;
+                    m_Text.push_back( new_char );
+                }
+                else if( name == "timer" )
+                {
+                    m_Timer = true;
+
+                    TextChar new_char;
+                    new_char.skip = true;
+                    new_char.variable = "UITextAreaTimer";
+                    new_char.colour = colour;
+                    Ogre::UTFString var = GetVariable( "UITextAreaTimer" );
+                    new_char.variable_len = var.size();
+                    m_Text.push_back( new_char );
+
+                    for( unsigned int i = 0; i < var.size(); ++i )
+                    {
+                        TextChar text_char;
+                        text_char.char_code = var[ i ];
+                        text_char.colour = colour;
+                        m_Text.push_back( text_char );
+                    }
+                }
+                else if( name == "variable" )
                 {
-                    style_child.colour = Ogre::StringConverter::parseColourValue(node->ToElement()->Attribute("value"));
+                    const std::string* string = node->ToElement()->Attribute( Ogre::String( "name" ) );
+
+                    if( string != NULL )
+                    {
+                        TextChar new_char;
+                        new_char.skip = true;
+                        new_char.variable = *string;
+                        new_char.colour = colour;
+                        Ogre::UTFString var = GetVariable( *string );
+                        new_char.variable_len = var.size();
+                        m_Text.push_back( new_char );
+
+                        for( unsigned int i = 0; i < var.size(); ++i )
+                        {
+                            TextChar text_char;
+                            text_char.char_code = var[ i ];
+                            text_char.colour = colour;
+                            m_Text.push_back( text_char );
+                        }
+                    }
+                }
+                else if( name == "include" )
+                {
+                    const std::string* text_name = node->ToElement()->Attribute( Ogre::String( "name" ) );
+
+                    if( text_name != NULL )
+                    {
+                        TiXmlNode* text = TextManager::getSingleton().GetText( *text_name );
+                        if( text != NULL )
+                        {
+                            PrepareTextFromNode( text, colour_child );
+                        }
+                    }
+                }
+                else if( name == "image" )
+                {
+                    Ogre::String name1 = GetString( node, "sprite" );
+                    if( name1 != "" )
+                    {
+                        TiXmlNode* sprites = UiManager::getSingleton().GetPrototype( "TextAreaSprite" );
+                        if( sprites != NULL )
+                        {
+                            sprites = sprites->FirstChild();
+                            while( sprites != NULL )
+                            {
+                                if( sprites->Type() == TiXmlNode::TINYXML_ELEMENT && sprites->ValueStr() == "sprite" )
+                                {
+                                    Ogre::String name2 = GetString( sprites, "name" );
+                                    if( name1 == name2 )
+                                    {
+                                        TextChar new_char;
+
+                                        UiSprite* sprite = new UiSprite( name1, m_Name + "." + name1, this );
+                                        Ogre::String image = GetString( sprites, "image" );
+                                        if( image != "" )
+                                        {
+                                            sprite->SetImage( image );
+                                        }
+                                        Ogre::String y_str = GetString( sprites, "y" );
+                                        if( y_str != "" )
+                                        {
+                                            float y_percent = 0;
+                                            float y = 0;
+                                            ParsePersent( y_percent, y, y_str );
+                                            new_char.sprite_y = y;
+                                        }
+                                        Ogre::String width_str = GetString( sprites, "width" );
+                                        if( width_str != "" )
+                                        {
+                                            float width_percent = 0;
+                                            float width = 0;
+                                            ParsePersent( width_percent, width, width_str );
+                                            sprite->SetWidth( 0, width );
+                                        }
+                                        Ogre::String height_str = GetString( sprites, "height" );
+                                        if( height_str != "" )
+                                        {
+                                            float height_percent = 0;
+                                            float height = 0;
+                                            ParsePersent( height_percent, height, height_str );
+                                            sprite->SetHeight( height_percent, height );
+                                        }
+
+                                        sprite->SetVisible( false );
+                                        AddChild( sprite );
+                                        new_char.sprite = sprite;
+                                        m_Text.push_back( new_char );
+                                        break;
+                                    }
+                                }
+
+                                sprites = sprites->NextSibling();
+                            }
+                        }
+                    }
                 }
 
                 TiXmlNode* node_child = node->FirstChild();
-                SetTextGeometryFromNode(node_child, data, style_child);
+                PrepareTextFromNode( node_child, colour_child );
             }
             break;
         }
@@ -269,87 +972,21 @@ UiTextArea::SetTextGeometryFromNode(TiXmlNode* node, TextBlockData& data, const
 }
 
 
+
 void
-UiTextArea::SetTextGeometry(const Ogre::UTFString& text, TextBlockData& data, const TextStyle& style)
+UiTextArea::PrepareTextFromText( const Ogre::UTFString& text, const Ogre::ColourValue& colour_child )
 {
-    float* writeIterator = (float*) m_VertexBuffer->lock(Ogre::HardwareBuffer::HBL_NORMAL);
-    writeIterator += data.position * 9 * 6;
-    m_RenderOp.vertexData->vertexCount = data.position * 6;
-
-
-    float local_x1 = data.local_x1;
-    float local_y1 = data.local_y1;
-    float x = m_FinalTranslate.x;
-    float y = m_FinalTranslate.y;
-
-    for(auto &c : text)
+    for( unsigned int i = 0; i < text.size(); ++i )
     {
-        UiCharData char_data = m_Font->GetCharData(c);
-
-        local_x1 += char_data.pre * m_FinalScale.x * m_ScreenHeight / 720.0f;
-        float local_x2 = local_x1 + char_data.width * m_FinalScale.x * m_ScreenHeight / 720.0f;
-        float local_y2 = local_y1 + char_data.height * m_FinalScale.y * m_ScreenHeight / 720.0f;
-
-        int x1, y1, x2, y2, x3, y3, x4, y4;
-
-        if(m_FinalRotation != 0)
-        {
-            float cos = Ogre::Math::Cos(Ogre::Radian(Ogre::Degree(m_FinalRotation)));
-            float sin = Ogre::Math::Sin(Ogre::Radian(Ogre::Degree(m_FinalRotation)));
-
-            x1 = static_cast<int>(local_x1 * cos - local_y1 * sin + x);
-            y1 = static_cast<int>(local_x1 * sin + local_y1 * cos + y);
-            x2 = static_cast<int>(local_x2 * cos - local_y1 * sin + x);
-            y2 = static_cast<int>(local_x2 * sin + local_y1 * cos + y);
-            x3 = static_cast<int>(local_x2 * cos - local_y2 * sin + x);
-            y3 = static_cast<int>(local_x2 * sin + local_y2 * cos + y);
-            x4 = static_cast<int>(local_x1 * cos - local_y2 * sin + x);
-            y4 = static_cast<int>(local_x1 * sin + local_y2 * cos + y);
-        }
-        else
-        {
-            x1 = static_cast<int>(local_x1 + x);
-            y1 = static_cast<int>(local_y1 + y);
-            x2 = static_cast<int>(local_x2 + x);
-            y2 = static_cast<int>(local_y1 + y);
-            x3 = static_cast<int>(local_x2 + x);
-            y3 = static_cast<int>(local_y2 + y);
-            x4 = static_cast<int>(local_x1 + x);
-            y4 = static_cast<int>(local_y2 + y);
-        }
-
-        local_x1 += (char_data.width + char_data.post) * m_FinalScale.x * m_ScreenHeight / 720.0f;
-
-        float width = static_cast<float>(m_Font->GetImageWidth());
-        float height = static_cast<float>(m_Font->GetImageHeight());
-
-        Ogre::Vector3 coords[4] = {
-            Ogre::Vector3((x1 / m_ScreenWidth) * 2 - 1, -((y1 / m_ScreenHeight) * 2 - 1), m_FinalZ),
-            Ogre::Vector3((x2 / m_ScreenWidth) * 2 - 1, -((y2 / m_ScreenHeight) * 2 - 1), m_FinalZ),
-            Ogre::Vector3((x3 / m_ScreenWidth) * 2 - 1, -((y3 / m_ScreenHeight) * 2 - 1), m_FinalZ),
-            Ogre::Vector3((x4 / m_ScreenWidth) * 2 - 1, -((y4 / m_ScreenHeight) * 2 - 1), m_FinalZ)
-        };
-        auto texture = Ogre::FloatRect(
-            (float)char_data.x / width, // left
-            (float)char_data.y / height, // top
-            (float)(char_data.x + char_data.width) / width, // right
-            (float)(char_data.y + char_data.height) / height // bottom
-       );
-        Ogre::ColourValue colour = style.colour;
-
-        // draw two triangles with a colour and texture.
-        WriteGlyph(writeIterator, coords, colour, texture);
-        m_RenderOp.vertexData->vertexCount += 6;
-        data.position += 1;
-    }
-
-    m_VertexBuffer->unlock();
-
-    data.local_x1 = local_x1;
-    data.local_y1 = local_y1;
+        TextChar new_char;
+        new_char.char_code = text[ i ];
+        new_char.colour = colour_child;
+        m_Text.push_back( new_char );
+    };
 }
 
 
+
 void
 UiTextArea::CreateVertexBuffer()
 {

+ 202 - 80
QGearsMain/src/core/UiWidget.cpp

@@ -82,10 +82,20 @@ UiWidget::Initialise()
     m_Rotation = 0.0f;
 
     m_Scissor = false;
+    m_LocalScissor = false;
+    m_GlobalScissor = true;
     m_ScissorTop = 0;
-    m_ScissorBottom = static_cast<int>(m_ScreenHeight);
+    m_ScissorXPercentTop = 0;
+    m_ScissorXTop = 0;
+    m_ScissorBottom = m_ScreenHeight;
+    m_ScissorXPercentBottom = 100;
+    m_ScissorXBottom = 0;
     m_ScissorLeft = 0;
-    m_ScissorRight = static_cast<int>(m_ScreenWidth);
+    m_ScissorYPercentLeft = 0;
+    m_ScissorYLeft = 0;
+    m_ScissorRight = m_ScreenWidth;
+    m_ScissorYPercentRight = 100;
+    m_ScissorYRight = 0;
 
     m_AnimationCurrent = nullptr;
     m_AnimationDefault = "";
@@ -132,27 +142,36 @@ UiWidget::Update()
                 time = time + delta_time - m_AnimationCurrent->GetLength();
                 PlayAnimation(m_AnimationDefault, UiAnimation::DEFAULT, time, -1);
             }
+            else
+            {
+                m_AnimationCurrent = NULL;
+            }
         }
         else
         {
             m_AnimationCurrent->AddTime(delta_time);
         }
     }
-    else if(m_AnimationCurrent == nullptr && m_AnimationState == UiAnimation::DEFAULT && m_AnimationDefault != "")
+    else if( m_AnimationCurrent == NULL && m_AnimationState == UiAnimation::DEFAULT && m_AnimationDefault != "" )
     {
-        PlayAnimation(m_AnimationDefault, UiAnimation::DEFAULT, 0, -1);
+        PlayAnimation( m_AnimationDefault, UiAnimation::DEFAULT, 0, -1 );
     }
 
-    for(size_t i = 0; i < m_Children.size(); ++i)
+
+
+    if( m_UpdateTransformation == true )
     {
-        m_Children[i]->Update();
+        UpdateTransformation();
     }
 
-    if(m_UpdateTransformation == true)
+
+
+    for( unsigned int i = 0; i < m_Children.size(); ++i )
     {
-        UpdateTransformation();
+        m_Children[ i ]->Update();
     }
 
+
     // debug output
     if(cv_debug_ui.GetI() >= 1)
     {
@@ -282,20 +301,40 @@ UiWidget::AddChild(UiWidget *widget)
 
 
 UiWidget*
-UiWidget::GetChild(const Ogre::String& name)
+UiWidget::GetChild( const Ogre::String& name )
 {
-    for(size_t i = 0; i < m_Children.size(); ++i)
+    for( unsigned int i = 0; i < m_Children.size(); ++i )
     {
-        if(m_Children[i]->GetName() == name)
+        if( m_Children[ i ]->GetName() == name )
         {
-            return m_Children[i];
+            return m_Children[ i ];
         }
     }
 
-    return nullptr;
+    return NULL;
+}
+
+
+
+UiWidget*
+UiWidget::GetChild( const unsigned int id )
+{
+    if( id >= m_Children.size() )
+    {
+        return NULL;
+    }
+
+    return m_Children[ id ];
 }
 
 
+
+unsigned int
+UiWidget::GetNumberOfChildren()
+{
+    return m_Children.size();
+}
+
 void
 UiWidget::RemoveAllChildren()
 {
@@ -394,6 +433,18 @@ UiWidget::ScriptAnimationSync()
 }
 
 
+
+void
+UiWidget::SetUpdateTransformation()
+{
+    for( unsigned int i = 0; i < m_Children.size(); ++i )
+    {
+        m_Children[ i ]->SetUpdateTransformation();
+    }
+
+    m_UpdateTransformation = true;
+}
+
 void
 UiWidget::UpdateTransformation()
 {
@@ -439,26 +490,25 @@ UiWidget::UpdateTransformation()
     }
     m_FinalTranslate.y += y;
 
-    m_FinalZ = (m_Parent != nullptr) ? m_Parent->GetFinalZ() + m_Z : m_Z;
+
+
+    m_FinalZ = ( m_Parent != NULL ) ? m_Parent->GetFinalZ() + m_Z : m_Z;
     m_FinalScale = area_scale * m_Scale;
-    m_FinalSize.x = (area_size.x * m_WidthPercent * m_Scale.x) / 100.0f + (m_Width * m_ScreenHeight / 720.0f) * m_FinalScale.x;
-    m_FinalSize.y = (area_size.y * m_HeightPercent * m_Scale.y) / 100.0f + (m_Height * m_ScreenHeight / 720.0f) * m_FinalScale.y;
-    m_FinalOrigin.x = (m_FinalSize.x * m_OriginXPercent) / 100.0f + m_OriginX * m_ScreenHeight * m_FinalScale.x / 720.0f;
-    m_FinalOrigin.y = (m_FinalSize.y * m_OriginYPercent) / 100.0f + m_OriginY * m_ScreenHeight * m_FinalScale.y / 720.0f;
+    m_FinalSize.x = ( area_size.x * m_WidthPercent * m_Scale.x ) / 100.0f + ( m_Width * m_ScreenHeight / 720.0f ) * m_FinalScale.x;
+    m_FinalSize.y = ( area_size.y * m_HeightPercent * m_Scale.y ) / 100.0f + ( m_Height * m_ScreenHeight / 720.0f ) * m_FinalScale.y;
+    m_FinalOrigin.x = ( m_FinalSize.x * m_OriginXPercent ) / 100.0f + m_OriginX * m_ScreenHeight * m_FinalScale.x / 720.0f;
+    m_FinalOrigin.y = ( m_FinalSize.y * m_OriginYPercent ) / 100.0f + m_OriginY * m_ScreenHeight * m_FinalScale.y / 720.0f;
     m_FinalRotation = area_rotation + m_Rotation;
 
-    // scissor update
-    m_ScissorTop = (m_Parent != nullptr) ? m_Parent->GetScissorTop() : 0;
-    m_ScissorBottom = (m_Parent != nullptr) ? m_Parent->GetScissorBottom() : static_cast<int>(m_ScreenHeight);
-    m_ScissorLeft = (m_Parent != nullptr) ? m_Parent->GetScissorLeft() : 0;
-    m_ScissorRight = (m_Parent != nullptr) ? m_Parent->GetScissorRight() : static_cast<int>(m_ScreenWidth);
 
-    if(m_Scissor == true)
+
+    // scissor update
+    if( m_LocalScissor == true )
     {
-        float local_x1 = -m_FinalOrigin.x;
-        float local_y1 = -m_FinalOrigin.y;
-        float local_x2 = m_FinalSize.x + local_x1;
-        float local_y2 = m_FinalSize.y + local_y1;
+        float local_x1 = m_FinalSize.x * m_ScissorXPercentTop / 100.0f + m_ScissorXTop * m_ScreenHeight * m_FinalScale.x / 720.0f - m_FinalOrigin.x;
+        float local_y1 = m_FinalSize.y * m_ScissorYPercentLeft / 100.0f + m_ScissorYLeft * m_ScreenHeight * m_FinalScale.y / 720.0f - m_FinalOrigin.y;
+        float local_x2 = m_FinalSize.x * m_ScissorXPercentBottom / 100.0f + m_ScissorXBottom * m_ScreenHeight * m_FinalScale.x / 720.0f - m_FinalOrigin.x;
+        float local_y2 = m_FinalSize.y * m_ScissorYPercentRight / 100.0f + m_ScissorYRight * m_ScreenHeight * m_FinalScale.y / 720.0f - m_FinalOrigin.y;
         float x = m_FinalTranslate.x;
         float y = m_FinalTranslate.y;
 
@@ -490,18 +540,39 @@ UiWidget::UpdateTransformation()
             y4 = static_cast<int>(local_y2 + y);
         }
 
-        m_ScissorTop = std::max(m_ScissorTop, std::min(std::min(y1 , y2), std::min(y3 , y4)));
-        m_ScissorBottom = std::min(m_ScissorBottom, std::max(std::max(y1 , y2), std::max(y3 , y4)));
-        m_ScissorLeft = std::max(m_ScissorLeft, std::min(std::min(x1 , x2), std::min(x3 , x4)));
-        m_ScissorRight = std::min(m_ScissorRight, std::max(std::max(x1 , x2), std::max(x3 , x4)));
+        m_Scissor = true;
+        m_ScissorTop = std::min( std::min( y1 , y2 ), std::min( y3 , y4 ) );
+        m_ScissorBottom = std::max( std::max( y1 , y2 ), std::max( y3 , y4 ) );
+        m_ScissorLeft = std::min( std::min( x1 , x2 ), std::min( x3 , x4 ) );
+        m_ScissorRight = std::max( std::max( x1 , x2 ), std::max( x3 , x4 ) );
     }
-
-    m_UpdateTransformation = false;
-
-    for(size_t i = 0; i < m_Children.size(); ++i)
+    if( m_Parent != NULL && m_GlobalScissor == true )
     {
-        m_Children[i]->UpdateTransformation();
+        bool use_scissor;
+        Ogre::Vector4 scissor = m_Parent->GetFinalScissor( use_scissor );
+        if( use_scissor == true )
+        {
+            m_Scissor = true;
+            if( m_LocalScissor == true )
+            {
+                m_ScissorTop = std::max( (float) m_ScissorTop, scissor.x );
+                m_ScissorBottom = std::min( (float) m_ScissorBottom, scissor.y );
+                m_ScissorLeft = std::max( (float) m_ScissorLeft, scissor.z );
+                m_ScissorRight = std::min( (float) m_ScissorRight, scissor.w );
+            }
+            else
+            {
+                m_ScissorTop = scissor.x;
+                m_ScissorBottom = scissor.y;
+                m_ScissorLeft = scissor.z;
+                m_ScissorRight = scissor.w;
+            }
+        }
     }
+
+
+
+    m_UpdateTransformation = false;
 }
 
 
@@ -554,6 +625,19 @@ UiWidget::GetFinalScale() const
 }
 
 
+
+Ogre::Vector4
+UiWidget::GetFinalScissor( bool& scissor ) const
+{
+    if( m_Scissor == true )
+    {
+        scissor = true;
+        return Ogre::Vector4( m_ScissorTop, m_ScissorBottom, m_ScissorLeft, m_ScissorRight );
+    }
+
+    scissor = false;
+    return Ogre::Vector4::ZERO;
+}
 float
 UiWidget::GetFinalRotation() const
 {
@@ -566,7 +650,7 @@ UiWidget::SetOriginX(const float percent, const float x)
 {
     m_OriginXPercent = percent;
     m_OriginX = x;
-    m_UpdateTransformation = true;
+    SetUpdateTransformation();
 }
 
 
@@ -575,134 +659,172 @@ UiWidget::SetOriginY(const float percent, const float y)
 {
     m_OriginYPercent = percent;
     m_OriginY = y;
-    m_UpdateTransformation = true;
+    SetUpdateTransformation();
 }
 
 
+
 void
-UiWidget::SetX(const float percent, const float x)
+UiWidget::SetX( const float percent, const float x )
 {
     m_XPercent = percent;
     m_X = x;
-    m_UpdateTransformation = true;
+    SetUpdateTransformation();
 }
 
 
+
 void
-UiWidget::SetY(const float percent, const float y)
+UiWidget::GetX( float& percent, float& x )
+{
+    percent = m_XPercent;
+    x = m_X;
+}
+
+
+
+void
+UiWidget::SetY( const float percent, const float y )
 {
     m_YPercent = percent;
     m_Y = y;
-    m_UpdateTransformation = true;
+    SetUpdateTransformation();
 }
 
 
+
+void
+UiWidget::GetY( float& percent, float& y )
+{
+    percent = m_YPercent;
+    y = m_Y;
+}
+
+
+
 void
-UiWidget::SetZ(const float z)
+UiWidget::SetZ( const float z )
 {
     m_Z = z;
-    m_UpdateTransformation = true;
+    SetUpdateTransformation();
 }
 
 
+
 void
-UiWidget::SetWidth(const float percent, const float width)
+UiWidget::SetWidth( const float percent, const float width )
 {
     m_WidthPercent = percent;
     m_Width = width;
-    m_UpdateTransformation = true;
+    SetUpdateTransformation();
 }
 
 
+
 void
-UiWidget::SetHeight(const float percent, const float height)
+UiWidget::GetWidth( float& percent, float& width )
 {
-    m_HeightPercent = percent;
-    m_Height = height;
-    m_UpdateTransformation = true;
+    percent = m_WidthPercent;
+    width = m_Width;
 }
 
 
+
 void
-UiWidget::SetScale(const Ogre::Vector2& scale)
+UiWidget::SetHeight( const float percent, const float height )
 {
-    m_Scale = scale;
-    m_UpdateTransformation = true;
+    m_HeightPercent = percent;
+    m_Height = height;
+    SetUpdateTransformation();
 }
 
 
+
 void
-UiWidget::SetRotation(const float degree)
+UiWidget::GetHeight( float& percent, float& height )
 {
-    m_Rotation = degree;
-    m_UpdateTransformation = true;
+    percent = m_HeightPercent;
+    height = m_Height;
 }
 
 
+
 void
-UiWidget::SetScissor(bool scissor)
+UiWidget::SetScale( const Ogre::Vector2& scale )
 {
-    m_Scissor = scissor;
-    m_UpdateTransformation = true;
+    m_Scale = scale;
+    SetUpdateTransformation();
 }
 
 
-int
-UiWidget::GetScissorTop() const
+
+void
+UiWidget::SetRotation( const float degree )
 {
-    return m_ScissorTop;
+    m_Rotation = degree;
+    SetUpdateTransformation();
 }
 
 
-int
-UiWidget::GetScissorBottom() const
+
+void
+UiWidget::SetScissorArea( const float percent_x1, const float x1, const float percent_y1, const float y1, const float percent_x2, const float x2, const float percent_y2, const float y2 )
 {
-    return m_ScissorBottom;
-}
+    m_LocalScissor = true;
 
+    m_ScissorXPercentTop = percent_x1;
+    m_ScissorXTop = x1;
+    m_ScissorXPercentBottom = percent_x2;
+    m_ScissorXBottom = x2;
+    m_ScissorYPercentLeft = percent_y1;
+    m_ScissorYLeft = y1;
+    m_ScissorYPercentRight = percent_y2;
+    m_ScissorYRight = y2;
 
-int
-UiWidget::GetScissorLeft() const
-{
-    return m_ScissorLeft;
+    SetUpdateTransformation();
 }
 
 
-int
-UiWidget::GetScissorRight() const
+
+void
+UiWidget::SetGlobalScissor( const bool global )
 {
-    return m_ScissorRight;
+    m_GlobalScissor = global;
+    SetUpdateTransformation();
 }
 
 
+
 void
-UiWidget::SetColour(const float r, const float g, const float b)
+UiWidget::SetColour( const float r, const float g, const float b )
 {
     m_Colour1.r = r; m_Colour1.g = g; m_Colour1.b = b;
     m_Colour2.r = r; m_Colour2.g = g; m_Colour2.b = b;
     m_Colour3.r = r; m_Colour3.g = g; m_Colour3.b = b;
     m_Colour4.r = r; m_Colour4.g = g; m_Colour4.b = b;
-    m_UpdateTransformation = true;
+    SetUpdateTransformation();
 }
 
 
+
 void
-UiWidget::SetColours(const float r1, const float g1, const float b1, const float r2, const float g2, const float b2, const float r3, const float g3, const float b3, const float r4, const float g4, const float b4)
+UiWidget::SetColours( const float r1, const float g1, const float b1, const float r2, const float g2, const float b2, const float r3, const float g3, const float b3, const float r4, const float g4, const float b4 )
 {
     m_Colour1.r = r1; m_Colour1.g = g1; m_Colour1.b = b1;
     m_Colour2.r = r2; m_Colour2.g = g2; m_Colour2.b = b2;
     m_Colour3.r = r3; m_Colour3.g = g3; m_Colour3.b = b3;
     m_Colour4.r = r4; m_Colour4.g = g4; m_Colour4.b = b4;
-    m_UpdateTransformation = true;
+    SetUpdateTransformation();
 }
 
 
+
 void
-UiWidget::SetAlpha(const float a)
+UiWidget::SetAlpha( const float a )
 {
     m_Colour1.a = a;
     m_Colour2.a = a;
     m_Colour3.a = a;
     m_Colour4.a = a;
-    m_UpdateTransformation = true;
+    SetUpdateTransformation();
 }

+ 254 - 1
QGearsMain/src/core/Utilites.cpp

@@ -2,12 +2,265 @@
 
 #include "core/Utilites.h"
 
+bool
+GetBool( TiXmlNode* node, const Ogre::String& tag, bool def )
+{
+    bool ret = def;
+
+    if( node->Type() == TiXmlNode::TINYXML_ELEMENT )
+    {
+        const std::string* string = node->ToElement()->Attribute( tag );
+        if( string != NULL )
+        {
+            ret = Ogre::StringConverter::parseBool( *string );
+        }
+    }
+
+    return ret;
+}
+
+
+
+int
+GetInt( TiXmlNode* node, const Ogre::String& tag, int def )
+{
+    int ret = def;
+
+    if( node->Type() == TiXmlNode::TINYXML_ELEMENT )
+    {
+        const std::string* string = node->ToElement()->Attribute( tag );
+        if( string != NULL )
+        {
+            ret = Ogre::StringConverter::parseInt( *string );
+        }
+    }
+
+    return ret;
+}
+
+
+
+float
+GetFloat( TiXmlNode* node, const Ogre::String& tag, float def )
+{
+    float ret = def;
+
+    if( node->Type() == TiXmlNode::TINYXML_ELEMENT )
+    {
+        const std::string* string = node->ToElement()->Attribute( tag );
+        if( string != NULL )
+        {
+            ret = Ogre::StringConverter::parseReal( *string );
+        }
+    }
+
+    return ret;
+}
+
+
+
+const Ogre::String
+GetString( TiXmlNode* node, const Ogre::String& tag, const Ogre::String& def )
+{
+    Ogre::String ret = def;
+
+    if( node->Type() == TiXmlNode::TINYXML_ELEMENT )
+    {
+        const std::string* string = node->ToElement()->Attribute( tag );
+        if( string != NULL )
+        {
+            ret = *string;
+        }
+    }
+
+    return ret;
+}
+
+
+
+const Ogre::UTFString
+GetUTFString( TiXmlNode* node, const Ogre::String& tag, const Ogre::UTFString& def )
+{
+    Ogre::UTFString ret = def;
+
+    if( node->Type() == TiXmlNode::TINYXML_ELEMENT )
+    {
+        const std::string* string = node->ToElement()->Attribute( tag );
+        if( string != NULL )
+        {
+            ret = ( *string ).c_str();
+        }
+    }
+
+    return ret;
+}
+
+
+
+const Ogre::Vector2
+GetVector2( TiXmlNode* node, const Ogre::String& tag, const Ogre::Vector2& def )
+{
+    Ogre::Vector2 ret = def;
+
+    if( node->Type() == TiXmlNode::TINYXML_ELEMENT )
+    {
+        const std::string* string = node->ToElement()->Attribute( tag );
+        if( string != NULL )
+        {
+            ret = Ogre::StringConverter::parseVector2( *string );
+        }
+    }
+
+    return ret;
+}
+
+
+
+const Ogre::Vector3
+GetVector3( TiXmlNode* node, const Ogre::String& tag, const Ogre::Vector3& def )
+{
+    Ogre::Vector3 ret = def;
+
+    if( node->Type() == TiXmlNode::TINYXML_ELEMENT )
+    {
+        const std::string* string = node->ToElement()->Attribute( tag );
+        if( string != NULL )
+        {
+            ret = Ogre::StringConverter::parseVector3( *string );
+        }
+    }
+
+    return ret;
+}
+
+
+
+const Ogre::Vector4
+GetVector4( TiXmlNode* node, const Ogre::String& tag, const Ogre::Vector4& def )
+{
+    Ogre::Vector4 ret = def;
+
+    if( node->Type() == TiXmlNode::TINYXML_ELEMENT )
+    {
+        const std::string* string = node->ToElement()->Attribute( tag );
+        if( string != NULL )
+        {
+            ret = Ogre::StringConverter::parseVector4( *string );
+        }
+    }
+
+    return ret;
+}
+
+
+
+const Ogre::Matrix4
+GetMatrix4( TiXmlNode* node, const Ogre::String& tag, const Ogre::Matrix4& def )
+{
+    Ogre::Matrix4 ret = def;
+
+    if( node->Type() == TiXmlNode::TINYXML_ELEMENT )
+    {
+        const std::string* string = node->ToElement()->Attribute( tag );
+        if( string != NULL )
+        {
+            ret = Ogre::StringConverter::parseMatrix4( *string );
+        }
+    }
+
+    return ret;
+}
+
+
+
+const Ogre::Quaternion
+GetQuaternion( TiXmlNode* node, const Ogre::String& tag, const Ogre::Quaternion& def )
+{
+    Ogre::Quaternion ret = def;
+
+    if( node->Type() == TiXmlNode::TINYXML_ELEMENT )
+    {
+        const std::string* string = node->ToElement()->Attribute( tag );
+        if( string != NULL )
+        {
+            ret = Ogre::StringConverter::parseQuaternion( *string );
+        }
+    }
+
+    return ret;
+}
+
+
+
+const Ogre::ColourValue
+GetColourValue( TiXmlNode* node, const Ogre::String& tag, const Ogre::ColourValue& def )
+{
+    Ogre::ColourValue ret = def;
+
+    if( node->Type() == TiXmlNode::TINYXML_ELEMENT )
+    {
+        const std::string* string = node->ToElement()->Attribute( tag );
+        if( string != NULL )
+        {
+            ret = Ogre::StringConverter::parseColourValue( *string );
+        }
+    }
+
+    return ret;
+}
+
+
+
+void
+ParsePersent( float& value_percent, float& value, const Ogre::String& string )
+{
+    if( string.at( string.size() - 1 ) == '%' )
+    {
+        value_percent = Ogre::StringConverter::parseReal( string.substr( 0, string.size() - 1 ) );
+        value = 0;
+    }
+    else
+    {
+        Ogre::StringVector param = Ogre::StringUtil::split( string, "%" );
+        if( param.size() > 1 )
+        {
+            value_percent = Ogre::StringConverter::parseReal( param[ 0 ] );
+            value = Ogre::StringConverter::parseReal( param[ 1 ] );
+        }
+        else
+        {
+            value_percent = 0;
+            value = Ogre::StringConverter::parseReal( string );
+        }
+    }
+}
+
+
+
+float
+ParseKeyFrameTime( const float length, const Ogre::String& string )
+{
+    float res = 0;
+
+    if( string.at( string.size() - 1 ) == '%' )
+    {
+        res = length * Ogre::StringConverter::parseReal( string.substr( 0, string.size() - 1 ) ) / 100;
+    }
+    else
+    {
+        res = Ogre::StringConverter::parseReal( string );
+    }
+
+    return res;
+}
+
+
 
 const Ogre::String
 CreateAutoName(const Ogre::String prefix)
 {
     static int enumerator = 0;
-    return prefix + Ogre::StringConverter::toString(enumerator++);
+    return prefix + Ogre::StringConverter::toString( enumerator++ );
 }
 
 

+ 2 - 1
QGearsMain/src/core/XmlFontFile.cpp

@@ -27,13 +27,14 @@ XmlFontFile::LoadFont()
     }
 
     Ogre::String name = GetString(node, "name", "");
+    Ogre::String language = GetString( node, "language", "" );
     Ogre::String image = GetString(node, "image", "");
     Ogre::Vector2 size = GetVector2(node, "image_size", Ogre::Vector2::ZERO);
     int height = GetInt(node, "height", 0);
 
     if(name != "" && image != "" && size.x != 0 && size.y != 0)
     {
-        UiFont* font = new UiFont(name);
+        UiFont* font = new UiFont( name, language );
         font->SetImage(image, (int)size.x, (int)size.y);
         font->SetHeight(height);
 

+ 161 - 73
QGearsMain/src/core/XmlScreenFile.cpp

@@ -4,7 +4,10 @@
 #include "core/UiSprite.h"
 #include "core/UiTextArea.h"
 #include "core/UiWidget.h"
+#include "core/TextManager.h"
 #include "core/XmlScreenFile.h"
+#include "core/Utilites.h"
+
 
 
 XmlScreenFile::XmlScreenFile(const Ogre::String& file):
@@ -119,8 +122,11 @@ XmlScreenFile::LoadScreenRecursive(TiXmlNode* node, const Ogre::String& base_nam
                         Ogre::String text = GetString(node, "text_name", "");
                         if(text != "")
                         {
-                            TiXmlNode* utf = UiManager::getSingleton().GetText(text);
-                            ((UiTextArea*)widget2)->SetText(utf);
+                            TiXmlNode* utf = TextManager::getSingleton().GetText( text );
+                            if( utf != nullptr )
+                            {
+                                ( ( UiTextArea* )widget2 )->SetText( utf );
+                            }
                         }
 
                         Ogre::String font = GetString(node, "font", "");
@@ -134,6 +140,11 @@ XmlScreenFile::LoadScreenRecursive(TiXmlNode* node, const Ogre::String& base_nam
                         {
                             ((UiTextArea*)widget2)->SetTextAlign((align == "center") ? UiTextArea::CENTER : ((align == "right") ? UiTextArea::RIGHT : UiTextArea::LEFT));
                         }
+                        Ogre::Vector4 padding = GetVector4( node, "padding", Ogre::Vector4::ZERO );
+                        if( padding != Ogre::Vector4::ZERO )
+                        {
+                            ( ( UiTextArea* )widget2 )->SetPadding( padding.x, padding.y, padding.z, padding.w );
+                        }
                     }
 
                     Ogre::String colours = GetString(node, "colours", "");
@@ -226,7 +237,26 @@ XmlScreenFile::LoadScreenRecursive(TiXmlNode* node, const Ogre::String& base_nam
                     Ogre::Vector2 scale = GetVector2(node, "scale", Ogre::Vector2(1.0f, 1.0f));
                     widget2->SetScale(scale);
                     widget2->SetRotation(GetFloat(node, "rotation", 0.0f));
-                    widget2->SetScissor(GetBool(node, "scissor", false));
+
+                    Ogre::String scissor_area  = GetString( node, "scissor_area" );
+                    if( scissor_area != "" )
+                    {
+                        Ogre::StringVector coords = Ogre::StringUtil::split( scissor_area, " " );
+                        if( coords.size() == 4 )
+                        {
+                            float percent_x1, x1, percent_y1, y1, percent_x2, x2, percent_y2, y2 = 0;
+                            ParsePersent( percent_x1, x1, coords[ 0 ] );
+                            ParsePersent( percent_y1, y1, coords[ 1 ] );
+                            ParsePersent( percent_x2, x2, coords[ 2 ] );
+                            ParsePersent( percent_y2, y2, coords[ 3 ] );
+                            widget2->SetScissorArea( percent_x1, x1, percent_y1, y1, percent_x2, x2, percent_y2, y2 );
+                        }
+                    }
+
+
+
+                    widget2->SetGlobalScissor( GetBool( node, "global_scissor", true ) );
+
                     widget2->SetVisible(GetBool(node, "visible", false));
 
                     if(node->ValueStr() == "sprite")
@@ -260,7 +290,8 @@ XmlScreenFile::LoadScreenRecursive(TiXmlNode* node, const Ogre::String& base_nam
             {
                 UiAnimation* animation = new UiAnimation(name, widget);
 
-                animation->SetLength(GetFloat(node, "length", 0));
+                float anim_length = GetFloat( node, "length", 0 );
+                animation->SetLength( anim_length );
 
                 Ogre::String scale = GetString(node, "scale", "");
                 if(scale != "")
@@ -274,116 +305,173 @@ XmlScreenFile::LoadScreenRecursive(TiXmlNode* node, const Ogre::String& base_nam
                         if(data.size() > 1)
                         {
                             UiKeyFrameVector2 key;
-                            key.time = Ogre::StringConverter::parseReal(data[0]);
-                            key.value = Ogre::StringConverter::parseVector2(data[1]);
-                            animation->AddScaleKeyFrame(key);
+                            key.time = ParseKeyFrameTime( anim_length, data[ 0 ] );
+                            key.value = Ogre::StringConverter::parseVector2( data[ 1 ] );
+                            animation->AddScaleKeyFrame( key );
                         }
                     }
                 }
 
-                Ogre::String x = GetString(node, "x", "");
-                if(x != "")
+
+
+                Ogre::String x = GetString( node, "x", "" );
+                if( x != "" )
                 {
-                    Ogre::StringVector key_frame = Ogre::StringUtil::split(x, ",");
-                    for(unsigned int i = 0; i < key_frame.size(); ++i)
+                    Ogre::StringVector key_frame = Ogre::StringUtil::split( x, "," );
+                    for( unsigned int i = 0; i < key_frame.size(); ++i )
                     {
-                        Ogre::StringUtil::trim(key_frame[i]);
+                        Ogre::StringUtil::trim( key_frame[ i ] );
 
-                        Ogre::StringVector data = Ogre::StringUtil::split(key_frame[i], ":");
-                        if(data.size() > 1)
+                        Ogre::StringVector data = Ogre::StringUtil::split( key_frame[ i ], ":" );
+                        if( data.size() > 1 )
                         {
                             UiKeyFrameVector2 key;
-                            key.time = Ogre::StringConverter::parseReal(data[0]);
-                            key.value = Ogre::StringConverter::parseVector2(data[1]);
-                            animation->AddXKeyFrame(key);
+                            key.time = ParseKeyFrameTime( anim_length, data[ 0 ] );
+                            ParsePersent( key.value.x, key.value.y, data[ 1 ] );
+                            animation->AddXKeyFrame( key );
                         }
                     }
                 }
 
-                Ogre::String y = GetString(node, "y", "");
-                if(y != "")
+
+
+                Ogre::String y = GetString( node, "y", "" );
+                if( y != "" )
                 {
-                    Ogre::StringVector key_frame = Ogre::StringUtil::split(y, ",");
-                    for(unsigned int i = 0; i < key_frame.size(); ++i)
+                    Ogre::StringVector key_frame = Ogre::StringUtil::split( y, "," );
+                    for( unsigned int i = 0; i < key_frame.size(); ++i )
                     {
-                        Ogre::StringUtil::trim(key_frame[i]);
+                        Ogre::StringUtil::trim( key_frame[ i ] );
 
-                        Ogre::StringVector data = Ogre::StringUtil::split(key_frame[i], ":");
-                        if(data.size() > 1)
+                        Ogre::StringVector data = Ogre::StringUtil::split( key_frame[ i ], ":" );
+                        if( data.size() > 1 )
                         {
                             UiKeyFrameVector2 key;
-                            key.time = Ogre::StringConverter::parseReal(data[0]);
-                            key.value = Ogre::StringConverter::parseVector2(data[1]);
-                            animation->AddYKeyFrame(key);
+                            key.time = ParseKeyFrameTime( anim_length, data[ 0 ] );
+                            ParsePersent( key.value.x, key.value.y, data[ 1 ] );
+                            animation->AddYKeyFrame( key );
                         }
                     }
                 }
 
-                Ogre::String rotation = GetString(node, "rotation", "");
-                if(rotation != "")
+
+
+                Ogre::String width = GetString( node, "width", "" );
+                if( width != "" )
                 {
-                    Ogre::StringVector key_frame = Ogre::StringUtil::split(rotation, ",");
-                    for(unsigned int i = 0; i < key_frame.size(); ++i)
+                    Ogre::StringVector key_frame = Ogre::StringUtil::split( width, "," );
+                    for( unsigned int i = 0; i < key_frame.size(); ++i )
                     {
-                        Ogre::StringUtil::trim(key_frame[i]);
+                        Ogre::StringUtil::trim( key_frame[ i ] );
 
-                        Ogre::StringVector data = Ogre::StringUtil::split(key_frame[i], ":");
-                        if(data.size() > 1)
+                        Ogre::StringVector data = Ogre::StringUtil::split( key_frame[ i ], ":" );
+                        if( data.size() > 1 )
+                        {
+                            UiKeyFrameVector2 key;
+                            key.time = ParseKeyFrameTime( anim_length, data[ 0 ] );
+                            ParsePersent( key.value.x, key.value.y, data[ 1 ] );
+                            animation->AddWidthKeyFrame( key );
+                        }
+                    }
+                }
+
+
+
+                Ogre::String height = GetString( node, "height", "" );
+                if( height != "" )
+                {
+                    Ogre::StringVector key_frame = Ogre::StringUtil::split( height, "," );
+                    for( unsigned int i = 0; i < key_frame.size(); ++i )
+                    {
+                        Ogre::StringUtil::trim( key_frame[ i ] );
+
+                        Ogre::StringVector data = Ogre::StringUtil::split( key_frame[ i ], ":" );
+                        if( data.size() > 1 )
+                        {
+                            UiKeyFrameVector2 key;
+                            key.time = ParseKeyFrameTime( anim_length, data[ 0 ] );
+                            ParsePersent( key.value.x, key.value.y, data[ 1 ] );
+                            animation->AddHeightKeyFrame( key );
+                        }
+                    }
+                }
+
+
+
+                Ogre::String rotation = GetString( node, "rotation", "" );
+                if( rotation != "" )
+                {
+                    Ogre::StringVector key_frame = Ogre::StringUtil::split( rotation, "," );
+                    for( unsigned int i = 0; i < key_frame.size(); ++i )
+                    {
+                        Ogre::StringUtil::trim( key_frame[ i ] );
+
+                        Ogre::StringVector data = Ogre::StringUtil::split( key_frame[ i ], ":" );
+                        if( data.size() > 1 )
                         {
                             UiKeyFrameFloat key;
-                            key.time = Ogre::StringConverter::parseReal(data[0]);
-                            key.value = Ogre::StringConverter::parseReal(data[1]);
-                            animation->AddRotationKeyFrame(key);
+                            key.time = ParseKeyFrameTime( anim_length, data[ 0 ] );
+                            key.value = Ogre::StringConverter::parseReal( data[ 1 ] );
+                            animation->AddRotationKeyFrame( key );
                         }
                     }
                 }
 
-                Ogre::String alpha = GetString(node, "alpha", "");
-                if(alpha != "")
+
+
+                Ogre::String alpha = GetString( node, "alpha", "" );
+                if( alpha != "" )
                 {
-                    Ogre::StringVector key_frame = Ogre::StringUtil::split(alpha, ",");
-                    for(unsigned int i = 0; i < key_frame.size(); ++i)
+                    Ogre::StringVector key_frame = Ogre::StringUtil::split( alpha, "," );
+                    for( unsigned int i = 0; i < key_frame.size(); ++i )
                     {
-                        Ogre::StringUtil::trim(key_frame[i]);
+                        Ogre::StringUtil::trim( key_frame[ i ] );
 
-                        Ogre::StringVector data = Ogre::StringUtil::split(key_frame[i], ":");
-                        if(data.size() > 1)
+                        Ogre::StringVector data = Ogre::StringUtil::split( key_frame[ i ], ":" );
+                        if( data.size() > 1 )
                         {
                             UiKeyFrameFloat key;
-                            key.time = Ogre::StringConverter::parseReal(data[0]);
-                            key.value = Ogre::StringConverter::parseReal(data[1]);
-                            animation->AddAlphaKeyFrame(key);
+                            key.time = ParseKeyFrameTime( anim_length, data[ 0 ] );
+                            key.value = Ogre::StringConverter::parseReal( data[ 1 ] );
+                            animation->AddAlphaKeyFrame( key );
                         }
                     }
                 }
-                widget->AddAnimation(animation);
-            }
-        }
-        node = node->NextSibling();
-    }
-}
 
 
-void
-XmlScreenFile::ParsePersent(float& value_percent, float& value, const Ogre::String& string)
-{
-    if(string.at(string.size() - 1) == '%')
-    {
-        value_percent = Ogre::StringConverter::parseReal(string.substr(0, string.size() - 1));
-        value = 0;
-    }
-    else
-    {
-        Ogre::StringVector param = Ogre::StringUtil::split(string, "%");
-        if(param.size() > 1)
-        {
-            value_percent = Ogre::StringConverter::parseReal(param[0]);
-            value = Ogre::StringConverter::parseReal(param[1]);
-        }
-        else
-        {
-            value_percent = 0;
-            value = Ogre::StringConverter::parseReal(string);
+
+                Ogre::String scissor_area = GetString( node, "scissor_area", "" );
+                if( scissor_area != "" )
+                {
+                    Ogre::StringVector key_frame = Ogre::StringUtil::split( scissor_area, "," );
+                    for( unsigned int i = 0; i < key_frame.size(); ++i )
+                    {
+                        Ogre::StringUtil::trim( key_frame[ i ] );
+
+                        Ogre::StringVector data = Ogre::StringUtil::split( key_frame[ i ], ":" );
+                        if( data.size() > 1 )
+                        {
+                            UiKeyFrameVector2 key1, key2, key3, key4;
+                            key1.time = ParseKeyFrameTime( anim_length, data[ 0 ] );
+                            key2.time = key1.time;
+                            key3.time = key1.time;
+                            key4.time = key1.time;
+                            Ogre::StringVector keys = Ogre::StringUtil::split( data[ 1 ], " " );
+                            float percent_x1, x1, percent_y1, y1, percent_x2, x2, percent_y2, y2 = 0;
+                            ParsePersent( key1.value.x, key1.value.y, keys[ 0 ] );
+                            ParsePersent( key2.value.x, key2.value.y, keys[ 1 ] );
+                            ParsePersent( key3.value.x, key3.value.y, keys[ 2 ] );
+                            ParsePersent( key4.value.x, key4.value.y, keys[ 3 ] );
+                            animation->AddScissorKeyFrame( key1, key2, key3, key4 );
+                        }
+                    }
+                }
+
+
+
+                widget->AddAnimation( animation );
+            }
         }
+        node = node->NextSibling();
     }
 }

+ 16 - 3
QGearsMain/src/core/XmlScreensFile.cpp

@@ -1,6 +1,7 @@
 #include "core/Logger.h"
 #include "core/XmlScreenFile.h"
 #include "core/XmlScreensFile.h"
+#include "core/XmlPrototypesFile.h"
 
 
 XmlScreensFile::XmlScreensFile(const Ogre::String& file):
@@ -19,14 +20,26 @@ XmlScreensFile::LoadScreens()
 {
     TiXmlNode* node = m_File.RootElement();
 
-    if(node == nullptr || node->ValueStr() != "screens")
+    if( node == nullptr || node->ValueStr() != "ui" )
     {
-        LOG_ERROR("UI XML Manager: " + m_File.ValueStr() + " is not a valid screens file! No <screens> in root.");
+        LOG_ERROR( "UI XML Manager: " + m_File.ValueStr() + " is not a valid ui file! No <ui> in root." );
         return;
     }
 
     node = node->FirstChild();
-    while(node != nullptr)
+    while( node != nullptr )
+    {
+        if( node->Type() == TiXmlNode::TINYXML_ELEMENT && node->ValueStr() == "prototype" )
+        {
+            XmlPrototypesFile prototypes( "./data/" + GetString( node, "file_name" ) );
+            prototypes.LoadPrototypes();
+        }
+        node = node->NextSibling();
+    }
+
+    node = m_File.RootElement();
+    node = node->FirstChild();
+    while( node != NULL )
     {
         if(node->Type() == TiXmlNode::TINYXML_ELEMENT && node->ValueStr() == "screen")
         {

+ 11 - 4
QGearsMain/src/core/XmlTextFile.cpp

@@ -1,6 +1,7 @@
 #include "core/Logger.h"
 #include "core/UiManager.h"
 #include "core/XmlTextFile.h"
+#include "core/TextManager.h"
 
 
 XmlTextFile::XmlTextFile(const Ogre::String& file):
@@ -15,13 +16,13 @@ XmlTextFile::~XmlTextFile()
 
 
 void
-XmlTextFile::LoadText()
+XmlTextFile::LoadTexts()
 {
     TiXmlNode* node = m_File.RootElement();
 
     if(node == nullptr || node->ValueStr() != "texts")
     {
-        LOG_ERROR("UI Manager: " + m_File.ValueStr() + " is not a valid text file! No <texts> in root.");
+        LOG_ERROR( "Text Manager: " + m_File.ValueStr() + " is not a valid text file! No <texts> in root." );
         return;
     }
 
@@ -31,9 +32,15 @@ XmlTextFile::LoadText()
         if(node->Type() == TiXmlNode::TINYXML_ELEMENT && node->ValueStr() == "text")
         {
             Ogre::String name = GetString(node, "name");
-            UiManager::getSingleton().AddText(name, node->Clone());
+            TextManager::getSingleton().AddText( name, node->Clone() );
+        }
+        else if( node->Type() == TiXmlNode::TINYXML_ELEMENT && node->ValueStr() == "dialog" )
+        {
+            Ogre::String name = GetString( node, "name" );
+            float width = GetFloat( node, "width" );
+            float height = GetFloat( node, "height" );
+            TextManager::getSingleton().AddDialog( name, node->Clone(), width, height );
         }
-
         node = node->NextSibling();
     }
 }

+ 41 - 14
QGearsMain/src/core/XmlTextsFile.cpp

@@ -1,7 +1,7 @@
 #include "core/Logger.h"
 #include "core/XmlTextFile.h"
 #include "core/XmlTextsFile.h"
-
+#include "core/TextManager.h"
 
 XmlTextsFile::XmlTextsFile( const Ogre::String& file):
     XmlFile( file)
@@ -14,38 +14,65 @@ XmlTextsFile::~XmlTextsFile()
 }
 
 
+
 void
-XmlTextsFile::LoadTexts( const Ogre::String& language)
+XmlTextsFile::GetAvailableLanguages( Ogre::StringVector& languages )
 {
     TiXmlNode* node = m_File.RootElement();
 
-    if( node == nullptr || node->ValueStr() != "texts")
+    if( node == NULL || node->ValueStr() != "texts" )
     {
-        LOG_ERROR( "UI Text Manager: " + m_File.ValueStr() + " is not a valid texts file! No <texts> in root.");
+        LOG_ERROR( "UI Text Manager: " + m_File.ValueStr() + " is not a valid texts file! No <texts> in root." );
         return;
     }
 
     node = node->FirstChild();
-    while( node != nullptr)
+    while( node != NULL )
+    {
+        if( node->Type() == TiXmlNode::TINYXML_ELEMENT && node->ValueStr() == "language" )
+        {
+            languages.push_back( GetString( node, "name" ) );
+        }
+        node = node->NextSibling();
+    }
+}
+
+
+
+void
+XmlTextsFile::LoadTexts()
+{
+    TiXmlNode* node = m_File.RootElement();
+
+    if( node == NULL || node->ValueStr() != "texts" )
+    {
+        LOG_ERROR( "Text Manager: " + m_File.ValueStr() + " is not a valid texts file! No <texts> in root." );
+        return;
+    }
+
+    Ogre::String language = TextManager::getSingleton().GetLanguage();
+
+    node = node->FirstChild();
+    while( node != nullptr )
     {
-        if( node->Type() == TiXmlNode::TINYXML_ELEMENT && node->ValueStr() == "language")
+        if( node->Type() == TiXmlNode::TINYXML_ELEMENT && node->ValueStr() == "language" )
         {
-            if( GetString( node, "name") == language)
+            if( GetString( node, "name" ) == language )
             {
                 TiXmlNode* node2 = node->FirstChild();
-                while( node2 != nullptr)
+                while( node2 != nullptr )
                 {
-                    if( node2->Type() == TiXmlNode::TINYXML_ELEMENT && node2->ValueStr() == "text")
+                    if( node2->Type() == TiXmlNode::TINYXML_ELEMENT && node2->ValueStr() == "text" )
                     {
-                        Ogre::String file = GetString( node2, "file");
-                        if( file != "")
+                        Ogre::String file = GetString( node2, "file" );
+                        if( file != "" )
                         {
-                            XmlTextFile text( "./data/" + file);
-                            text.LoadText();
+                            XmlTextFile text( "./data/" + file );
+                            text.LoadTexts();
                         }
                         else
                         {
-                            LOG_ERROR( "Empty filename in language " + language + ".");
+                            LOG_ERROR( "Empty filename in language " + language + "." );
                         }
                     }
                     node2 = node2->NextSibling();

+ 27 - 22
utilities/ffvii_field_dat_dumper/src/DatFile.cpp

@@ -141,14 +141,14 @@ static const unsigned short japanese_chars[256] = {
 
 static const unsigned short japanese_chars_fa[256] = {
     // 0    1       2       3       4       5       6       7       8       9       A       B       C       D       E       F
-    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x00 - 0x0F
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x2759, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x00 - 0x0F
     0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x10 - 0x1F
     0x0672, 0x7F4F, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x3478, 0x4466, 0x8364, 0x0000, 0x0000, 0x0000, // 0x20 - 0x2F
     0x0000, 0x0000, 0x0000, 0x0000, 0x666B, 0x5E79, 0x0000, 0x0000, 0xA898, 0x0000, 0x176C, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x30 - 0x3F
     0x885B, 0x0000, 0x7D54, 0x0000, 0xD552, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x6297, 0x0000, 0x0000, 0x0000, 0x0854, 0x0000, // 0x40 - 0x4F
     0x0000, 0x0000, 0x0E66, 0x0000, 0x0000, 0x9C62, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x004E, 0x0000, 0x0580, // 0x50 - 0x5F
     0x0000, 0x0000, 0x857F, 0x0000, 0x0000, 0x0000, 0x9950, 0x6856, 0x0000, 0x549B, 0xD56C, 0x0000, 0x0000, 0x0000, 0x0000, 0xFA51, // 0x60 - 0x6F
-    0x0163, 0xF876, 0x4B62, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xB965, 0x4C88, 0x0000, // 0x70 - 0x7F
+    0x0163, 0xF876, 0x4B62, 0x0000, 0xBA78, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xB965, 0x4C88, 0x0000, // 0x70 - 0x7F
     0x9A5B, 0x0000, 0x0000, 0x4D52, 0x1F77, 0x0000, 0x9A89, 0x1752, 0x8C5F, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xDE56, 0x0000, // 0x80 - 0x8F
     0x9A7D, 0x7565, 0x0000, 0x0000, 0x0000, 0x0000, 0x3E5C, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0882, 0x0000, 0x0000, // 0x90 - 0x9F
     0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x3E5F, 0x0000, 0x0000, 0x0000, 0x4266, 0x0000, 0x0000, 0x2662, 0x0000, // 0xA0 - 0xAF
@@ -166,12 +166,12 @@ static const unsigned short japanese_chars_fb[256] = {
     0x0000, 0x0000, 0xB182, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0B4E, 0x0000, 0x6551, 0x4851, 0x0D4E, 0x505B, 0x9B4F, 0x4B5C, // 0x00 - 0x0F
     0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x8E96, 0x0000, 0x0000, 0xE890, 0x0000, 0x3458, 0x0000, 0xF24E, 0x9395, 0x0000, 0x0000, // 0x10 - 0x1F
     0x5096, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x554F, 0x0000, 0x9965, 0x0000, 0x0A4E, 0x0000, 0x8B4E, 0x0000, 0x0000, // 0x20 - 0x2F
-    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x6559, 0x0000, 0x0000, 0x0000, 0x0000, 0x5167, 0x0000, 0x0000, 0x0000, 0x0000, // 0x30 - 0x3F
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x6559, 0x0000, 0x0000, 0x0000, 0x1D52, 0x5167, 0x0000, 0x0000, 0x0000, 0x0000, // 0x30 - 0x3F
     0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x40 - 0x4F
     0x0000, 0x0000, 0xCA8E, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xBA87, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x50 - 0x5F
     0x0000, 0x7751, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xB672, 0x4B61, 0x0000, // 0x60 - 0x6F
     0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x8B95, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x70 - 0x7F
-    0x0000, 0x0C54, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x7354, 0x0000, 0x0000, 0x0000, 0x0D50, 0x0000, 0x0000, 0x0000, // 0x80 - 0x8F
+    0x0000, 0x0C54, 0x1F90, 0x4590, 0x0000, 0x0000, 0x0000, 0x0000, 0x7354, 0x0000, 0x0000, 0x0000, 0x0D50, 0x0000, 0x0000, 0x0000, // 0x80 - 0x8F
     0x0000, 0xBA4E, 0xCA4E, 0x0000, 0x0000, 0x535F, 0x0000, 0x0000, 0xDB98, 0xE54E, 0x1659, 0x0000, 0x0000, 0x0000, 0xAB8E, 0x0000, // 0x90 - 0x9F
     0xCB65, 0x0000, 0x0000, 0x0000, 0x5F6A, 0xB068, 0x0000, 0x8970, 0xB065, 0x214E, 0x2C67, 0x1B54, 0x0000, 0x8551, 0x5C4F, 0x668B, // 0xA0 - 0xAF
     0x7972, 0x0000, 0x0000, 0x0000, 0x747A, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xB38D, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0xB0 - 0xBF
@@ -188,8 +188,8 @@ static const unsigned short japanese_chars_fc[256] = {
     0x0000, 0x0000, 0x188A, 0x0000, 0x7890, 0x6A75, 0x5788, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x00 - 0x0F
     0x9358, 0xC35F, 0x0000, 0x0000, 0x0000, 0x0000, 0x5390, 0x0000, 0x0000, 0x0000, 0x0000, 0xFB5D, 0x0000, 0x0000, 0x0000, 0x0000, // 0x10 - 0x1F
     0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x884E, 0x0000, 0x3D84, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x20 - 0x2F
-    0xE565, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x30 - 0x3F
-    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x296E, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x40 - 0x4F
+    0xE565, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xE353, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x30 - 0x3F
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x296E, 0x0000, 0x0000, 0x0000, 0x0000, 0x708D, 0x0000, 0x0000, 0x0000, 0x0000, // 0x40 - 0x4F
     0x0000, 0x0000, 0x7153, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x008A, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x50 - 0x5F
     0x3159, 0x5765, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x60 - 0x6F
     0x0000, 0x0000, 0xBC62, 0x0000, 0x0000, 0x0000, 0x5965, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x70 - 0x7F
@@ -209,15 +209,15 @@ static const unsigned short japanese_chars_fd[256] = {
     // 0    1       2       3       4       5       6       7       8       9       A       B       C       D       E       F
     0x0000, 0x1D4F, 0x0000, 0xA263, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x00 - 0x0F
     0xE682, 0x0000, 0xF056, 0x0000, 0x0000, 0x0000, 0x0000, 0xA25B, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x10 - 0x1F
-    0x0000, 0x2B59, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xB88C, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xDD4F, 0x2F5E, // 0x20 - 0x2F
-    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x7289, 0x0000, 0x216B, 0x0000, 0x207D, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x30 - 0x3F
+    0x0000, 0x2B59, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xB88C, 0x1F67, 0x0000, 0x0000, 0x0000, 0x0000, 0xDD4F, 0x2F5E, // 0x20 - 0x2F
+    0x0000, 0x0000, 0x0000, 0x1154, 0x0000, 0x0000, 0x7289, 0x0000, 0x216B, 0x0000, 0x207D, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x30 - 0x3F
     0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xB78C, 0x0000, 0x0000, 0x0000, 0x7C5E, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x40 - 0x4F
     0x0000, 0x0000, 0x0000, 0x0000, 0x8179, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x50 - 0x5F
     0x0000, 0x975E, 0x0000, 0x0000, 0x0000, 0xCA7D, 0x1478, 0x0000, 0x0000, 0x8766, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x60 - 0x6F
     0xC599, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x70 - 0x7F
     0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xFD88, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x80 - 0x8F
     0x0000, 0x0000, 0x3293, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x5453, 0x0000, 0x0000, // 0x90 - 0x9F
-    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x8D8E, 0x0000, 0x0000, 0x0000, 0x0000, 0x3052, 0x0000, 0x0000, 0x0000, 0x0000, // 0xA0 - 0xAF
+    0x0000, 0x0000, 0x0000, 0x0000, 0x3181, 0x0000, 0x8D8E, 0x0000, 0x0000, 0x0000, 0x0000, 0x3052, 0x0000, 0x0000, 0x0000, 0x0000, // 0xA0 - 0xAF
     0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0xB0 - 0xBF
     0x9F52, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x5291, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0xC0 - 0xCF
     0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0xD0 - 0xDF
@@ -374,19 +374,19 @@ DatFile::DumpText( const Ogre::String& export_path, const Field& field, bool eng
             {
                 export_text->Log(dialog);
                 dialog.clear();
-                export_text->LogW("<new_window />");
+                export_text->LogW("<next_page />");
             }
             else if (temp == 0xEA)
             {
                 export_text->Log(dialog);
                 dialog.clear();
-                export_text->LogW("<character id=\"0\" />");
+                export_text->LogW("<include name=\"char_cloud\" />");
             }
             else if (temp == 0xEB)
             {
                 export_text->Log(dialog);
                 dialog.clear();
-                export_text->LogW("<character id=\"1\" />");
+                export_text->LogW("<include name=\"char_barret\" />");
             }
             else if (temp == 0xEC)
             {
@@ -452,25 +452,25 @@ DatFile::DumpText( const Ogre::String& export_path, const Field& field, bool eng
             {
                 export_text->Log(dialog);
                 dialog.clear();
-                export_text->LogW("<image id=\"circle\" />");
+                export_text->LogW("<image sprite=\"ButtonCircle\" />");
             }
             else if (temp == 0xF7)
             {
                 export_text->Log(dialog);
                 dialog.clear();
-                export_text->LogW("<image id=\"triangle\" />");
+                export_text->LogW("<image sprite=\"ButtonTriangle\" />");
             }
             else if (temp == 0xF8)
             {
                 export_text->Log(dialog);
                 dialog.clear();
-                export_text->LogW("<image id=\"square\" />");
+                export_text->LogW("<image sprite=\"ButtonSquare\" />");
             }
             else if (temp == 0xF9)
             {
                 export_text->Log(dialog);
                 dialog.clear();
-                export_text->LogW("<image id=\"cross\" />");
+                export_text->LogW("<image sprite=\"ButtonCross\" />");
             }
             else if ((temp == 0xFA || temp == 0xFB ||temp == 0xFC ||temp == 0xFD) && english == false)
             {
@@ -570,7 +570,7 @@ DatFile::DumpText( const Ogre::String& export_path, const Field& field, bool eng
                 {
                     export_text->Log(dialog);
                     dialog.clear();
-                    export_text->LogW("<colour id=\"white\" />");
+                    export_text->LogW("</colour>");
                 }
                 else if (temp2 == 0xDC)
                 {
@@ -585,7 +585,7 @@ DatFile::DumpText( const Ogre::String& export_path, const Field& field, bool eng
                     ++offset;
                     export_text->Log(dialog);
                     dialog.clear();
-                    export_text->LogW("<pause wait=\"" + IntToString(wait) + "\" />");
+                    export_text->LogW("<pause time=\"" + IntToString(wait) + "\" />");
                 }
                 else
                 {
@@ -1749,7 +1749,12 @@ DatFile::DumpScript(const Ogre::String& export_path, const Field& field)
 
                 case XYZI:
                 {
-                    export_script->Log(entity_list[i] + ":set_position( " + ParseGetVariable(GetU8(script + 1) >> 4, (s16)GetU16LE(script + 3), 0, downscaler) + ", " + ParseGetVariable(GetU8(script + 1) & 0x0F, (s16)GetU16LE(script + 5), 0, downscaler) + ", " + ParseGetVariable(GetU8(script + 2) >> 4, (s16)GetU16LE(script + 7), 0, downscaler) + " ) -- triangle_id=" + ParseGetVariable(GetU8(script + 2) & 0x0F, (s16)GetU16LE(script + 9)) + "\n");
+                    export_script->Log(entity_list[i] + ":set_position( " +
+                        
+                        ParseGetVariable(GetU8(script + 1) >> 4,   (s16)GetU16LE(script + 3), 0, downscaler) + ", " + 
+                        ParseGetVariable(GetU8(script + 1) & 0x0F, (s16)GetU16LE(script + 5), 0, downscaler) + ", " + 
+                        ParseGetVariable(GetU8(script + 2) >> 4,   (s16)GetU16LE(script + 7), 0, downscaler) + 
+                        " ) -- triangle_id=" + ParseGetVariable(GetU8(script + 2) & 0x0F, (s16)GetU16LE(script + 9)) + "\n");
                     AdvanceScript(11, script, end);
                 } break;
 
@@ -2766,9 +2771,9 @@ DatFile::GetCamera( Ogre::Vector3& position, Ogre::Quaternion& orientation, Ogre
     matrix[ 1 ][ 2 ] = ( s16 )GetU16LE( offset_to_camera + 0x0e ) / 4096.0f;
     matrix[ 2 ][ 2 ] = ( s16 )GetU16LE( offset_to_camera + 0x12 ) / 4096.0f;
     // get camera position in camera space
-    position.x = -(s32)GetU32LE(offset_to_camera + 0x14);// / downscaler;
-    position.y = -(s32)GetU32LE(offset_to_camera + 0x18);// / downscaler;
-    position.z = -(s32)GetU32LE(offset_to_camera + 0x1c);// / downscaler;
+    position.x  = -( s32 )GetU32LE( offset_to_camera + 0x14 ) / downscaler;
+    position.y  = -( s32 )GetU32LE( offset_to_camera + 0x18 ) / downscaler;
+    position.z  = -( s32 )GetU32LE( offset_to_camera + 0x1c ) / downscaler;
 
     orientation.FromRotationMatrix( matrix );
     position = orientation * position;

+ 11 - 11
utilities/ffvii_font_exporter/src/FontFile.cpp

@@ -51,14 +51,14 @@ unsigned short japanese_chars[256] = {
 
 unsigned short japanese_chars_fa[256] = {
     // 0    1       2       3       4       5       6       7       8       9       A       B       C       D       E       F
-    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x00 - 0x0F
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x2759, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x00 - 0x0F
     0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x10 - 0x1F
     0x0672, 0x7F4F, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x3478, 0x4466, 0x8364, 0x0000, 0x0000, 0x0000, // 0x20 - 0x2F
     0x0000, 0x0000, 0x0000, 0x0000, 0x666B, 0x5E79, 0x0000, 0x0000, 0xA898, 0x0000, 0x176C, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x30 - 0x3F
     0x885B, 0x0000, 0x7D54, 0x0000, 0xD552, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x6297, 0x0000, 0x0000, 0x0000, 0x0854, 0x0000, // 0x40 - 0x4F
     0x0000, 0x0000, 0x0E66, 0x0000, 0x0000, 0x9C62, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x004E, 0x0000, 0x0580, // 0x50 - 0x5F
     0x0000, 0x0000, 0x857F, 0x0000, 0x0000, 0x0000, 0x9950, 0x6856, 0x0000, 0x549B, 0xD56C, 0x0000, 0x0000, 0x0000, 0x0000, 0xFA51, // 0x60 - 0x6F
-    0x0163, 0xF876, 0x4B62, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xB965, 0x4C88, 0x0000, // 0x70 - 0x7F
+    0x0163, 0xF876, 0x4B62, 0x0000, 0xBA78, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xB965, 0x4C88, 0x0000, // 0x70 - 0x7F
     0x9A5B, 0x0000, 0x0000, 0x4D52, 0x1F77, 0x0000, 0x9A89, 0x1752, 0x8C5F, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xDE56, 0x0000, // 0x80 - 0x8F
     0x9A7D, 0x7565, 0x0000, 0x0000, 0x0000, 0x0000, 0x3E5C, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0882, 0x0000, 0x0000, // 0x90 - 0x9F
     0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x3E5F, 0x0000, 0x0000, 0x0000, 0x4266, 0x0000, 0x0000, 0x2662, 0x0000, // 0xA0 - 0xAF
@@ -76,12 +76,12 @@ unsigned short japanese_chars_fb[256] = {
     0x0000, 0x0000, 0xB182, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0B4E, 0x0000, 0x6551, 0x4851, 0x0D4E, 0x505B, 0x9B4F, 0x4B5C, // 0x00 - 0x0F
     0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x8E96, 0x0000, 0x0000, 0xE890, 0x0000, 0x3458, 0x0000, 0xF24E, 0x9395, 0x0000, 0x0000, // 0x10 - 0x1F
     0x5096, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x554F, 0x0000, 0x9965, 0x0000, 0x0A4E, 0x0000, 0x8B4E, 0x0000, 0x0000, // 0x20 - 0x2F
-    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x6559, 0x0000, 0x0000, 0x0000, 0x0000, 0x5167, 0x0000, 0x0000, 0x0000, 0x0000, // 0x30 - 0x3F
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x6559, 0x0000, 0x0000, 0x0000, 0x1D52, 0x5167, 0x0000, 0x0000, 0x0000, 0x0000, // 0x30 - 0x3F
     0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x40 - 0x4F
     0x0000, 0x0000, 0xCA8E, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xBA87, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x50 - 0x5F
     0x0000, 0x7751, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xB672, 0x4B61, 0x0000, // 0x60 - 0x6F
     0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x8B95, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x70 - 0x7F
-    0x0000, 0x0C54, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x7354, 0x0000, 0x0000, 0x0000, 0x0D50, 0x0000, 0x0000, 0x0000, // 0x80 - 0x8F
+    0x0000, 0x0C54, 0x1F90, 0x4590, 0x0000, 0x0000, 0x0000, 0x0000, 0x7354, 0x0000, 0x0000, 0x0000, 0x0D50, 0x0000, 0x0000, 0x0000, // 0x80 - 0x8F
     0x0000, 0xBA4E, 0xCA4E, 0x0000, 0x0000, 0x535F, 0x0000, 0x0000, 0xDB98, 0xE54E, 0x1659, 0x0000, 0x0000, 0x0000, 0xAB8E, 0x0000, // 0x90 - 0x9F
     0xCB65, 0x0000, 0x0000, 0x0000, 0x5F6A, 0xB068, 0x0000, 0x8970, 0xB065, 0x214E, 0x2C67, 0x1B54, 0x0000, 0x8551, 0x5C4F, 0x668B, // 0xA0 - 0xAF
     0x7972, 0x0000, 0x0000, 0x0000, 0x747A, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xB38D, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0xB0 - 0xBF
@@ -98,8 +98,8 @@ unsigned short japanese_chars_fc[256] = {
     0x0000, 0x0000, 0x188A, 0x0000, 0x7890, 0x6A75, 0x5788, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x00 - 0x0F
     0x9358, 0xC35F, 0x0000, 0x0000, 0x0000, 0x0000, 0x5390, 0x0000, 0x0000, 0x0000, 0x0000, 0xFB5D, 0x0000, 0x0000, 0x0000, 0x0000, // 0x10 - 0x1F
     0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x884E, 0x0000, 0x3D84, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x20 - 0x2F
-    0xE565, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x30 - 0x3F
-    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x296E, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x40 - 0x4F
+    0xE565, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xE353, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x30 - 0x3F
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x296E, 0x0000, 0x0000, 0x0000, 0x0000, 0x708D, 0x0000, 0x0000, 0x0000, 0x0000, // 0x40 - 0x4F
     0x0000, 0x0000, 0x7153, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x008A, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x50 - 0x5F
     0x3159, 0x5765, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x60 - 0x6F
     0x0000, 0x0000, 0xBC62, 0x0000, 0x0000, 0x0000, 0x5965, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x70 - 0x7F
@@ -119,15 +119,15 @@ unsigned short japanese_chars_fd[256] = {
     // 0    1       2       3       4       5       6       7       8       9       A       B       C       D       E       F
     0x0000, 0x1D4F, 0x0000, 0xA263, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x00 - 0x0F
     0xE682, 0x0000, 0xF056, 0x0000, 0x0000, 0x0000, 0x0000, 0xA25B, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x10 - 0x1F
-    0x0000, 0x2B59, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xB88C, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xDD4F, 0x2F5E, // 0x20 - 0x2F
-    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x7289, 0x0000, 0x216B, 0x0000, 0x207D, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x30 - 0x3F
+    0x0000, 0x2B59, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xB88C, 0x1F67, 0x0000, 0x0000, 0x0000, 0x0000, 0xDD4F, 0x2F5E, // 0x20 - 0x2F
+    0x0000, 0x0000, 0x0000, 0x1154, 0x0000, 0x0000, 0x7289, 0x0000, 0x216B, 0x0000, 0x207D, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x30 - 0x3F
     0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xB78C, 0x0000, 0x0000, 0x0000, 0x7C5E, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x40 - 0x4F
     0x0000, 0x0000, 0x0000, 0x0000, 0x8179, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x50 - 0x5F
     0x0000, 0x975E, 0x0000, 0x0000, 0x0000, 0xCA7D, 0x1478, 0x0000, 0x0000, 0x8766, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x60 - 0x6F
     0xC599, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x70 - 0x7F
     0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xFD88, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x80 - 0x8F
     0x0000, 0x0000, 0x3293, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x5453, 0x0000, 0x0000, // 0x90 - 0x9F
-    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x8D8E, 0x0000, 0x0000, 0x0000, 0x0000, 0x3052, 0x0000, 0x0000, 0x0000, 0x0000, // 0xA0 - 0xAF
+    0x0000, 0x0000, 0x0000, 0x0000, 0x3181, 0x0000, 0x8D8E, 0x0000, 0x0000, 0x0000, 0x0000, 0x3052, 0x0000, 0x0000, 0x0000, 0x0000, // 0xA0 - 0xAF
     0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0xB0 - 0xBF
     0x9F52, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x5291, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0xC0 - 0xCF
     0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0xD0 - 0xDF
@@ -210,7 +210,7 @@ FontFile::Export( const Ogre::String &export_file, bool english )
 
     if( english == true )
     {
-        export_text->LogW( "<font name=\"FFVIIFont\" image=\"ui/fonts/ffvii_en.png\" image_size=\"256 256\" height=\"16\">\n" );
+        export_text->LogW( "<font name=\"FFVIIFont\" language=\"English\" image=\"fonts/ffvii_en.png\" image_size=\"256 256\" height=\"16\">\n" );
 
         for (int i = 0; i < 256; ++i)
         {
@@ -240,7 +240,7 @@ FontFile::Export( const Ogre::String &export_file, bool english )
     }
     else
     {
-        export_text->LogW( "<font name=\"FFVIIFont\" image=\"ui/fonts/ffvii_jp.png\" image_size=\"512 256\" height=\"16\">\n" );
+        export_text->LogW( "<font name=\"FFVIIFont\" language=\"Japanese\" image=\"fonts/ffvii_jp.png\" image_size=\"512 256\" height=\"16\">\n" );
 
         for (int i = 0; i < 256; ++i)
         {