diff --git a/src/action/action_build.cpp b/src/action/action_build.cpp
index 9756b6c61..566d7e6e5 100644
--- a/src/action/action_build.cpp
+++ b/src/action/action_build.cpp
@@ -115,7 +115,7 @@ global void HandleActionBuild(Unit* unit)
     if( !CanBuildUnitType(unit,type,x,y) ) {
 	// FIXME: use general notify/messages
         if( unit->Player==ThisPlayer ) {
-	    SetMessage("You cannot build here.");
+	    SetMessage("You cannot build %s here.", type->Name);
 	} else {
 	    AiCanNotBuild(unit,type);
 	}
@@ -252,7 +252,7 @@ global void HandleActionBuilded(Unit* unit)
 
 	// FIXME: General message system
 	if( unit->Player==ThisPlayer ) {
-	    SetMessage("Work complete");
+	    SetMessage2( unit->X, unit->Y, "New %s done", type->Name );
 	    PlayUnitSound(peon,VoiceWorkCompleted);
 	} else {
 	    AiWorkComplete(peon,unit);
diff --git a/src/action/action_research.cpp b/src/action/action_research.cpp
index 4b7fae4b4..fa47c06c8 100644
--- a/src/action/action_research.cpp
+++ b/src/action/action_research.cpp
@@ -45,7 +45,7 @@ global void HandleActionResearch(Unit* unit)
     if( unit->Command.Data.Research.Ticks>=upgrade->Costs[TimeCost] ) {
 
 	// FIXME: should als speak and tell ai
-	SetMessage("Upgrade complete");
+	SetMessage2( unit->X, unit->Y, "%s: Upgrade complete", unit->Type->Name );
 
         UpgradeAcquire(unit->Player,upgrade);
 
diff --git a/src/action/action_train.cpp b/src/action/action_train.cpp
index 8897b13cd..b43f02c13 100644
--- a/src/action/action_train.cpp
+++ b/src/action/action_train.cpp
@@ -101,7 +101,7 @@ global void HandleActionTrain(Unit* unit)
 
 	// FIXME: GameMessage
 	if( player==ThisPlayer ) {
-	    SetMessage("Training complete");
+	    SetMessage2( nunit->X, nunit->Y, "New %s ready", nunit->Type->Name);
 	    PlayUnitSound(nunit,VoiceReady);
 	} else {
 	    AiTrainingComplete(unit,nunit);
diff --git a/src/action/action_upgradeto.cpp b/src/action/action_upgradeto.cpp
index 50d19222a..47a689e47 100644
--- a/src/action/action_upgradeto.cpp
+++ b/src/action/action_upgradeto.cpp
@@ -64,7 +64,7 @@ global void HandleActionUpgradeTo(Unit* unit)
 
 	// FIXME: SendNotify("upgrade-complete");
 	if( player==ThisPlayer ) {
-	    SetMessage("Upgrade complete");
+	    SetMessage2( unit->X, unit->Y, "Upgrade to %s complete", unit->Type->Name );
 	} else {
 	    // FIXME: AiUpgradeToComplete(unit,type);
 	}
diff --git a/src/include/freecraft.h b/src/include/freecraft.h
index 48c0c52d5..05da69698 100644
--- a/src/include/freecraft.h
+++ b/src/include/freecraft.h
@@ -297,9 +297,11 @@ extern int SyncRand(void);
 extern int main1(int argc,char* argv[]);/// init freecraft.
 extern volatile void Exit(int err);	/// exit freecraft.
 
-extern void SetMessage(char* message);
+extern void SetMessage( char* fmt, ... );
+extern void SetMessage2( int x, int y, char* fmt, ... );
 extern void SetMessageDup(const char* message);
 extern void SetMessageDupCat(const char* message);
+extern void CenterOnMessage();
 extern void ClearMessage(void);
 extern void SetStatusLine(char* status);
 extern void ClearStatusLine(void);
diff --git a/src/include/interface.h b/src/include/interface.h
index 19c8f873d..3d3b74b81 100644
--- a/src/include/interface.h
+++ b/src/include/interface.h
@@ -255,7 +255,7 @@ extern void DrawMessage(void);
 
 extern void DrawResources(void);
 extern void DrawMessage(void);
-extern void SetMessage(char* message);
+extern void SetMessage( char* fmt, ... );
 extern void ClearMessage(void);
 extern void DrawStatusLine(void);
 extern void DrawCosts(void);
diff --git a/src/stratagus/interface.cpp b/src/stratagus/interface.cpp
index e4ea523b2..7a8ba8c31 100644
--- a/src/stratagus/interface.cpp
+++ b/src/stratagus/interface.cpp
@@ -194,6 +194,10 @@ local int CommandKey(int key)
 	    ToggleGrabMouse();
 	    break;
 
+        case ' ':
+            CenterOnMessage();
+            break; 
+
 //	TAB toggles minimap.
 //	FIXME: more...
 	case '\t':
diff --git a/src/stratagus/player.cpp b/src/stratagus/player.cpp
index c88790c7a..b17886f40 100644
--- a/src/stratagus/player.cpp
+++ b/src/stratagus/player.cpp
@@ -329,7 +329,7 @@ global int PlayerCheckCosts(const Player* player,const int* costs)
 			,DEFAULT_NAMES[i],DEFAULT_ACTIONS[i],DEFAULT_NAMES[i]);
 		//	FIXME: use the general notify function vor this
 		if( player==ThisPlayer ) {
-		    SetMessageDup(buf);
+		    SetMessageDup(buf); //FIXME: vladi: can SetMessage be used instead?
 		} else {
 		    DebugLevel3("Ai: %s.\n",buf);
 		}
diff --git a/src/ui/mainscr.cpp b/src/ui/mainscr.cpp
index a548c1322..791c59831 100644
--- a/src/ui/mainscr.cpp
+++ b/src/ui/mainscr.cpp
@@ -20,6 +20,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <stdarg.h>
 
 #include "freecraft.h"
 #include "video.h"
@@ -34,6 +35,7 @@
 #include "icons.h"
 #include "interface.h"
 #include "ui.h"
+#include "map.h"
 
 #define OriginalTraining	0	/// 1 for the original training display
 
@@ -474,20 +476,84 @@ global void DrawResources(void)
 
 // FIXME: need messages for chat!
 
+#define MESSAGES_TIMEOUT  FRAMES_PER_SECOND*2 // two seconds
+
 local char  MessageBuffer[40];		// message buffer
 local char* Message;			// message in map window
-local int   MessageCounter;		// how long to display message
+local int   MessageFrameTimeout;	// frame to expire message
+
+#define MESSAGES_MAX  10
+
+local char Messages[ MESSAGES_MAX ][64];
+local int  MessagesCount;
+
+local char MessagesEvent[ MESSAGES_MAX ][64];
+local int  MessagesEventX[ MESSAGES_MAX ];
+local int  MessagesEventY[ MESSAGES_MAX ];
+local int  MessagesEventCount;
+local int  MessagesEventIndex;
 
 /**
-**	Draw message.
+**	Shift messages array with one.
+**
+**	
+*/
+global void ShiftMessages()
+{
+  int z;
+  if ( MessagesCount == 0 ) return;
+  for ( z = 0; z < MESSAGES_MAX; z++ )
+    if ( z < MESSAGES_MAX-1)
+      {
+      strcpy( Messages[z], Messages[z+1] );
+      }
+    else
+      {
+      strcpy( Messages[z], "" );
+      }
+  MessagesCount--;    
+}
+
+/**
+**	Shift messages events array with one.
+**
+**	
+*/
+global void ShiftMessagesEvent()
+{
+  int z;
+  if ( MessagesEventCount == 0 ) return;
+  for ( z = 0; z < MESSAGES_MAX; z++ )
+    if ( z < MESSAGES_MAX-1)
+      {
+      MessagesEventX[z] = MessagesEventX[z+1];
+      MessagesEventY[z] = MessagesEventY[z+1];
+      }
+    else
+      {
+      MessagesEventX[z] = -1;
+      MessagesEventY[z] = -1;
+      }
+  MessagesCount--;    
+}
+
+/**
+**	Draw message(s).
 */
 global void DrawMessage(void)
 {
-    if( Message ) {
-	DrawReverseText(TheUI.MapX+10,TheUI.MapHeight-20,GameFont,Message);
-	if( !--MessageCounter ) {
-	    ClearMessage();
-	}
+  int z;
+  if ( MessageFrameTimeout < FrameCounter )
+    {
+    ShiftMessages();
+    MessageFrameTimeout = FrameCounter + MESSAGES_TIMEOUT;
+    }
+  for ( z = 0; z < MessagesCount; z++ )
+    {
+     if ( Messages[z][0] == '*' )
+       DrawText(TheUI.MapX+8,TheUI.MapY+8 + z*16,GameFont,Messages[z]+1);
+     else
+       DrawReverseText(TheUI.MapX+8,TheUI.MapY+8 + z*16,GameFont,Messages[z]);
     }
 }
 
@@ -496,11 +562,50 @@ global void DrawMessage(void)
 **
 **	@param message	To be displayed in text overlay.
 */
-global void SetMessage(char* message)
+global void SetMessage( char* fmt, ... )
 {
-    Message=message;
+    char temp[128];
+    va_list va;
+    va_start( va, fmt );
+    vsprintf( temp, fmt, va );
+    va_end( va );
+    if ( MessagesCount == MESSAGES_MAX )
+      ShiftMessages();
+    strcpy( Messages[ MessagesCount ], temp );  
+    MessagesCount++;
     MustRedraw|=RedrawMessage|RedrawMap;
-    MessageCounter=FRAMES_PER_SECOND*2;
+    MessageFrameTimeout = FrameCounter + MESSAGES_TIMEOUT;
+}
+
+/**
+**	Set message to display.
+**
+**	@param message	To be displayed in text overlay.
+*/
+global void SetMessage2( int x, int y, char* fmt, ... )
+{
+    //FIXME: vladi: I know this can be just separated func w/o msg but
+    //       it is handy to stick all in one call, someone?
+
+    char temp[128];
+    va_list va;
+    va_start( va, fmt );
+    vsprintf( temp, fmt, va );
+    va_end( va );
+    if ( MessagesCount == MESSAGES_MAX )
+      ShiftMessages();
+    strcpy( Messages[ MessagesCount ], temp );  
+    MessagesCount++;
+    
+    if ( MessagesEventCount == MESSAGES_MAX )
+      ShiftMessagesEvent();
+    strcpy( MessagesEvent[ MessagesEventCount ], temp );
+    MessagesEventX[ MessagesEventCount ] = x;
+    MessagesEventY[ MessagesEventCount ] = y;
+    MessagesEventCount++;
+    
+    MustRedraw|=RedrawMessage|RedrawMap;
+    MessageFrameTimeout = FrameCounter + MESSAGES_TIMEOUT;
 }
 
 /**
@@ -510,6 +615,9 @@ global void SetMessage(char* message)
 */
 global void SetMessageDup(const char* message)
 {
+    //FIXME: is this function correct now?
+    //       it was, before multi-messages support done
+
     strncpy(MessageBuffer,message,sizeof(MessageBuffer));
     MessageBuffer[sizeof(MessageBuffer)-1]='\0';
 
@@ -523,6 +631,9 @@ global void SetMessageDup(const char* message)
 */
 global void SetMessageDupCat(const char* message)
 {
+    //FIXME: is this function correct now?
+    //       it was, before multi-messages support done
+
     strncat(MessageBuffer,message,sizeof(MessageBuffer)-strlen(MessageBuffer));
     MessageBuffer[sizeof(MessageBuffer)-1]='\0';
 
@@ -534,9 +645,24 @@ global void SetMessageDupCat(const char* message)
 */
 global void ClearMessage(void)
 {
+    //FIXME: is this function correct now?
+    //       it was, before multi-messages support done
+
     Message=NULL;
     MustRedraw|=RedrawMessage|RedrawMap;
-    MessageCounter=0;
+    MessageFrameTimeout = FrameCounter;
+}
+
+global void CenterOnMessage(void)
+{
+  if ( MessagesEventIndex >= MessagesEventCount )
+    MessagesEventIndex = 0;
+  if ( MessagesEventIndex >= MessagesEventCount )
+    return;
+  MapCenter( MessagesEventX[ MessagesEventIndex ], 
+             MessagesEventY[ MessagesEventIndex ] );  
+  SetMessage( "*Event: %s", MessagesEvent[ MessagesEventIndex ] );
+  MessagesEventIndex++;
 }
 
 /*----------------------------------------------------------------------------