diff --git a/client/CMT.cpp b/client/CMT.cpp
index 63cd3945f..f89abe0ae 100644
--- a/client/CMT.cpp
+++ b/client/CMT.cpp
@@ -70,6 +70,67 @@ TTF_Font * TNRB16, *TNR, *GEOR13, *GEORXX, *GEORM, *GEOR16;
 void processCommand(const std::string &message, CClient *&client);
 static void setScreenRes(int w, int h, int bpp, bool fullscreen);
 void dispose();
+void playIntro();
+
+void init()
+{
+	timeHandler tmh, pomtime;
+#if SDL_BYTEORDER == SDL_BIG_ENDIAN
+	int rmask = 0xff000000;int gmask = 0x00ff0000;int bmask = 0x0000ff00;int amask = 0x000000ff;
+#else
+	int rmask = 0x000000ff;	int gmask = 0x0000ff00;	int bmask = 0x00ff0000;	int amask = 0xff000000;
+#endif
+	CSDL_Ext::std32bppSurface = SDL_CreateRGBSurface(SDL_SWSURFACE, 1, 1, 32, rmask, gmask, bmask, amask);
+	tlog0 << "\tInitializing minors: " << pomtime.getDif() << std::endl;
+
+	TTF_Init();
+	atexit(TTF_Quit);
+	TNRB16 = TTF_OpenFont("Fonts" PATHSEPARATOR "tnrb.ttf",16);
+	GEOR13 = TTF_OpenFont("Fonts" PATHSEPARATOR "georgia.ttf",13);
+	GEOR16 = TTF_OpenFont("Fonts" PATHSEPARATOR "georgia.ttf",16);
+	GEORXX = TTF_OpenFont("Fonts" PATHSEPARATOR "tnrb.ttf",22);
+	GEORM = TTF_OpenFont("Fonts" PATHSEPARATOR "georgia.ttf",10);
+	if(! (TNRB16 && GEOR16 && GEORXX && GEORM))
+	{
+		tlog1 << "One of the fonts couldn't be loaded!\n";
+		exit(-1);
+	}
+	THC tlog0<<"\tInitializing fonts: "<<pomtime.getDif()<<std::endl;
+
+	//initializing audio
+	// Note: because of interface button range, volume can only be a
+	// multiple of 11, from 0 to 99.
+	CGI->soundh = new CSoundHandler;
+	CGI->soundh->init();
+	CGI->soundh->setVolume(88);
+	CGI->musich = new CMusicHandler;
+	CGI->musich->init();
+	CGI->musich->setVolume(88);
+	tlog0<<"\tInitializing sound: "<<pomtime.getDif()<<std::endl;
+	tlog0<<"Initializing screen, fonts and sound handling: "<<tmh.getDif()<<std::endl;
+
+	initDLL(::console,logfile);
+	CGI->setFromLib();
+	CGI->soundh->initCreaturesSounds(CGI->creh->creatures);
+	CGI->soundh->initSpellsSounds(CGI->spellh->spells);
+	tlog0<<"Initializing VCMI_Lib: "<<tmh.getDif()<<std::endl;
+
+	pomtime.getDif();
+	CGI->curh = new CCursorHandler;
+	CGI->curh->initCursor();
+	CGI->curh->show();
+	tlog0<<"Screen handler: "<<pomtime.getDif()<<std::endl;
+	pomtime.getDif();
+	graphics = new Graphics();
+	graphics->loadHeroAnim();
+	tlog0<<"\tMain graphics: "<<tmh.getDif()<<std::endl;
+	tlog0<<"Initializing game graphics: "<<tmh.getDif()<<std::endl;
+
+	CMessage::init();
+	tlog0<<"Message handler: "<<tmh.getDif()<<std::endl;
+	CPG = new CPreGame(); //main menu and submenus
+	tlog0<<"Initialization CPreGame (together): "<<tmh.getDif()<<std::endl;
+}
 
 #ifndef __GNUC__
 int _tmain(int argc, _TCHAR* argv[])
@@ -77,9 +138,8 @@ int _tmain(int argc, _TCHAR* argv[])
 int main(int argc, char** argv)
 #endif
 {
-
 	tlog0 << "Starting... " << std::endl;
-	THC timeHandler tmh, total, pomtime;
+	timeHandler total, pomtime;
 	CClient *client = NULL;
 	std::cout.flags(std::ios::unitbuf);
 	logfile = new std::ofstream("VCMI_Client_log.txt");
@@ -95,77 +155,29 @@ int main(int argc, char** argv)
 	srand ( time(NULL) );
 	CPG=NULL;
 	atexit(SDL_Quit);
-	CGameInfo * cgi = CGI = new CGameInfo; //contains all global informations about game (texts, lodHandlers, map handler itp.)
+	CGI = new CGameInfo; //contains all global informations about game (texts, lodHandlers, map handler itp.)
 	if(SDL_Init(SDL_INIT_VIDEO|SDL_INIT_TIMER|SDL_INIT_AUDIO)==0)
 	{
 		setScreenRes(800,600,conf.cc.bpp,conf.cc.fullscreen);
 		tlog0 <<"\tInitializing screen: "<<pomtime.getDif() << std::endl;
 
-		#if SDL_BYTEORDER == SDL_BIG_ENDIAN
-			int rmask = 0xff000000;int gmask = 0x00ff0000;int bmask = 0x0000ff00;int amask = 0x000000ff;
-		#else
-			int rmask = 0x000000ff;	int gmask = 0x0000ff00;	int bmask = 0x00ff0000;	int amask = 0xff000000;
-		#endif
-		CSDL_Ext::std32bppSurface = SDL_CreateRGBSurface(SDL_SWSURFACE, 1, 1, 32, rmask, gmask, bmask, amask);
-		tlog0 << "\tInitializing minors: " << pomtime.getDif() << std::endl;
-
-		TTF_Init();
-		TNRB16 = TTF_OpenFont("Fonts" PATHSEPARATOR "tnrb.ttf",16);
-		GEOR13 = TTF_OpenFont("Fonts" PATHSEPARATOR "georgia.ttf",13);
-		GEOR16 = TTF_OpenFont("Fonts" PATHSEPARATOR "georgia.ttf",16);
-		GEORXX = TTF_OpenFont("Fonts" PATHSEPARATOR "tnrb.ttf",22);
-		GEORM = TTF_OpenFont("Fonts" PATHSEPARATOR "georgia.ttf",10);
-		if(! (TNRB16 && GEOR16 && GEORXX && GEORM))
-		{
-			tlog1 << "One of the fonts couldn't be loaded!\n";
-			throw "One of the fonts couldn't be loaded!\n";
-		}
-		atexit(TTF_Quit);
-		THC tlog0<<"\tInitializing fonts: "<<pomtime.getDif()<<std::endl;
-
-		//initializing audio
-		// Note: because of interface button range, volume can only be a
-		// multiple of 11, from 0 to 99.
-		cgi->soundh = new CSoundHandler;
-		cgi->soundh->init();
-		cgi->soundh->setVolume(88);
-		cgi->musich = new CMusicHandler;
-		cgi->musich->init();
-		cgi->musich->setVolume(88);
-		tlog0<<"\tInitializing sound: "<<pomtime.getDif()<<std::endl;
-
 		// Initialize video
-		cgi->videoh = new CVideoPlayer;
+		CGI->videoh = new CVideoPlayer;
 		tlog0<<"\tInitializing video: "<<pomtime.getDif()<<std::endl;
 
-		tlog0<<"Initializing screen, fonts and sound handling: "<<tmh.getDif()<<std::endl;
-		initDLL(::console,logfile);
-		CGI->setFromLib();
-		cgi->soundh->initCreaturesSounds(CGI->creh->creatures);
-		cgi->soundh->initSpellsSounds(CGI->spellh->spells);
-		tlog0<<"Initializing VCMI_Lib: "<<tmh.getDif()<<std::endl;
-
-		pomtime.getDif();
-		cgi->curh = new CCursorHandler;
-		cgi->curh->initCursor();
-		cgi->curh->show();
-		tlog0<<"Screen handler: "<<pomtime.getDif()<<std::endl;
-		pomtime.getDif();
-		graphics = new Graphics();
-		graphics->loadHeroAnim();
-		tlog0<<"\tMain graphics: "<<tmh.getDif()<<std::endl;
-		tlog0<<"Initializing game graphics: "<<tmh.getDif()<<std::endl;
-
-		CMessage::init();
-		tlog0<<"Message handler: "<<tmh.getDif()<<std::endl;
-		CPreGame * cpg = new CPreGame(); //main menu and submenus
-		tlog0<<"Initialization CPreGame (together): "<<tmh.getDif()<<std::endl;
+		//we can properly play intro only in the main thread, so we have to move loading to the separate thread
+		boost::thread loading(init);
+		playIntro();
+		SDL_FillRect(screen,NULL,0);
+		SDL_Flip(screen);
+		loading.join();
 		tlog0<<"Initialization of VCMI (together): "<<total.getDif()<<std::endl;
 
-		SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
 
-		cgi->musich->playMusic(musicBase::mainMenu, -1);
-		StartInfo *options = new StartInfo(cpg->runLoop());
+		SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
+		CGI->musich->playMusic(musicBase::mainMenu, -1);
+		CPG->showMainMenu();
+		StartInfo *options = new StartInfo(CPG->runLoop());
 
 		if(screen->w != conf.cc.resx   ||   screen->h != conf.cc.resy)
 		{
@@ -174,19 +186,19 @@ int main(int argc, char** argv)
 		CClient cl;
 		if(options->mode == 0) //new game
 		{
-			tmh.getDif();
+			pomtime.getDif();
 			char portc[10];
 			SDL_itoa(conf.cc.port,portc,10);
 			CClient::runServer(portc);
-			tlog0<<"Preparing shared memory and starting server: "<<tmh.getDif()<<std::endl;
+			tlog0<<"Preparing shared memory and starting server: "<<pomtime.getDif()<<std::endl;
 
-			tmh.getDif();pomtime.getDif();//reset timers
+			pomtime.getDif();//reset timers
 
 			CConnection *c=NULL;
 			//wait until server is ready
 			tlog0<<"Waiting for server... ";
 			cl.waitForServer();
-			tlog0 << tmh.getDif()<<std::endl;
+			tlog0 << pomtime.getDif()<<std::endl;
 			while(!c)
 			{
 				try
@@ -200,10 +212,10 @@ int main(int argc, char** argv)
 					SDL_Delay(2000);
 				}
 			}
-			THC tlog0<<"\tConnecting to the server: "<<tmh.getDif()<<std::endl;
+			THC tlog0<<"\tConnecting to the server: "<<pomtime.getDif()<<std::endl;
 			cl.newGame(c,options);
 			client = &cl;
-			cgi->musich->stopMusic();
+			CGI->musich->stopMusic();
 			boost::thread t(boost::bind(&CClient::run,&cl));
 		}
 		else //load game
@@ -212,7 +224,7 @@ int main(int argc, char** argv)
 			boost::algorithm::erase_last(fname,".vlgm1");
 			cl.load(fname);
 			client = &cl;
-			cgi->musich->stopMusic();
+			CGI->musich->stopMusic();
 			boost::thread t(boost::bind(&CClient::run,&cl));
 		}
 
@@ -354,6 +366,18 @@ void processCommand(const std::string &message, CClient *&client)
 	}
 }
 
+
+//plays intro, ends when intro is over or button has been pressed (handles events)
+void playIntro()
+{
+#ifdef _WIN32
+	if(CGI->videoh->openAndPlayVideo("3DOLOGO.SMK", 60, 40, screen, true))
+	{
+		CGI->videoh->openAndPlayVideo("AZVS.SMK", 60, 80, screen, true);
+	}
+#endif
+}
+
 void dispose()
 {
 	delete logfile;
diff --git a/client/CPreGame.cpp b/client/CPreGame.cpp
index 5b161b316..8f08be374 100644
--- a/client/CPreGame.cpp
+++ b/client/CPreGame.cpp
@@ -23,6 +23,7 @@
 #include <cstdlib>
 #include "../lib/Connection.h"
 #include "../hch/CMusicHandler.h"
+#include "../hch/CVideoHandler.h"
 /*
  * CPreGame.cpp, part of VCMI engine
  *
@@ -1593,8 +1594,6 @@ CPreGame::CPreGame()
 	tlog0<<"\tCPreGame: scenario choice initialization: "<<tmh.getDif()<<std::endl;
 	initOptions();
 	tlog0<<"\tCPreGame: scenario options initialization: "<<tmh.getDif()<<std::endl;
-	showMainMenu();
-	tlog0<<"\tCPreGame: displaying main menu: "<<tmh.getDif()<<std::endl;
 	playerName="Player";
 }
 void CPreGame::initOptions()
@@ -1777,7 +1776,7 @@ void CPreGame::showNewMenu()
 	SDL_BlitSurface(ourNewMenu->credits->ourImages[0].bitmap,NULL,screen,&ourNewMenu->lCredits);
 	SDL_BlitSurface(ourNewMenu->quit->ourImages[0].bitmap,NULL,screen,&ourNewMenu->lQuit);
 	//SDL_Flip(screen);
-	CSDL_Ext::update(screen);
+	//CSDL_Ext::update(screen);
 	first = true;
 }
 void CPreGame::initMainMenu()
@@ -1835,7 +1834,7 @@ void CPreGame::showMainMenu()
 	SDL_BlitSurface(ourMainMenu->credits->ourImages[0].bitmap,NULL,screen,&ourMainMenu->lCredits);
 	SDL_BlitSurface(ourMainMenu->quit->ourImages[0].bitmap,NULL,screen,&ourMainMenu->lQuit);
 	//SDL_Flip(screen);
-	CSDL_Ext::update(screen);
+	//CSDL_Ext::update(screen);
 }
 void CPreGame::highlightButton(int which, int on)
 {
@@ -1870,7 +1869,7 @@ void CPreGame::highlightButton(int which, int on)
 		}
 	}
 	//SDL_Flip(screen);
-	CSDL_Ext::update(screen);
+	//CSDL_Ext::update(screen);
 }
 void CPreGame::showCenBox (std::string data)
 {
@@ -2054,6 +2053,11 @@ StartInfo CPreGame::runLoop()
 	SDL_Event sEvent;
 	ret.turnTime = 0;
 
+#ifdef _WIN32
+	CGI->videoh->open("ACREDIT.SMK");
+	CGI->videoh->show(8, 105, screen, false);
+#endif
+
 	while(run)
 	{
 		try
@@ -2321,12 +2325,19 @@ StartInfo CPreGame::runLoop()
 			}
 		} HANDLE_EXCEPTION
 
+#ifdef _WIN32
+		if(currentItems())
+			CGI->videoh->update(8, 105, screen, true, false);
+#endif
+
 		CGI->curh->draw1();
 		SDL_Flip(screen);
 		CGI->curh->draw2();
 		SDL_Delay(20); //give time for other apps
 	}
 	ret.mode = (fromMenu==newGame) ? 0 : 1;
+	CGI->videoh->close();
+
 	return ret;
 }
 std::string CPreGame::buttonText(int which)
@@ -2454,7 +2465,7 @@ void CPreGame::showLoadMenu()
 	SDL_BlitSurface(ourLoadMenu->credits->ourImages[0].bitmap,NULL,screen,&ourLoadMenu->lCredits);
 	SDL_BlitSurface(ourLoadMenu->quit->ourImages[0].bitmap,NULL,screen,&ourLoadMenu->lQuit);
 	//SDL_Flip(screen);
-	CSDL_Ext::update(screen);
+	//CSDL_Ext::update(screen);
 	first = true;
 }
 
diff --git a/client/CSpellWindow.cpp b/client/CSpellWindow.cpp
index 7d519abf0..edba1edf9 100644
--- a/client/CSpellWindow.cpp
+++ b/client/CSpellWindow.cpp
@@ -639,43 +639,76 @@ void CSpellWindow::deactivate()
 void CSpellWindow::turnPageLeft()
 {
 	// Note: video decoders are different, and one is buggy.
-#ifdef _WIN32
-	const int y = pos.y+15;
-#else
-	const int y = pos.y+14;
-#endif	
 
-	if (CGI->videoh->open("PGTRNLFT.SMK", pos.x+13, y)) {
-		while(CGI->videoh->nextFrame()) {
-			SDL_framerateDelay(LOCPLINT->mainFPSmng);
 #ifndef _WIN32
+	if (CGI->videoh->open("PGTRNLFT.SMK", pos.x+13, pos.y+14)) 
+	{
+		while(CGI->videoh->nextFrame()) 
+		{
+			SDL_framerateDelay(LOCPLINT->mainFPSmng);
 			SDL_framerateDelay(LOCPLINT->mainFPSmng);
 			SDL_framerateDelay(LOCPLINT->mainFPSmng);
-#endif
 		}
 		CGI->videoh->close();
 	}
+#else
+	CGI->videoh->openAndPlayVideo("PGTRNLFT.SMK", pos.x+13, pos.y+15, screen);
+#endif
+
+
+//#ifdef _WIN32
+//	const int y = pos.y+15;
+//
+//#endif	
+//
+//	if (CGI->videoh->open("PGTRNLFT.SMK", pos.x+13, y)) {
+//		while(CGI->videoh->nextFrame()) {
+//			SDL_framerateDelay(LOCPLINT->mainFPSmng);
+//#ifndef _WIN32
+//			SDL_framerateDelay(LOCPLINT->mainFPSmng);
+//			SDL_framerateDelay(LOCPLINT->mainFPSmng);
+//#endif
+//		}
+//		CGI->videoh->close();
+//	}
 }
 
 void CSpellWindow::turnPageRight()
 {
 	// Note: video decoders are different, and one is buggy.
-#ifdef _WIN32
-	const int y = pos.y+15;
-#else
-	const int y = pos.y+14;
-#endif	
 
-	if (CGI->videoh->open("PGTRNRGH.SMK", pos.x+13, y)) {
-		while(CGI->videoh->nextFrame()) {
-			SDL_framerateDelay(LOCPLINT->mainFPSmng);
+
 #ifndef _WIN32
+	if (CGI->videoh->open("PGTRNRGH.SMK", pos.x+13, pos.y+14)) 
+	{
+		while(CGI->videoh->nextFrame()) 
+		{
+			SDL_framerateDelay(LOCPLINT->mainFPSmng);
 			SDL_framerateDelay(LOCPLINT->mainFPSmng);
 			SDL_framerateDelay(LOCPLINT->mainFPSmng);
-#endif
 		}
 		CGI->videoh->close();
 	}
+#else
+	CGI->videoh->openAndPlayVideo("PGTRNRGH.SMK", pos.x+13, pos.y+15, screen);
+#endif
+
+//#ifdef _WIN32
+//	const int y = pos.y+15;
+//#else
+//	const int y = pos.y+14;
+//#endif	
+//
+//	if (CGI->videoh->open("PGTRNRGH.SMK", pos.x+13, y)) {
+//		while(CGI->videoh->nextFrame()) {
+//			SDL_framerateDelay(LOCPLINT->mainFPSmng);
+//#ifndef _WIN32
+//			SDL_framerateDelay(LOCPLINT->mainFPSmng);
+//			SDL_framerateDelay(LOCPLINT->mainFPSmng);
+//#endif
+//		}
+//		CGI->videoh->close();
+//	}
 }
 
 CSpellWindow::SpellArea::SpellArea(SDL_Rect pos, CSpellWindow * owner)
diff --git a/hch/CVideoHandler.cpp b/hch/CVideoHandler.cpp
index 30c7aad41..1aa863550 100644
--- a/hch/CVideoHandler.cpp
+++ b/hch/CVideoHandler.cpp
@@ -7,14 +7,53 @@
 #ifdef _WIN32
 
 #include "../client/SDL_Extensions.h"
+#include <boost/algorithm/string/predicate.hpp>
 
 
+void checkForError(bool throwing = true)
+{
+#ifdef _WIN32
+	int error = GetLastError();
+	if(!error)
+		return;
+
+
+	tlog1 << "Error " << error << " encountered!\n";
+	std::string msg;
+	char* pTemp = NULL;
+	FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM,
+		NULL, error,  MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT ), (LPSTR)&pTemp, 1, NULL );
+	tlog1 << "Error: " << pTemp << std::endl;
+	msg = pTemp;
+	LocalFree( pTemp );
+	pTemp = NULL;
+	if(throwing)
+		throw msg;
+#endif
+}
+
+void blitBuffer(char *buffer, int x, int y, int w, int h, SDL_Surface *dst)
+{
+	const int bpp = dst->format->BytesPerPixel;	
+	char *dest;
+	for(int i = h; i > 0; i--)
+	{
+		dest = (char*)dst->pixels + dst->pitch*(y+h-i) + x*dst->format->BytesPerPixel;
+		memcpy(dest, buffer, bpp*w);
+		buffer += bpp*w;
+	}
+}
 
 void DLLHandler::Instantiate(const char *filename)
 {
 	name = filename;
 #ifdef _WIN32
 	dll = LoadLibraryA(filename);
+	if(!dll)
+	{
+		tlog1 << "Failed loading " << filename << std::endl;
+		checkForError();
+	}
 #else
 	dll = dlopen(filename,RTLD_LOCAL | RTLD_LAZY);
 #endif
@@ -22,11 +61,18 @@ void DLLHandler::Instantiate(const char *filename)
 
 void *DLLHandler::FindAddress(const char *symbol)
 {
+	void *ret;
 #ifdef _WIN32
-	return (void*) GetProcAddress(dll,symbol);
+	ret = (void*) GetProcAddress(dll,symbol);
+	if(!ret)
+	{
+		tlog1 << "Failed to find " << symbol << " in " << name << std::endl;
+		checkForError();
+	}
 #else
-	return (void *)dlsym(dll, symbol);
+	ret = (void *)dlsym(dll, symbol);
 #endif
+	return ret;
 }
 
 DLLHandler::~DLLHandler()
@@ -34,7 +80,11 @@ DLLHandler::~DLLHandler()
 	if(dll)
 	{
 	#ifdef _WIN32
-		FreeLibrary(dll);
+		if(!FreeLibrary(dll))
+		{
+			tlog1 << "Failed to free " << name << std::endl;
+			checkForError();
+		}
 	#else
 		dlclose(dll);
 	#endif
@@ -46,29 +96,22 @@ DLLHandler::DLLHandler()
 	dll = NULL;
 }
 
-
-void checkForError()
-{
-#ifdef _WIN32
-	int error = GetLastError();
-	if(error)
-		tlog1 << "Error " << error << " encountered!\n";
-#endif
-}
-
-
 CBIKHandler::CBIKHandler()
 {
 	Instantiate("BINKW32.DLL");
 
-	binkGetError = FindAddress("_BinkGetError@0");
+	//binkGetError = FindAddress("_BinkGetError@0");
 	binkOpen = (BinkOpen)FindAddress("_BinkOpen@8");
 	binkSetSoundSystem = (BinkSetSoundSystem)FindAddress("_BinkSetSoundSystem@8");
-	getPalette = (BinkGetPalette)FindAddress("_BinkGetPalette@4");
+	//getPalette = (BinkGetPalette)FindAddress("_BinkGetPalette@4");
 	binkNextFrame = (BinkNextFrame)FindAddress("_BinkNextFrame@4");
 	binkDoFrame = (BinkDoFrame)FindAddress("_BinkDoFrame@4");
 	binkCopyToBuffer = (BinkCopyToBuffer)FindAddress("_BinkCopyToBuffer@28");
 	binkWait = (BinkWait)FindAddress("_BinkWait@4");
+	binkClose =  (BinkClose)FindAddress("_BinkClose@4");
+
+	hBinkFile = NULL;
+	hBink = NULL;
 }
 
 void CBIKHandler::open(std::string name)
@@ -86,36 +129,27 @@ void CBIKHandler::open(std::string name)
 
 	if(hBinkFile == INVALID_HANDLE_VALUE)
 	{
+		tlog1 << "BIK handler: failed to open " << name << std::endl;
 		checkForError();
-		return ;
+		return;
 	}
 
-	void *waveout = FindAddress("_BinkOpenWaveOut@4");
+	void *waveout = GetProcAddress(dll,"_BinkOpenWaveOut@4");
 	if(waveout)
 		binkSetSoundSystem(waveout,NULL);
 
 	hBink = binkOpen(hBinkFile, 0x8a800000);
-	width = hBink->width;
-	height = hBink->height;
-	buffer = new char[width * height * 3];
+	buffer = new char[hBink->width * hBink->width * 3];
 }
 
-void CBIKHandler::show( int x, int y, SDL_Surface *dst )
+void CBIKHandler::show( int x, int y, SDL_Surface *dst, bool update )
 {
 	int w = hBink->width, h = hBink->height;
-	//memset(buffer,0,w * h * 3);
 	binkDoFrame(hBink);
 	binkCopyToBuffer(hBink, buffer, w*3, h, 0, 0, 0);
-	char *src = buffer;
-	char *dest;
-	for(int i = h; i > 0; i--)
-	{
-		dest = (char*)dst->pixels + dst->pitch*(h-i) + x*dst->format->BytesPerPixel;
-		memcpy(dest,src,3*w);
-		src += 3*w;
-	}
-
-	SDL_UpdateRect(dst,x,y,hBink->width, hBink->height);
+	blitBuffer(buffer, x, y, w, h, dst);
+	if(update)
+		SDL_UpdateRect(dst, x, y, w, h);
 }
 
 void CBIKHandler::nextFrame()
@@ -125,6 +159,10 @@ void CBIKHandler::nextFrame()
 
 void CBIKHandler::close()
 {
+	binkClose(hBink);
+	hBink = NULL;
+	CloseHandle(hBinkFile);
+	hBinkFile = NULL;
 	delete [] buffer;
 }
 
@@ -133,80 +171,29 @@ bool CBIKHandler::wait()
 	return binkWait(hBink);
 }
 
-// Reference RSGrapics.RSGetPixelFormat
-PixelFormat getPixelFormat(TBitmap &b)
+int CBIKHandler::curFrame() const
 {
-	DIBSECTION DS;
-	DS.dsBmih.biBitCount = 2;
-	DS.dsBmih.biCompression = 0; //not sure about that
-	PixelFormat result = b.pixelFormat;
-
-	  if ( (result!= pfCustom)
-		  || (b.handleType = bmDDB)
-		 // || (GetObject(b.Handle, SizeOf(DS), @DS) = 0) 
-		  )
-		  exit(0);
-
-	  switch (DS.dsBmih.biBitCount)
-	  {
-		case 16:
-			switch (DS.dsBmih.biCompression)
-			{
-				case BI_RGB:
-					result = pf15bit;
-					break;
-				case BI_BITFIELDS:
-					if ( DS.dsBitfields[1]==0x7E0 )
-						result = pf16bit;
-					if ( DS.dsBitfields[1]==0x7E0 )
-						result = pf15bit;
-					break;
-			}
-			break;
-		case 32:
-			switch (DS.dsBmih.biCompression)
-			{
-				case BI_RGB:
-					result = pf32bit;
-					break;
-				case BI_BITFIELDS:
-					if ( DS.dsBitfields[1]==0xFF0000 )
-						result = pf32bit;
-					break;
-			}
-			break;
-	  }
-	return result;
+	return hBink->currentFrame;
 }
 
-void CSmackPlayer::preparePic(TBitmap &b)
+int CBIKHandler::frameCount() const
 {
-	switch (getPixelFormat(b))
-	{
-	case pf15bit:
-	case pf16bit:
-		break;
-	default:
-		b.pixelFormat = pf16bit;
-	};
+	return hBink->frameCount;
 }
 
-
 void CSmackPlayer::nextFrame()
 {
 	ptrSmackNextFrame(data);
 }
 
-
 bool CSmackPlayer::wait()
 {
 	return ptrSmackWait(data);
 }
 
-void CSmackPlayer::init()
+CSmackPlayer::CSmackPlayer()
 {
 	Instantiate("smackw32.dll");
-	tlog0 << "smackw32.dll loaded" << std::endl;
 
 	ptrSmackNextFrame = (SmackNextFrame)FindAddress("_SmackNextFrame@4");
 	ptrSmackWait = (SmackWait)FindAddress("_SmackWait@4");
@@ -214,110 +201,210 @@ void CSmackPlayer::init()
 	ptrSmackToBuffer = (SmackToBuffer)FindAddress("_SmackToBuffer@28");
 	ptrSmackOpen = (SmackOpen)FindAddress("_SmackOpen@12");
 	ptrSmackSoundOnOff = (SmackSoundOnOff)FindAddress("_SmackSoundOnOff@8");
-	tlog0 << "Functions located" << std::endl;
+	ptrSmackClose = (SmackClose)FindAddress("_SmackClose@4");
+}
+
+CSmackPlayer::~CSmackPlayer()
+{
+	if(data)
+		close();
+}
+
+void CSmackPlayer::close()
+{
+	ptrSmackClose(data);
+	data = NULL;
+	delete [] buffer;
+	buffer = NULL;
+}
+
+void CSmackPlayer::open( std::string name )
+{
+	Uint32 flags[2] = {0xff400, 0xfe400};
+
+	data = ptrSmackOpen( (void*)name.c_str(), flags[1], -1);
+	if (!data) 
+	{
+		tlog1 << "Smack cannot open " << name << std::endl;
+		return;
+	}
+
+	buffer = new char[data->width*data->height*2];
+	buf = buffer+data->width*(data->height-1)*2;	// adjust pointer position for later use by 'SmackToBuffer'
+}
+
+void CSmackPlayer::show( int x, int y, SDL_Surface *dst, bool update)
+{
+	int w = data->width, h = data->height;
+	int stripe = (-w*2) & (~3);
+
+	//put frame to the buffer
+	ptrSmackToBuffer(data, 0, 0, stripe, w, buf, 0x80000000);
+	ptrSmackDoFrame(data);
+
+
+	/* Lock the screen for direct access to the pixels */
+	if ( SDL_MUSTLOCK(dst) ) 
+	{
+		if ( SDL_LockSurface(dst) < 0 ) 
+		{
+			fprintf(stderr, "Can't lock screen: %s\n", SDL_GetError());
+			return;
+		}
+	}
+
+	// draw the frame
+	Uint16* addr = (Uint16*) (buffer+w*(h-1)*2-2);
+	for( int j=0; j<h-1; j++)	// why -1 ?
+	{
+		for ( int i=w-1; i>=0; i--)
+		{
+			Uint16 pixel = *addr;
+
+			Uint8 *p = (Uint8 *)dst->pixels + (j+y) * dst->pitch + (i + x) * dst->format->BytesPerPixel;
+			p[2] = ((pixel & 0x7c00) >> 10) * 8;
+			p[1] = ((pixel & 0x3e0) >> 5) * 8;
+			p[0] = ((pixel & 0x1F)) * 8;
+
+			addr--;
+		}
+	}
+
+	if ( SDL_MUSTLOCK(dst) ) 
+	{
+		SDL_UnlockSurface(dst);
+	}
+
+	if(update)
+		SDL_UpdateRect(dst, x, y, w, h);
+}
+
+int CSmackPlayer::curFrame() const
+{
+	return data->currentFrame;
+}
+
+int CSmackPlayer::frameCount() const
+{
+	return data->frameCount;
 }
 
 CVideoPlayer::CVideoPlayer()
 {
 	vidh = new CVidHandler(std::string(DATA_DIR "Data" PATHSEPARATOR "VIDEO.VID"));
-	smkPlayer = new CSmackPlayer;
-	smkPlayer->init();
+	current = NULL;
 }
 
 CVideoPlayer::~CVideoPlayer()
 {
-	delete smkPlayer;
 	delete vidh;
 }
 
-bool CVideoPlayer::init()
+void CVideoPlayer::open(std::string name)
 {
-	return true;
+	if(boost::algorithm::ends_with(name, ".BIK"))
+		current = &bikPlayer;
+	else
+		current = &smkPlayer;
+
+	fname = name;
+
+	//extract video from video.vid so we can play it
+	vidh->extract(name, name);
+	current->open(name);
 }
 
-bool CVideoPlayer::open(std::string fname, int x, int y)
-{
-	vidh->extract(fname, fname);
-
-	Uint32 flags[2] = {0xff400, 0xfe400};
-
-	smkPlayer->data = smkPlayer->ptrSmackOpen( (void*)fname.c_str(), flags[1], -1);
-	if (smkPlayer->data ==NULL) 
-	{
-		tlog1<<"No "<<fname<<" file!"<<std::endl;
-		return false;
-	}
-
-	buffer = new char[smkPlayer->data->width*smkPlayer->data->height*2];
-	buf = buffer+smkPlayer->data->width*(smkPlayer->data->height-1)*2;	// adjust pointer position for later use by 'SmackToBuffer'
-
-	xPos = x;
-	yPos = y;
-	frame = 0;
-
-	return true;
-}
-
-void CVideoPlayer::close()
-{
-	delete [] buffer;
-}
-
-bool CVideoPlayer::nextFrame()
+void CVideoPlayer::close()
 {
-	if(frame < smkPlayer->data->frameCount)
+	if(!current)
 	{
-		++frame;
-
-		int stripe = (-smkPlayer->data->width*2) & (~3);
-		Uint32 unknown = 0x80000000;
-		smkPlayer->ptrSmackToBuffer(smkPlayer->data , 0, 0, stripe, smkPlayer->data->width, buf, unknown);
-		smkPlayer->ptrSmackDoFrame(smkPlayer->data );
-		// now bitmap is in buffer
-		// but I don't know exactly how to parse these 15bit color and draw it onto 16bit screen
-
-
-		/* Lock the screen for direct access to the pixels */
-		if ( SDL_MUSTLOCK(screen) ) 
-		{
-			if ( SDL_LockSurface(screen) < 0 ) 
-			{
-				fprintf(stderr, "Can't lock screen: %s\n", SDL_GetError());
-				return 0;
-			}
-		}
-
-		// draw the frame!!
-		Uint16* addr = (Uint16*) (buffer+smkPlayer->data->width*(smkPlayer->data->height-1)*2-2);
-		for( int j=0; j<smkPlayer->data->height-1; j++)	// why -1 ?
-		{
-			for ( int i=smkPlayer->data->width-1; i>=0; i--)
-			{
-				Uint16 pixel = *addr;
-
-				Uint8 *p = (Uint8 *)screen->pixels + (j+yPos) * screen->pitch + (i + xPos) * screen->format->BytesPerPixel;
-				p[2] = ((pixel & 0x7c00) >> 10) * 8;
-				p[1] = ((pixel & 0x3e0) >> 5) * 8;
-				p[0] = ((pixel & 0x1F)) * 8;
-
-				addr--;
-			}
-		}
-
-		if ( SDL_MUSTLOCK(screen) ) 
-		{
-			SDL_UnlockSurface(screen);
-		}
-		/* Update just the part of the display that we've changed */
-		SDL_UpdateRect(screen, xPos, yPos, smkPlayer->data->width, smkPlayer->data->height);
-		SDL_Delay(50);
-		smkPlayer->ptrSmackWait(smkPlayer->data);
-		smkPlayer->ptrSmackNextFrame(smkPlayer->data);
+		tlog2 << "Closing no opened player...?" << std::endl;
+		return;
 	}
-	else //end of video
+
+	current->close();
+	current = NULL;
+	if(!DeleteFileA(fname.c_str()))
 	{
-		return false;
+		tlog1 << "Cannot remove temporarily extracted video file: " << fname;
+		checkForError(false);
 	}
+	fname.clear();
+}
+
+void CVideoPlayer::nextFrame()
+{
+	current->nextFrame();
+}
+
+void CVideoPlayer::show(int x, int y, SDL_Surface *dst, bool update)
+{
+	current->show(x, y, dst, update);
+}
+
+bool CVideoPlayer::wait()
+{
+	return current->wait();
+}
+
+int CVideoPlayer::curFrame() const
+{
+	return current->curFrame();
+}
+
+int CVideoPlayer::frameCount() const
+{
+	return current->frameCount();
+}
+
+bool CVideoPlayer::openAndPlayVideo(std::string name, int x, int y, SDL_Surface *dst, bool stopOnKey)
+{
+	open(name);
+	bool ret = playVideo(x, y, dst, stopOnKey);
+	close();
+	return ret;
+}
+
+void CVideoPlayer::update( int x, int y, SDL_Surface *dst, bool redraw, bool update )
+{
+	bool w = wait(); //check if should keep current frame
+
+	if(!w)
+		nextFrame();
+
+	if(!w || redraw) //redraw if changed frame or we was told to
+		show(x,y,dst,update);
+}
+
+//reads events and throws on key down
+bool keyDown()
+{
+	SDL_Event ev;
+	while(SDL_PollEvent(&ev))
+	{
+		if(ev.type == SDL_KEYDOWN || ev.type == SDL_MOUSEBUTTONDOWN)
+			return true;
+	}
+	return false;
+}
+
+bool CVideoPlayer::playVideo(int x, int y, SDL_Surface *dst, bool stopOnKey)
+{
+	int frame = 0;
+	while(frame < frameCount()) //play all frames
+	{
+		if(stopOnKey && keyDown())
+			return false;
+
+		if(!wait())
+		{
+			show(x, y, dst);
+			nextFrame();
+			frame++;
+		}
+		SDL_Delay(20);
+	}
+
 	return true;
 }
 
diff --git a/hch/CVideoHandler.h b/hch/CVideoHandler.h
index 9194d9197..864dd32c3 100644
--- a/hch/CVideoHandler.h
+++ b/hch/CVideoHandler.h
@@ -50,57 +50,53 @@ public:
 
 typedef void*(__stdcall*  BinkSetSoundSystem)(void * soundfun, void*);
 typedef HBINK(__stdcall*  BinkOpen)(HANDLE bikfile, int flags);
-typedef si32(__stdcall*  BinkGetPalette)(HBINK);
+typedef void(__stdcall*  BinkClose)(HBINK);
+//typedef si32(__stdcall*  BinkGetPalette)(HBINK);
 typedef void(__stdcall*  BinkNextFrame)(HBINK);
 typedef void(__stdcall*  BinkDoFrame)(HBINK);
 typedef ui8(__stdcall*  BinkWait)(HBINK);
 typedef si32(__stdcall*  BinkCopyToBuffer)(HBINK, void* buffer, int stride, int height, int x, int y, int mode);
 
+
+class IVideoPlayer
+{
+public:
+	virtual void open(std::string name)=0;
+	virtual void close()=0;
+	virtual void nextFrame()=0;
+	virtual void show(int x, int y, SDL_Surface *dst, bool update = true)=0;
+	virtual bool wait()=0;
+	virtual int curFrame() const =0;
+	virtual int frameCount() const =0;
+};
 
-class CBIKHandler : public DLLHandler
+class CBIKHandler : public DLLHandler, public IVideoPlayer
 {
 public:
-	int newmode;
 	HANDLE hBinkFile;
 	HBINK hBink;
 	char * buffer;
 	BinkSetSoundSystem binkSetSoundSystem;
 	BinkOpen binkOpen;
-	BinkGetPalette getPalette;
+	//BinkGetPalette getPalette;
 	BinkNextFrame binkNextFrame;
 	BinkDoFrame binkDoFrame;
 	BinkCopyToBuffer binkCopyToBuffer;
 	BinkWait binkWait;
-
-	void * waveOutOpen, * binkGetError;
-
-	int width, height;
+	BinkClose binkClose;
 
 	CBIKHandler();
 	void open(std::string name);
 	void close();
 	void nextFrame();
-	void show(int x, int y, SDL_Surface *dst);
+	void show(int x, int y, SDL_Surface *dst, bool update = true);
 	bool wait();
+	int curFrame() const;
+	int frameCount() const;
 };
 
 //////////SMK Player ///////////////////////////////////////////////////////
 
-typedef enum { bmDIB, bmDDB} BitmapHandleType;
-typedef enum { pfDevice, pf1bit, pf4bit, pf8bit, pf15bit, pf16bit, pf24bit, pf32bit, pfCustom} PixelFormat;
-typedef enum {tmAuto, tmFixed} TransparentMode;
-
-class TBitmap
-{
-public:
-	ui32	width;
-	ui32 height;
-	PixelFormat pixelFormat;
-	BitmapHandleType handleType;
-	char* buffer;
-
-};
-
 struct SmackStruct
 {
     si32 version;
@@ -127,7 +123,7 @@ typedef void (__stdcall* SmackSoundOnOff) (SmackStruct*, bool);
 
 
 
-class CSmackPlayer: public DLLHandler
+class CSmackPlayer: public DLLHandler, public IVideoPlayer
 {
 public:
 	SmackOpen ptrSmackOpen;
@@ -136,39 +132,50 @@ public:
 	SmackNextFrame ptrSmackNextFrame;
 	SmackWait ptrSmackWait;
 	SmackSoundOnOff ptrSmackSoundOnOff;
+	SmackClose ptrSmackClose;
+
+	char *buffer, *buf;
 	SmackStruct* data;
 
-	void init();
-	void preparePic(TBitmap &b);
-	TBitmap extractFrame(TBitmap &b);
+	CSmackPlayer();
+	~CSmackPlayer();
+	void open(std::string name);
+	void close();
 	void nextFrame();
-	bool wait();
+	void show(int x, int y, SDL_Surface *dst, bool update = true);
+	bool wait();
+	int curFrame() const;
+	int frameCount() const;
 };
 
 class CVidHandler;
 
-class CVideoPlayer
+class CVideoPlayer : public IVideoPlayer
 {
 private:
 	CVidHandler * vidh; //.vid file handling
-	CSmackPlayer * smkPlayer;
-
-	int frame;
-	int xPos, yPos;
-	char * buffer;
-	char * buf;
 
+	CSmackPlayer smkPlayer; //for .SMK
+	CBIKHandler bikPlayer; //for .BIK
+	IVideoPlayer *current; //points to bik or smk player, appropriate to type of currently played video
 
 	std::string fname; //name of current video file (empty if idle)
-
 public:
 	CVideoPlayer(); //c-tor
 	~CVideoPlayer(); //d-tor
 
-	bool init();
-	bool open(std::string fname, int x, int y); //x, y -> position where animation should be displayed on the screen
-	void close();
-	bool nextFrame(); // display next frame
+
+	void open(std::string name);
+	void close();
+	void nextFrame(); //move animation to the next frame
+	void show(int x, int y, SDL_Surface *dst, bool update = true); //blit current frame
+	void update(int x, int y, SDL_Surface *dst, bool redraw, bool update = true); //moves to next frame if appropriate, and blits it or blits only if redraw paremeter is set true
+	bool wait(); //true if we should wait before displaying next frame (for keeping FPS)
+	int curFrame() const; //current frame number <1, framecount>
+	int frameCount() const;
+
+	bool openAndPlayVideo(std::string name, int x, int y, SDL_Surface *dst, bool stopOnKey = false); //opens video, calls playVideo, closes video; returns playVideo result (if whole video has been played)
+	bool playVideo(int x, int y, SDL_Surface *dst, bool stopOnKey = false); //plays whole opened video; returns: true when whole video has been shown, false when it has been interrupted
 };
 
 #else