[Scummvm-cvs-logs] scummvm master -> d80d08128b2a030a65ce4f48776f5c63370ac598

DrMcCoy drmccoy at drmccoy.de
Mon Jul 30 01:55:59 CEST 2012


This automated email contains information about 63 new commits which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .

Summary:
dd35e72a7e GOB: Return proper errors in GobEngine::run()
2d05974b5c GOB: const correctness in SoundBlaster::playComposition()
945115f099 GOB: Don't crash when the engine wasn't fully initialized on exit
099a76ea20 GOB: Don't crash when there's no _inter object
1cb6cc0218 GOB: Don't crash when drawPackedSprite() can't open the sprite
b5fa752b78 GOB: Keep the mouse responsive while waiting for the frame to end
00fa997039 GOB: Move drawString into Font
bba2028fba GOB: Move the method definitions out of the GobMetaEngine class definition
4a380ce668 GOB: Add detection tables for Baba Yaga and Abracadabra
55c75756ea GOB: Add a more complex detection for Once Upon A Time titles
4819468d9a GOB: Add PreGob stubs for the Once Upon A Time games
8b19e10104 GOB: Add some generic PreGob graphics functions
38fe3c3cd9 GOB: Add palettes for Once Upon A Time
27782700a5 GOB: Add some PreGob and Once Upon A Time cursor functions
83896dea3e GOB: Add PreGob input/event utility functions
4fc3a88c5f GOB: Add support for different methods of handling Endianness
734fc767d2 GOB: Open the Once Upon A Time archives
3313302a15 GOB: Load the Once Upon A Time fonts
aae8c60759 GOB: Verify the language in Once Upon A Time
412ae53854 GOB: Add PreGob animation utility functions
ef3b4af9d8 GOB: Implement the copy protection in Once Upon A Time
67d7c3f11f GOB: Show a mock-up of the Once Upon A Time title
9af01cd584 GOB: Move the background saving into its own class BackBuffer
4b3aa88c8a GOB: Add a simple class for PreGob TXT files
139b03c4bc GOB: Add a PreGob method to get a localized file name
60cebba95c GOB: Show the Once Upon A Time wait/load screen
2f3aaf0e07 GOB: Show the Once Upon A Time fairytale quote
92bd9c864a GOB: Show the specific game title in Once Upon A Time
bccfdb559f GOB: Move the intro parts into OnceUpon::showIntro()
233a3f54fc GOB: Stubbily implement the Once Upon A Time menus
34cf81a4b6 GOB: Add some PreGob sound utility functions
a98ba5f038 GOB: Play a click sound in the Once Upon A Time menus
e477b7d2b9 GOB: Move the Once Upon A Time palettes into their own file
4663ab2373 GOB: Fix some broken German text in Once Upon A Time
9e997fea1b GOB: Add "long" PreGob language suffixes
9d564ecd26 GOB: Implement the animal names bit Once Upon A Time
24644c0012 GOB: Implement the Once Upon A Time "Bye Bye" screen
305ab6847a GOB: Reorganize and clean up PreGob / Once Upon A Time
60f52ab9a0 GOB: Add the frame for normal Once Upon A Time game play
df18bc9583 GOB: Implement parts of the Once Upon A Time end sequence
a547633911 GOB: ANIObject can now predict the position/size of future frames
0b030dd341 GOB: Implement parts of the Stork section in Once Upon A Time
e17d4a5c0c GOB: Implement GCT drawing
d7c81c2755 GOB: Implement GCT text drawing in the Stork section
90415cf083 GOB: Implement GCT text drawing in the end section
75e7cca692 GOB: Add support for entering non-ASCII CP850 characters
5b02192477 GOB: Add Font::hasChar()
10b9be2851 GOB: Add Util::toCP850Lower() / toCP850Upper()
57b1b7ad24 GOB: Implement the Once Upon A Time character generator
baec4d8778 GOB: Move recolor() into class Surface
20a96733a5 GOB: Add CMPFile::recolor() and ANIFile::recolor()
6533047514 GOB: Add the walking child in the character generator
9c32fd2360 GOB: Add PreGob::beep()
943c6af82a GOB: Add the sounds in the Once Upon A Time character generator
4bc80cd881 GOB: Allow spaces in the Once Upon A Time character generator
734329dcc1 GOB: Name the Once Upon A Time frame a bit more
f4cd726802 GOB: Add a class handling simple SEQ files
850472f21e GOB: Implement the proper Once Upon A Time title sequence
3189729c97 GOB: Don't leak in sampleLoad() when loading fails
25bc7467b4 GOB: Use Sound::sampleLoad in PreGob
dd2768a2e4 GOB: Reorder a few things
b001168658 GOB: Implement the parents section in Once Upon A Time
d80d08128b Merge branch 'pregob' (WIP Once Upon A Time)


Commit: dd35e72a7eefa922eba68dd28e8a18cbb98c0b16
    https://github.com/scummvm/scummvm/commit/dd35e72a7eefa922eba68dd28e8a18cbb98c0b16
Author: Sven Hesse (drmccoy at users.sourceforge.net)
Date: 2012-07-29T16:24:17-07:00

Commit Message:
GOB: Return proper errors in GobEngine::run()

Changed paths:
    engines/gob/gob.cpp
    engines/gob/gob.h



diff --git a/engines/gob/gob.cpp b/engines/gob/gob.cpp
index 3d8a18e..3202b5e 100644
--- a/engines/gob/gob.cpp
+++ b/engines/gob/gob.cpp
@@ -274,15 +274,15 @@ void GobEngine::setTrueColor(bool trueColor) {
 }
 
 Common::Error GobEngine::run() {
-	if (!initGameParts()) {
-		GUIErrorMessage("GobEngine::init(): Unknown version of game engine");
-		return Common::kUnknownError;
-	}
+	Common::Error err;
 
-	if (!initGraphics()) {
-		GUIErrorMessage("GobEngine::init(): Failed to set up graphics");
-		return Common::kUnknownError;
-	}
+	err = initGameParts();
+	if (err.getCode() != Common::kNoError)
+		return err;
+
+	err = initGraphics();
+	if (err.getCode() != Common::kNoError)
+		return err;
 
 	// On some systems it's not safe to run CD audio games from the CD.
 	if (isCD())
@@ -392,7 +392,7 @@ void GobEngine::pauseGame() {
 	pauseEngineIntern(false);
 }
 
-bool GobEngine::initGameParts() {
+Common::Error GobEngine::initGameParts() {
 	_resourceSizeWorkaround = false;
 
 	// just detect some devices some of which will be always there if the music is not disabled
@@ -605,9 +605,10 @@ bool GobEngine::initGameParts() {
 		_scenery  = new Scenery_v2(this);
 		_saveLoad = new SaveLoad_v2(this, _targetName.c_str());
 		break;
+
 	default:
 		deinitGameParts();
-		return false;
+		return Common::kUnsupportedGameidError;
 	}
 
 	// Setup mixer
@@ -615,7 +616,7 @@ bool GobEngine::initGameParts() {
 
 	_inter->setupOpcodes();
 
-	return true;
+	return Common::kNoError;
 }
 
 void GobEngine::deinitGameParts() {
@@ -637,10 +638,10 @@ void GobEngine::deinitGameParts() {
 	delete _dataIO;    _dataIO = 0;
 }
 
-bool GobEngine::initGraphics() {
+Common::Error GobEngine::initGraphics() {
 	if        (is800x600()) {
 		warning("GobEngine::initGraphics(): 800x600 games currently unsupported");
-		return false;
+		return Common::kUnsupportedGameidError;
 	} else if (is640x480()) {
 		_width  = 640;
 		_height = 480;
@@ -664,7 +665,7 @@ bool GobEngine::initGraphics() {
 
 	_global->_primarySurfDesc = SurfacePtr(new Surface(_width, _height, _pixelFormat.bytesPerPixel));
 
-	return true;
+	return Common::kNoError;
 }
 
 } // End of namespace Gob
diff --git a/engines/gob/gob.h b/engines/gob/gob.h
index 52f3ba8..d3d2bf1 100644
--- a/engines/gob/gob.h
+++ b/engines/gob/gob.h
@@ -176,10 +176,10 @@ private:
 	virtual void pauseEngineIntern(bool pause);
 	virtual void syncSoundSettings();
 
-	bool initGameParts();
-	void deinitGameParts();
+	Common::Error initGameParts();
+	Common::Error initGraphics();
 
-	bool initGraphics();
+	void deinitGameParts();
 
 public:
 	static const Common::Language _gobToScummVMLang[];


Commit: 2d05974b5cfef94be9e3edad02e66169a215db4c
    https://github.com/scummvm/scummvm/commit/2d05974b5cfef94be9e3edad02e66169a215db4c
Author: Sven Hesse (drmccoy at users.sourceforge.net)
Date: 2012-07-29T16:24:18-07:00

Commit Message:
GOB: const correctness in SoundBlaster::playComposition()

Changed paths:
    engines/gob/inter_bargon.cpp
    engines/gob/sound/sound.cpp
    engines/gob/sound/sound.h
    engines/gob/sound/soundblaster.cpp
    engines/gob/sound/soundblaster.h



diff --git a/engines/gob/inter_bargon.cpp b/engines/gob/inter_bargon.cpp
index 134203f..029f7c6 100644
--- a/engines/gob/inter_bargon.cpp
+++ b/engines/gob/inter_bargon.cpp
@@ -119,7 +119,7 @@ void Inter_Bargon::oBargon_intro2(OpGobParams &params) {
 	MouseButtons buttons;
 	SurfacePtr surface;
 	SoundDesc samples[4];
-	int16 comp[5] = { 0, 1, 2, 3, -1 };
+	static const int16 comp[5] = { 0, 1, 2, 3, -1 };
 	static const char *const sndFiles[] = {"1INTROII.snd", "2INTROII.snd", "1INTRO3.snd", "2INTRO3.snd"};
 
 	surface = _vm->_video->initSurfDesc(320, 200);
@@ -167,8 +167,8 @@ void Inter_Bargon::oBargon_intro3(OpGobParams &params) {
 	MouseButtons buttons;
 	Video::Color *palBak;
 	SoundDesc samples[2];
-	int16 comp[3] = { 0, 1, -1 };
 	byte *palettes[4];
+	static const int16 comp[3] = { 0, 1, -1 };
 	static const char *const sndFiles[] = {"1INTROIV.snd", "2INTROIV.snd"};
 	static const char *const palFiles[] = {"2ou2.clt", "2ou3.clt", "2ou4.clt", "2ou5.clt"};
 
diff --git a/engines/gob/sound/sound.cpp b/engines/gob/sound/sound.cpp
index 403bd63..69a668e 100644
--- a/engines/gob/sound/sound.cpp
+++ b/engines/gob/sound/sound.cpp
@@ -458,7 +458,7 @@ void Sound::blasterStop(int16 fadeLength, SoundDesc *sndDesc) {
 	_blaster->stopSound(fadeLength, sndDesc);
 }
 
-void Sound::blasterPlayComposition(int16 *composition, int16 freqVal,
+void Sound::blasterPlayComposition(const int16 *composition, int16 freqVal,
 		SoundDesc *sndDescs, int8 sndCount) {
 	if (!_blaster)
 		return;
diff --git a/engines/gob/sound/sound.h b/engines/gob/sound/sound.h
index 6ad0ec5..7beffb5 100644
--- a/engines/gob/sound/sound.h
+++ b/engines/gob/sound/sound.h
@@ -60,7 +60,7 @@ public:
 			int16 frequency, int16 fadeLength = 0);
 	void blasterStop(int16 fadeLength, SoundDesc *sndDesc = 0);
 
-	void blasterPlayComposition(int16 *composition, int16 freqVal,
+	void blasterPlayComposition(const int16 *composition, int16 freqVal,
 			SoundDesc *sndDescs = 0, int8 sndCount = kSoundsCount);
 	void blasterStopComposition();
 	void blasterRepeatComposition(int32 repCount);
diff --git a/engines/gob/sound/soundblaster.cpp b/engines/gob/sound/soundblaster.cpp
index 19c2346..f267eee 100644
--- a/engines/gob/sound/soundblaster.cpp
+++ b/engines/gob/sound/soundblaster.cpp
@@ -88,7 +88,7 @@ void SoundBlaster::nextCompositionPos() {
 	_compositionPos = -1;
 }
 
-void SoundBlaster::playComposition(int16 *composition, int16 freqVal,
+void SoundBlaster::playComposition(const int16 *composition, int16 freqVal,
 		SoundDesc *sndDescs, int8 sndCount) {
 
 	_compositionSamples = sndDescs;
diff --git a/engines/gob/sound/soundblaster.h b/engines/gob/sound/soundblaster.h
index c740ba2..3c4968d 100644
--- a/engines/gob/sound/soundblaster.h
+++ b/engines/gob/sound/soundblaster.h
@@ -41,7 +41,7 @@ public:
 			int16 frequency, int16 fadeLength = 0);
 	void stopSound(int16 fadeLength, SoundDesc *sndDesc = 0);
 
-	void playComposition(int16 *composition, int16 freqVal,
+	void playComposition(const int16 *composition, int16 freqVal,
 			SoundDesc *sndDescs = 0, int8 sndCount = 60);
 	void stopComposition();
 	void endComposition();


Commit: 945115f09927ff2e9e7d5197524bb929f4ba5561
    https://github.com/scummvm/scummvm/commit/945115f09927ff2e9e7d5197524bb929f4ba5561
Author: Sven Hesse (drmccoy at users.sourceforge.net)
Date: 2012-07-29T16:24:18-07:00

Commit Message:
GOB: Don't crash when the engine wasn't fully initialized on exit

Changed paths:
    engines/gob/game.cpp



diff --git a/engines/gob/game.cpp b/engines/gob/game.cpp
index 0d19533..de0c3f2 100644
--- a/engines/gob/game.cpp
+++ b/engines/gob/game.cpp
@@ -64,7 +64,7 @@ void Environments::clear() {
 	// Deleting unique variables, script and resources
 
 	for (uint i = 0; i < kEnvironmentCount; i++) {
-		if (_environments[i].variables == _vm->_inter->_variables)
+		if (_vm->_inter && (_environments[i].variables == _vm->_inter->_variables))
 			continue;
 
 		if (!has(_environments[i].variables, i + 1))


Commit: 099a76ea20fa0f8290815f988d2202b6702d589b
    https://github.com/scummvm/scummvm/commit/099a76ea20fa0f8290815f988d2202b6702d589b
Author: Sven Hesse (drmccoy at users.sourceforge.net)
Date: 2012-07-29T16:24:18-07:00

Commit Message:
GOB: Don't crash when there's no _inter object

Changed paths:
    engines/gob/draw.cpp
    engines/gob/gob.cpp



diff --git a/engines/gob/draw.cpp b/engines/gob/draw.cpp
index fe59b11..9253a0a 100644
--- a/engines/gob/draw.cpp
+++ b/engines/gob/draw.cpp
@@ -256,7 +256,7 @@ void Draw::blitInvalidated() {
 	if (_cursorIndex == 4)
 		blitCursor();
 
-	if (_vm->_inter->_terminate)
+	if (_vm->_inter && _vm->_inter->_terminate)
 		return;
 
 	if (_noInvalidated && !_applyPal)
@@ -446,7 +446,7 @@ void Draw::printTextCentered(int16 id, int16 left, int16 top, int16 right,
 	adjustCoords(1, &left, &top);
 	adjustCoords(1, &right, &bottom);
 
-	uint16 centerOffset = _vm->_game->_script->getFunctionOffset(TOTFile::kFunctionCenter);
+	uint16 centerOffset = _vm->_game->_script ? _vm->_game->_script->getFunctionOffset(TOTFile::kFunctionCenter) : 0;
 	if (centerOffset != 0) {
 		_vm->_game->_script->call(centerOffset);
 
@@ -505,7 +505,7 @@ void Draw::oPlaytoons_sub_F_1B(uint16 id, int16 left, int16 top, int16 right, in
 	adjustCoords(1, &left, &top);
 	adjustCoords(1, &right,  &bottom);
 
-	uint16 centerOffset = _vm->_game->_script->getFunctionOffset(TOTFile::kFunctionCenter);
+	uint16 centerOffset = _vm->_game->_script ? _vm->_game->_script->getFunctionOffset(TOTFile::kFunctionCenter) : 0;
 	if (centerOffset != 0) {
 		_vm->_game->_script->call(centerOffset);
 
diff --git a/engines/gob/gob.cpp b/engines/gob/gob.cpp
index 3202b5e..ef9a711 100644
--- a/engines/gob/gob.cpp
+++ b/engines/gob/gob.cpp
@@ -368,11 +368,12 @@ void GobEngine::pauseEngineIntern(bool pause) {
 
 		_game->_startTimeKey += duration;
 		_draw->_cursorTimeKey += duration;
-		if (_inter->_soundEndTimeKey != 0)
+		if (_inter && (_inter->_soundEndTimeKey != 0))
 			_inter->_soundEndTimeKey += duration;
 	}
 
-	_vidPlayer->pauseAll(pause);
+	if (_vidPlayer)
+		_vidPlayer->pauseAll(pause);
 	_mixer->pauseAll(pause);
 }
 


Commit: 1cb6cc0218382bbf5fe487fd0e84d233e56592bb
    https://github.com/scummvm/scummvm/commit/1cb6cc0218382bbf5fe487fd0e84d233e56592bb
Author: Sven Hesse (drmccoy at users.sourceforge.net)
Date: 2012-07-29T16:24:18-07:00

Commit Message:
GOB: Don't crash when drawPackedSprite() can't open the sprite

Changed paths:
    engines/gob/video.cpp



diff --git a/engines/gob/video.cpp b/engines/gob/video.cpp
index 3b1c642..f1f014c 100644
--- a/engines/gob/video.cpp
+++ b/engines/gob/video.cpp
@@ -332,6 +332,10 @@ void Video::drawPackedSprite(byte *sprBuf, int16 width, int16 height,
 void Video::drawPackedSprite(const char *path, Surface &dest, int width) {
 	int32 size;
 	byte *data = _vm->_dataIO->getFile(path, size);
+	if (!data) {
+		warning("Video::drawPackedSprite(): Failed to open sprite \"%s\"", path);
+		return;
+	}
 
 	drawPackedSprite(data, width, dest.getHeight(), 0, 0, 0, dest);
 	delete[] data;


Commit: b5fa752b78c63bedcb53d38fb11244b7e99f9941
    https://github.com/scummvm/scummvm/commit/b5fa752b78c63bedcb53d38fb11244b7e99f9941
Author: Sven Hesse (drmccoy at users.sourceforge.net)
Date: 2012-07-29T16:24:18-07:00

Commit Message:
GOB: Keep the mouse responsive while waiting for the frame to end

Changed paths:
    engines/gob/minigames/geisha/penetration.cpp
    engines/gob/util.cpp
    engines/gob/util.h



diff --git a/engines/gob/minigames/geisha/penetration.cpp b/engines/gob/minigames/geisha/penetration.cpp
index 3be9f1f..05695e5 100644
--- a/engines/gob/minigames/geisha/penetration.cpp
+++ b/engines/gob/minigames/geisha/penetration.cpp
@@ -505,7 +505,7 @@ bool Penetration::play(bool hasAccessPass, bool hasMaxEnergy, bool testMode) {
 		// Draw, fade in if necessary and wait for the end of the frame
 		_vm->_draw->blitInvalidated();
 		fadeIn();
-		_vm->_util->waitEndFrame();
+		_vm->_util->waitEndFrame(false);
 
 		// Handle the input
 		checkInput();
diff --git a/engines/gob/util.cpp b/engines/gob/util.cpp
index 64dfcf9..5d6ae78 100644
--- a/engines/gob/util.cpp
+++ b/engines/gob/util.cpp
@@ -367,21 +367,29 @@ void Util::notifyNewAnim() {
 	_startFrameTime = getTimeKey();
 }
 
-void Util::waitEndFrame() {
+void Util::waitEndFrame(bool handleInput) {
 	int32 time;
 
-	_vm->_video->waitRetrace();
-
 	time = getTimeKey() - _startFrameTime;
 	if ((time > 1000) || (time < 0)) {
+		_vm->_video->retrace();
 		_startFrameTime = getTimeKey();
 		return;
 	}
 
-	int32 toWait = _frameWaitTime - time;
+	int32 toWait = 0;
+	do {
+		if (toWait > 0)
+			delay(MIN<int>(toWait, 10));
+
+		if (handleInput)
+			processInput();
+
+		_vm->_video->retrace();
 
-	if (toWait > 0)
-		delay(toWait);
+		time   = getTimeKey() - _startFrameTime;
+		toWait = _frameWaitTime - time;
+	} while (toWait > 0);
 
 	_startFrameTime = getTimeKey();
 }
diff --git a/engines/gob/util.h b/engines/gob/util.h
index b26a78a..30bff72 100644
--- a/engines/gob/util.h
+++ b/engines/gob/util.h
@@ -124,7 +124,7 @@ public:
 	int16 getFrameRate();
 	void setFrameRate(int16 rate);
 	void notifyNewAnim();
-	void waitEndFrame();
+	void waitEndFrame(bool handleInput = true);
 	void setScrollOffset(int16 x = -1, int16 y = -1);
 
 	static void insertStr(const char *str1, char *str2, int16 pos);


Commit: 00fa997039525eeeacc34734e9a12e53f7b847dd
    https://github.com/scummvm/scummvm/commit/00fa997039525eeeacc34734e9a12e53f7b847dd
Author: Sven Hesse (drmccoy at users.sourceforge.net)
Date: 2012-07-29T16:24:18-07:00

Commit Message:
GOB: Move drawString into Font

Changed paths:
    engines/gob/draw.cpp
    engines/gob/draw.h
    engines/gob/draw_fascin.cpp
    engines/gob/draw_playtoons.cpp
    engines/gob/draw_v2.cpp
    engines/gob/inter_v5.cpp
    engines/gob/minigames/geisha/penetration.cpp
    engines/gob/video.cpp
    engines/gob/video.h



diff --git a/engines/gob/draw.cpp b/engines/gob/draw.cpp
index 9253a0a..3932987 100644
--- a/engines/gob/draw.cpp
+++ b/engines/gob/draw.cpp
@@ -425,21 +425,6 @@ int Draw::stringLength(const char *str, uint16 fontIndex) {
 	return len;
 }
 
-void Draw::drawString(const char *str, int16 x, int16 y, int16 color1, int16 color2,
-		int16 transp, Surface &dest, const Font &font) {
-
-	while (*str != '\0') {
-		const int16 charRight  = x + font.getCharWidth(*str);
-		const int16 charBottom = y + font.getCharHeight();
-
-		if ((charRight <= dest.getWidth()) && (charBottom <= dest.getHeight()))
-			font.drawLetter(dest, *str, x, y, color1, color2, transp);
-
-		x += font.getCharWidth(*str);
-		str++;
-	}
-}
-
 void Draw::printTextCentered(int16 id, int16 left, int16 top, int16 right,
 		int16 bottom, const char *str, int16 fontIndex, int16 color) {
 
diff --git a/engines/gob/draw.h b/engines/gob/draw.h
index e7af1f9a..b51c646 100644
--- a/engines/gob/draw.h
+++ b/engines/gob/draw.h
@@ -194,8 +194,6 @@ public:
 		adjustCoords(adjust, (int16 *)coord1, (int16 *)coord2);
 	}
 	int stringLength(const char *str, uint16 fontIndex);
-	void drawString(const char *str, int16 x, int16 y, int16 color1, int16 color2,
-			int16 transp, Surface &dest, const Font &font);
 	void printTextCentered(int16 id, int16 left, int16 top, int16 right,
 			int16 bottom, const char *str, int16 fontIndex, int16 color);
 	void oPlaytoons_sub_F_1B( uint16 id, int16 left, int16 top, int16 right, int16 bottom, char *paramStr, int16 var3, int16 var4, int16 shortId);
diff --git a/engines/gob/draw_fascin.cpp b/engines/gob/draw_fascin.cpp
index 54cd52b..12009d7 100644
--- a/engines/gob/draw_fascin.cpp
+++ b/engines/gob/draw_fascin.cpp
@@ -222,8 +222,8 @@ void Draw_Fascination::spriteOperation(int16 operation) {
 								_destSpriteX, _destSpriteY, _frontColor, _backColor, _transparency);
 					}
 				} else {
-					drawString(_textToPrint, _destSpriteX, _destSpriteY, _frontColor,
-							_backColor, _transparency, *_spritesArray[_destSurface], *font);
+					font->drawString(_textToPrint, _destSpriteX, _destSpriteY, _frontColor,
+							_backColor, _transparency, *_spritesArray[_destSurface]);
 					_destSpriteX += len * font->getCharWidth();
 				}
 			} else {
diff --git a/engines/gob/draw_playtoons.cpp b/engines/gob/draw_playtoons.cpp
index a443f81..76e2ae5 100644
--- a/engines/gob/draw_playtoons.cpp
+++ b/engines/gob/draw_playtoons.cpp
@@ -283,8 +283,8 @@ void Draw_Playtoons::spriteOperation(int16 operation) {
 								_destSpriteX, _destSpriteY, _frontColor, _backColor, _transparency);
 					}
 				} else {
-					drawString(_textToPrint, _destSpriteX, _destSpriteY, _frontColor,
-							_backColor, _transparency, *_spritesArray[_destSurface], *font);
+					font->drawString(_textToPrint, _destSpriteX, _destSpriteY, _frontColor,
+							_backColor, _transparency, *_spritesArray[_destSurface]);
 					_destSpriteX += len * font->getCharWidth();
 				}
 			} else {
diff --git a/engines/gob/draw_v2.cpp b/engines/gob/draw_v2.cpp
index b637ecb..ac43c7b 100644
--- a/engines/gob/draw_v2.cpp
+++ b/engines/gob/draw_v2.cpp
@@ -831,8 +831,8 @@ void Draw_v2::spriteOperation(int16 operation) {
 								getColor(_backColor), _transparency);
 					}
 				} else {
-					drawString(_textToPrint, _destSpriteX, _destSpriteY, getColor(_frontColor),
-							getColor(_backColor), _transparency, *_spritesArray[_destSurface], *font);
+					font->drawString(_textToPrint, _destSpriteX, _destSpriteY, getColor(_frontColor),
+							getColor(_backColor), _transparency, *_spritesArray[_destSurface]);
 					_destSpriteX += len * font->getCharWidth();
 				}
 			} else {
diff --git a/engines/gob/inter_v5.cpp b/engines/gob/inter_v5.cpp
index c0e8978..24905b0 100644
--- a/engines/gob/inter_v5.cpp
+++ b/engines/gob/inter_v5.cpp
@@ -281,7 +281,7 @@ void Inter_v5::o5_getSystemCDSpeed(OpGobParams &params) {
 
 	Font *font;
 	if ((font = _vm->_draw->loadFont("SPEED.LET"))) {
-		_vm->_draw->drawString("100 %", 402, 89, 112, 144, 0, *_vm->_draw->_backSurface, *font);
+		font->drawString("100 %", 402, 89, 112, 144, 0, *_vm->_draw->_backSurface);
 		_vm->_draw->forceBlit();
 
 		delete font;
@@ -293,7 +293,7 @@ void Inter_v5::o5_getSystemRAM(OpGobParams &params) {
 
 	Font *font;
 	if ((font = _vm->_draw->loadFont("SPEED.LET"))) {
-		_vm->_draw->drawString("100 %", 402, 168, 112, 144, 0, *_vm->_draw->_backSurface, *font);
+		font->drawString("100 %", 402, 168, 112, 144, 0, *_vm->_draw->_backSurface);
 		_vm->_draw->forceBlit();
 
 		delete font;
@@ -305,7 +305,7 @@ void Inter_v5::o5_getSystemCPUSpeed(OpGobParams &params) {
 
 	Font *font;
 	if ((font = _vm->_draw->loadFont("SPEED.LET"))) {
-		_vm->_draw->drawString("100 %", 402, 248, 112, 144, 0, *_vm->_draw->_backSurface, *font);
+		font->drawString("100 %", 402, 248, 112, 144, 0, *_vm->_draw->_backSurface);
 		_vm->_draw->forceBlit();
 
 		delete font;
@@ -317,7 +317,7 @@ void Inter_v5::o5_getSystemDrawSpeed(OpGobParams &params) {
 
 	Font *font;
 	if ((font = _vm->_draw->loadFont("SPEED.LET"))) {
-		_vm->_draw->drawString("100 %", 402, 326, 112, 144, 0, *_vm->_draw->_backSurface, *font);
+		font->drawString("100 %", 402, 326, 112, 144, 0, *_vm->_draw->_backSurface);
 		_vm->_draw->forceBlit();
 
 		delete font;
@@ -329,7 +329,7 @@ void Inter_v5::o5_totalSystemSpecs(OpGobParams &params) {
 
 	Font *font;
 	if ((font = _vm->_draw->loadFont("SPEED.LET"))) {
-		_vm->_draw->drawString("100 %", 402, 405, 112, 144, 0, *_vm->_draw->_backSurface, *font);
+		font->drawString("100 %", 402, 405, 112, 144, 0, *_vm->_draw->_backSurface);
 		_vm->_draw->forceBlit();
 
 		delete font;
diff --git a/engines/gob/minigames/geisha/penetration.cpp b/engines/gob/minigames/geisha/penetration.cpp
index 05695e5..c8c4f2b 100644
--- a/engines/gob/minigames/geisha/penetration.cpp
+++ b/engines/gob/minigames/geisha/penetration.cpp
@@ -778,29 +778,24 @@ void Penetration::drawFloorText() {
 	else if (_floor == 2)
 		floorString = strings[kString1stBasement];
 
+	Surface &surface = *_vm->_draw->_backSurface;
+
 	if (floorString)
-		_vm->_draw->drawString(floorString, 10, 15, kColorFloorText, kColorBlack, 1,
-		                       *_vm->_draw->_backSurface, *font);
+		font->drawString(floorString, 10, 15, kColorFloorText, kColorBlack, 1, surface);
 
 	if (_exits.size() > 0) {
 		int exitCount = kString2Exits;
 		if (_exits.size() == 1)
 			exitCount = kString1Exit;
 
-		_vm->_draw->drawString(strings[kStringYouHave]    , 10, 38, kColorExitText, kColorBlack, 1,
-		                       *_vm->_draw->_backSurface, *font);
-		_vm->_draw->drawString(strings[exitCount]         , 10, 53, kColorExitText, kColorBlack, 1,
-		                       *_vm->_draw->_backSurface, *font);
-		_vm->_draw->drawString(strings[kStringToReach]    , 10, 68, kColorExitText, kColorBlack, 1,
-		                       *_vm->_draw->_backSurface, *font);
-		_vm->_draw->drawString(strings[kStringUpperLevel1], 10, 84, kColorExitText, kColorBlack, 1,
-		                       *_vm->_draw->_backSurface, *font);
-		_vm->_draw->drawString(strings[kStringUpperLevel2], 10, 98, kColorExitText, kColorBlack, 1,
-		                       *_vm->_draw->_backSurface, *font);
+		font->drawString(strings[kStringYouHave]    , 10, 38, kColorExitText, kColorBlack, 1, surface);
+		font->drawString(strings[exitCount]         , 10, 53, kColorExitText, kColorBlack, 1, surface);
+		font->drawString(strings[kStringToReach]    , 10, 68, kColorExitText, kColorBlack, 1, surface);
+		font->drawString(strings[kStringUpperLevel1], 10, 84, kColorExitText, kColorBlack, 1, surface);
+		font->drawString(strings[kStringUpperLevel2], 10, 98, kColorExitText, kColorBlack, 1, surface);
 
 	} else
-		_vm->_draw->drawString(strings[kStringNoExit], 10, 53, kColorExitText, kColorBlack, 1,
-		                       *_vm->_draw->_backSurface, *font);
+		font->drawString(strings[kStringNoExit], 10, 53, kColorExitText, kColorBlack, 1, surface);
 }
 
 void Penetration::drawEndText() {
@@ -814,21 +809,17 @@ void Penetration::drawEndText() {
 	if (!font)
 		return;
 
+	Surface &surface = *_vm->_draw->_backSurface;
+
 	const char **strings = kStrings[getLanguage()];
 
-	_vm->_draw->drawString(strings[kStringLevel0]     , 11, 21, kColorExitText, kColorBlack, 1,
-	                       *_vm->_draw->_backSurface, *font);
-	_vm->_draw->drawString(strings[kStringPenetration], 11, 42, kColorExitText, kColorBlack, 1,
-	                       *_vm->_draw->_backSurface, *font);
-	_vm->_draw->drawString(strings[kStringSuccessful] , 11, 58, kColorExitText, kColorBlack, 1,
-	                       *_vm->_draw->_backSurface, *font);
-
-	_vm->_draw->drawString(strings[kStringDanger]   , 11,  82, kColorFloorText, kColorBlack, 1,
-	                       *_vm->_draw->_backSurface, *font);
-	_vm->_draw->drawString(strings[kStringGynoides] , 11,  98, kColorFloorText, kColorBlack, 1,
-	                       *_vm->_draw->_backSurface, *font);
-	_vm->_draw->drawString(strings[kStringActivated], 11, 113, kColorFloorText, kColorBlack, 1,
-	                       *_vm->_draw->_backSurface, *font);
+	font->drawString(strings[kStringLevel0]     , 11, 21, kColorExitText, kColorBlack, 1, surface);
+	font->drawString(strings[kStringPenetration], 11, 42, kColorExitText, kColorBlack, 1, surface);
+	font->drawString(strings[kStringSuccessful] , 11, 58, kColorExitText, kColorBlack, 1, surface);
+
+	font->drawString(strings[kStringDanger]   , 11,  82, kColorFloorText, kColorBlack, 1, surface);
+	font->drawString(strings[kStringGynoides] , 11,  98, kColorFloorText, kColorBlack, 1, surface);
+	font->drawString(strings[kStringActivated], 11, 113, kColorFloorText, kColorBlack, 1, surface);
 
 	_vm->_draw->dirtiedRect(_vm->_draw->_backSurface, kTextAreaLeft, kTextAreaTop, kTextAreaRight, kTextAreaBigBottom);
 	_vm->_draw->blitInvalidated();
diff --git a/engines/gob/video.cpp b/engines/gob/video.cpp
index f1f014c..8bcf14e 100644
--- a/engines/gob/video.cpp
+++ b/engines/gob/video.cpp
@@ -134,6 +134,23 @@ void Font::drawLetter(Surface &surf, uint8 c, uint16 x, uint16 y,
 	}
 }
 
+void Font::drawString(const Common::String &str, int16 x, int16 y, int16 color1, int16 color2,
+                      bool transp, Surface &dest) const {
+
+	const char *s = str.c_str();
+
+	while (*s != '\0') {
+		const int16 charRight  = x + getCharWidth(*s);
+		const int16 charBottom = y + getCharHeight();
+
+		if ((x >= 0) && (y >= 0) && (charRight <= dest.getWidth()) && (charBottom <= dest.getHeight()))
+			drawLetter(dest, *s, x, y, color1, color2, transp);
+
+		x += getCharWidth(*s);
+		s++;
+	}
+}
+
 const byte *Font::getCharData(uint8 c) const {
 	if (_endItem == 0) {
 		warning("Font::getCharData(): _endItem == 0");
diff --git a/engines/gob/video.h b/engines/gob/video.h
index ecbb579..a8c1480 100644
--- a/engines/gob/video.h
+++ b/engines/gob/video.h
@@ -46,6 +46,9 @@ public:
 	void drawLetter(Surface &surf, uint8 c, uint16 x, uint16 y,
 	                uint32 color1, uint32 color2, bool transp) const;
 
+	void drawString(const Common::String &str, int16 x, int16 y, int16 color1, int16 color2,
+	                bool transp, Surface &dest) const;
+
 private:
 	const byte *_dataPtr;
 	const byte  *_data;


Commit: bba2028fbaa1c2b3b2b89badd6bf8f36cbbe1cc1
    https://github.com/scummvm/scummvm/commit/bba2028fbaa1c2b3b2b89badd6bf8f36cbbe1cc1
Author: Sven Hesse (drmccoy at users.sourceforge.net)
Date: 2012-07-29T16:26:58-07:00

Commit Message:
GOB: Move the method definitions out of the GobMetaEngine class definition

Changed paths:
    engines/gob/detection/detection.cpp



diff --git a/engines/gob/detection/detection.cpp b/engines/gob/detection/detection.cpp
index 14da546..8b4fab4 100644
--- a/engines/gob/detection/detection.cpp
+++ b/engines/gob/detection/detection.cpp
@@ -30,43 +30,51 @@
 
 class GobMetaEngine : public AdvancedMetaEngine {
 public:
-	GobMetaEngine() : AdvancedMetaEngine(Gob::gameDescriptions, sizeof(Gob::GOBGameDescription), gobGames) {
-		_singleid = "gob";
-		_guioptions = GUIO1(GUIO_NOLAUNCHLOAD);
-	}
-
-	virtual GameDescriptor findGame(const char *gameid) const {
-		return Engines::findGameID(gameid, _gameids, obsoleteGameIDsTable);
-	}
+	GobMetaEngine();
 
-	virtual const ADGameDescription *fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist) const {
-		ADFilePropertiesMap filesProps;
+	virtual GameDescriptor findGame(const char *gameid) const;
 
-		const ADGameDescription *game = detectGameFilebased(allFiles, fslist, Gob::fileBased, &filesProps);
-		if (!game)
-			return 0;
+	virtual const ADGameDescription *fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist) const;
 
-		reportUnknown(fslist.begin()->getParent(), filesProps);
-		return game;
-	}
-
-	virtual const char *getName() const {
-		return "Gob";
-	}
-
-	virtual const char *getOriginalCopyright() const {
-		return "Goblins Games (C) Coktel Vision";
-	}
+	virtual const char *getName() const;
+	virtual const char *getOriginalCopyright() const;
 
 	virtual bool hasFeature(MetaEngineFeature f) const;
 
-	virtual Common::Error createInstance(OSystem *syst, Engine **engine) const {
-		Engines::upgradeTargetIfNecessary(obsoleteGameIDsTable);
-		return AdvancedMetaEngine::createInstance(syst, engine);
-	}
+	virtual Common::Error createInstance(OSystem *syst, Engine **engine) const;
 	virtual bool createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const;
 };
 
+GobMetaEngine::GobMetaEngine() :
+	AdvancedMetaEngine(Gob::gameDescriptions, sizeof(Gob::GOBGameDescription), gobGames) {
+
+	_singleid   = "gob";
+	_guioptions = GUIO1(GUIO_NOLAUNCHLOAD);
+}
+
+GameDescriptor GobMetaEngine::findGame(const char *gameid) const {
+	return Engines::findGameID(gameid, _gameids, obsoleteGameIDsTable);
+}
+
+const ADGameDescription *GobMetaEngine::fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist) const {
+	ADFilePropertiesMap filesProps;
+
+	const ADGameDescription *game = detectGameFilebased(allFiles, fslist, Gob::fileBased, &filesProps);
+	if (!game)
+		return 0;
+
+	reportUnknown(fslist.begin()->getParent(), filesProps);
+	return game;
+}
+
+const char *GobMetaEngine::getName() const {
+	return "Gob";
+}
+
+const char *GobMetaEngine::getOriginalCopyright() const {
+	return "Goblins Games (C) Coktel Vision";
+}
+
 bool GobMetaEngine::hasFeature(MetaEngineFeature f) const {
 	return false;
 }
@@ -75,6 +83,12 @@ bool Gob::GobEngine::hasFeature(EngineFeature f) const {
 	return
 		(f == kSupportsRTL);
 }
+
+Common::Error GobMetaEngine::createInstance(OSystem *syst, Engine **engine) const {
+	Engines::upgradeTargetIfNecessary(obsoleteGameIDsTable);
+	return AdvancedMetaEngine::createInstance(syst, engine);
+}
+
 bool GobMetaEngine::createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const {
 	const Gob::GOBGameDescription *gd = (const Gob::GOBGameDescription *)desc;
 	if (gd) {
@@ -84,6 +98,7 @@ bool GobMetaEngine::createInstance(OSystem *syst, Engine **engine, const ADGameD
 	return gd != 0;
 }
 
+
 #if PLUGIN_ENABLED_DYNAMIC(GOB)
 	REGISTER_PLUGIN_DYNAMIC(GOB, PLUGIN_TYPE_ENGINE, GobMetaEngine);
 #else


Commit: 4a380ce668c45e5eaba1cdba9406d0c7fe7f3635
    https://github.com/scummvm/scummvm/commit/4a380ce668c45e5eaba1cdba9406d0c7fe7f3635
Author: Sven Hesse (drmccoy at users.sourceforge.net)
Date: 2012-07-29T16:44:41-07:00

Commit Message:
GOB: Add detection tables for Baba Yaga and Abracadabra

Changed paths:
  A engines/gob/detection/tables_onceupon.h
    engines/gob/detection/tables.h
    engines/gob/detection/tables_ajworld.h
    engines/gob/detection/tables_fallback.h
    engines/gob/gob.h



diff --git a/engines/gob/detection/tables.h b/engines/gob/detection/tables.h
index 5d211ac..271f75a 100644
--- a/engines/gob/detection/tables.h
+++ b/engines/gob/detection/tables.h
@@ -48,7 +48,10 @@ static const PlainGameDescriptor gobGames[] = {
 	{"gob2cd", "Gobliins 2 CD"},
 	{"ween", "Ween: The Prophecy"},
 	{"bargon", "Bargon Attack"},
+	{"babayaga", "Once Upon A Time: Baba Yaga"},
+	{"abracadabra", "Once Upon A Time: Abracadabra"},
 	{"littlered", "Once Upon A Time: Little Red Riding Hood"},
+	{"onceupon", "Once Upon A Time"},
 	{"ajworld", "A.J.'s World of Discovery"},
 	{"gob3", "Goblins Quest 3"},
 	{"gob3cd", "Goblins Quest 3 CD"},
@@ -94,6 +97,7 @@ static const GOBGameDescription gameDescriptions[] = {
 	#include "gob/detection/tables_ween.h"      // Ween: The Prophecy
 	#include "gob/detection/tables_bargon.h"    // Bargon Attack
 	#include "gob/detection/tables_littlered.h" // Once Upon A Time: Little Red Riding Hood
+	#include "gob/detection/tables_onceupon.h"  // Once Upon A Time: Baba Yaga and Abracadabra
 	#include "gob/detection/tables_lit.h"       // Lost in Time
 	#include "gob/detection/tables_fascin.h"    // Fascination
 	#include "gob/detection/tables_geisha.h"    // Geisha
diff --git a/engines/gob/detection/tables_ajworld.h b/engines/gob/detection/tables_ajworld.h
index c78d11a..d86bdb1 100644
--- a/engines/gob/detection/tables_ajworld.h
+++ b/engines/gob/detection/tables_ajworld.h
@@ -1,4 +1,3 @@
-
 /* ScummVM - Graphic Adventure Engine
  *
  * ScummVM is the legal property of its developers, whose names
diff --git a/engines/gob/detection/tables_fallback.h b/engines/gob/detection/tables_fallback.h
index 2853ee7..0e0aa92 100644
--- a/engines/gob/detection/tables_fallback.h
+++ b/engines/gob/detection/tables_fallback.h
@@ -362,6 +362,20 @@ static const GOBGameDescription fallbackDescs[] = {
 	},
 	{ //24
 		{
+			"onceupon",
+			"unknown",
+			AD_ENTRY1(0, 0),
+			UNK_LANG,
+			kPlatformUnknown,
+			ADGF_NO_FLAGS,
+			GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH)
+		},
+		kGameTypeOnceUponATime,
+		kFeaturesEGA,
+		0, 0, 0
+	},
+	{ //25
+		{
 			"adi2",
 			"",
 			AD_ENTRY1(0, 0),
@@ -374,7 +388,7 @@ static const GOBGameDescription fallbackDescs[] = {
 		kFeatures640x480,
 		"adi2.stk", 0, 0
 	},
-	{ //25
+	{ //26
 		{
 			"adi4",
 			"",
@@ -388,7 +402,7 @@ static const GOBGameDescription fallbackDescs[] = {
 		kFeatures640x480,
 		"adif41.stk", 0, 0
 	},
-	{ //26
+	{ //27
 		{
 			"coktelplayer",
 			"unknown",
@@ -430,9 +444,10 @@ static const ADFileBasedFallback fileBased[] = {
 	{ &fallbackDescs[21].desc, { "disk1.stk", "disk2.stk", "disk3.stk", 0 } },
 	{ &fallbackDescs[22].desc, { "intro.stk", "stk2.stk", "stk3.stk", 0 } },
 	{ &fallbackDescs[23].desc, { "intro.stk", "stk2.stk", "stk3.stk", "mod.babayaga", 0 } },
-	{ &fallbackDescs[24].desc, { "adi2.stk", 0 } },
-	{ &fallbackDescs[25].desc, { "adif41.stk", "adim41.stk", 0 } },
-	{ &fallbackDescs[26].desc, { "coktelplayer.scn", 0 } },
+	{ &fallbackDescs[24].desc, { "stk1.stk", "stk2.stk", "stk3.stk", 0 } },
+	{ &fallbackDescs[25].desc, { "adi2.stk", 0 } },
+	{ &fallbackDescs[26].desc, { "adif41.stk", "adim41.stk", 0 } },
+	{ &fallbackDescs[27].desc, { "coktelplayer.scn", 0 } },
 	{ 0, { 0 } }
 };
 
diff --git a/engines/gob/detection/tables_onceupon.h b/engines/gob/detection/tables_onceupon.h
new file mode 100644
index 0000000..366024d
--- /dev/null
+++ b/engines/gob/detection/tables_onceupon.h
@@ -0,0 +1,518 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/* Detection tables for Once Upon A Time: Baba Yaga and Abracadabra. */
+
+#ifndef GOB_DETECTION_TABLES_ONCEUPON_H
+#define GOB_DETECTION_TABLES_ONCEUPON_H
+
+// -- Once Upon A Time: Abracadabra, Amiga --
+
+{
+	{
+		"abracadabra",
+		"",
+		{
+			{"stk1.stk", 0, "a8e963eea170155548e5bc1d0f07d50d", 209806},
+			{"stk2.stk", 0, "e4b21818af03930dc9cab2ad4c93cb5b", 362106},
+			{"stk3.stk", 0, "76874ad92782f9b2de57beafc05ec877", 353482},
+			{0, 0, 0, 0}
+		},
+		FR_FRA,
+		kPlatformAmiga,
+		ADGF_NO_FLAGS,
+		GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH)
+	},
+	kGameTypeAbracadabra,
+	kFeaturesEGA,
+	0, 0, 0
+},
+{
+	{
+		"abracadabra",
+		"",
+		{
+			{"stk1.stk", 0, "a8e963eea170155548e5bc1d0f07d50d", 209806},
+			{"stk2.stk", 0, "e4b21818af03930dc9cab2ad4c93cb5b", 362106},
+			{"stk3.stk", 0, "76874ad92782f9b2de57beafc05ec877", 353482},
+			{0, 0, 0, 0}
+		},
+		DE_DEU,
+		kPlatformAmiga,
+		ADGF_NO_FLAGS,
+		GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH)
+	},
+	kGameTypeAbracadabra,
+	kFeaturesEGA,
+	0, 0, 0
+},
+{
+	{
+		"abracadabra",
+		"",
+		{
+			{"stk1.stk", 0, "a8e963eea170155548e5bc1d0f07d50d", 209806},
+			{"stk2.stk", 0, "e4b21818af03930dc9cab2ad4c93cb5b", 362106},
+			{"stk3.stk", 0, "76874ad92782f9b2de57beafc05ec877", 353482},
+			{0, 0, 0, 0}
+		},
+		EN_ANY,
+		kPlatformAmiga,
+		ADGF_NO_FLAGS,
+		GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH)
+	},
+	kGameTypeAbracadabra,
+	kFeaturesEGA,
+	0, 0, 0
+},
+{
+	{
+		"abracadabra",
+		"",
+		{
+			{"stk1.stk", 0, "a8e963eea170155548e5bc1d0f07d50d", 209806},
+			{"stk2.stk", 0, "e4b21818af03930dc9cab2ad4c93cb5b", 362106},
+			{"stk3.stk", 0, "76874ad92782f9b2de57beafc05ec877", 353482},
+			{0, 0, 0, 0}
+		},
+		IT_ITA,
+		kPlatformAmiga,
+		ADGF_NO_FLAGS,
+		GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH)
+	},
+	kGameTypeAbracadabra,
+	kFeaturesEGA,
+	0, 0, 0
+},
+{
+	{
+		"abracadabra",
+		"",
+		{
+			{"stk1.stk", 0, "a8e963eea170155548e5bc1d0f07d50d", 209806},
+			{"stk2.stk", 0, "e4b21818af03930dc9cab2ad4c93cb5b", 362106},
+			{"stk3.stk", 0, "76874ad92782f9b2de57beafc05ec877", 353482},
+			{0, 0, 0, 0}
+		},
+		ES_ESP,
+		kPlatformAmiga,
+		ADGF_NO_FLAGS,
+		GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH)
+	},
+	kGameTypeAbracadabra,
+	kFeaturesEGA,
+	0, 0, 0
+},
+
+// -- Once Upon A Time: Abracadabra, Atari ST --
+
+{
+	{
+		"abracadabra",
+		"",
+		{
+			{"stk1.stk", 0, "a8e963eea170155548e5bc1d0f07d50d", 209806},
+			{"stk2.stk", 0, "c6440aaf068ec3149ae89bc5c41ebf02", 362123},
+			{"stk3.stk", 0, "5af3c1202ba6fcf8dad2b2125e1c1383", 353257},
+			{0, 0, 0, 0}
+		},
+		FR_FRA,
+		kPlatformAtariST,
+		ADGF_NO_FLAGS,
+		GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH)
+	},
+	kGameTypeAbracadabra,
+	kFeaturesEGA,
+	0, 0, 0
+},
+{
+	{
+		"abracadabra",
+		"",
+		{
+			{"stk1.stk", 0, "a8e963eea170155548e5bc1d0f07d50d", 209806},
+			{"stk2.stk", 0, "c6440aaf068ec3149ae89bc5c41ebf02", 362123},
+			{"stk3.stk", 0, "5af3c1202ba6fcf8dad2b2125e1c1383", 353257},
+			{0, 0, 0, 0}
+		},
+		DE_DEU,
+		kPlatformAtariST,
+		ADGF_NO_FLAGS,
+		GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH)
+	},
+	kGameTypeAbracadabra,
+	kFeaturesEGA,
+	0, 0, 0
+},
+{
+	{
+		"abracadabra",
+		"",
+		{
+			{"stk1.stk", 0, "a8e963eea170155548e5bc1d0f07d50d", 209806},
+			{"stk2.stk", 0, "c6440aaf068ec3149ae89bc5c41ebf02", 362123},
+			{"stk3.stk", 0, "5af3c1202ba6fcf8dad2b2125e1c1383", 353257},
+			{0, 0, 0, 0}
+		},
+		EN_ANY,
+		kPlatformAtariST,
+		ADGF_NO_FLAGS,
+		GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH)
+	},
+	kGameTypeAbracadabra,
+	kFeaturesEGA,
+	0, 0, 0
+},
+{
+	{
+		"abracadabra",
+		"",
+		{
+			{"stk1.stk", 0, "a8e963eea170155548e5bc1d0f07d50d", 209806},
+			{"stk2.stk", 0, "c6440aaf068ec3149ae89bc5c41ebf02", 362123},
+			{"stk3.stk", 0, "5af3c1202ba6fcf8dad2b2125e1c1383", 353257},
+			{0, 0, 0, 0}
+		},
+		IT_ITA,
+		kPlatformAtariST,
+		ADGF_NO_FLAGS,
+		GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH)
+	},
+	kGameTypeAbracadabra,
+	kFeaturesEGA,
+	0, 0, 0
+},
+{
+	{
+		"abracadabra",
+		"",
+		{
+			{"stk1.stk", 0, "a8e963eea170155548e5bc1d0f07d50d", 209806},
+			{"stk2.stk", 0, "c6440aaf068ec3149ae89bc5c41ebf02", 362123},
+			{"stk3.stk", 0, "5af3c1202ba6fcf8dad2b2125e1c1383", 353257},
+			{0, 0, 0, 0}
+		},
+		ES_ESP,
+		kPlatformAtariST,
+		ADGF_NO_FLAGS,
+		GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH)
+	},
+	kGameTypeAbracadabra,
+	kFeaturesEGA,
+	0, 0, 0
+},
+
+// -- Once Upon A Time: Baba Yaga, DOS EGA Floppy --
+
+{
+	{
+		"babayaga",
+		"",
+		{
+			{"stk1.stk", 0, "3c777f43e6fb49fde9222543447e135a", 204813},
+			{"stk2.stk", 0, "6cf0b009dd185a8f589e91a1f9c33df5", 361582},
+			{"stk3.stk", 0, "6473183ca4db1b5b5cea047f9af59a26", 328925},
+			{0, 0, 0, 0}
+		},
+		FR_FRA,
+		kPlatformPC,
+		ADGF_NO_FLAGS,
+		GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH)
+	},
+	kGameTypeBabaYaga,
+	kFeaturesAdLib | kFeaturesEGA,
+	0, 0, 0
+},
+{
+	{
+		"babayaga",
+		"",
+		{
+			{"stk1.stk", 0, "3c777f43e6fb49fde9222543447e135a", 204813},
+			{"stk2.stk", 0, "6cf0b009dd185a8f589e91a1f9c33df5", 361582},
+			{"stk3.stk", 0, "6473183ca4db1b5b5cea047f9af59a26", 328925},
+			{0, 0, 0, 0}
+		},
+		DE_DEU,
+		kPlatformPC,
+		ADGF_NO_FLAGS,
+		GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH)
+	},
+	kGameTypeBabaYaga,
+	kFeaturesAdLib | kFeaturesEGA,
+	0, 0, 0
+},
+{
+	{
+		"babayaga",
+		"",
+		{
+			{"stk1.stk", 0, "3c777f43e6fb49fde9222543447e135a", 204813},
+			{"stk2.stk", 0, "6cf0b009dd185a8f589e91a1f9c33df5", 361582},
+			{"stk3.stk", 0, "6473183ca4db1b5b5cea047f9af59a26", 328925},
+			{0, 0, 0, 0}
+		},
+		EN_ANY,
+		kPlatformPC,
+		ADGF_NO_FLAGS,
+		GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH)
+	},
+	kGameTypeBabaYaga,
+	kFeaturesAdLib | kFeaturesEGA,
+	0, 0, 0
+},
+{
+	{
+		"babayaga",
+		"",
+		{
+			{"stk1.stk", 0, "3c777f43e6fb49fde9222543447e135a", 204813},
+			{"stk2.stk", 0, "6cf0b009dd185a8f589e91a1f9c33df5", 361582},
+			{"stk3.stk", 0, "6473183ca4db1b5b5cea047f9af59a26", 328925},
+			{0, 0, 0, 0}
+		},
+		IT_ITA,
+		kPlatformPC,
+		ADGF_NO_FLAGS,
+		GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH)
+	},
+	kGameTypeBabaYaga,
+	kFeaturesAdLib | kFeaturesEGA,
+	0, 0, 0
+},
+{
+	{
+		"babayaga",
+		"",
+		{
+			{"stk1.stk", 0, "3c777f43e6fb49fde9222543447e135a", 204813},
+			{"stk2.stk", 0, "6cf0b009dd185a8f589e91a1f9c33df5", 361582},
+			{"stk3.stk", 0, "6473183ca4db1b5b5cea047f9af59a26", 328925},
+			{0, 0, 0, 0}
+		},
+		ES_ESP,
+		kPlatformPC,
+		ADGF_NO_FLAGS,
+		GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH)
+	},
+	kGameTypeBabaYaga,
+	kFeaturesAdLib | kFeaturesEGA,
+	0, 0, 0
+},
+
+// -- Once Upon A Time: Baba Yaga, Amiga --
+
+{
+	{
+		"babayaga",
+		"",
+		{
+			{"stk1.stk", 0, "bcc823d2888057031e54716ed1b3c80e", 205090},
+			{"stk2.stk", 0, "f76bf7c2ff60d816d69962d1a593207c", 362122},
+			{"stk3.stk", 0, "6227d1aefdf39d88dcf83e38bea2a9af", 328922},
+			{0, 0, 0, 0}
+		},
+		FR_FRA,
+		kPlatformAmiga,
+		ADGF_NO_FLAGS,
+		GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH)
+	},
+	kGameTypeBabaYaga,
+	kFeaturesEGA,
+	0, 0, 0
+},
+{
+	{
+		"babayaga",
+		"",
+		{
+			{"stk1.stk", 0, "bcc823d2888057031e54716ed1b3c80e", 205090},
+			{"stk2.stk", 0, "f76bf7c2ff60d816d69962d1a593207c", 362122},
+			{"stk3.stk", 0, "6227d1aefdf39d88dcf83e38bea2a9af", 328922},
+			{0, 0, 0, 0}
+		},
+		DE_DEU,
+		kPlatformAmiga,
+		ADGF_NO_FLAGS,
+		GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH)
+	},
+	kGameTypeBabaYaga,
+	kFeaturesEGA,
+	0, 0, 0
+},
+{
+	{
+		"babayaga",
+		"",
+		{
+			{"stk1.stk", 0, "bcc823d2888057031e54716ed1b3c80e", 205090},
+			{"stk2.stk", 0, "f76bf7c2ff60d816d69962d1a593207c", 362122},
+			{"stk3.stk", 0, "6227d1aefdf39d88dcf83e38bea2a9af", 328922},
+			{0, 0, 0, 0}
+		},
+		EN_ANY,
+		kPlatformAmiga,
+		ADGF_NO_FLAGS,
+		GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH)
+	},
+	kGameTypeBabaYaga,
+	kFeaturesEGA,
+	0, 0, 0
+},
+{
+	{
+		"babayaga",
+		"",
+		{
+			{"stk1.stk", 0, "bcc823d2888057031e54716ed1b3c80e", 205090},
+			{"stk2.stk", 0, "f76bf7c2ff60d816d69962d1a593207c", 362122},
+			{"stk3.stk", 0, "6227d1aefdf39d88dcf83e38bea2a9af", 328922},
+			{0, 0, 0, 0}
+		},
+		IT_ITA,
+		kPlatformAmiga,
+		ADGF_NO_FLAGS,
+		GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH)
+	},
+	kGameTypeBabaYaga,
+	kFeaturesEGA,
+	0, 0, 0
+},
+{
+	{
+		"babayaga",
+		"",
+		{
+			{"stk1.stk", 0, "bcc823d2888057031e54716ed1b3c80e", 205090},
+			{"stk2.stk", 0, "f76bf7c2ff60d816d69962d1a593207c", 362122},
+			{"stk3.stk", 0, "6227d1aefdf39d88dcf83e38bea2a9af", 328922},
+			{0, 0, 0, 0}
+		},
+		ES_ESP,
+		kPlatformAmiga,
+		ADGF_NO_FLAGS,
+		GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH)
+	},
+	kGameTypeBabaYaga,
+	kFeaturesEGA,
+	0, 0, 0
+},
+
+// -- Once Upon A Time: Baba Yaga, Atari ST --
+
+{
+	{
+		"babayaga",
+		"",
+		{
+			{"stk1.stk", 0, "17a4e3e7a18cc97231c92d280c7878a1", 205095},
+			{"stk2.stk", 0, "bfbc380e5461f63af28e9e6b10f334b5", 362128},
+			{"stk3.stk", 0, "6227d1aefdf39d88dcf83e38bea2a9af", 328922},
+			{0, 0, 0, 0}
+		},
+		FR_FRA,
+		kPlatformAtariST,
+		ADGF_NO_FLAGS,
+		GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH)
+	},
+	kGameTypeBabaYaga,
+	kFeaturesEGA,
+	0, 0, 0
+},
+{
+	{
+		"babayaga",
+		"",
+		{
+			{"stk1.stk", 0, "17a4e3e7a18cc97231c92d280c7878a1", 205095},
+			{"stk2.stk", 0, "bfbc380e5461f63af28e9e6b10f334b5", 362128},
+			{"stk3.stk", 0, "6227d1aefdf39d88dcf83e38bea2a9af", 328922},
+			{0, 0, 0, 0}
+		},
+		DE_DEU,
+		kPlatformAtariST,
+		ADGF_NO_FLAGS,
+		GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH)
+	},
+	kGameTypeBabaYaga,
+	kFeaturesEGA,
+	0, 0, 0
+},
+{
+	{
+		"babayaga",
+		"",
+		{
+			{"stk1.stk", 0, "17a4e3e7a18cc97231c92d280c7878a1", 205095},
+			{"stk2.stk", 0, "bfbc380e5461f63af28e9e6b10f334b5", 362128},
+			{"stk3.stk", 0, "6227d1aefdf39d88dcf83e38bea2a9af", 328922},
+			{0, 0, 0, 0}
+		},
+		EN_ANY,
+		kPlatformAtariST,
+		ADGF_NO_FLAGS,
+		GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH)
+	},
+	kGameTypeBabaYaga,
+	kFeaturesEGA,
+	0, 0, 0
+},
+{
+	{
+		"babayaga",
+		"",
+		{
+			{"stk1.stk", 0, "17a4e3e7a18cc97231c92d280c7878a1", 205095},
+			{"stk2.stk", 0, "bfbc380e5461f63af28e9e6b10f334b5", 362128},
+			{"stk3.stk", 0, "6227d1aefdf39d88dcf83e38bea2a9af", 328922},
+			{0, 0, 0, 0}
+		},
+		IT_ITA,
+		kPlatformAtariST,
+		ADGF_NO_FLAGS,
+		GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH)
+	},
+	kGameTypeBabaYaga,
+	kFeaturesEGA,
+	0, 0, 0
+},
+{
+	{
+		"babayaga",
+		"",
+		{
+			{"stk1.stk", 0, "17a4e3e7a18cc97231c92d280c7878a1", 205095},
+			{"stk2.stk", 0, "bfbc380e5461f63af28e9e6b10f334b5", 362128},
+			{"stk3.stk", 0, "6227d1aefdf39d88dcf83e38bea2a9af", 328922},
+			{0, 0, 0, 0}
+		},
+		ES_ESP,
+		kPlatformAtariST,
+		ADGF_NO_FLAGS,
+		GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH)
+	},
+	kGameTypeBabaYaga,
+	kFeaturesEGA,
+	0, 0, 0
+},
+
+#endif // GOB_DETECTION_TABLES_ONCEUPON_H
diff --git a/engines/gob/gob.h b/engines/gob/gob.h
index d3d2bf1..5d4c3d7 100644
--- a/engines/gob/gob.h
+++ b/engines/gob/gob.h
@@ -129,7 +129,10 @@ enum GameType {
 	kGameTypeAdi4,
 	kGameTypeAdibou2,
 	kGameTypeAdibou1,
+	kGameTypeAbracadabra,
+	kGameTypeBabaYaga,
 	kGameTypeLittleRed,
+	kGameTypeOnceUponATime, // Need more inspection to see if Baba Yaga or Abracadabra
 	kGameTypeAJWorld
 };
 


Commit: 55c75756ea3c38cdd7074caff7085e35a658c9e7
    https://github.com/scummvm/scummvm/commit/55c75756ea3c38cdd7074caff7085e35a658c9e7
Author: Sven Hesse (drmccoy at users.sourceforge.net)
Date: 2012-07-29T16:44:42-07:00

Commit Message:
GOB: Add a more complex detection for Once Upon A Time titles

The hard-coded Once Upon A Time titles, Abracadabra and Baba Yaga,
are impossible to distinguish by file name alone. The same is true
for the each three platforms, DOS, Amiga and Atari ST.

We do need to know exactly which game and platform a specific path
holds, though, because they're
a) completely hard-coded
b) the data files have platform-specific endianness

Therefore, when the filename-based fallback detector finds one of
those games, we open the archives and look inside them.
We detect the specific game by looking at which animal names are
present; and the platform by inspecting the endianness of the
title screen's DEC file, in addition to the existence of a MOD
file to distinguish the Atari ST from the Amiga version.

Changed paths:
    engines/gob/detection/detection.cpp
    engines/gob/detection/tables_fallback.h



diff --git a/engines/gob/detection/detection.cpp b/engines/gob/detection/detection.cpp
index 8b4fab4..8fb0052 100644
--- a/engines/gob/detection/detection.cpp
+++ b/engines/gob/detection/detection.cpp
@@ -25,6 +25,7 @@
 #include "engines/obsolete.h"
 
 #include "gob/gob.h"
+#include "gob/dataio.h"
 
 #include "gob/detection/tables.h"
 
@@ -43,6 +44,12 @@ public:
 
 	virtual Common::Error createInstance(OSystem *syst, Engine **engine) const;
 	virtual bool createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const;
+
+private:
+	/**
+	 * Inspect the game archives to detect which Once Upon A Time game this is.
+	 */
+	static const Gob::GOBGameDescription *detectOnceUponATime(const Common::FSList &fslist);
 };
 
 GobMetaEngine::GobMetaEngine() :
@@ -59,12 +66,96 @@ GameDescriptor GobMetaEngine::findGame(const char *gameid) const {
 const ADGameDescription *GobMetaEngine::fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist) const {
 	ADFilePropertiesMap filesProps;
 
-	const ADGameDescription *game = detectGameFilebased(allFiles, fslist, Gob::fileBased, &filesProps);
+	const Gob::GOBGameDescription *game;
+	game = (const Gob::GOBGameDescription *)detectGameFilebased(allFiles, fslist, Gob::fileBased, &filesProps);
 	if (!game)
 		return 0;
 
+	if (game->gameType == Gob::kGameTypeOnceUponATime) {
+		game = detectOnceUponATime(fslist);
+		if (!game)
+			return 0;
+	}
+
 	reportUnknown(fslist.begin()->getParent(), filesProps);
-	return game;
+	return (const ADGameDescription *)game;
+}
+
+const Gob::GOBGameDescription *GobMetaEngine::detectOnceUponATime(const Common::FSList &fslist) {
+	// Add the game path to the search manager
+	SearchMan.clear();
+	SearchMan.addDirectory(fslist.begin()->getParent().getPath(), fslist.begin()->getParent());
+
+	// Open the archives
+	Gob::DataIO dataIO;
+	if (!dataIO.openArchive("stk1.stk", true) ||
+	    !dataIO.openArchive("stk2.stk", true) ||
+	    !dataIO.openArchive("stk3.stk", true)) {
+
+		SearchMan.clear();
+		return 0;
+	}
+
+	Gob::OnceUponATime gameType         = Gob::kOnceUponATimeInvalid;
+	Gob::OnceUponATimePlatform platform = Gob::kOnceUponATimePlatformInvalid;
+
+	// If these animal files are present, it's Abracadabra
+	if (dataIO.hasFile("arai.anm") &&
+	    dataIO.hasFile("crab.anm") &&
+	    dataIO.hasFile("crap.anm") &&
+	    dataIO.hasFile("drag.anm") &&
+	    dataIO.hasFile("guep.anm") &&
+	    dataIO.hasFile("loup.anm") &&
+	    dataIO.hasFile("mous.anm") &&
+	    dataIO.hasFile("rhin.anm") &&
+	    dataIO.hasFile("saut.anm") &&
+	    dataIO.hasFile("scor.anm"))
+		gameType = Gob::kOnceUponATimeAbracadabra;
+
+	// If these animal files are present, it's Baba Yaga
+	if (dataIO.hasFile("abei.anm") &&
+	    dataIO.hasFile("arai.anm") &&
+	    dataIO.hasFile("drag.anm") &&
+	    dataIO.hasFile("fauc.anm") &&
+	    dataIO.hasFile("gren.anm") &&
+	    dataIO.hasFile("rena.anm") &&
+	    dataIO.hasFile("sang.anm") &&
+	    dataIO.hasFile("serp.anm") &&
+	    dataIO.hasFile("tort.anm") &&
+	    dataIO.hasFile("vaut.anm"))
+		gameType = Gob::kOnceUponATimeBabaYaga;
+
+	// Detect the platform by endianness and existence of a MOD file
+	Common::SeekableReadStream *villeDEC = dataIO.getFile("ville.dec");
+	if (villeDEC && (villeDEC->size() > 6)) {
+		byte data[6];
+
+		if (villeDEC->read(data, 6) == 6) {
+			if        (!memcmp(data, "\000\000\000\001\000\007", 6)) {
+				// Big endian -> Amiga or Atari ST
+
+				if (dataIO.hasFile("mod.babayaga"))
+					platform = Gob::kOnceUponATimePlatformAmiga;
+				else
+					platform = Gob::kOnceUponATimePlatformAtariST;
+
+			} else if (!memcmp(data, "\000\000\001\000\007\000", 6))
+				// Little endian -> DOS
+				platform = Gob::kOnceUponATimePlatformDOS;
+		}
+
+		delete villeDEC;
+	}
+
+	SearchMan.clear();
+
+	if ((gameType == Gob::kOnceUponATimeInvalid) || (platform == Gob::kOnceUponATimePlatformInvalid)) {
+		warning("GobMetaEngine::detectOnceUponATime(): Detection failed (%d, %d)",
+		        (int) gameType, (int) platform);
+		return 0;
+	}
+
+	return &Gob::fallbackOnceUpon[gameType][platform];
 }
 
 const char *GobMetaEngine::getName() const {
diff --git a/engines/gob/detection/tables_fallback.h b/engines/gob/detection/tables_fallback.h
index 0e0aa92..05f579c 100644
--- a/engines/gob/detection/tables_fallback.h
+++ b/engines/gob/detection/tables_fallback.h
@@ -23,6 +23,8 @@
 #ifndef GOB_DETECTION_TABLES_FALLBACK_H
 #define GOB_DETECTION_TABLES_FALLBACK_H
 
+// -- Tables for the filename-based fallback --
+
 static const GOBGameDescription fallbackDescs[] = {
 	{ //0
 		{
@@ -451,4 +453,112 @@ static const ADFileBasedFallback fileBased[] = {
 	{ 0, { 0 } }
 };
 
+// -- Tables for detecting the specific Once Upon A Time game --
+
+enum OnceUponATime {
+	kOnceUponATimeInvalid     = -1,
+	kOnceUponATimeAbracadabra =  0,
+	kOnceUponATimeBabaYaga    =  1,
+	kOnceUponATimeMAX
+};
+
+enum OnceUponATimePlatform {
+	kOnceUponATimePlatformInvalid = -1,
+	kOnceUponATimePlatformDOS     =  0,
+	kOnceUponATimePlatformAmiga   =  1,
+	kOnceUponATimePlatformAtariST =  2,
+	kOnceUponATimePlatformMAX
+};
+
+static const GOBGameDescription fallbackOnceUpon[kOnceUponATimeMAX][kOnceUponATimePlatformMAX] = {
+	{ // kOnceUponATimeAbracadabra
+		{ // kOnceUponATimePlatformDOS
+			{
+				"abracadabra",
+				"",
+				AD_ENTRY1(0, 0),
+				UNK_LANG,
+				kPlatformPC,
+				ADGF_NO_FLAGS,
+				GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH)
+			},
+			kGameTypeAbracadabra,
+			kFeaturesAdLib | kFeaturesEGA,
+			0, 0, 0
+		},
+		{ // kOnceUponATimePlatformAmiga
+			{
+				"abracadabra",
+				"",
+				AD_ENTRY1(0, 0),
+				UNK_LANG,
+				kPlatformAmiga,
+				ADGF_NO_FLAGS,
+				GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH)
+			},
+			kGameTypeAbracadabra,
+			kFeaturesEGA,
+			0, 0, 0
+		},
+		{ // kOnceUponATimePlatformAtariST
+			{
+				"abracadabra",
+				"",
+				AD_ENTRY1(0, 0),
+				UNK_LANG,
+				kPlatformAtariST,
+				ADGF_NO_FLAGS,
+				GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH)
+			},
+			kGameTypeAbracadabra,
+			kFeaturesEGA,
+			0, 0, 0
+		}
+	},
+	{ // kOnceUponATimeBabaYaga
+		{ // kOnceUponATimePlatformDOS
+			{
+				"babayaga",
+				"",
+				AD_ENTRY1(0, 0),
+				UNK_LANG,
+				kPlatformPC,
+				ADGF_NO_FLAGS,
+				GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH)
+			},
+			kGameTypeBabaYaga,
+			kFeaturesAdLib | kFeaturesEGA,
+			0, 0, 0
+		},
+		{ // kOnceUponATimePlatformAmiga
+			{
+				"babayaga",
+				"",
+				AD_ENTRY1(0, 0),
+				UNK_LANG,
+				kPlatformAmiga,
+				ADGF_NO_FLAGS,
+				GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH)
+			},
+			kGameTypeBabaYaga,
+			kFeaturesEGA,
+			0, 0, 0
+		},
+		{ // kOnceUponATimePlatformAtariST
+			{
+				"babayaga",
+				"",
+				AD_ENTRY1(0, 0),
+				UNK_LANG,
+				kPlatformAtariST,
+				ADGF_NO_FLAGS,
+				GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH)
+			},
+			kGameTypeBabaYaga,
+			kFeaturesEGA,
+			0, 0, 0
+		}
+	}
+};
+
 #endif // GOB_DETECTION_TABLES_FALLBACK_H


Commit: 4819468d9ad8218d04a2e4563ef71d7d00964515
    https://github.com/scummvm/scummvm/commit/4819468d9ad8218d04a2e4563ef71d7d00964515
Author: Sven Hesse (drmccoy at users.sourceforge.net)
Date: 2012-07-29T16:44:42-07:00

Commit Message:
GOB: Add PreGob stubs for the Once Upon A Time games

Changed paths:
  A engines/gob/pregob/onceupon/abracadabra.cpp
  A engines/gob/pregob/onceupon/abracadabra.h
  A engines/gob/pregob/onceupon/babayaga.cpp
  A engines/gob/pregob/onceupon/babayaga.h
  A engines/gob/pregob/onceupon/onceupon.cpp
  A engines/gob/pregob/onceupon/onceupon.h
  A engines/gob/pregob/pregob.cpp
  A engines/gob/pregob/pregob.h
    engines/gob/gob.cpp
    engines/gob/gob.h
    engines/gob/init.cpp
    engines/gob/module.mk



diff --git a/engines/gob/gob.cpp b/engines/gob/gob.cpp
index ef9a711..02aea63 100644
--- a/engines/gob/gob.cpp
+++ b/engines/gob/gob.cpp
@@ -48,6 +48,10 @@
 #include "gob/videoplayer.h"
 #include "gob/save/saveload.h"
 
+#include "gob/pregob/pregob.h"
+#include "gob/pregob/onceupon/abracadabra.h"
+#include "gob/pregob/onceupon/babayaga.h"
+
 namespace Gob {
 
 #define MAX_TIME_DELTA 100
@@ -115,7 +119,7 @@ GobEngine::GobEngine(OSystem *syst) : Engine(syst), _rnd("gob") {
 	_vidPlayer = 0; _init     = 0; _inter   = 0;
 	_map       = 0; _palAnim  = 0; _scenery = 0;
 	_draw      = 0; _util     = 0; _video   = 0;
-	_saveLoad  = 0;
+	_saveLoad  = 0; _preGob   = 0;
 
 	_pauseStart = 0;
 
@@ -398,7 +402,6 @@ Common::Error GobEngine::initGameParts() {
 
 	// just detect some devices some of which will be always there if the music is not disabled
 	_noMusic = MidiDriver::getMusicType(MidiDriver::detectDevice(MDT_PCSPK | MDT_MIDI | MDT_ADLIB)) == MT_NULL ? true : false;
-	_saveLoad = 0;
 
 	_global    = new Global(this);
 	_util      = new Util(this);
@@ -607,6 +610,28 @@ Common::Error GobEngine::initGameParts() {
 		_saveLoad = new SaveLoad_v2(this, _targetName.c_str());
 		break;
 
+	case kGameTypeAbracadabra:
+		_init     = new Init_v2(this);
+		_video    = new Video_v2(this);
+		_mult     = new Mult_v2(this);
+		_draw     = new Draw_v2(this);
+		_map      = new Map_v2(this);
+		_goblin   = new Goblin_v2(this);
+		_scenery  = new Scenery_v2(this);
+		_preGob   = new OnceUpon::Abracadabra(this);
+		break;
+
+	case kGameTypeBabaYaga:
+		_init     = new Init_v2(this);
+		_video    = new Video_v2(this);
+		_mult     = new Mult_v2(this);
+		_draw     = new Draw_v2(this);
+		_map      = new Map_v2(this);
+		_goblin   = new Goblin_v2(this);
+		_scenery  = new Scenery_v2(this);
+		_preGob   = new OnceUpon::BabaYaga(this);
+		break;
+
 	default:
 		deinitGameParts();
 		return Common::kUnsupportedGameidError;
@@ -615,12 +640,14 @@ Common::Error GobEngine::initGameParts() {
 	// Setup mixer
 	syncSoundSettings();
 
-	_inter->setupOpcodes();
+	if (_inter)
+		_inter->setupOpcodes();
 
 	return Common::kNoError;
 }
 
 void GobEngine::deinitGameParts() {
+	delete _preGob;    _preGob = 0;
 	delete _saveLoad;  _saveLoad = 0;
 	delete _mult;      _mult = 0;
 	delete _vidPlayer; _vidPlayer = 0;
diff --git a/engines/gob/gob.h b/engines/gob/gob.h
index 5d4c3d7..9b91909 100644
--- a/engines/gob/gob.h
+++ b/engines/gob/gob.h
@@ -75,6 +75,7 @@ class Scenery;
 class Util;
 class SaveLoad;
 class GobConsole;
+class PreGob;
 
 #define WRITE_VAR_UINT32(var, val)  _vm->_inter->_variables->writeVar32(var, val)
 #define WRITE_VAR_UINT16(var, val)  _vm->_inter->_variables->writeVar16(var, val)
@@ -223,6 +224,7 @@ public:
 	Inter *_inter;
 	SaveLoad *_saveLoad;
 	VideoPlayer *_vidPlayer;
+	PreGob *_preGob;
 
 	const char *getLangDesc(int16 language) const;
 	void validateLanguage();
diff --git a/engines/gob/init.cpp b/engines/gob/init.cpp
index a61261f..814d4d1 100644
--- a/engines/gob/init.cpp
+++ b/engines/gob/init.cpp
@@ -34,9 +34,13 @@
 #include "gob/inter.h"
 #include "gob/video.h"
 #include "gob/videoplayer.h"
+
+#include "gob/sound/sound.h"
+
 #include "gob/demos/scnplayer.h"
 #include "gob/demos/batplayer.h"
-#include "gob/sound/sound.h"
+
+#include "gob/pregob/pregob.h"
 
 namespace Gob {
 
@@ -118,6 +122,14 @@ void Init::initGame() {
 		return;
 	}
 
+	if (_vm->_preGob) {
+		_vm->_preGob->run();
+		delete _palDesc;
+		_vm->_video->initPrimary(-1);
+		cleanup();
+		return;
+	}
+
 	Common::SeekableReadStream *infFile = _vm->_dataIO->getFile("intro.inf");
 	if (!infFile) {
 
diff --git a/engines/gob/module.mk b/engines/gob/module.mk
index 3395046..8a79204 100644
--- a/engines/gob/module.mk
+++ b/engines/gob/module.mk
@@ -77,6 +77,10 @@ MODULE_OBJS := \
 	demos/scnplayer.o \
 	demos/batplayer.o \
 	detection/detection.o \
+	pregob/pregob.o \
+	pregob/onceupon/onceupon.o \
+	pregob/onceupon/abracadabra.o \
+	pregob/onceupon/babayaga.o \
 	minigames/geisha/evilfish.o \
 	minigames/geisha/oko.o \
 	minigames/geisha/meter.o \
diff --git a/engines/gob/pregob/onceupon/abracadabra.cpp b/engines/gob/pregob/onceupon/abracadabra.cpp
new file mode 100644
index 0000000..14a362c
--- /dev/null
+++ b/engines/gob/pregob/onceupon/abracadabra.cpp
@@ -0,0 +1,43 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "common/textconsole.h"
+
+#include "gob/pregob/onceupon/abracadabra.h"
+
+namespace Gob {
+
+namespace OnceUpon {
+
+Abracadabra::Abracadabra(GobEngine *vm) : OnceUpon(vm) {
+}
+
+Abracadabra::~Abracadabra() {
+}
+
+void Abracadabra::run() {
+	warning("TODO: Abracadabra::run()");
+}
+
+} // End of namespace OnceUpon
+
+} // End of namespace Gob
diff --git a/engines/gob/pregob/onceupon/abracadabra.h b/engines/gob/pregob/onceupon/abracadabra.h
new file mode 100644
index 0000000..855d2bf
--- /dev/null
+++ b/engines/gob/pregob/onceupon/abracadabra.h
@@ -0,0 +1,44 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef GOB_PREGOB_ONCEUPON_ABRACADABRA_H
+#define GOB_PREGOB_ONCEUPON_ABRACADABRA_H
+
+#include "gob/pregob/onceupon/onceupon.h"
+
+namespace Gob {
+
+namespace OnceUpon {
+
+class Abracadabra : public OnceUpon {
+public:
+	Abracadabra(GobEngine *vm);
+	~Abracadabra();
+
+	void run();
+};
+
+} // End of namespace OnceUpon
+
+} // End of namespace Gob
+
+#endif // GOB_PREGOB_ONCEUPON_ABRACADABRA_H
diff --git a/engines/gob/pregob/onceupon/babayaga.cpp b/engines/gob/pregob/onceupon/babayaga.cpp
new file mode 100644
index 0000000..f2c7569
--- /dev/null
+++ b/engines/gob/pregob/onceupon/babayaga.cpp
@@ -0,0 +1,43 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "common/textconsole.h"
+
+#include "gob/pregob/onceupon/babayaga.h"
+
+namespace Gob {
+
+namespace OnceUpon {
+
+BabaYaga::BabaYaga(GobEngine *vm) : OnceUpon(vm) {
+}
+
+BabaYaga::~BabaYaga() {
+}
+
+void BabaYaga::run() {
+	warning("TODO: BabaYaga::run()");
+}
+
+} // End of namespace OnceUpon
+
+} // End of namespace Gob
diff --git a/engines/gob/pregob/onceupon/babayaga.h b/engines/gob/pregob/onceupon/babayaga.h
new file mode 100644
index 0000000..b3339b0
--- /dev/null
+++ b/engines/gob/pregob/onceupon/babayaga.h
@@ -0,0 +1,44 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef GOB_PREGOB_ONCEUPON_BABAYAGA_H
+#define GOB_PREGOB_ONCEUPON_BABAYAGA_H
+
+#include "gob/pregob/onceupon/onceupon.h"
+
+namespace Gob {
+
+namespace OnceUpon {
+
+class BabaYaga : public OnceUpon {
+public:
+	BabaYaga(GobEngine *vm);
+	~BabaYaga();
+
+	void run();
+};
+
+} // End of namespace OnceUpon
+
+} // End of namespace Gob
+
+#endif // GOB_PREGOB_ONCEUPON_BABAYAGA_H
diff --git a/engines/gob/pregob/onceupon/onceupon.cpp b/engines/gob/pregob/onceupon/onceupon.cpp
new file mode 100644
index 0000000..639f5b1
--- /dev/null
+++ b/engines/gob/pregob/onceupon/onceupon.cpp
@@ -0,0 +1,37 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "gob/pregob/onceupon/onceupon.h"
+
+namespace Gob {
+
+namespace OnceUpon {
+
+OnceUpon::OnceUpon(GobEngine *vm) : PreGob(vm) {
+}
+
+OnceUpon::~OnceUpon() {
+}
+
+} // End of namespace OnceUpon
+
+} // End of namespace Gob
diff --git a/engines/gob/pregob/onceupon/onceupon.h b/engines/gob/pregob/onceupon/onceupon.h
new file mode 100644
index 0000000..f937701
--- /dev/null
+++ b/engines/gob/pregob/onceupon/onceupon.h
@@ -0,0 +1,42 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef GOB_PREGOB_ONCEUPON_ONCEUPON_H
+#define GOB_PREGOB_ONCEUPON_ONCEUPON_H
+
+#include "gob/pregob/pregob.h"
+
+namespace Gob {
+
+namespace OnceUpon {
+
+class OnceUpon : public PreGob {
+public:
+	OnceUpon(GobEngine *vm);
+	~OnceUpon();
+};
+
+} // End of namespace OnceUpon
+
+} // End of namespace Gob
+
+#endif // GOB_PREGOB_ONCEUPON_ONCEUPON_H
diff --git a/engines/gob/pregob/pregob.cpp b/engines/gob/pregob/pregob.cpp
new file mode 100644
index 0000000..ab47ada
--- /dev/null
+++ b/engines/gob/pregob/pregob.cpp
@@ -0,0 +1,35 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "gob/gob.h"
+
+#include "gob/pregob/pregob.h"
+
+namespace Gob {
+
+PreGob::PreGob(GobEngine *vm) : _vm(vm) {
+}
+
+PreGob::~PreGob() {
+}
+
+} // End of namespace Gob
diff --git a/engines/gob/pregob/pregob.h b/engines/gob/pregob/pregob.h
new file mode 100644
index 0000000..e77e0ba
--- /dev/null
+++ b/engines/gob/pregob/pregob.h
@@ -0,0 +1,43 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef GOB_PREGOB_PREGOB_H
+#define GOB_PREGOB_PREGOB_H
+
+namespace Gob {
+
+class GobEngine;
+
+class PreGob {
+public:
+	PreGob(GobEngine *vm);
+	virtual ~PreGob();
+
+	virtual void run() = 0;
+
+protected:
+	GobEngine *_vm;
+};
+
+} // End of namespace Gob
+
+#endif // GOB_PREGOB_PREGOB_H


Commit: 8b19e10104a98a95963ad2ee97b255d6804e7fdd
    https://github.com/scummvm/scummvm/commit/8b19e10104a98a95963ad2ee97b255d6804e7fdd
Author: Sven Hesse (drmccoy at users.sourceforge.net)
Date: 2012-07-29T16:44:42-07:00

Commit Message:
GOB: Add some generic PreGob graphics functions

Changed paths:
    engines/gob/pregob/pregob.cpp
    engines/gob/pregob/pregob.h



diff --git a/engines/gob/pregob/pregob.cpp b/engines/gob/pregob/pregob.cpp
index ab47ada..aea2902 100644
--- a/engines/gob/pregob/pregob.cpp
+++ b/engines/gob/pregob/pregob.cpp
@@ -21,15 +21,73 @@
  */
 
 #include "gob/gob.h"
+#include "gob/global.h"
+#include "gob/util.h"
+#include "gob/palanim.h"
+#include "gob/draw.h"
+#include "gob/video.h"
 
 #include "gob/pregob/pregob.h"
 
 namespace Gob {
 
-PreGob::PreGob(GobEngine *vm) : _vm(vm) {
+PreGob::PreGob(GobEngine *vm) : _vm(vm), _fadedOut(false) {
 }
 
 PreGob::~PreGob() {
 }
 
+void PreGob::fadeOut() {
+	if (_fadedOut || _vm->shouldQuit())
+		return;
+
+	// Fade to black
+	_vm->_palAnim->fade(0, 0, 0);
+
+	_fadedOut = true;
+}
+
+void PreGob::fadeIn() {
+	if (!_fadedOut || _vm->shouldQuit())
+		return;
+
+	// Fade to palette
+	_vm->_draw->blitInvalidated();
+	_vm->_palAnim->fade(_vm->_global->_pPaletteDesc, 0, 0);
+	_vm->_draw->dirtiedRect(_vm->_draw->_backSurface, 0, 0, 319, 199);
+
+	_fadedOut = false;
+}
+
+void PreGob::clearScreen() {
+	_vm->_draw->_backSurface->clear();
+	_vm->_draw->dirtiedRect(_vm->_draw->_backSurface, 0, 0, 319, 199);
+	_vm->_draw->blitInvalidated();
+	_vm->_video->retrace();
+}
+
+void PreGob::initScreen() {
+	_vm->_util->setFrameRate(15);
+
+	_fadedOut = true;
+
+	_vm->_draw->initScreen();
+
+	_vm->_draw->_backSurface->clear();
+	_vm->_util->clearPalette();
+
+	_vm->_draw->forceBlit();
+	_vm->_video->retrace();
+
+	_vm->_util->processInput();
+}
+
+void PreGob::setPalette(const byte *palette, uint16 size) {
+	memcpy(_vm->_draw->_vgaPalette, palette, 3 * size);
+
+	// If we didn't fade out prior, immediately set the palette
+	if (!_fadedOut)
+		_vm->_video->setFullPalette(_vm->_global->_pPaletteDesc);
+}
+
 } // End of namespace Gob
diff --git a/engines/gob/pregob/pregob.h b/engines/gob/pregob/pregob.h
index e77e0ba..6418d6f 100644
--- a/engines/gob/pregob/pregob.h
+++ b/engines/gob/pregob/pregob.h
@@ -35,7 +35,24 @@ public:
 	virtual void run() = 0;
 
 protected:
+	void initScreen(); ///< Initialize the game screen.
+
+	void fadeOut(); ///< Fade to black.
+	void fadeIn();  ///< Fade to the current palette.
+
+	void clearScreen();
+
+	/** Change the palette.
+	 *
+	 *  @param palette The palette to change to.
+	 *  @param size Size of the palette in colors.
+	 */
+	void setPalette(const byte *palette, uint16 size); ///< Change the palette
+
 	GobEngine *_vm;
+
+private:
+	bool _fadedOut; ///< Did we fade out?
 };
 
 } // End of namespace Gob


Commit: 38fe3c3cd9e656b3e3f2b35011895d6703a1a896
    https://github.com/scummvm/scummvm/commit/38fe3c3cd9e656b3e3f2b35011895d6703a1a896
Author: Sven Hesse (drmccoy at users.sourceforge.net)
Date: 2012-07-29T16:44:42-07:00

Commit Message:
GOB: Add palettes for Once Upon A Time

Changed paths:
    engines/gob/pregob/onceupon/abracadabra.cpp
    engines/gob/pregob/onceupon/babayaga.cpp
    engines/gob/pregob/onceupon/onceupon.cpp
    engines/gob/pregob/onceupon/onceupon.h



diff --git a/engines/gob/pregob/onceupon/abracadabra.cpp b/engines/gob/pregob/onceupon/abracadabra.cpp
index 14a362c..84d84e8 100644
--- a/engines/gob/pregob/onceupon/abracadabra.cpp
+++ b/engines/gob/pregob/onceupon/abracadabra.cpp
@@ -36,6 +36,8 @@ Abracadabra::~Abracadabra() {
 
 void Abracadabra::run() {
 	warning("TODO: Abracadabra::run()");
+
+	initScreen();
 }
 
 } // End of namespace OnceUpon
diff --git a/engines/gob/pregob/onceupon/babayaga.cpp b/engines/gob/pregob/onceupon/babayaga.cpp
index f2c7569..21355ab 100644
--- a/engines/gob/pregob/onceupon/babayaga.cpp
+++ b/engines/gob/pregob/onceupon/babayaga.cpp
@@ -36,6 +36,8 @@ BabaYaga::~BabaYaga() {
 
 void BabaYaga::run() {
 	warning("TODO: BabaYaga::run()");
+
+	initScreen();
 }
 
 } // End of namespace OnceUpon
diff --git a/engines/gob/pregob/onceupon/onceupon.cpp b/engines/gob/pregob/onceupon/onceupon.cpp
index 639f5b1..35127cb 100644
--- a/engines/gob/pregob/onceupon/onceupon.cpp
+++ b/engines/gob/pregob/onceupon/onceupon.cpp
@@ -20,8 +20,147 @@
  *
  */
 
+#include "gob/gob.h"
+#include "gob/util.h"
+#include "gob/dataio.h"
+#include "gob/draw.h"
+#include "gob/video.h"
+
 #include "gob/pregob/onceupon/onceupon.h"
 
+static const  int kPaletteSize  = 16;
+static const uint kPaletteCount = 20;
+
+static const byte kCopyProtectionPalette[3 * kPaletteSize] = {
+	0x00, 0x00, 0x00, 0x19, 0x00, 0x19, 0x00, 0x3F, 0x00, 0x00, 0x2A, 0x2A,
+	0x2A, 0x00, 0x00, 0x2A, 0x00, 0x2A, 0x2A, 0x15, 0x00, 0x00, 0x19, 0x12,
+	0x00, 0x00, 0x00, 0x15, 0x15, 0x3F, 0x15, 0x3F, 0x15, 0x00, 0x20, 0x3F,
+	0x3F, 0x00, 0x00, 0x3F, 0x00, 0x20, 0x3F, 0x3F, 0x00, 0x3F, 0x3F, 0x3F
+};
+
+static const byte kGamePalettes[kPaletteCount][3 * kPaletteSize] = {
+	{
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x18, 0x00, 0x00, 0x3C,
+		0x1C, 0x28, 0x00, 0x10, 0x18, 0x00, 0x1C, 0x1C, 0x20, 0x14, 0x14, 0x14,
+		0x14, 0x20, 0x04, 0x00, 0x00, 0x24, 0x3C, 0x3C, 0x3C, 0x00, 0x00, 0x00,
+		0x3C, 0x2C, 0x00, 0x3C, 0x18, 0x00, 0x3C, 0x04, 0x00, 0x1C, 0x00, 0x00
+	},
+	{
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x3C, 0x3C, 0x3C, 0x14, 0x20, 0x04,
+		0x3C, 0x2C, 0x00, 0x02, 0x00, 0x18, 0x3C, 0x04, 0x00, 0x1C, 0x00, 0x00,
+		0x14, 0x20, 0x04, 0x00, 0x00, 0x24, 0x3C, 0x3C, 0x3C, 0x00, 0x00, 0x00,
+		0x3C, 0x2C, 0x00, 0x3C, 0x18, 0x00, 0x3C, 0x04, 0x00, 0x1C, 0x00, 0x00
+	},
+	{
+		0x00, 0x00, 0x00, 0x38, 0x20, 0x3C, 0x2C, 0x10, 0x30, 0x20, 0x08, 0x28,
+		0x14, 0x00, 0x1C, 0x20, 0x20, 0x38, 0x18, 0x18, 0x2C, 0x10, 0x10, 0x24,
+		0x14, 0x20, 0x04, 0x00, 0x00, 0x24, 0x3C, 0x3C, 0x3C, 0x00, 0x00, 0x00,
+		0x3C, 0x2C, 0x00, 0x3C, 0x18, 0x00, 0x3C, 0x04, 0x00, 0x1C, 0x00, 0x00
+	},
+	{
+		0x00, 0x00, 0x00, 0x3C, 0x20, 0x20, 0x24, 0x14, 0x14, 0x1C, 0x10, 0x10,
+		0x14, 0x0C, 0x0C, 0x1C, 0x1C, 0x1C, 0x18, 0x18, 0x18, 0x10, 0x10, 0x10,
+		0x14, 0x20, 0x04, 0x00, 0x00, 0x24, 0x3C, 0x3C, 0x3C, 0x00, 0x00, 0x00,
+		0x3C, 0x2C, 0x00, 0x3C, 0x18, 0x00, 0x3C, 0x04, 0x00, 0x1C, 0x00, 0x00
+	},
+	{
+		0x00, 0x00, 0x00, 0x10, 0x28, 0x1C, 0x10, 0x1C, 0x10, 0x10, 0x14, 0x0C,
+		0x1C, 0x1C, 0x3C, 0x24, 0x24, 0x3C, 0x18, 0x18, 0x24, 0x10, 0x10, 0x18,
+		0x14, 0x20, 0x04, 0x00, 0x00, 0x24, 0x3C, 0x3C, 0x3C, 0x00, 0x00, 0x00,
+		0x3C, 0x2C, 0x00, 0x3C, 0x18, 0x00, 0x3C, 0x04, 0x00, 0x1C, 0x00, 0x00
+	},
+	{
+		0x00, 0x00, 0x00, 0x3F, 0x26, 0x3F, 0x36, 0x1C, 0x36, 0x2C, 0x12, 0x2A,
+		0x27, 0x0C, 0x24, 0x22, 0x07, 0x1E, 0x1D, 0x03, 0x18, 0x16, 0x00, 0x10,
+		0x14, 0x20, 0x04, 0x00, 0x00, 0x24, 0x3C, 0x3C, 0x3A, 0x00, 0x00, 0x00,
+		0x3C, 0x2C, 0x00, 0x3C, 0x18, 0x00, 0x3C, 0x04, 0x00, 0x1C, 0x00, 0x00
+	},
+	{
+		0x00, 0x00, 0x00, 0x3F, 0x39, 0x26, 0x38, 0x34, 0x1C, 0x30, 0x2F, 0x13,
+		0x27, 0x29, 0x0C, 0x1D, 0x22, 0x07, 0x14, 0x1B, 0x03, 0x0C, 0x14, 0x00,
+		0x14, 0x20, 0x04, 0x00, 0x00, 0x24, 0x3C, 0x3C, 0x3A, 0x00, 0x00, 0x00,
+		0x3C, 0x2C, 0x00, 0x3C, 0x18, 0x00, 0x3C, 0x04, 0x00, 0x1C, 0x00, 0x00
+	},
+	{
+		0x00, 0x00, 0x00, 0x24, 0x3C, 0x3C, 0x1C, 0x34, 0x38, 0x14, 0x2C, 0x30,
+		0x0C, 0x20, 0x2C, 0x08, 0x18, 0x28, 0x04, 0x10, 0x20, 0x00, 0x08, 0x1C,
+		0x14, 0x20, 0x04, 0x00, 0x00, 0x24, 0x3C, 0x3C, 0x38, 0x00, 0x00, 0x00,
+		0x3C, 0x2C, 0x00, 0x3C, 0x18, 0x00, 0x3C, 0x04, 0x00, 0x1C, 0x00, 0x00
+	},
+	{
+		0x00, 0x00, 0x00, 0x3C, 0x2C, 0x24, 0x38, 0x24, 0x1C, 0x30, 0x1C, 0x14,
+		0x28, 0x18, 0x0C, 0x20, 0x10, 0x04, 0x1C, 0x0C, 0x00, 0x14, 0x08, 0x00,
+		0x14, 0x20, 0x04, 0x00, 0x00, 0x24, 0x3C, 0x3C, 0x38, 0x00, 0x00, 0x00,
+		0x3C, 0x2C, 0x00, 0x3C, 0x18, 0x00, 0x3C, 0x04, 0x00, 0x1C, 0x00, 0x00
+	},
+	{
+		0x00, 0x00, 0x00, 0x3C, 0x34, 0x24, 0x38, 0x2C, 0x1C, 0x30, 0x24, 0x14,
+		0x2C, 0x1C, 0x10, 0x30, 0x30, 0x3C, 0x1C, 0x1C, 0x38, 0x0C, 0x0C, 0x38,
+		0x14, 0x20, 0x04, 0x00, 0x00, 0x24, 0x3C, 0x3C, 0x3C, 0x00, 0x00, 0x00,
+		0x3C, 0x2C, 0x00, 0x3C, 0x18, 0x00, 0x3C, 0x04, 0x00, 0x1C, 0x00, 0x00
+	},
+	{
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x02, 0x03, 0x14, 0x07, 0x07, 0x1D,
+		0x0E, 0x0E, 0x25, 0x17, 0x17, 0x2E, 0x21, 0x22, 0x36, 0x2F, 0x2F, 0x3F,
+		0x3F, 0x3F, 0x3F, 0x3F, 0x3B, 0x0D, 0x3A, 0x31, 0x0A, 0x35, 0x28, 0x07,
+		0x30, 0x21, 0x04, 0x2B, 0x19, 0x02, 0x26, 0x12, 0x01, 0x16, 0x0B, 0x00
+	},
+	{
+		0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x21, 0x01, 0x00, 0x2A, 0x02, 0x00,
+		0x33, 0x03, 0x00, 0x3D, 0x06, 0x00, 0x2A, 0x19, 0x05, 0x15, 0x14, 0x14,
+		0x22, 0x1F, 0x1E, 0x2F, 0x2C, 0x28, 0x3F, 0x3C, 0x29, 0x3F, 0x38, 0x0B,
+		0x3B, 0x30, 0x0A, 0x37, 0x29, 0x08, 0x33, 0x23, 0x07, 0x2F, 0x1D, 0x06
+	},
+	{
+		0x00, 0x00, 0x00, 0x00, 0x1C, 0x38, 0x34, 0x30, 0x28, 0x2C, 0x24, 0x1C,
+		0x24, 0x18, 0x10, 0x1C, 0x10, 0x08, 0x14, 0x04, 0x04, 0x10, 0x00, 0x00,
+		0x14, 0x20, 0x04, 0x00, 0x00, 0x24, 0x3C, 0x3C, 0x38, 0x00, 0x00, 0x00,
+		0x3C, 0x2C, 0x00, 0x3C, 0x18, 0x00, 0x3C, 0x04, 0x00, 0x1C, 0x00, 0x00
+	},
+	{
+		0x00, 0x00, 0x00, 0x00, 0x1C, 0x38, 0x34, 0x30, 0x28, 0x2C, 0x24, 0x1C,
+		0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+		0x14, 0x20, 0x04, 0x00, 0x00, 0x24, 0x3C, 0x3C, 0x38, 0x00, 0x00, 0x00,
+		0x3C, 0x2C, 0x00, 0x3C, 0x18, 0x00, 0x3C, 0x04, 0x00, 0x1C, 0x00, 0x00
+	},
+	{
+		0x00, 0x00, 0x00, 0x1A, 0x30, 0x37, 0x14, 0x28, 0x31, 0x10, 0x20, 0x2C,
+		0x0C, 0x19, 0x27, 0x08, 0x12, 0x21, 0x05, 0x0C, 0x1C, 0x03, 0x07, 0x16,
+		0x01, 0x03, 0x11, 0x00, 0x00, 0x0C, 0x3C, 0x3C, 0x3C, 0x00, 0x00, 0x00,
+		0x3C, 0x2C, 0x00, 0x3C, 0x18, 0x00, 0x3C, 0x04, 0x00, 0x1C, 0x00, 0x00
+	},
+	{
+		0x00, 0x00, 0x00, 0x34, 0x30, 0x34, 0x30, 0x24, 0x30, 0x28, 0x1C, 0x28,
+		0x24, 0x14, 0x24, 0x1C, 0x0C, 0x1C, 0x18, 0x08, 0x18, 0x14, 0x04, 0x14,
+		0x0C, 0x04, 0x0C, 0x08, 0x00, 0x08, 0x3C, 0x3C, 0x3C, 0x00, 0x00, 0x00,
+		0x3C, 0x2C, 0x00, 0x3C, 0x18, 0x00, 0x3C, 0x04, 0x00, 0x1C, 0x00, 0x00
+	},
+	{
+		0x00, 0x00, 0x00, 0x2C, 0x24, 0x0C, 0x34, 0x34, 0x28, 0x2C, 0x2C, 0x1C,
+		0x24, 0x24, 0x10, 0x1C, 0x18, 0x08, 0x14, 0x14, 0x08, 0x10, 0x10, 0x04,
+		0x0C, 0x0C, 0x04, 0x00, 0x00, 0x24, 0x3C, 0x3C, 0x38, 0x00, 0x00, 0x00,
+		0x3C, 0x2C, 0x00, 0x3C, 0x18, 0x00, 0x3C, 0x04, 0x00, 0x1C, 0x00, 0x00
+	},
+	{
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x28, 0x31, 0x10, 0x20, 0x2C,
+		0x0C, 0x19, 0x27, 0x08, 0x12, 0x21, 0x05, 0x0C, 0x1C, 0x03, 0x07, 0x16,
+		0x01, 0x03, 0x11, 0x00, 0x3C, 0x00, 0x3C, 0x3C, 0x3C, 0x00, 0x00, 0x00,
+		0x3C, 0x2C, 0x00, 0x3C, 0x18, 0x00, 0x3C, 0x04, 0x00, 0x1C, 0x00, 0x00
+	},
+	{
+		0x00, 0x00, 0x00, 0x10, 0x28, 0x1C, 0x10, 0x1C, 0x10, 0x10, 0x14, 0x0C,
+		0x1C, 0x1C, 0x3C, 0x24, 0x24, 0x3C, 0x18, 0x18, 0x24, 0x10, 0x10, 0x18,
+		0x14, 0x20, 0x04, 0x00, 0x00, 0x24, 0x3C, 0x3C, 0x3C, 0x00, 0x00, 0x00,
+		0x3C, 0x2C, 0x00, 0x3C, 0x18, 0x00, 0x3C, 0x04, 0x00, 0x1C, 0x00, 0x00
+	},
+	{
+		0x00, 0x00, 0x00, 0x10, 0x28, 0x1C, 0x10, 0x1C, 0x10, 0x10, 0x14, 0x0C,
+		0x1C, 0x1C, 0x3C, 0x24, 0x24, 0x3C, 0x18, 0x18, 0x24, 0x10, 0x10, 0x18,
+		0x14, 0x20, 0x04, 0x00, 0x00, 0x24, 0x3C, 0x3C, 0x3C, 0x00, 0x00, 0x00,
+		0x3C, 0x2C, 0x00, 0x3C, 0x18, 0x00, 0x3C, 0x04, 0x00, 0x1C, 0x00, 0x00
+	}
+};
+
 namespace Gob {
 
 namespace OnceUpon {
@@ -32,6 +171,17 @@ OnceUpon::OnceUpon(GobEngine *vm) : PreGob(vm) {
 OnceUpon::~OnceUpon() {
 }
 
+void OnceUpon::setCopyProtectionPalette() {
+	setPalette(kCopyProtectionPalette, kPaletteSize);
+}
+
+void OnceUpon::setGamePalette(uint palette) {
+	if (palette >= kPaletteCount)
+		return;
+
+	setPalette(kGamePalettes[palette], kPaletteSize);
+}
+
 } // End of namespace OnceUpon
 
 } // End of namespace Gob
diff --git a/engines/gob/pregob/onceupon/onceupon.h b/engines/gob/pregob/onceupon/onceupon.h
index f937701..816d4dc 100644
--- a/engines/gob/pregob/onceupon/onceupon.h
+++ b/engines/gob/pregob/onceupon/onceupon.h
@@ -23,6 +23,8 @@
 #ifndef GOB_PREGOB_ONCEUPON_ONCEUPON_H
 #define GOB_PREGOB_ONCEUPON_ONCEUPON_H
 
+#include "common/system.h"
+
 #include "gob/pregob/pregob.h"
 
 namespace Gob {
@@ -33,6 +35,12 @@ class OnceUpon : public PreGob {
 public:
 	OnceUpon(GobEngine *vm);
 	~OnceUpon();
+
+protected:
+	void setGamePalette(uint palette);
+
+private:
+	void setCopyProtectionPalette();
 };
 
 } // End of namespace OnceUpon


Commit: 27782700a5631a25129b12779abb540a906f6a96
    https://github.com/scummvm/scummvm/commit/27782700a5631a25129b12779abb540a906f6a96
Author: Sven Hesse (drmccoy at users.sourceforge.net)
Date: 2012-07-29T16:44:42-07:00

Commit Message:
GOB: Add some PreGob and Once Upon A Time cursor functions

Changed paths:
    engines/gob/draw.cpp
    engines/gob/draw_v2.cpp
    engines/gob/pregob/onceupon/onceupon.cpp
    engines/gob/pregob/onceupon/onceupon.h
    engines/gob/pregob/pregob.cpp
    engines/gob/pregob/pregob.h
    engines/gob/video.cpp



diff --git a/engines/gob/draw.cpp b/engines/gob/draw.cpp
index 3932987..8c69194 100644
--- a/engines/gob/draw.cpp
+++ b/engines/gob/draw.cpp
@@ -271,7 +271,9 @@ void Draw::blitInvalidated() {
 		return;
 	}
 
-	_showCursor = (_showCursor & ~2) | ((_showCursor & 1) << 1);
+	if (_cursorSprites)
+		_showCursor = (_showCursor & ~2) | ((_showCursor & 1) << 1);
+
 	if (_applyPal) {
 		clearPalette();
 		forceBlit();
diff --git a/engines/gob/draw_v2.cpp b/engines/gob/draw_v2.cpp
index ac43c7b..f547527 100644
--- a/engines/gob/draw_v2.cpp
+++ b/engines/gob/draw_v2.cpp
@@ -74,13 +74,16 @@ void Draw_v2::closeScreen() {
 }
 
 void Draw_v2::blitCursor() {
-	if (_cursorIndex == -1)
+	if (!_cursorSprites || (_cursorIndex == -1))
 		return;
 
 	_showCursor = (_showCursor & ~2) | ((_showCursor & 1) << 1);
 }
 
 void Draw_v2::animateCursor(int16 cursor) {
+	if (!_cursorSprites)
+		return;
+
 	int16 cursorIndex = cursor;
 	int16 newX = 0, newY = 0;
 	uint16 hotspotX, hotspotY;
diff --git a/engines/gob/pregob/onceupon/onceupon.cpp b/engines/gob/pregob/onceupon/onceupon.cpp
index 35127cb..7f7dffa 100644
--- a/engines/gob/pregob/onceupon/onceupon.cpp
+++ b/engines/gob/pregob/onceupon/onceupon.cpp
@@ -23,6 +23,7 @@
 #include "gob/gob.h"
 #include "gob/util.h"
 #include "gob/dataio.h"
+#include "gob/surface.h"
 #include "gob/draw.h"
 #include "gob/video.h"
 
diff --git a/engines/gob/pregob/onceupon/onceupon.h b/engines/gob/pregob/onceupon/onceupon.h
index 816d4dc..c1c4d6f 100644
--- a/engines/gob/pregob/onceupon/onceupon.h
+++ b/engines/gob/pregob/onceupon/onceupon.h
@@ -29,6 +29,8 @@
 
 namespace Gob {
 
+class Surface;
+
 namespace OnceUpon {
 
 class OnceUpon : public PreGob {
diff --git a/engines/gob/pregob/pregob.cpp b/engines/gob/pregob/pregob.cpp
index aea2902..18aac50 100644
--- a/engines/gob/pregob/pregob.cpp
+++ b/engines/gob/pregob/pregob.cpp
@@ -20,9 +20,12 @@
  *
  */
 
+#include "graphics/cursorman.h"
+
 #include "gob/gob.h"
 #include "gob/global.h"
 #include "gob/util.h"
+#include "gob/surface.h"
 #include "gob/palanim.h"
 #include "gob/draw.h"
 #include "gob/video.h"
@@ -90,4 +93,48 @@ void PreGob::setPalette(const byte *palette, uint16 size) {
 		_vm->_video->setFullPalette(_vm->_global->_pPaletteDesc);
 }
 
+void PreGob::addCursor() {
+	CursorMan.pushCursor(0, 0, 0, 0, 0, 0);
+}
+
+void PreGob::removeCursor() {
+	CursorMan.popCursor();
+}
+
+void PreGob::setCursor(Surface &sprite, int16 hotspotX, int16 hotspotY) {
+	CursorMan.replaceCursor(sprite.getData(), sprite.getWidth(), sprite.getHeight(), hotspotX, hotspotY, 0);
+}
+
+void PreGob::setCursor(Surface &sprite, int16 left, int16 top, int16 right, int16 bottom,
+                       int16 hotspotX, int16 hotspotY) {
+
+	const int width  = right  - left + 1;
+	const int height = bottom - top  + 1;
+
+	if ((width <= 0) || (height <= 0))
+		return;
+
+	Surface cursor(width, height, 1);
+
+	cursor.blit(sprite, left, top, right, bottom, 0, 0);
+
+	setCursor(cursor, hotspotX, hotspotX);
+}
+
+void PreGob::showCursor() {
+	CursorMan.showMouse(true);
+
+	_vm->_draw->_showCursor = 4;
+}
+
+void PreGob::hideCursor() {
+	CursorMan.showMouse(false);
+
+	_vm->_draw->_showCursor = 0;
+}
+
+bool PreGob::isCursorVisible() const {
+	return CursorMan.isVisible();
+}
+
 } // End of namespace Gob
diff --git a/engines/gob/pregob/pregob.h b/engines/gob/pregob/pregob.h
index 6418d6f..e0f7ca9 100644
--- a/engines/gob/pregob/pregob.h
+++ b/engines/gob/pregob/pregob.h
@@ -26,6 +26,7 @@
 namespace Gob {
 
 class GobEngine;
+class Surface;
 
 class PreGob {
 public:
@@ -49,6 +50,19 @@ protected:
 	 */
 	void setPalette(const byte *palette, uint16 size); ///< Change the palette
 
+	void addCursor();
+	void removeCursor();
+
+	void setCursor(Surface &sprite, int16 hotspotX, int16 hotspotY);
+	void setCursor(Surface &sprite, int16 left, int16 top, int16 right, int16 bottom,
+	               int16 hotspotX, int16 hotspotY);
+
+	void showCursor();
+	void hideCursor();
+
+	bool isCursorVisible() const;
+
+
 	GobEngine *_vm;
 
 private:
diff --git a/engines/gob/video.cpp b/engines/gob/video.cpp
index 8bcf14e..62bb210 100644
--- a/engines/gob/video.cpp
+++ b/engines/gob/video.cpp
@@ -242,7 +242,7 @@ void Video::setSize(bool defaultTo1XScaler) {
 
 void Video::retrace(bool mouse) {
 	if (mouse)
-		CursorMan.showMouse((_vm->_draw->_showCursor & 2) != 0);
+		CursorMan.showMouse((_vm->_draw->_showCursor & 6) != 0);
 
 	if (_vm->_global->_primarySurfDesc) {
 		int screenX = _screenDeltaX;


Commit: 83896dea3edc3bcfb1e414b61644c7ca266e1cce
    https://github.com/scummvm/scummvm/commit/83896dea3edc3bcfb1e414b61644c7ca266e1cce
Author: Sven Hesse (drmccoy at users.sourceforge.net)
Date: 2012-07-29T16:44:42-07:00

Commit Message:
GOB: Add PreGob input/event utility functions

Changed paths:
    engines/gob/pregob/pregob.cpp
    engines/gob/pregob/pregob.h



diff --git a/engines/gob/pregob/pregob.cpp b/engines/gob/pregob/pregob.cpp
index 18aac50..1c3fb82 100644
--- a/engines/gob/pregob/pregob.cpp
+++ b/engines/gob/pregob/pregob.cpp
@@ -137,4 +137,48 @@ bool PreGob::isCursorVisible() const {
 	return CursorMan.isVisible();
 }
 
+void PreGob::endFrame(bool doInput) {
+	_vm->_draw->blitInvalidated();
+	_vm->_util->waitEndFrame();
+
+	if (doInput)
+		_vm->_util->processInput();
+}
+
+int16 PreGob::checkInput(int16 &mouseX, int16 &mouseY, MouseButtons &mouseButtons) {
+	_vm->_util->getMouseState(&mouseX, &mouseY, &mouseButtons);
+	_vm->_util->forceMouseUp();
+
+	return _vm->_util->checkKey();
+}
+
+int16 PreGob::waitInput(int16 &mouseX, int16 &mouseY, MouseButtons &mouseButtons) {
+	bool finished = false;
+
+	int16 key = 0;
+	while (!_vm->shouldQuit() && !finished) {
+		endFrame(true);
+
+		key = checkInput(mouseX, mouseY, mouseButtons);
+
+		finished = (mouseButtons != kMouseButtonsNone) || (key != 0);
+	}
+
+	return key;
+}
+
+int16 PreGob::waitInput() {
+	int16 mouseX, mouseY;
+	MouseButtons mouseButtons;
+
+	return waitInput(mouseX, mouseY, mouseButtons);
+}
+
+bool PreGob::hasInput() {
+	int16 mouseX, mouseY;
+	MouseButtons mouseButtons;
+
+	return checkInput(mouseX, mouseY, mouseButtons) || (mouseButtons != kMouseButtonsNone);
+}
+
 } // End of namespace Gob
diff --git a/engines/gob/pregob/pregob.h b/engines/gob/pregob/pregob.h
index e0f7ca9..4cf4a39 100644
--- a/engines/gob/pregob/pregob.h
+++ b/engines/gob/pregob/pregob.h
@@ -23,6 +23,8 @@
 #ifndef GOB_PREGOB_PREGOB_H
 #define GOB_PREGOB_PREGOB_H
 
+#include "gob/util.h"
+
 namespace Gob {
 
 class GobEngine;
@@ -62,6 +64,13 @@ protected:
 
 	bool isCursorVisible() const;
 
+	void endFrame(bool doInput);
+
+	int16 checkInput(int16 &mouseX, int16 &mouseY, MouseButtons &mouseButtons);
+	int16 waitInput (int16 &mouseX, int16 &mouseY, MouseButtons &mouseButtons);
+	int16 waitInput();
+	bool  hasInput();
+
 
 	GobEngine *_vm;
 


Commit: 4fc3a88c5f0b053323aeaeac658dafb8e4606662
    https://github.com/scummvm/scummvm/commit/4fc3a88c5f0b053323aeaeac658dafb8e4606662
Author: Sven Hesse (drmccoy at users.sourceforge.net)
Date: 2012-07-29T16:44:42-07:00

Commit Message:
GOB: Add support for different methods of handling Endianness

The Once Upon A Time games handle endianness different in ANI, DEC
and RXY files than Geisha does. We need to support both approaches.

Changed paths:
    engines/gob/anifile.cpp
    engines/gob/cmpfile.cpp
    engines/gob/decfile.cpp
    engines/gob/gob.cpp
    engines/gob/gob.h
    engines/gob/rxyfile.cpp
    engines/gob/rxyfile.h



diff --git a/engines/gob/anifile.cpp b/engines/gob/anifile.cpp
index 2671fe0..e6bf30f 100644
--- a/engines/gob/anifile.cpp
+++ b/engines/gob/anifile.cpp
@@ -37,30 +37,38 @@ ANIFile::ANIFile(GobEngine *vm, const Common::String &fileName,
                  uint16 width, uint8 bpp) : _vm(vm),
 	_width(width), _bpp(bpp), _hasPadding(false) {
 
-	Common::SeekableReadStream *ani = _vm->_dataIO->getFile(fileName);
-	if (ani) {
-		Common::SeekableSubReadStreamEndian sub(ani, 0, ani->size(), false, DisposeAfterUse::YES);
+	bool bigEndian = false;
+	Common::String endianFileName = fileName;
 
-		load(sub, fileName);
-		return;
-	}
+	if ((_vm->getEndiannessMethod() == kEndiannessMethodAltFile) &&
+	    !_vm->_dataIO->hasFile(fileName)) {
+		// If the game has alternate big-endian files, look if one exist
+
+		Common::String alternateFileName = fileName;
+		alternateFileName.setChar('_', 0);
 
-	// File doesn't exist, try to open the big-endian'd alternate file
-	Common::String alternateFileName = fileName;
-	alternateFileName.setChar('_', 0);
+		if (_vm->_dataIO->hasFile(alternateFileName)) {
+			bigEndian      = true;
+			endianFileName = alternateFileName;
+		}
+	} else if ((_vm->getEndiannessMethod() == kEndiannessMethodBE) ||
+	           ((_vm->getEndiannessMethod() == kEndiannessMethodSystem) &&
+	            (_vm->getEndianness() == kEndiannessBE)))
+		// Game always little endian or it follows the system and it is big endian
+		bigEndian = true;
 
-	ani = _vm->_dataIO->getFile(alternateFileName);
+	Common::SeekableReadStream *ani = _vm->_dataIO->getFile(endianFileName);
 	if (ani) {
-		Common::SeekableSubReadStreamEndian sub(ani, 0, ani->size(), true, DisposeAfterUse::YES);
+		Common::SeekableSubReadStreamEndian sub(ani, 0, ani->size(), bigEndian, DisposeAfterUse::YES);
 
 		// The big endian version pads a few fields to even size
-		_hasPadding = true;
+		_hasPadding = bigEndian;
 
 		load(sub, fileName);
 		return;
 	}
 
-	warning("ANIFile::ANIFile(): No such file \"%s\"", fileName.c_str());
+	warning("ANIFile::ANIFile(): No such file \"%s\" (\"%s\")", endianFileName.c_str(), fileName.c_str());
 }
 
 ANIFile::~ANIFile() {
diff --git a/engines/gob/cmpfile.cpp b/engines/gob/cmpfile.cpp
index 7b21c4c..1cd1375 100644
--- a/engines/gob/cmpfile.cpp
+++ b/engines/gob/cmpfile.cpp
@@ -21,6 +21,7 @@
  */
 
 #include "common/stream.h"
+#include "common/substream.h"
 #include "common/str.h"
 
 #include "gob/gob.h"
@@ -143,7 +144,13 @@ void CMPFile::loadCMP(Common::SeekableReadStream &cmp) {
 }
 
 void CMPFile::loadRXY(Common::SeekableReadStream &rxy) {
-	_coordinates = new RXYFile(rxy);
+	bool bigEndian = (_vm->getEndiannessMethod() == kEndiannessMethodBE) ||
+	                 ((_vm->getEndiannessMethod() == kEndiannessMethodSystem) &&
+	                  (_vm->getEndianness() == kEndiannessBE));
+
+	Common::SeekableSubReadStreamEndian sub(&rxy, 0, rxy.size(), bigEndian, DisposeAfterUse::NO);
+
+	_coordinates = new RXYFile(sub);
 
 	for (uint i = 0; i < _coordinates->size(); i++) {
 		const RXYFile::Coordinates &c = (*_coordinates)[i];
diff --git a/engines/gob/decfile.cpp b/engines/gob/decfile.cpp
index fb67c52..85b4c09 100644
--- a/engines/gob/decfile.cpp
+++ b/engines/gob/decfile.cpp
@@ -38,30 +38,38 @@ DECFile::DECFile(GobEngine *vm, const Common::String &fileName,
                  uint16 width, uint16 height, uint8 bpp) : _vm(vm),
 	_width(width), _height(height), _bpp(bpp), _hasPadding(false), _backdrop(0) {
 
-	Common::SeekableReadStream *dec = _vm->_dataIO->getFile(fileName);
-	if (dec) {
-		Common::SeekableSubReadStreamEndian sub(dec, 0, dec->size(), false, DisposeAfterUse::YES);
-
-		load(sub, fileName);
-		return;
-	}
-
-	// File doesn't exist, try to open the big-endian'd alternate file
-	Common::String alternateFileName = fileName;
-	alternateFileName.setChar('_', 0);
-
-	dec = _vm->_dataIO->getFile(alternateFileName);
-	if (dec) {
-		Common::SeekableSubReadStreamEndian sub(dec, 0, dec->size(), true, DisposeAfterUse::YES);
+	bool bigEndian = false;
+	Common::String endianFileName = fileName;
+
+	if ((_vm->getEndiannessMethod() == kEndiannessMethodAltFile) &&
+	    !_vm->_dataIO->hasFile(fileName)) {
+		// If the game has alternate big-endian files, look if one exist
+
+		Common::String alternateFileName = fileName;
+		alternateFileName.setChar('_', 0);
+
+		if (_vm->_dataIO->hasFile(alternateFileName)) {
+			bigEndian      = true;
+			endianFileName = alternateFileName;
+		}
+	} else if ((_vm->getEndiannessMethod() == kEndiannessMethodBE) ||
+	           ((_vm->getEndiannessMethod() == kEndiannessMethodSystem) &&
+	            (_vm->getEndianness() == kEndiannessBE)))
+		// Game always little endian or it follows the system and it is big endian
+		bigEndian = true;
+
+	Common::SeekableReadStream *ani = _vm->_dataIO->getFile(endianFileName);
+	if (ani) {
+		Common::SeekableSubReadStreamEndian sub(ani, 0, ani->size(), bigEndian, DisposeAfterUse::YES);
 
 		// The big endian version pads a few fields to even size
-		_hasPadding = true;
+		_hasPadding = bigEndian;
 
 		load(sub, fileName);
 		return;
 	}
 
-	warning("DECFile::DECFile(): No such file \"%s\"", fileName.c_str());
+	warning("DECFile::DECFile(): No such file \"%s\" (\"%s\")", endianFileName.c_str(), fileName.c_str());
 }
 
 DECFile::~DECFile() {
diff --git a/engines/gob/gob.cpp b/engines/gob/gob.cpp
index 02aea63..fcf98f0 100644
--- a/engines/gob/gob.cpp
+++ b/engines/gob/gob.cpp
@@ -184,6 +184,10 @@ void GobEngine::validateVideoMode(int16 videoMode) {
 		error("Video mode 0x%X is not supported", videoMode);
 }
 
+EndiannessMethod GobEngine::getEndiannessMethod() const {
+	return _endiannessMethod;
+}
+
 Endianness GobEngine::getEndianness() const {
 	if ((getPlatform() == Common::kPlatformAmiga) ||
 	    (getPlatform() == Common::kPlatformMacintosh) ||
@@ -403,6 +407,8 @@ Common::Error GobEngine::initGameParts() {
 	// just detect some devices some of which will be always there if the music is not disabled
 	_noMusic = MidiDriver::getMusicType(MidiDriver::detectDevice(MDT_PCSPK | MDT_MIDI | MDT_ADLIB)) == MT_NULL ? true : false;
 
+	_endiannessMethod = kEndiannessMethodSystem;
+
 	_global    = new Global(this);
 	_util      = new Util(this);
 	_dataIO    = new DataIO();
@@ -433,6 +439,8 @@ Common::Error GobEngine::initGameParts() {
 		_goblin   = new Goblin_v1(this);
 		_scenery  = new Scenery_v1(this);
 		_saveLoad = new SaveLoad_Geisha(this, _targetName.c_str());
+
+		_endiannessMethod = kEndiannessMethodAltFile;
 		break;
 
 	case kGameTypeFascination:
diff --git a/engines/gob/gob.h b/engines/gob/gob.h
index 9b91909..df73404 100644
--- a/engines/gob/gob.h
+++ b/engines/gob/gob.h
@@ -149,6 +149,13 @@ enum Features {
 	kFeaturesTrueColor = 1 << 7
 };
 
+enum EndiannessMethod {
+	kEndiannessMethodLE,     ///< Always little endian.
+	kEndiannessMethodBE,     ///< Always big endian.
+	kEndiannessMethodSystem, ///< Follows system endianness.
+	kEndiannessMethodAltFile ///< Different endianness in alternate file.
+};
+
 enum {
 	kDebugFuncOp     = 1 <<  0,
 	kDebugDrawOp     = 1 <<  1,
@@ -172,6 +179,8 @@ private:
 	int32 _features;
 	Common::Platform _platform;
 
+	EndiannessMethod _endiannessMethod;
+
 	uint32 _pauseStart;
 
 	// Engine APIs
@@ -232,6 +241,7 @@ public:
 
 	void pauseGame();
 
+	EndiannessMethod getEndiannessMethod() const;
 	Endianness getEndianness() const;
 	Common::Platform getPlatform() const;
 	GameType getGameType() const;
diff --git a/engines/gob/rxyfile.cpp b/engines/gob/rxyfile.cpp
index 9702dc8..2ff8c12 100644
--- a/engines/gob/rxyfile.cpp
+++ b/engines/gob/rxyfile.cpp
@@ -21,12 +21,19 @@
  */
 
 #include "common/stream.h"
+#include "common/substream.h"
 
 #include "gob/rxyfile.h"
 
 namespace Gob {
 
 RXYFile::RXYFile(Common::SeekableReadStream &rxy) : _width(0), _height(0) {
+	Common::SeekableSubReadStreamEndian sub(&rxy, 0, rxy.size(), false, DisposeAfterUse::NO);
+
+	load(sub);
+}
+
+RXYFile::RXYFile(Common::SeekableSubReadStreamEndian &rxy) : _width(0), _height(0) {
 	load(rxy);
 }
 
@@ -64,22 +71,22 @@ const RXYFile::Coordinates &RXYFile::operator[](uint i) const {
 	return _coords[i];
 }
 
-void RXYFile::load(Common::SeekableReadStream &rxy) {
+void RXYFile::load(Common::SeekableSubReadStreamEndian &rxy) {
 	if (rxy.size() < 2)
 		return;
 
 	rxy.seek(0);
 
-	_realCount = rxy.readUint16LE();
+	_realCount = rxy.readUint16();
 
 	uint16 count = (rxy.size() - 2) / 8;
 
 	_coords.resize(count);
 	for (CoordArray::iterator c = _coords.begin(); c != _coords.end(); ++c) {
-		c->left   = rxy.readUint16LE();
-		c->right  = rxy.readUint16LE();
-		c->top    = rxy.readUint16LE();
-		c->bottom = rxy.readUint16LE();
+		c->left   = rxy.readUint16();
+		c->right  = rxy.readUint16();
+		c->top    = rxy.readUint16();
+		c->bottom = rxy.readUint16();
 
 		if (c->left != 0xFFFF) {
 			_width  = MAX<uint16>(_width , c->right  + 1);
diff --git a/engines/gob/rxyfile.h b/engines/gob/rxyfile.h
index bc9600b..4fd46c5 100644
--- a/engines/gob/rxyfile.h
+++ b/engines/gob/rxyfile.h
@@ -28,6 +28,7 @@
 
 namespace Common {
 	class SeekableReadStream;
+	class SeekableSubReadStreamEndian;
 }
 
 namespace Gob {
@@ -46,6 +47,7 @@ public:
 	};
 
 	RXYFile(Common::SeekableReadStream &rxy);
+	RXYFile(Common::SeekableSubReadStreamEndian &rxy);
 	RXYFile(uint16 width, uint16 height);
 	~RXYFile();
 
@@ -71,7 +73,7 @@ private:
 	uint16 _height;
 
 
-	void load(Common::SeekableReadStream &rxy);
+	void load(Common::SeekableSubReadStreamEndian &rxy);
 };
 
 } // End of namespace Gob


Commit: 734fc767d25d47b5da703dc1b4a3cfb494234155
    https://github.com/scummvm/scummvm/commit/734fc767d25d47b5da703dc1b4a3cfb494234155
Author: Sven Hesse (drmccoy at users.sourceforge.net)
Date: 2012-07-29T16:44:42-07:00

Commit Message:
GOB: Open the Once Upon A Time archives

Changed paths:
    engines/gob/pregob/onceupon/abracadabra.cpp
    engines/gob/pregob/onceupon/babayaga.cpp
    engines/gob/pregob/onceupon/onceupon.cpp
    engines/gob/pregob/onceupon/onceupon.h



diff --git a/engines/gob/pregob/onceupon/abracadabra.cpp b/engines/gob/pregob/onceupon/abracadabra.cpp
index 84d84e8..6cfdfa7 100644
--- a/engines/gob/pregob/onceupon/abracadabra.cpp
+++ b/engines/gob/pregob/onceupon/abracadabra.cpp
@@ -35,9 +35,9 @@ Abracadabra::~Abracadabra() {
 }
 
 void Abracadabra::run() {
-	warning("TODO: Abracadabra::run()");
+	init();
 
-	initScreen();
+	warning("TODO: Abracadabra::run()");
 }
 
 } // End of namespace OnceUpon
diff --git a/engines/gob/pregob/onceupon/babayaga.cpp b/engines/gob/pregob/onceupon/babayaga.cpp
index 21355ab..9f4f53c 100644
--- a/engines/gob/pregob/onceupon/babayaga.cpp
+++ b/engines/gob/pregob/onceupon/babayaga.cpp
@@ -35,9 +35,9 @@ BabaYaga::~BabaYaga() {
 }
 
 void BabaYaga::run() {
-	warning("TODO: BabaYaga::run()");
+	init();
 
-	initScreen();
+	warning("TODO: BabaYaga::run()");
 }
 
 } // End of namespace OnceUpon
diff --git a/engines/gob/pregob/onceupon/onceupon.cpp b/engines/gob/pregob/onceupon/onceupon.cpp
index 7f7dffa..e3d1a85 100644
--- a/engines/gob/pregob/onceupon/onceupon.cpp
+++ b/engines/gob/pregob/onceupon/onceupon.cpp
@@ -166,10 +166,37 @@ namespace Gob {
 
 namespace OnceUpon {
 
-OnceUpon::OnceUpon(GobEngine *vm) : PreGob(vm) {
+OnceUpon::OnceUpon(GobEngine *vm) : PreGob(vm), _openedArchives(false) {
+
 }
 
 OnceUpon::~OnceUpon() {
+	deinit();
+}
+
+void OnceUpon::init() {
+	deinit();
+
+	bool hasSTK1 = _vm->_dataIO->openArchive("stk1.stk", true);
+	bool hasSTK2 = _vm->_dataIO->openArchive("stk2.stk", true);
+	bool hasSTK3 = _vm->_dataIO->openArchive("stk3.stk", true);
+
+	if (!hasSTK1 || !hasSTK2 || !hasSTK3)
+		error("OnceUpon::OnceUpon(): Failed to open archives");
+
+	_openedArchives = true;
+
+	initScreen();
+}
+
+void OnceUpon::deinit() {
+	if (_openedArchives) {
+		_vm->_dataIO->closeArchive(true);
+		_vm->_dataIO->closeArchive(true);
+		_vm->_dataIO->closeArchive(true);
+	}
+
+	_openedArchives = false;
 }
 
 void OnceUpon::setCopyProtectionPalette() {
diff --git a/engines/gob/pregob/onceupon/onceupon.h b/engines/gob/pregob/onceupon/onceupon.h
index c1c4d6f..e5f7085 100644
--- a/engines/gob/pregob/onceupon/onceupon.h
+++ b/engines/gob/pregob/onceupon/onceupon.h
@@ -39,10 +39,16 @@ public:
 	~OnceUpon();
 
 protected:
+	void init();
+	void deinit();
+
 	void setGamePalette(uint palette);
 
 private:
 	void setCopyProtectionPalette();
+
+
+	bool _openedArchives;
 };
 
 } // End of namespace OnceUpon


Commit: 3313302a157fc08d3965c6cb114e3a3f4d366c4b
    https://github.com/scummvm/scummvm/commit/3313302a157fc08d3965c6cb114e3a3f4d366c4b
Author: Sven Hesse (drmccoy at users.sourceforge.net)
Date: 2012-07-29T16:44:42-07:00

Commit Message:
GOB: Load the Once Upon A Time fonts

Changed paths:
    engines/gob/pregob/onceupon/onceupon.cpp
    engines/gob/pregob/onceupon/onceupon.h



diff --git a/engines/gob/pregob/onceupon/onceupon.cpp b/engines/gob/pregob/onceupon/onceupon.cpp
index e3d1a85..6b12dd8 100644
--- a/engines/gob/pregob/onceupon/onceupon.cpp
+++ b/engines/gob/pregob/onceupon/onceupon.cpp
@@ -166,7 +166,8 @@ namespace Gob {
 
 namespace OnceUpon {
 
-OnceUpon::OnceUpon(GobEngine *vm) : PreGob(vm), _openedArchives(false) {
+OnceUpon::OnceUpon(GobEngine *vm) : PreGob(vm), _jeudak(0), _lettre(0), _plettre(0), _glettre(0),
+	_openedArchives(false) {
 
 }
 
@@ -186,10 +187,29 @@ void OnceUpon::init() {
 
 	_openedArchives = true;
 
+	_jeudak  = _vm->_draw->loadFont("jeudak.let");
+	_lettre  = _vm->_draw->loadFont("lettre.let");
+	_plettre = _vm->_draw->loadFont("plettre.let");
+	_glettre = _vm->_draw->loadFont("glettre.let");
+
+	if (!_jeudak || !_lettre || !_plettre || !_glettre)
+		error("OnceUpon::OnceUpon(): Failed to fonts (%d, %d, %d, %d)",
+		      _jeudak != 0, _lettre != 0, _plettre != 0, _glettre != 0);
+
 	initScreen();
 }
 
 void OnceUpon::deinit() {
+	delete _jeudak;
+	delete _lettre;
+	delete _plettre;
+	delete _glettre;
+
+	_jeudak  = 0;
+	_lettre  = 0;
+	_plettre = 0;
+	_glettre = 0;
+
 	if (_openedArchives) {
 		_vm->_dataIO->closeArchive(true);
 		_vm->_dataIO->closeArchive(true);
diff --git a/engines/gob/pregob/onceupon/onceupon.h b/engines/gob/pregob/onceupon/onceupon.h
index e5f7085..cfc1253 100644
--- a/engines/gob/pregob/onceupon/onceupon.h
+++ b/engines/gob/pregob/onceupon/onceupon.h
@@ -30,6 +30,7 @@
 namespace Gob {
 
 class Surface;
+class Font;
 
 namespace OnceUpon {
 
@@ -44,6 +45,12 @@ protected:
 
 	void setGamePalette(uint palette);
 
+
+	Font *_jeudak;
+	Font *_lettre;
+	Font *_plettre;
+	Font *_glettre;
+
 private:
 	void setCopyProtectionPalette();
 


Commit: aae8c607596d9ce228935c01297902381c8b442c
    https://github.com/scummvm/scummvm/commit/aae8c607596d9ce228935c01297902381c8b442c
Author: Sven Hesse (drmccoy at users.sourceforge.net)
Date: 2012-07-29T16:44:42-07:00

Commit Message:
GOB: Verify the language in Once Upon A Time

Changed paths:
    engines/gob/pregob/onceupon/onceupon.cpp



diff --git a/engines/gob/pregob/onceupon/onceupon.cpp b/engines/gob/pregob/onceupon/onceupon.cpp
index 6b12dd8..adea776 100644
--- a/engines/gob/pregob/onceupon/onceupon.cpp
+++ b/engines/gob/pregob/onceupon/onceupon.cpp
@@ -21,6 +21,7 @@
  */
 
 #include "gob/gob.h"
+#include "gob/global.h"
 #include "gob/util.h"
 #include "gob/dataio.h"
 #include "gob/surface.h"
@@ -196,6 +197,15 @@ void OnceUpon::init() {
 		error("OnceUpon::OnceUpon(): Failed to fonts (%d, %d, %d, %d)",
 		      _jeudak != 0, _lettre != 0, _plettre != 0, _glettre != 0);
 
+	if (_vm->_global->_language == kLanguageAmerican)
+		_vm->_global->_language = kLanguageBritish;
+
+	if ((_vm->_global->_language >= kLanguageCount))
+		error("We do not support the language \"%s\".\n"
+		      "If you are certain that your game copy includes this language,\n"
+		      "please contact the ScummVM team with details about this version.\n"
+		      "Thanks", _vm->getLangDesc(_vm->_global->_language));
+
 	initScreen();
 }
 


Commit: 412ae53854dc2ef352a3f3e990f0d2b56d97ad7e
    https://github.com/scummvm/scummvm/commit/412ae53854dc2ef352a3f3e990f0d2b56d97ad7e
Author: Sven Hesse (drmccoy at users.sourceforge.net)
Date: 2012-07-29T16:44:43-07:00

Commit Message:
GOB: Add PreGob animation utility functions

Changed paths:
    engines/gob/pregob/pregob.cpp
    engines/gob/pregob/pregob.h



diff --git a/engines/gob/pregob/pregob.cpp b/engines/gob/pregob/pregob.cpp
index 1c3fb82..b9c36d7 100644
--- a/engines/gob/pregob/pregob.cpp
+++ b/engines/gob/pregob/pregob.cpp
@@ -29,6 +29,7 @@
 #include "gob/palanim.h"
 #include "gob/draw.h"
 #include "gob/video.h"
+#include "gob/aniobject.h"
 
 #include "gob/pregob/pregob.h"
 
@@ -181,4 +182,24 @@ bool PreGob::hasInput() {
 	return checkInput(mouseX, mouseY, mouseButtons) || (mouseButtons != kMouseButtonsNone);
 }
 
+void PreGob::clearAnim(ANIObject &ani) {
+	int16 left, top, right, bottom;
+
+	if (ani.clear(*_vm->_draw->_backSurface, left, top, right, bottom))
+		_vm->_draw->dirtiedRect(_vm->_draw->_backSurface, left, top, right, bottom);
+}
+
+void PreGob::drawAnim(ANIObject &ani) {
+	int16 left, top, right, bottom;
+
+	if (ani.draw(*_vm->_draw->_backSurface, left, top, right, bottom))
+		_vm->_draw->dirtiedRect(_vm->_draw->_backSurface, left, top, right, bottom);
+	ani.advance();
+}
+
+void PreGob::redrawAnim(ANIObject &ani) {
+	clearAnim(ani);
+	drawAnim(ani);
+}
+
 } // End of namespace Gob
diff --git a/engines/gob/pregob/pregob.h b/engines/gob/pregob/pregob.h
index 4cf4a39..9efdbe8 100644
--- a/engines/gob/pregob/pregob.h
+++ b/engines/gob/pregob/pregob.h
@@ -30,6 +30,8 @@ namespace Gob {
 class GobEngine;
 class Surface;
 
+class ANIObject;
+
 class PreGob {
 public:
 	PreGob(GobEngine *vm);
@@ -71,6 +73,10 @@ protected:
 	int16 waitInput();
 	bool  hasInput();
 
+	void clearAnim(ANIObject &ani);
+	void drawAnim(ANIObject &ani);
+	void redrawAnim(ANIObject &ani);
+
 
 	GobEngine *_vm;
 


Commit: ef3b4af9d8d221f52aaed900a2997b486ed2e6e4
    https://github.com/scummvm/scummvm/commit/ef3b4af9d8d221f52aaed900a2997b486ed2e6e4
Author: Sven Hesse (drmccoy at users.sourceforge.net)
Date: 2012-07-29T16:44:43-07:00

Commit Message:
GOB: Implement the copy protection in Once Upon A Time

Changed paths:
    engines/gob/pregob/onceupon/abracadabra.cpp
    engines/gob/pregob/onceupon/babayaga.cpp
    engines/gob/pregob/onceupon/onceupon.cpp
    engines/gob/pregob/onceupon/onceupon.h



diff --git a/engines/gob/pregob/onceupon/abracadabra.cpp b/engines/gob/pregob/onceupon/abracadabra.cpp
index 6cfdfa7..d8dd8b3 100644
--- a/engines/gob/pregob/onceupon/abracadabra.cpp
+++ b/engines/gob/pregob/onceupon/abracadabra.cpp
@@ -22,8 +22,28 @@
 
 #include "common/textconsole.h"
 
+#include "gob/gob.h"
+
 #include "gob/pregob/onceupon/abracadabra.h"
 
+static const uint8 kCopyProtectionColors[7] = {
+	14, 11, 13,  1,  7, 12,  2
+};
+
+static const uint8 kCopyProtectionShapes[7 * 20] = {
+	3, 4, 3, 0, 1, 2, 0, 2, 2, 0, 2, 4, 0, 3, 4, 1, 1, 4, 1, 3,
+	0, 2, 0, 4, 2, 4, 4, 2, 3, 0, 1, 1, 1, 1, 3, 0, 4, 2, 3, 4,
+	0, 0, 1, 2, 1, 1, 2, 4, 3, 1, 4, 2, 4, 4, 2, 4, 1, 2, 3, 3,
+	1, 0, 2, 3, 4, 2, 3, 2, 2, 0, 0, 0, 4, 2, 3, 4, 4, 0, 4, 1,
+	4, 2, 1, 1, 1, 1, 4, 3, 4, 2, 3, 0, 0, 3, 0, 2, 3, 0, 2, 4,
+	4, 2, 4, 3, 0, 4, 0, 2, 3, 1, 4, 1, 3, 1, 0, 0, 2, 1, 3, 2,
+	3, 1, 0, 3, 1, 3, 4, 2, 4, 4, 3, 2, 0, 2, 0, 1, 2, 0, 1, 4
+};
+
+static const uint8 kCopyProtectionObfuscate[4] = {
+	1, 0, 2, 3
+};
+
 namespace Gob {
 
 namespace OnceUpon {
@@ -37,6 +57,10 @@ Abracadabra::~Abracadabra() {
 void Abracadabra::run() {
 	init();
 
+	bool correctCP = doCopyProtection(kCopyProtectionColors, kCopyProtectionShapes, kCopyProtectionObfuscate);
+	if (_vm->shouldQuit() || !correctCP)
+		return;
+
 	warning("TODO: Abracadabra::run()");
 }
 
diff --git a/engines/gob/pregob/onceupon/babayaga.cpp b/engines/gob/pregob/onceupon/babayaga.cpp
index 9f4f53c..aad1fc6 100644
--- a/engines/gob/pregob/onceupon/babayaga.cpp
+++ b/engines/gob/pregob/onceupon/babayaga.cpp
@@ -22,8 +22,28 @@
 
 #include "common/textconsole.h"
 
+#include "gob/gob.h"
+
 #include "gob/pregob/onceupon/babayaga.h"
 
+static const uint8 kCopyProtectionColors[7] = {
+	14, 11, 13,  1,  7, 12,  2
+};
+
+static const uint8 kCopyProtectionShapes[7 * 20] = {
+	0, 0, 1, 2, 1, 1, 2, 4, 3, 1, 4, 2, 4, 4, 2, 4, 1, 2, 3, 3,
+	3, 1, 0, 3, 1, 3, 4, 2, 4, 4, 3, 2, 0, 2, 0, 1, 2, 0, 1, 4,
+	1, 0, 2, 3, 4, 2, 3, 2, 2, 0, 0, 0, 4, 2, 3, 4, 4, 0, 4, 1,
+	0, 2, 0, 4, 2, 4, 4, 2, 3, 0, 1, 1, 1, 1, 3, 0, 4, 2, 3, 4,
+	3, 4, 3, 0, 1, 2, 0, 2, 2, 0, 2, 4, 0, 3, 4, 1, 1, 4, 1, 3,
+	4, 2, 1, 1, 1, 1, 4, 3, 4, 2, 3, 0, 0, 3, 0, 2, 3, 0, 2, 4,
+	4, 2, 4, 3, 0, 4, 0, 2, 3, 1, 4, 1, 3, 1, 0, 0, 2, 1, 3, 2
+};
+
+static const uint8 kCopyProtectionObfuscate[4] = {
+	0, 1, 2, 3
+};
+
 namespace Gob {
 
 namespace OnceUpon {
@@ -37,6 +57,10 @@ BabaYaga::~BabaYaga() {
 void BabaYaga::run() {
 	init();
 
+	bool correctCP = doCopyProtection(kCopyProtectionColors, kCopyProtectionShapes, kCopyProtectionObfuscate);
+	if (_vm->shouldQuit() || !correctCP)
+		return;
+
 	warning("TODO: BabaYaga::run()");
 }
 
diff --git a/engines/gob/pregob/onceupon/onceupon.cpp b/engines/gob/pregob/onceupon/onceupon.cpp
index adea776..aa85e1c 100644
--- a/engines/gob/pregob/onceupon/onceupon.cpp
+++ b/engines/gob/pregob/onceupon/onceupon.cpp
@@ -27,6 +27,8 @@
 #include "gob/surface.h"
 #include "gob/draw.h"
 #include "gob/video.h"
+#include "gob/anifile.h"
+#include "gob/aniobject.h"
 
 #include "gob/pregob/onceupon/onceupon.h"
 
@@ -163,6 +165,62 @@ static const byte kGamePalettes[kPaletteCount][3 * kPaletteSize] = {
 	}
 };
 
+static const uint kLanguageCount = 5;
+
+static const uint kCopyProtectionHelpStringCount = 3;
+
+static const char *kCopyProtectionHelpStrings[kLanguageCount][kCopyProtectionHelpStringCount] = {
+	{ // French
+		"Consulte le livret des animaux, rep\212re la",
+		"page correspondant \205 la couleur de l\'\202cran",
+		"et clique le symbole associ\202 \205 l\'animal affich\202.",
+	},
+	{ // German
+		"Suche im Tieralbum die Seite, die der Farbe auf",
+		"dem Bildschirm entspricht und klicke auf das",
+		"Tiersymbol.",
+	},
+	{ // English
+		"Consult the book of animals, find the page",
+		"corresponding to the colour of screen and click",
+		"the symbol associated with the animal displayed.",
+	},
+	{ // Spanish
+		"Consulta el libro de los animales, localiza la ",
+		"p\240gina que corresponde al color de la pantalla.",
+		"Cliquea el s\241mbolo asociado al animal que aparece.",
+	},
+	{ // Italian
+		"Guarda il libretto degli animali, trova la",
+		"pagina che corrisponde al colore dello schermo,",
+		"clicca il simbolo associato all\'animale presentato",
+	}
+};
+
+static const char *kCopyProtectionWrongStrings[kLanguageCount] = {
+	"Tu t\'es tromp\202, dommage...", // French
+	"Schade, du hast dich geirrt."  , // German
+	"You are wrong, what a pity!"   , // English
+	"Te equivocas, l\240stima..."   , // Spanish
+	"Sei Sbagliato, peccato..."       // Italian
+};
+
+static const uint kCopyProtectionShapeCount = 5;
+
+static const int16 kCopyProtectionShapeCoords[kCopyProtectionShapeCount][6] = {
+	{  0,  51,  26,  75,  60, 154},
+	{ 28,  51,  58,  81,  96, 151},
+	{ 60,  51,  94,  79, 136, 152},
+	{ 96,  51, 136,  71, 180, 155},
+	{140,  51, 170,  77, 228, 153}
+};
+
+enum ClownAnimation {
+	kClownAnimationClownCheer = 0,
+	kClownAnimationClownStand = 1,
+	kClownAnimationClownCry   = 6
+};
+
 namespace Gob {
 
 namespace OnceUpon {
@@ -240,6 +298,195 @@ void OnceUpon::setGamePalette(uint palette) {
 	setPalette(kGamePalettes[palette], kPaletteSize);
 }
 
+enum CopyProtectionState {
+	kCPStateSetup,     // Set up the screen
+	kCPStateWaitUser,  // Waiting for the user to pick a shape
+	kCPStateWaitClown, // Waiting for the clown animation to finish
+	kCPStateFinish     // Finishing
+};
+
+bool OnceUpon::doCopyProtection(const uint8 colors[7], const uint8 shapes[7 * 20], const uint8 obfuscate[4]) {
+	fadeOut();
+	setCopyProtectionPalette();
+
+	Surface sprites[2] = {Surface(320, 200, 1), Surface(320, 200, 1)};
+
+	_vm->_video->drawPackedSprite("grille1.cmp", sprites[0]);
+	_vm->_video->drawPackedSprite("grille2.cmp", sprites[1]);
+
+	ANIFile   ani  (_vm, "grille.ani", 320);
+	ANIObject clown(ani);
+
+	setCursor(sprites[1], 5, 110, 20, 134, 3, 0);
+
+	CopyProtectionState state = kCPStateSetup;
+
+	uint8 triesLeft   =  2;
+	int8  animalShape = -1;
+	bool  hasCorrect  = false;
+
+	while (!_vm->shouldQuit() && (state != kCPStateFinish)) {
+		clearAnim(clown);
+
+		// Set up the screen
+		if (state == kCPStateSetup) {
+			animalShape = cpSetup(colors, shapes, obfuscate, sprites);
+
+			setAnimState(clown, kClownAnimationClownStand, false, false);
+			state = kCPStateWaitUser;
+		}
+
+		drawAnim(clown);
+
+		// If we're waiting for the clown and he finished, evaluate if we're finished
+		if (!clown.isVisible() && (state == kCPStateWaitClown))
+			state = (hasCorrect || (--triesLeft == 0)) ? kCPStateFinish : kCPStateSetup;
+
+		showCursor();
+		fadeIn();
+
+		endFrame(true);
+
+		int16 mouseX, mouseY;
+		MouseButtons mouseButtons;
+
+		checkInput(mouseX, mouseY, mouseButtons);
+
+		if (state == kCPStateWaitUser) {
+			// Look if we clicked a shaped and got it right
+
+			int8 guessedShape = -1;
+			if (mouseButtons == kMouseButtonsLeft)
+				guessedShape = cpFindShape(mouseX, mouseY);
+
+			if (guessedShape >= 0) {
+				hasCorrect  = guessedShape == animalShape;
+				animalShape = -1;
+
+				setAnimState(clown, hasCorrect ? kClownAnimationClownCheer : kClownAnimationClownCry, true, false);
+				state = kCPStateWaitClown;
+			}
+		}
+	}
+
+	fadeOut();
+	hideCursor();
+	clearScreen();
+
+	// Display the "You are wrong" screen
+	if (!hasCorrect)
+		cpWrong();
+
+	return hasCorrect;
+}
+
+int8 OnceUpon::cpSetup(const uint8 colors[7], const uint8 shapes[7 * 20], const uint8 obfuscate[4],
+                       const Surface sprites[2]) {
+
+	fadeOut();
+	hideCursor();
+
+	// Get a random animal and animal color
+	int8 animalColor = _vm->_util->getRandom(7);
+	while ((colors[animalColor] == 1) || (colors[animalColor] == 7) || (colors[animalColor] == 11))
+		animalColor = _vm->_util->getRandom(7);
+
+	int8 animal = _vm->_util->getRandom(20);
+
+	int8 animalShape = shapes[animalColor * 20 + animal];
+	if (animal < 4)
+		animal = obfuscate[animal];
+
+	// Get the position of the animal sprite
+	int16 animalLeft = (animal % 4) * 80;
+	int16 animalTop  = (animal / 4) * 50;
+
+	uint8 sprite = 0;
+	if (animalTop >= 200) {
+		animalTop -= 200;
+		sprite = 1;
+	}
+
+	int16 animalRight  = animalLeft + 80 - 1;
+	int16 animalBottom = animalTop  + 50 - 1;
+
+	// Fill with the animal color
+	_vm->_draw->_backSurface->fill(colors[animalColor]);
+
+	// Print the help line strings
+	for (uint i = 0; i < kCopyProtectionHelpStringCount; i++) {
+		const char * const helpString = kCopyProtectionHelpStrings[_vm->_global->_language][i];
+
+		const int x = 160 - (strlen(helpString) * _plettre->getCharWidth()) / 2;
+		const int y = i * 10 + 5;
+
+		_plettre->drawString(helpString, x, y, 8, 0, true, *_vm->_draw->_backSurface);
+	}
+
+	// White rectangle with black border
+	_vm->_draw->_backSurface->fillRect( 93, 43, 226, 134, 15);
+	_vm->_draw->_backSurface->drawRect( 92, 42, 227, 135,  0);
+
+	// Draw the animal in the animal color
+	_vm->_draw->_backSurface->fillRect(120, 63, 199, 112, colors[animalColor]);
+	_vm->_draw->_backSurface->blit(sprites[sprite], animalLeft, animalTop, animalRight, animalBottom, 120, 63, 0);
+
+	// Draw the shapes
+	for (uint i = 0; i < kCopyProtectionShapeCount; i++) {
+		const int16 * const coords = kCopyProtectionShapeCoords[i];
+
+		_vm->_draw->_backSurface->blit(sprites[1], coords[0], coords[1], coords[2], coords[3], coords[4], coords[5], 0);
+	}
+
+	_vm->_draw->forceBlit();
+
+	return animalShape;
+}
+
+int8 OnceUpon::cpFindShape(int16 x, int16 y) const {
+	// Look through all shapes and check if the coordinates are inside one of them
+	for (uint i = 0; i < kCopyProtectionShapeCount; i++) {
+		const int16 * const coords = kCopyProtectionShapeCoords[i];
+
+		const int16 left   = coords[4];
+		const int16 top    = coords[5];
+		const int16 right  = coords[4] + (coords[2] - coords[0] + 1) - 1;
+		const int16 bottom = coords[5] + (coords[3] - coords[1] + 1) - 1;
+
+		if ((x >= left) && (x <= right) && (y >= top) && (y <= bottom))
+			return i;
+	}
+
+	return -1;
+}
+
+void OnceUpon::cpWrong() {
+	// Display the "You are wrong" string, centered
+
+	const char * const wrongString = kCopyProtectionWrongStrings[_vm->_global->_language];
+	const int          wrongX      = 160 - (strlen(wrongString) * _plettre->getCharWidth()) / 2;
+
+	_vm->_draw->_backSurface->clear();
+	_plettre->drawString(wrongString, wrongX, 100, 15, 0, true, *_vm->_draw->_backSurface);
+
+	_vm->_draw->forceBlit();
+
+	fadeIn();
+
+	waitInput();
+
+	fadeOut();
+	clearScreen();
+}
+
+void OnceUpon::setAnimState(ANIObject &ani, uint16 state, bool once, bool pause) const {
+	ani.setAnimation(state);
+	ani.setMode(once ? ANIObject::kModeOnce : ANIObject::kModeContinuous);
+	ani.setPause(pause);
+	ani.setVisible(true);
+	ani.setPosition();
+}
+
 } // End of namespace OnceUpon
 
 } // End of namespace Gob
diff --git a/engines/gob/pregob/onceupon/onceupon.h b/engines/gob/pregob/onceupon/onceupon.h
index cfc1253..abcde68 100644
--- a/engines/gob/pregob/onceupon/onceupon.h
+++ b/engines/gob/pregob/onceupon/onceupon.h
@@ -32,6 +32,8 @@ namespace Gob {
 class Surface;
 class Font;
 
+class ANIObject;
+
 namespace OnceUpon {
 
 class OnceUpon : public PreGob {
@@ -45,6 +47,8 @@ protected:
 
 	void setGamePalette(uint palette);
 
+	bool doCopyProtection(const uint8 colors[7], const uint8 shapes[7 * 20], const uint8 obfuscate[4]);
+
 
 	Font *_jeudak;
 	Font *_lettre;
@@ -54,6 +58,13 @@ protected:
 private:
 	void setCopyProtectionPalette();
 
+	void setAnimState(ANIObject &ani, uint16 state, bool once, bool pause) const;
+
+	// Copy protection helpers
+	int8 cpSetup(const uint8 colors[7], const uint8 shapes[7 * 20], const uint8 obfuscate[4], const Surface sprites[2]);
+	int8 cpFindShape(int16 x, int16 y) const;
+	void cpWrong();
+
 
 	bool _openedArchives;
 };


Commit: 67d7c3f11fdaf697f7f3c3779643121793ba4eb7
    https://github.com/scummvm/scummvm/commit/67d7c3f11fdaf697f7f3c3779643121793ba4eb7
Author: Sven Hesse (drmccoy at users.sourceforge.net)
Date: 2012-07-29T16:44:43-07:00

Commit Message:
GOB: Show a mock-up of the Once Upon A Time title

The actual intro is described in a SEQ file. We don't support
those yet.

Changed paths:
    engines/gob/pregob/onceupon/abracadabra.cpp
    engines/gob/pregob/onceupon/babayaga.cpp
    engines/gob/pregob/onceupon/onceupon.cpp
    engines/gob/pregob/onceupon/onceupon.h



diff --git a/engines/gob/pregob/onceupon/abracadabra.cpp b/engines/gob/pregob/onceupon/abracadabra.cpp
index d8dd8b3..8ece3d1 100644
--- a/engines/gob/pregob/onceupon/abracadabra.cpp
+++ b/engines/gob/pregob/onceupon/abracadabra.cpp
@@ -61,7 +61,7 @@ void Abracadabra::run() {
 	if (_vm->shouldQuit() || !correctCP)
 		return;
 
-	warning("TODO: Abracadabra::run()");
+	showTitle();
 }
 
 } // End of namespace OnceUpon
diff --git a/engines/gob/pregob/onceupon/babayaga.cpp b/engines/gob/pregob/onceupon/babayaga.cpp
index aad1fc6..1eb6034 100644
--- a/engines/gob/pregob/onceupon/babayaga.cpp
+++ b/engines/gob/pregob/onceupon/babayaga.cpp
@@ -61,7 +61,7 @@ void BabaYaga::run() {
 	if (_vm->shouldQuit() || !correctCP)
 		return;
 
-	warning("TODO: BabaYaga::run()");
+	showTitle();
 }
 
 } // End of namespace OnceUpon
diff --git a/engines/gob/pregob/onceupon/onceupon.cpp b/engines/gob/pregob/onceupon/onceupon.cpp
index aa85e1c..a5d05ce 100644
--- a/engines/gob/pregob/onceupon/onceupon.cpp
+++ b/engines/gob/pregob/onceupon/onceupon.cpp
@@ -30,6 +30,8 @@
 #include "gob/anifile.h"
 #include "gob/aniobject.h"
 
+#include "gob/sound/sound.h"
+
 #include "gob/pregob/onceupon/onceupon.h"
 
 static const  int kPaletteSize  = 16;
@@ -487,6 +489,91 @@ void OnceUpon::setAnimState(ANIObject &ani, uint16 state, bool once, bool pause)
 	ani.setPosition();
 }
 
+void OnceUpon::showTitle() {
+	// Show the Once Upon A Time title animation
+	// NOTE: This is currently only a mock-up. The real animation is in "ville.seq".
+
+	fadeOut();
+	setGamePalette(10);
+
+	warning("OnceUpon::showTitle(): Actually play the SEQ");
+
+	clearScreen();
+
+	_vm->_video->drawPackedSprite("ville.cmp", *_vm->_draw->_backSurface);
+	_vm->_draw->forceBlit();
+
+	ANIFile   ani  (_vm, "pres.ani", 320);
+	ANIObject title(ani);
+
+	setAnimState(title, 8, false, false);
+
+	playTitleMusic();
+
+	while (!_vm->shouldQuit()) {
+		redrawAnim(title);
+
+		fadeIn();
+
+		endFrame(true);
+
+		if (hasInput())
+			break;
+	}
+
+	fadeOut();
+	stopTitleMusic();
+}
+
+void OnceUpon::playTitleMusic() {
+	if      (_vm->getPlatform() == Common::kPlatformPC)
+		playTitleMusicDOS();
+	else if (_vm->getPlatform() == Common::kPlatformAmiga)
+		playTitleMusicAmiga();
+	else if (_vm->getPlatform() == Common::kPlatformAtariST)
+		playTitleMusicAtariST();
+}
+
+void OnceUpon::playTitleMusicDOS() {
+	// Play an AdLib track
+
+	_vm->_sound->adlibLoadTBR("babayaga.tbr");
+	_vm->_sound->adlibLoadMDY("babayaga.mdy");
+	_vm->_sound->adlibSetRepeating(-1);
+	_vm->_sound->adlibPlay();
+}
+
+void OnceUpon::playTitleMusicAmiga() {
+	// Play a Protracker track
+
+	_vm->_sound->protrackerPlay("mod.babayaga");
+}
+
+void OnceUpon::playTitleMusicAtariST() {
+	// Play a Soundblaster composition
+
+	static const int16        titleMusic[21] = { 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 2, 0, 1, 0, 0, 0, 0, 0, -1};
+	static const char * const titleFiles[ 3] = {"baba1.snd", "baba2.snd", "baba3.snd"};
+
+	for (uint i = 0; i < ARRAYSIZE(titleFiles); i++)
+		_vm->_sound->sampleLoad(_vm->_sound->sampleGetBySlot(i), SOUND_SND, titleFiles[i]);
+
+	_vm->_sound->blasterPlayComposition(titleMusic, 0);
+	_vm->_sound->blasterRepeatComposition(-1);
+}
+
+void OnceUpon::stopTitleMusic() {
+	_vm->_sound->adlibSetRepeating(0);
+	_vm->_sound->blasterRepeatComposition(0);
+
+	_vm->_sound->adlibStop();
+	_vm->_sound->blasterStopComposition();
+	_vm->_sound->protrackerStop();
+
+	for (int i = 0; i < Sound::kSoundsCount; i++)
+		_vm->_sound->sampleFree(_vm->_sound->sampleGetBySlot(i));
+}
+
 } // End of namespace OnceUpon
 
 } // End of namespace Gob
diff --git a/engines/gob/pregob/onceupon/onceupon.h b/engines/gob/pregob/onceupon/onceupon.h
index abcde68..8b454e0 100644
--- a/engines/gob/pregob/onceupon/onceupon.h
+++ b/engines/gob/pregob/onceupon/onceupon.h
@@ -49,6 +49,8 @@ protected:
 
 	bool doCopyProtection(const uint8 colors[7], const uint8 shapes[7 * 20], const uint8 obfuscate[4]);
 
+	void showTitle();
+
 
 	Font *_jeudak;
 	Font *_lettre;
@@ -65,6 +67,11 @@ private:
 	int8 cpFindShape(int16 x, int16 y) const;
 	void cpWrong();
 
+	void playTitleMusic();
+	void playTitleMusicDOS();
+	void playTitleMusicAmiga();
+	void playTitleMusicAtariST();
+	void stopTitleMusic();
 
 	bool _openedArchives;
 };


Commit: 9af01cd58417e796b82cf6bb36e1bd30b0875f0e
    https://github.com/scummvm/scummvm/commit/9af01cd58417e796b82cf6bb36e1bd30b0875f0e
Author: Sven Hesse (drmccoy at users.sourceforge.net)
Date: 2012-07-29T16:44:43-07:00

Commit Message:
GOB: Move the background saving into its own class BackBuffer

Changed paths:
  A engines/gob/backbuffer.cpp
  A engines/gob/backbuffer.h
    engines/gob/aniobject.cpp
    engines/gob/aniobject.h
    engines/gob/module.mk



diff --git a/engines/gob/aniobject.cpp b/engines/gob/aniobject.cpp
index 8d739fb..8d3a689 100644
--- a/engines/gob/aniobject.cpp
+++ b/engines/gob/aniobject.cpp
@@ -28,23 +28,20 @@
 namespace Gob {
 
 ANIObject::ANIObject(const ANIFile &ani) : _ani(&ani), _cmp(0),
-	_visible(false), _paused(false), _mode(kModeContinuous),
-	_x(0), _y(0), _background(0), _drawn(false) {
+	_visible(false), _paused(false), _mode(kModeContinuous), _x(0), _y(0) {
 
 	setAnimation(0);
 	setPosition();
 }
 
 ANIObject::ANIObject(const CMPFile &cmp) : _ani(0), _cmp(&cmp),
-	_visible(false), _paused(false), _mode(kModeContinuous),
-	_x(0), _y(0), _background(0), _drawn(false) {
+	_visible(false), _paused(false), _mode(kModeContinuous), _x(0), _y(0) {
 
 	setAnimation(0);
 	setPosition();
 }
 
 ANIObject::~ANIObject() {
-	delete _background;
 }
 
 void ANIObject::setVisible(bool visible) {
@@ -188,46 +185,36 @@ bool ANIObject::draw(Surface &dest, int16 &left, int16 &top,
 bool ANIObject::drawCMP(Surface &dest, int16 &left, int16 &top,
                                        int16 &right, int16 &bottom) {
 
-	if (!_background) {
+	if (!hasBuffer()) {
 		uint16 width, height;
 
 		_cmp->getMaxSize(width, height);
 
-		_background = new Surface(width, height, dest.getBPP());
+		resizeBuffer(width, height);
 	}
 
-	const uint16 cR = _cmp->getWidth (_animation) - 1;
-	const uint16 cB = _cmp->getHeight(_animation) - 1;
+	left   = _x;
+	top    = _y;
+	right  = _x + _cmp->getWidth (_animation) - 1;
+	bottom = _y + _cmp->getHeight(_animation) - 1;
 
-	_backgroundLeft   = CLIP<int16>(   + _x, 0, dest.getWidth () - 1);
-	_backgroundTop    = CLIP<int16>(   + _y, 0, dest.getHeight() - 1);
-	_backgroundRight  = CLIP<int16>(cR + _x, 0, dest.getWidth () - 1);
-	_backgroundBottom = CLIP<int16>(cB + _y, 0, dest.getHeight() - 1);
-
-	_background->blit(dest, _backgroundLeft , _backgroundTop,
-	                        _backgroundRight, _backgroundBottom, 0, 0);
+	if (!saveScreen(dest, left, top, right, bottom))
+		return false;
 
 	_cmp->draw(dest, _animation, _x, _y, 0);
 
-	_drawn = true;
-
-	left   = _backgroundLeft;
-	top    = _backgroundTop;
-	right  = _backgroundRight;
-	bottom = _backgroundBottom;
-
 	return true;
 }
 
 bool ANIObject::drawANI(Surface &dest, int16 &left, int16 &top,
                                        int16 &right, int16 &bottom) {
 
-	if (!_background) {
+	if (!hasBuffer()) {
 		uint16 width, height;
 
 		_ani->getMaxSize(width, height);
 
-		_background = new Surface(width, height, dest.getBPP());
+		resizeBuffer(width, height);
 	}
 
 	const ANIFile::Animation &animation = _ani->getAnimationInfo(_animation);
@@ -236,45 +223,23 @@ bool ANIObject::drawANI(Surface &dest, int16 &left, int16 &top,
 
 	const ANIFile::FrameArea &area = animation.frameAreas[_frame];
 
-	_backgroundLeft   = CLIP<int16>(area.left   + _x, 0, dest.getWidth () - 1);
-	_backgroundTop    = CLIP<int16>(area.top    + _y, 0, dest.getHeight() - 1);
-	_backgroundRight  = CLIP<int16>(area.right  + _x, 0, dest.getWidth () - 1);
-	_backgroundBottom = CLIP<int16>(area.bottom + _y, 0, dest.getHeight() - 1);
+	left   = _x + area.left;
+	top    = _y + area.top;
+	right  = _x + area.right;
+	bottom = _y + area.bottom;
 
-	_background->blit(dest, _backgroundLeft , _backgroundTop,
-	                        _backgroundRight, _backgroundBottom, 0, 0);
+	if (!saveScreen(dest, left, top, right, bottom))
+		return false;
 
 	_ani->draw(dest, _animation, _frame, _x, _y);
 
-	_drawn = true;
-
-	left   = _backgroundLeft;
-	top    = _backgroundTop;
-	right  = _backgroundRight;
-	bottom = _backgroundBottom;
-
 	return true;
 }
 
 bool ANIObject::clear(Surface &dest, int16 &left, int16 &top,
                                      int16 &right, int16 &bottom) {
 
-	if (!_drawn)
-		return false;
-
-	const int16 bgRight  = _backgroundRight  - _backgroundLeft;
-	const int16 bgBottom = _backgroundBottom - _backgroundTop;
-
-	dest.blit(*_background, 0, 0, bgRight, bgBottom, _backgroundLeft, _backgroundTop);
-
-	_drawn = false;
-
-	left   = _backgroundLeft;
-	top    = _backgroundTop;
-	right  = _backgroundRight;
-	bottom = _backgroundBottom;
-
-	return true;
+	return restoreScreen(dest, left, top, right, bottom);
 }
 
 void ANIObject::advance() {
diff --git a/engines/gob/aniobject.h b/engines/gob/aniobject.h
index 00f42b4..3c374f7 100644
--- a/engines/gob/aniobject.h
+++ b/engines/gob/aniobject.h
@@ -25,6 +25,8 @@
 
 #include "common/system.h"
 
+#include "gob/backbuffer.h"
+
 namespace Gob {
 
 class ANIFile;
@@ -32,7 +34,7 @@ class CMPFile;
 class Surface;
 
 /** An ANI object, controlling an animation within an ANI file. */
-class ANIObject {
+class ANIObject : public BackBuffer {
 public:
 	enum Mode {
 		kModeContinuous, ///< Play the animation continuously.
@@ -118,13 +120,6 @@ private:
 	int16 _x; ///< The current X position.
 	int16 _y; ///< The current Y position.
 
-	Surface *_background; ///< The saved background.
-	bool _drawn;          ///< Was the animation drawn?
-
-	int16 _backgroundLeft;   ///< The left position of the saved background.
-	int16 _backgroundTop;    ///< The top of the saved background.
-	int16 _backgroundRight;  ///< The right position of the saved background.
-	int16 _backgroundBottom; ///< The bottom position of the saved background.
 
 	bool drawCMP(Surface &dest, int16 &left, int16 &top, int16 &right, int16 &bottom);
 	bool drawANI(Surface &dest, int16 &left, int16 &top, int16 &right, int16 &bottom);
diff --git a/engines/gob/backbuffer.cpp b/engines/gob/backbuffer.cpp
new file mode 100644
index 0000000..752042d
--- /dev/null
+++ b/engines/gob/backbuffer.cpp
@@ -0,0 +1,100 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "common/util.h"
+
+#include "gob/backbuffer.h"
+#include "gob/surface.h"
+
+namespace Gob {
+
+BackBuffer::BackBuffer() : _background(0), _saved(false) {
+}
+
+BackBuffer::~BackBuffer() {
+	delete _background;
+}
+
+bool BackBuffer::hasBuffer() const {
+	return _background != 0;
+}
+
+bool BackBuffer::hasSavedBackground() const {
+	return _saved;
+}
+
+void BackBuffer::trashBuffer() {
+	_saved = false;
+}
+
+void BackBuffer::resizeBuffer(uint16 width, uint16 height) {
+	trashBuffer();
+
+	if (_background && (_background->getWidth() == width) && (_background->getHeight() == height))
+		return;
+
+	delete _background;
+
+	_background = new Surface(width, height, 1);
+}
+
+bool BackBuffer::saveScreen(const Surface &dest, int16 &left, int16 &top, int16 &right, int16 &bottom) {
+	if (!_background)
+		return false;
+
+	const int16 width  = MIN<int16>(right  - left + 1, _background->getWidth ());
+	const int16 height = MIN<int16>(bottom - top  + 1, _background->getHeight());
+	if ((width <= 0) || (height <= 0))
+		return false;
+
+	right  = left + width  - 1;
+	bottom = top  + height - 1;
+
+	_saveLeft   = left;
+	_saveTop    = top;
+	_saveRight  = right;
+	_saveBottom = bottom;
+
+	_background->blit(dest, _saveLeft, _saveTop, _saveRight, _saveBottom, 0, 0);
+
+	_saved = true;
+
+	return true;
+}
+
+bool BackBuffer::restoreScreen(Surface &dest, int16 &left, int16 &top, int16 &right, int16 &bottom) {
+	if (!_saved)
+		return false;
+
+	left   = _saveLeft;
+	top    = _saveTop;
+	right  = _saveRight;
+	bottom = _saveBottom;
+
+	dest.blit(*_background, 0, 0, right - left, bottom - top, left, top);
+
+	_saved = false;
+
+	return true;
+}
+
+} // End of namespace Gob
diff --git a/engines/gob/backbuffer.h b/engines/gob/backbuffer.h
new file mode 100644
index 0000000..c978689
--- /dev/null
+++ b/engines/gob/backbuffer.h
@@ -0,0 +1,59 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef GOB_BACKBUFFER_H
+#define GOB_BACKBUFFER_H
+
+#include "common/system.h"
+
+namespace Gob {
+
+class Surface;
+
+class BackBuffer {
+public:
+	BackBuffer();
+	~BackBuffer();
+
+protected:
+	void trashBuffer();
+	void resizeBuffer(uint16 width, uint16 height);
+
+	bool saveScreen   (const Surface &dest, int16 &left, int16 &top, int16 &right, int16 &bottom);
+	bool restoreScreen(      Surface &dest, int16 &left, int16 &top, int16 &right, int16 &bottom);
+
+	bool hasBuffer() const;
+	bool hasSavedBackground() const;
+
+private:
+	Surface *_background; ///< The saved background.
+	bool _saved;          ///< Was the background saved?
+
+	int16 _saveLeft;   ///< The left position of the saved background.
+	int16 _saveTop;    ///< The top of the saved background.
+	int16 _saveRight;  ///< The right position of the saved background.
+	int16 _saveBottom; ///< The bottom position of the saved background.
+};
+
+} // End of namespace Gob
+
+#endif // GOB_BACKBUFFER_H
diff --git a/engines/gob/module.mk b/engines/gob/module.mk
index 8a79204..2169602 100644
--- a/engines/gob/module.mk
+++ b/engines/gob/module.mk
@@ -3,6 +3,7 @@ MODULE := engines/gob
 MODULE_OBJS := \
 	anifile.o \
 	aniobject.o \
+	backbuffer.o \
 	cheater.o \
 	cheater_geisha.o \
 	cmpfile.o \


Commit: 4b3aa88c8aaaec4f13435c46a7a3cf4ef00a08df
    https://github.com/scummvm/scummvm/commit/4b3aa88c8aaaec4f13435c46a7a3cf4ef00a08df
Author: Sven Hesse (drmccoy at users.sourceforge.net)
Date: 2012-07-29T16:44:43-07:00

Commit Message:
GOB: Add a simple class for PreGob TXT files

Changed paths:
  A engines/gob/pregob/txtfile.cpp
  A engines/gob/pregob/txtfile.h
    engines/gob/module.mk
    engines/gob/pregob/pregob.cpp
    engines/gob/pregob/pregob.h



diff --git a/engines/gob/module.mk b/engines/gob/module.mk
index 2169602..f8b477b 100644
--- a/engines/gob/module.mk
+++ b/engines/gob/module.mk
@@ -79,6 +79,7 @@ MODULE_OBJS := \
 	demos/batplayer.o \
 	detection/detection.o \
 	pregob/pregob.o \
+	pregob/txtfile.o \
 	pregob/onceupon/onceupon.o \
 	pregob/onceupon/abracadabra.o \
 	pregob/onceupon/babayaga.o \
diff --git a/engines/gob/pregob/pregob.cpp b/engines/gob/pregob/pregob.cpp
index b9c36d7..98b1a2e 100644
--- a/engines/gob/pregob/pregob.cpp
+++ b/engines/gob/pregob/pregob.cpp
@@ -26,6 +26,7 @@
 #include "gob/global.h"
 #include "gob/util.h"
 #include "gob/surface.h"
+#include "gob/dataio.h"
 #include "gob/palanim.h"
 #include "gob/draw.h"
 #include "gob/video.h"
@@ -202,4 +203,16 @@ void PreGob::redrawAnim(ANIObject &ani) {
 	drawAnim(ani);
 }
 
+TXTFile *PreGob::loadTXT(const Common::String &txtFile, TXTFile::Format format) const {
+	Common::SeekableReadStream *txtStream = _vm->_dataIO->getFile(txtFile);
+	if (!txtStream)
+		error("PreGob::loadTXT(): Failed to open \"%s\"", txtFile.c_str());
+
+	TXTFile *txt = new TXTFile(*txtStream, format);
+
+	delete txtStream;
+
+	return txt;
+}
+
 } // End of namespace Gob
diff --git a/engines/gob/pregob/pregob.h b/engines/gob/pregob/pregob.h
index 9efdbe8..d087bb0 100644
--- a/engines/gob/pregob/pregob.h
+++ b/engines/gob/pregob/pregob.h
@@ -25,6 +25,8 @@
 
 #include "gob/util.h"
 
+#include "gob/pregob/txtfile.h"
+
 namespace Gob {
 
 class GobEngine;
@@ -77,6 +79,8 @@ protected:
 	void drawAnim(ANIObject &ani);
 	void redrawAnim(ANIObject &ani);
 
+	TXTFile *loadTXT(const Common::String &txtFile, TXTFile::Format format) const;
+
 
 	GobEngine *_vm;
 
diff --git a/engines/gob/pregob/txtfile.cpp b/engines/gob/pregob/txtfile.cpp
new file mode 100644
index 0000000..3ff0d4b
--- /dev/null
+++ b/engines/gob/pregob/txtfile.cpp
@@ -0,0 +1,232 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "common/stream.h"
+
+#include "gob/draw.h"
+
+#include "gob/pregob/txtfile.h"
+
+namespace Gob {
+
+TXTFile::TXTFile(Common::SeekableReadStream &txt, Format format) {
+	load(txt, format);
+}
+
+TXTFile::~TXTFile() {
+}
+
+TXTFile::LineArray &TXTFile::getLines() {
+	return _lines;
+}
+
+void TXTFile::load(Common::SeekableReadStream &txt, Format format) {
+	if (format == kFormatStringPositionColorFont) {
+		int numLines = getInt(txt);
+
+		_lines.reserve(numLines);
+	}
+
+	while (!txt.eos()) {
+		Line line;
+
+		line.text  =                                              getStr(txt);
+		line.x     = (format >= kFormatStringPosition)          ? getInt(txt) : 0;
+		line.y     = (format >= kFormatStringPosition)          ? getInt(txt) : 0;
+		line.color = (format >= kFormatStringPositionColor)     ? getInt(txt) : 0;
+		line.font  = (format >= kFormatStringPositionColorFont) ? getInt(txt) : 0;
+
+		_lines.push_back(line);
+	}
+
+	while (!_lines.empty() && _lines.back().text.empty())
+		_lines.pop_back();
+}
+
+bool TXTFile::draw(Surface &surface, int16 &left, int16 &top, int16 &right, int16 &bottom,
+                   const Font * const *fonts, uint fontCount, int color) {
+
+	trashBuffer();
+
+	if (!getArea(left, top, right, bottom, fonts, fontCount))
+		return false;
+
+	resizeBuffer(right - left + 1, bottom - top + 1);
+	saveScreen(surface, left, top, right, bottom);
+
+	for (LineArray::const_iterator l = _lines.begin(); l != _lines.end(); ++l) {
+		if (l->font >= fontCount)
+			continue;
+
+		fonts[l->font]->drawString(l->text, l->x, l->y, (color < 0) ? l->color : color, 0, true, surface);
+	}
+
+	return true;
+}
+
+bool TXTFile::draw(uint line, Surface &surface, int16 &left, int16 &top, int16 &right, int16 &bottom,
+                   const Font * const *fonts, uint fontCount, int color) {
+
+	trashBuffer();
+
+	if (!getArea(line, left, top, right, bottom, fonts, fontCount))
+		return false;
+
+	resizeBuffer(right - left + 1, bottom - top + 1);
+	saveScreen(surface, left, top, right, bottom);
+
+	const Line &l = _lines[line];
+
+	fonts[l.font]->drawString(l.text, l.x, l.y, (color < 0) ? l.color : color, 0, true, surface);
+
+	return true;
+}
+
+bool TXTFile::draw(Surface &surface, const Font * const *fonts, uint fontCount, int color) {
+	int16 left, top, right, bottom;
+
+	return draw(surface, left, top, right, bottom, fonts, fontCount, color);
+}
+
+bool TXTFile::draw(uint line, Surface &surface, const Font * const *fonts, uint fontCount, int color) {
+	int16 left, top, right, bottom;
+
+	return draw(line, surface, left, top, right, bottom, fonts, fontCount, color);
+}
+
+bool TXTFile::clear(Surface &surface, int16 &left, int16 &top, int16 &right, int16 &bottom) {
+	return restoreScreen(surface, left, top, right, bottom);
+}
+
+bool TXTFile::getArea(int16 &left, int16 &top, int16 &right, int16 &bottom,
+                      const Font * const *fonts, uint fontCount) const {
+
+	bool hasLine = false;
+
+	left   = 0x7FFF;
+	top    = 0x7FFF;
+	right  = 0x0000;
+	bottom = 0x0000;
+
+	for (uint i = 0; i < _lines.size(); i++) {
+		int16 lLeft, lTop, lRight, lBottom;
+
+		if (getArea(i, lLeft, lTop, lRight, lBottom, fonts, fontCount)) {
+			left   = MIN(left  , lLeft  );
+			top    = MIN(top   , lTop   );
+			right  = MAX(right , lRight );
+			bottom = MAX(bottom, lBottom);
+
+			hasLine = true;
+		}
+	}
+
+	return hasLine;
+}
+
+bool TXTFile::getArea(uint line, int16 &left, int16 &top, int16 &right, int16 &bottom,
+                      const Font * const *fonts, uint fontCount) const {
+
+
+	if ((line >= _lines.size()) || (_lines[line].font >= fontCount))
+		return false;
+
+	const Line &l = _lines[line];
+
+	left   = l.x;
+	top    = l.y;
+	right  = l.x + l.text.size() * fonts[l.font]->getCharWidth()  - 1;
+	bottom = l.y +                 fonts[l.font]->getCharHeight() - 1;
+
+	return true;
+}
+
+Common::String TXTFile::getStr(Common::SeekableReadStream &txt) {
+	// Skip all ' ', '\n' and '\r'
+	while (!txt.eos()) {
+		char c = txt.readByte();
+		if (txt.eos())
+			break;
+
+		if ((c != ' ') && (c != '\n') && (c != '\r')) {
+			txt.seek(-1, SEEK_CUR);
+			break;
+		}
+	}
+
+	if (txt.eos())
+		return "";
+
+	// Read string until ' ', '\n' or '\r'
+	Common::String string;
+	while (!txt.eos()) {
+		char c = txt.readByte();
+		if ((c == ' ') || (c == '\n') || (c == '\r'))
+			break;
+
+		string += c;
+	}
+
+	// Replace all '#' with ' ' and throw out non-printables
+	Common::String cleanString;
+
+	for (uint i = 0; i < string.size(); i++) {
+		if      (string[i] == '#')
+			cleanString += ' ';
+		else if ((unsigned char)string[i] >= ' ')
+			cleanString += string[i];
+	}
+
+	return cleanString;
+}
+
+int TXTFile::getInt(Common::SeekableReadStream &txt) {
+	// Skip all [^-0-9]
+	while (!txt.eos()) {
+		char c = txt.readByte();
+		if (txt.eos())
+			break;
+
+		if ((c == '-') || ((c >= '0') && (c <= '9'))) {
+			txt.seek(-1, SEEK_CUR);
+			break;
+		}
+	}
+
+	if (txt.eos())
+		return 0;
+
+	// Read until [^-0-9]
+	Common::String string;
+	while (!txt.eos()) {
+		char c = txt.readByte();
+		if ((c != '-') && ((c < '0') || (c > '9')))
+			break;
+
+		string += c;
+	}
+
+	// Convert to integer
+	return atoi(string.c_str());
+}
+
+} // End of namespace Gob
diff --git a/engines/gob/pregob/txtfile.h b/engines/gob/pregob/txtfile.h
new file mode 100644
index 0000000..c623b58
--- /dev/null
+++ b/engines/gob/pregob/txtfile.h
@@ -0,0 +1,91 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef GOB_PREGOB_TXTFILE_H
+#define GOB_PREGOB_TXTFILE_H
+
+#include "common/system.h"
+#include "common/str.h"
+#include "common/array.h"
+
+#include "gob/backbuffer.h"
+
+namespace Common {
+	class SeekableReadStream;
+}
+
+namespace Gob {
+
+class Surface;
+class Font;
+
+class TXTFile : public BackBuffer {
+public:
+	enum Format {
+		kFormatString,
+		kFormatStringPosition,
+		kFormatStringPositionColor,
+		kFormatStringPositionColorFont
+	};
+
+	struct Line {
+		Common::String text;
+		int x, y;
+		int color;
+		uint font;
+	};
+
+	typedef Common::Array<Line> LineArray;
+
+	TXTFile(Common::SeekableReadStream &txt, Format format);
+	~TXTFile();
+
+	LineArray &getLines();
+
+	bool draw(           Surface &surface, const Font * const *fonts, uint fontCount, int color = -1);
+	bool draw(uint line, Surface &surface, const Font * const *fonts, uint fontCount, int color = -1);
+
+	bool draw(           Surface &surface, int16 &left, int16 &top, int16 &right, int16 &bottom,
+	          const Font * const *fonts, uint fontCount, int color = -1);
+	bool draw(uint line, Surface &surface, int16 &left, int16 &top, int16 &right, int16 &bottom,
+	          const Font * const *fonts, uint fontCount, int color = -1);
+
+	bool clear(Surface &surface, int16 &left, int16 &top, int16 &right, int16 &bottom);
+
+private:
+	LineArray _lines;
+
+	void load(Common::SeekableReadStream &txt, Format format);
+
+	Common::String getStr(Common::SeekableReadStream &txt);
+	int getInt(Common::SeekableReadStream &txt);
+
+
+	bool getArea(           int16 &left, int16 &top, int16 &right, int16 &bottom,
+	             const Font * const *fonts, uint fontCount) const;
+	bool getArea(uint line, int16 &left, int16 &top, int16 &right, int16 &bottom,
+	             const Font * const *fonts, uint fontCount) const;
+};
+
+} // End of namespace Gob
+
+#endif // GOB_PREGOB_TXTFILE_H


Commit: 139b03c4bcafea260e79e3e83db897c71db41907
    https://github.com/scummvm/scummvm/commit/139b03c4bcafea260e79e3e83db897c71db41907
Author: Sven Hesse (drmccoy at users.sourceforge.net)
Date: 2012-07-29T16:44:43-07:00

Commit Message:
GOB: Add a PreGob method to get a localized file name

Changed paths:
    engines/gob/pregob/pregob.cpp
    engines/gob/pregob/pregob.h



diff --git a/engines/gob/pregob/pregob.cpp b/engines/gob/pregob/pregob.cpp
index 98b1a2e..582ebc6 100644
--- a/engines/gob/pregob/pregob.cpp
+++ b/engines/gob/pregob/pregob.cpp
@@ -34,6 +34,8 @@
 
 #include "gob/pregob/pregob.h"
 
+static char kLanguageSuffix[5] = { 't', 'g', 'a', 'e', 'i' };
+
 namespace Gob {
 
 PreGob::PreGob(GobEngine *vm) : _vm(vm), _fadedOut(false) {
@@ -203,6 +205,13 @@ void PreGob::redrawAnim(ANIObject &ani) {
 	drawAnim(ani);
 }
 
+Common::String PreGob::getLocFile(const Common::String &file) const {
+	if (_vm->_global->_language >= ARRAYSIZE(kLanguageSuffix))
+		return file;
+
+	return file + kLanguageSuffix[_vm->_global->_language];
+}
+
 TXTFile *PreGob::loadTXT(const Common::String &txtFile, TXTFile::Format format) const {
 	Common::SeekableReadStream *txtStream = _vm->_dataIO->getFile(txtFile);
 	if (!txtStream)
diff --git a/engines/gob/pregob/pregob.h b/engines/gob/pregob/pregob.h
index d087bb0..902a7c4 100644
--- a/engines/gob/pregob/pregob.h
+++ b/engines/gob/pregob/pregob.h
@@ -23,6 +23,8 @@
 #ifndef GOB_PREGOB_PREGOB_H
 #define GOB_PREGOB_PREGOB_H
 
+#include "common/str.h"
+
 #include "gob/util.h"
 
 #include "gob/pregob/txtfile.h"
@@ -79,6 +81,7 @@ protected:
 	void drawAnim(ANIObject &ani);
 	void redrawAnim(ANIObject &ani);
 
+	Common::String getLocFile(const Common::String &file) const;
 	TXTFile *loadTXT(const Common::String &txtFile, TXTFile::Format format) const;
 
 


Commit: 60cebba95ca1d30f2926acd2d415d09c75e2bd42
    https://github.com/scummvm/scummvm/commit/60cebba95ca1d30f2926acd2d415d09c75e2bd42
Author: Sven Hesse (drmccoy at users.sourceforge.net)
Date: 2012-07-29T16:44:43-07:00

Commit Message:
GOB: Show the Once Upon A Time wait/load screen

Changed paths:
    engines/gob/pregob/onceupon/abracadabra.cpp
    engines/gob/pregob/onceupon/babayaga.cpp
    engines/gob/pregob/onceupon/onceupon.cpp
    engines/gob/pregob/onceupon/onceupon.h



diff --git a/engines/gob/pregob/onceupon/abracadabra.cpp b/engines/gob/pregob/onceupon/abracadabra.cpp
index 8ece3d1..27845cd 100644
--- a/engines/gob/pregob/onceupon/abracadabra.cpp
+++ b/engines/gob/pregob/onceupon/abracadabra.cpp
@@ -61,6 +61,10 @@ void Abracadabra::run() {
 	if (_vm->shouldQuit() || !correctCP)
 		return;
 
+	showWait();
+	if (_vm->shouldQuit())
+		return;
+
 	showTitle();
 }
 
diff --git a/engines/gob/pregob/onceupon/babayaga.cpp b/engines/gob/pregob/onceupon/babayaga.cpp
index 1eb6034..1dbda82 100644
--- a/engines/gob/pregob/onceupon/babayaga.cpp
+++ b/engines/gob/pregob/onceupon/babayaga.cpp
@@ -61,6 +61,10 @@ void BabaYaga::run() {
 	if (_vm->shouldQuit() || !correctCP)
 		return;
 
+	showWait();
+	if (_vm->shouldQuit())
+		return;
+
 	showTitle();
 }
 
diff --git a/engines/gob/pregob/onceupon/onceupon.cpp b/engines/gob/pregob/onceupon/onceupon.cpp
index a5d05ce..6f5d95b 100644
--- a/engines/gob/pregob/onceupon/onceupon.cpp
+++ b/engines/gob/pregob/onceupon/onceupon.cpp
@@ -489,6 +489,23 @@ void OnceUpon::setAnimState(ANIObject &ani, uint16 state, bool once, bool pause)
 	ani.setPosition();
 }
 
+void OnceUpon::showWait() {
+	// Show the loading floppy
+
+	fadeOut();
+	clearScreen();
+	setGamePalette(10);
+
+	Surface wait(320, 43, 1);
+
+	_vm->_video->drawPackedSprite("wait.cmp", wait);
+	_vm->_draw->_backSurface->blit(wait, 0, 0, 72, 33, 122, 84);
+
+	_vm->_draw->forceBlit();
+
+	fadeIn();
+}
+
 void OnceUpon::showTitle() {
 	// Show the Once Upon A Time title animation
 	// NOTE: This is currently only a mock-up. The real animation is in "ville.seq".
diff --git a/engines/gob/pregob/onceupon/onceupon.h b/engines/gob/pregob/onceupon/onceupon.h
index 8b454e0..99fb514 100644
--- a/engines/gob/pregob/onceupon/onceupon.h
+++ b/engines/gob/pregob/onceupon/onceupon.h
@@ -49,6 +49,7 @@ protected:
 
 	bool doCopyProtection(const uint8 colors[7], const uint8 shapes[7 * 20], const uint8 obfuscate[4]);
 
+	void showWait();
 	void showTitle();
 
 


Commit: 2f3aaf0e07a7309b2ba74c7e888b03c24534d4d0
    https://github.com/scummvm/scummvm/commit/2f3aaf0e07a7309b2ba74c7e888b03c24534d4d0
Author: Sven Hesse (drmccoy at users.sourceforge.net)
Date: 2012-07-29T16:44:43-07:00

Commit Message:
GOB: Show the Once Upon A Time fairytale quote

Changed paths:
    engines/gob/pregob/onceupon/abracadabra.cpp
    engines/gob/pregob/onceupon/babayaga.cpp
    engines/gob/pregob/onceupon/onceupon.cpp
    engines/gob/pregob/onceupon/onceupon.h



diff --git a/engines/gob/pregob/onceupon/abracadabra.cpp b/engines/gob/pregob/onceupon/abracadabra.cpp
index 27845cd..abf9fdc 100644
--- a/engines/gob/pregob/onceupon/abracadabra.cpp
+++ b/engines/gob/pregob/onceupon/abracadabra.cpp
@@ -65,6 +65,10 @@ void Abracadabra::run() {
 	if (_vm->shouldQuit())
 		return;
 
+	showQuote();
+	if (_vm->shouldQuit())
+		return;
+
 	showTitle();
 }
 
diff --git a/engines/gob/pregob/onceupon/babayaga.cpp b/engines/gob/pregob/onceupon/babayaga.cpp
index 1dbda82..9bca0e2 100644
--- a/engines/gob/pregob/onceupon/babayaga.cpp
+++ b/engines/gob/pregob/onceupon/babayaga.cpp
@@ -65,6 +65,10 @@ void BabaYaga::run() {
 	if (_vm->shouldQuit())
 		return;
 
+	showQuote();
+	if (_vm->shouldQuit())
+		return;
+
 	showTitle();
 }
 
diff --git a/engines/gob/pregob/onceupon/onceupon.cpp b/engines/gob/pregob/onceupon/onceupon.cpp
index 6f5d95b..7332265 100644
--- a/engines/gob/pregob/onceupon/onceupon.cpp
+++ b/engines/gob/pregob/onceupon/onceupon.cpp
@@ -506,6 +506,28 @@ void OnceUpon::showWait() {
 	fadeIn();
 }
 
+void OnceUpon::showQuote() {
+	// Show the quote about fairytales
+
+	fadeOut();
+	clearScreen();
+	setGamePalette(11);
+
+	static const Font *fonts[3] = { _plettre, _glettre, _plettre };
+
+	TXTFile *quote = loadTXT(getLocFile("gene.tx"), TXTFile::kFormatStringPositionColorFont);
+	quote->draw(*_vm->_draw->_backSurface, fonts, ARRAYSIZE(fonts));
+	delete quote;
+
+	_vm->_draw->forceBlit();
+
+	fadeIn();
+
+	waitInput();
+
+	fadeOut();
+}
+
 void OnceUpon::showTitle() {
 	// Show the Once Upon A Time title animation
 	// NOTE: This is currently only a mock-up. The real animation is in "ville.seq".
diff --git a/engines/gob/pregob/onceupon/onceupon.h b/engines/gob/pregob/onceupon/onceupon.h
index 99fb514..97f7e6b 100644
--- a/engines/gob/pregob/onceupon/onceupon.h
+++ b/engines/gob/pregob/onceupon/onceupon.h
@@ -50,6 +50,7 @@ protected:
 	bool doCopyProtection(const uint8 colors[7], const uint8 shapes[7 * 20], const uint8 obfuscate[4]);
 
 	void showWait();
+	void showQuote();
 	void showTitle();
 
 


Commit: 92bd9c864ab5238aa51ad6a327cfb7249bcc934f
    https://github.com/scummvm/scummvm/commit/92bd9c864ab5238aa51ad6a327cfb7249bcc934f
Author: Sven Hesse (drmccoy at users.sourceforge.net)
Date: 2012-07-29T16:44:43-07:00

Commit Message:
GOB: Show the specific game title in Once Upon A Time

Changed paths:
    engines/gob/pregob/onceupon/abracadabra.cpp
    engines/gob/pregob/onceupon/babayaga.cpp
    engines/gob/pregob/onceupon/onceupon.cpp
    engines/gob/pregob/onceupon/onceupon.h



diff --git a/engines/gob/pregob/onceupon/abracadabra.cpp b/engines/gob/pregob/onceupon/abracadabra.cpp
index abf9fdc..5c1bd01 100644
--- a/engines/gob/pregob/onceupon/abracadabra.cpp
+++ b/engines/gob/pregob/onceupon/abracadabra.cpp
@@ -57,19 +57,33 @@ Abracadabra::~Abracadabra() {
 void Abracadabra::run() {
 	init();
 
+	// Copy protection
 	bool correctCP = doCopyProtection(kCopyProtectionColors, kCopyProtectionShapes, kCopyProtectionObfuscate);
 	if (_vm->shouldQuit() || !correctCP)
 		return;
 
+	// "Loading"
 	showWait();
 	if (_vm->shouldQuit())
 		return;
 
+	// Quote about fairy tales
 	showQuote();
 	if (_vm->shouldQuit())
 		return;
 
+	// Once Upon A Time title
 	showTitle();
+	if (_vm->shouldQuit())
+		return;
+
+	// Game title screen
+	showChapter(0);
+	if (_vm->shouldQuit())
+		return;
+
+	// "Loading"
+	showWait();
 }
 
 } // End of namespace OnceUpon
diff --git a/engines/gob/pregob/onceupon/babayaga.cpp b/engines/gob/pregob/onceupon/babayaga.cpp
index 9bca0e2..608d85e 100644
--- a/engines/gob/pregob/onceupon/babayaga.cpp
+++ b/engines/gob/pregob/onceupon/babayaga.cpp
@@ -57,19 +57,33 @@ BabaYaga::~BabaYaga() {
 void BabaYaga::run() {
 	init();
 
+	// Copy protection
 	bool correctCP = doCopyProtection(kCopyProtectionColors, kCopyProtectionShapes, kCopyProtectionObfuscate);
 	if (_vm->shouldQuit() || !correctCP)
 		return;
 
+	// "Loading"
 	showWait();
 	if (_vm->shouldQuit())
 		return;
 
+	// Quote about fairy tales
 	showQuote();
 	if (_vm->shouldQuit())
 		return;
 
+	// Once Upon A Time title
 	showTitle();
+	if (_vm->shouldQuit())
+		return;
+
+	// Game title screen
+	showChapter(0);
+	if (_vm->shouldQuit())
+		return;
+
+	// "Loading"
+	showWait();
 }
 
 } // End of namespace OnceUpon
diff --git a/engines/gob/pregob/onceupon/onceupon.cpp b/engines/gob/pregob/onceupon/onceupon.cpp
index 7332265..6d185d0 100644
--- a/engines/gob/pregob/onceupon/onceupon.cpp
+++ b/engines/gob/pregob/onceupon/onceupon.cpp
@@ -613,6 +613,33 @@ void OnceUpon::stopTitleMusic() {
 		_vm->_sound->sampleFree(_vm->_sound->sampleGetBySlot(i));
 }
 
+void OnceUpon::showChapter(int chapter) {
+	// Display the intro text to a chapter
+
+	fadeOut();
+	clearScreen();
+	setGamePalette(11);
+
+	// Parchment background
+	_vm->_video->drawPackedSprite("parch.cmp", *_vm->_draw->_backSurface);
+
+	static const Font *fonts[3] = { _plettre, _glettre, _plettre };
+
+	const Common::String chapterFile = getLocFile(Common::String::format("gene%d.tx", chapter));
+
+	TXTFile *gameTitle = loadTXT(chapterFile, TXTFile::kFormatStringPositionColorFont);
+	gameTitle->draw(*_vm->_draw->_backSurface, fonts, ARRAYSIZE(fonts));
+	delete gameTitle;
+
+	_vm->_draw->forceBlit();
+
+	fadeIn();
+
+	waitInput();
+
+	fadeOut();
+}
+
 } // End of namespace OnceUpon
 
 } // End of namespace Gob
diff --git a/engines/gob/pregob/onceupon/onceupon.h b/engines/gob/pregob/onceupon/onceupon.h
index 97f7e6b..96f88cb 100644
--- a/engines/gob/pregob/onceupon/onceupon.h
+++ b/engines/gob/pregob/onceupon/onceupon.h
@@ -52,6 +52,7 @@ protected:
 	void showWait();
 	void showQuote();
 	void showTitle();
+	void showChapter(int chapter);
 
 
 	Font *_jeudak;


Commit: bccfdb559fccdf3eff86cea22495a50260b3ad90
    https://github.com/scummvm/scummvm/commit/bccfdb559fccdf3eff86cea22495a50260b3ad90
Author: Sven Hesse (drmccoy at users.sourceforge.net)
Date: 2012-07-29T16:44:43-07:00

Commit Message:
GOB: Move the intro parts into OnceUpon::showIntro()

Changed paths:
    engines/gob/pregob/onceupon/abracadabra.cpp
    engines/gob/pregob/onceupon/babayaga.cpp
    engines/gob/pregob/onceupon/onceupon.cpp
    engines/gob/pregob/onceupon/onceupon.h



diff --git a/engines/gob/pregob/onceupon/abracadabra.cpp b/engines/gob/pregob/onceupon/abracadabra.cpp
index 5c1bd01..9db018c 100644
--- a/engines/gob/pregob/onceupon/abracadabra.cpp
+++ b/engines/gob/pregob/onceupon/abracadabra.cpp
@@ -62,28 +62,8 @@ void Abracadabra::run() {
 	if (_vm->shouldQuit() || !correctCP)
 		return;
 
-	// "Loading"
-	showWait();
-	if (_vm->shouldQuit())
-		return;
-
-	// Quote about fairy tales
-	showQuote();
-	if (_vm->shouldQuit())
-		return;
-
-	// Once Upon A Time title
-	showTitle();
-	if (_vm->shouldQuit())
-		return;
-
-	// Game title screen
-	showChapter(0);
-	if (_vm->shouldQuit())
-		return;
-
-	// "Loading"
-	showWait();
+	// Show the intro
+	showIntro();
 }
 
 } // End of namespace OnceUpon
diff --git a/engines/gob/pregob/onceupon/babayaga.cpp b/engines/gob/pregob/onceupon/babayaga.cpp
index 608d85e..8b80a38 100644
--- a/engines/gob/pregob/onceupon/babayaga.cpp
+++ b/engines/gob/pregob/onceupon/babayaga.cpp
@@ -62,28 +62,8 @@ void BabaYaga::run() {
 	if (_vm->shouldQuit() || !correctCP)
 		return;
 
-	// "Loading"
-	showWait();
-	if (_vm->shouldQuit())
-		return;
-
-	// Quote about fairy tales
-	showQuote();
-	if (_vm->shouldQuit())
-		return;
-
-	// Once Upon A Time title
-	showTitle();
-	if (_vm->shouldQuit())
-		return;
-
-	// Game title screen
-	showChapter(0);
-	if (_vm->shouldQuit())
-		return;
-
-	// "Loading"
-	showWait();
+	// Show the intro
+	showIntro();
 }
 
 } // End of namespace OnceUpon
diff --git a/engines/gob/pregob/onceupon/onceupon.cpp b/engines/gob/pregob/onceupon/onceupon.cpp
index 6d185d0..f2708b3 100644
--- a/engines/gob/pregob/onceupon/onceupon.cpp
+++ b/engines/gob/pregob/onceupon/onceupon.cpp
@@ -506,6 +506,33 @@ void OnceUpon::showWait() {
 	fadeIn();
 }
 
+void OnceUpon::showIntro() {
+	// Show all intro parts
+
+	// "Loading"
+	showWait();
+	if (_vm->shouldQuit())
+		return;
+
+	// Quote about fairy tales
+	showQuote();
+	if (_vm->shouldQuit())
+		return;
+
+	// Once Upon A Time title
+	showTitle();
+	if (_vm->shouldQuit())
+		return;
+
+	// Game title screen
+	showChapter(0);
+	if (_vm->shouldQuit())
+		return;
+
+	// "Loading"
+	showWait();
+}
+
 void OnceUpon::showQuote() {
 	// Show the quote about fairytales
 
diff --git a/engines/gob/pregob/onceupon/onceupon.h b/engines/gob/pregob/onceupon/onceupon.h
index 96f88cb..968c70e 100644
--- a/engines/gob/pregob/onceupon/onceupon.h
+++ b/engines/gob/pregob/onceupon/onceupon.h
@@ -49,12 +49,13 @@ protected:
 
 	bool doCopyProtection(const uint8 colors[7], const uint8 shapes[7 * 20], const uint8 obfuscate[4]);
 
-	void showWait();
-	void showQuote();
-	void showTitle();
-	void showChapter(int chapter);
+	void showWait();  ///< Show the wait / loading screen.
+	void showIntro(); ///< Show the whole intro.
 
+	void showChapter(int chapter); ///< Show a chapter intro text.
 
+
+	// Fonts
 	Font *_jeudak;
 	Font *_lettre;
 	Font *_plettre;
@@ -70,12 +71,18 @@ private:
 	int8 cpFindShape(int16 x, int16 y) const;
 	void cpWrong();
 
+	// Intro parts
+	void showQuote();
+	void showTitle();
+
+	// Title music
 	void playTitleMusic();
 	void playTitleMusicDOS();
 	void playTitleMusicAmiga();
 	void playTitleMusicAtariST();
 	void stopTitleMusic();
 
+
 	bool _openedArchives;
 };
 


Commit: 233a3f54fc3913669fd4c56a6c3a16da5aa5f5b6
    https://github.com/scummvm/scummvm/commit/233a3f54fc3913669fd4c56a6c3a16da5aa5f5b6
Author: Sven Hesse (drmccoy at users.sourceforge.net)
Date: 2012-07-29T16:44:43-07:00

Commit Message:
GOB: Stubbily implement the Once Upon A Time menus

Changed paths:
    engines/gob/pregob/onceupon/abracadabra.cpp
    engines/gob/pregob/onceupon/abracadabra.h
    engines/gob/pregob/onceupon/babayaga.cpp
    engines/gob/pregob/onceupon/babayaga.h
    engines/gob/pregob/onceupon/onceupon.cpp
    engines/gob/pregob/onceupon/onceupon.h



diff --git a/engines/gob/pregob/onceupon/abracadabra.cpp b/engines/gob/pregob/onceupon/abracadabra.cpp
index 9db018c..696e4d9 100644
--- a/engines/gob/pregob/onceupon/abracadabra.cpp
+++ b/engines/gob/pregob/onceupon/abracadabra.cpp
@@ -48,7 +48,13 @@ namespace Gob {
 
 namespace OnceUpon {
 
+const OnceUpon::MenuButton Abracadabra::kAnimalsButtons = {
+	true, 131, 127, 183, 164, 193, 0, 243, 35, 132, 128, 0
+};
+
+
 Abracadabra::Abracadabra(GobEngine *vm) : OnceUpon(vm) {
+	setAnimalsButton(&kAnimalsButtons);
 }
 
 Abracadabra::~Abracadabra() {
@@ -64,6 +70,31 @@ void Abracadabra::run() {
 
 	// Show the intro
 	showIntro();
+	if (_vm->shouldQuit())
+		return;
+
+	mainLoop();
+
+	if (!_vm->shouldQuit())
+		warning("Abracadabra::run(): TODO: Show \"Bye Bye\"");
+}
+
+void Abracadabra::mainLoop() {
+	clearScreen();
+
+	MenuType mainMenu = kMenuTypeMainStart;
+
+	while (!_vm->shouldQuit()) {
+		MenuAction action = doMenu(mainMenu);
+		if      (action == kMenuActionPlay)
+			warning("Abracadabra::mainLoop(): TODO: Play");
+		else if (action == kMenuActionRestart)
+			warning("Abracadabra::mainLoop(): TODO: Restart");
+		else if (action == kMenuActionAnimals)
+			warning("Abracadabra::mainLoop(): TODO: Animals");
+		else if (action == kMenuActionQuit)
+			break;
+	}
 }
 
 } // End of namespace OnceUpon
diff --git a/engines/gob/pregob/onceupon/abracadabra.h b/engines/gob/pregob/onceupon/abracadabra.h
index 855d2bf..64deaf4 100644
--- a/engines/gob/pregob/onceupon/abracadabra.h
+++ b/engines/gob/pregob/onceupon/abracadabra.h
@@ -35,6 +35,12 @@ public:
 	~Abracadabra();
 
 	void run();
+
+private:
+	static const MenuButton kAnimalsButtons;
+
+
+	void mainLoop();
 };
 
 } // End of namespace OnceUpon
diff --git a/engines/gob/pregob/onceupon/babayaga.cpp b/engines/gob/pregob/onceupon/babayaga.cpp
index 8b80a38..b752bb0 100644
--- a/engines/gob/pregob/onceupon/babayaga.cpp
+++ b/engines/gob/pregob/onceupon/babayaga.cpp
@@ -48,7 +48,13 @@ namespace Gob {
 
 namespace OnceUpon {
 
+const OnceUpon::MenuButton BabaYaga::kAnimalsButtons = {
+	true, 131, 127, 183, 164, 193, 0, 245, 37, 131, 127, 0
+};
+
+
 BabaYaga::BabaYaga(GobEngine *vm) : OnceUpon(vm) {
+	setAnimalsButton(&kAnimalsButtons);
 }
 
 BabaYaga::~BabaYaga() {
@@ -64,6 +70,31 @@ void BabaYaga::run() {
 
 	// Show the intro
 	showIntro();
+	if (_vm->shouldQuit())
+		return;
+
+	mainLoop();
+
+	if (!_vm->shouldQuit())
+		warning("BabaYaga::run(): TODO: Show \"Bye Bye\"");
+}
+
+void BabaYaga::mainLoop() {
+	clearScreen();
+
+	MenuType mainMenu = kMenuTypeMainStart;
+
+	while (!_vm->shouldQuit()) {
+		MenuAction action = doMenu(mainMenu);
+		if      (action == kMenuActionPlay)
+			warning("BabaYaga::mainLoop(): TODO: Play");
+		else if (action == kMenuActionRestart)
+			warning("BabaYaga::mainLoop(): TODO: Restart");
+		else if (action == kMenuActionAnimals)
+			warning("BabaYaga::mainLoop(): TODO: Animals");
+		else if (action == kMenuActionQuit)
+			break;
+	}
 }
 
 } // End of namespace OnceUpon
diff --git a/engines/gob/pregob/onceupon/babayaga.h b/engines/gob/pregob/onceupon/babayaga.h
index b3339b0..98d4524 100644
--- a/engines/gob/pregob/onceupon/babayaga.h
+++ b/engines/gob/pregob/onceupon/babayaga.h
@@ -35,6 +35,12 @@ public:
 	~BabaYaga();
 
 	void run();
+
+private:
+	static const MenuButton kAnimalsButtons;
+
+
+	void mainLoop();
 };
 
 } // End of namespace OnceUpon
diff --git a/engines/gob/pregob/onceupon/onceupon.cpp b/engines/gob/pregob/onceupon/onceupon.cpp
index f2708b3..67004d2 100644
--- a/engines/gob/pregob/onceupon/onceupon.cpp
+++ b/engines/gob/pregob/onceupon/onceupon.cpp
@@ -227,8 +227,28 @@ namespace Gob {
 
 namespace OnceUpon {
 
+const OnceUpon::MenuButton OnceUpon::kMainMenuDifficultyButton[3] = {
+	{false,  29, 18,  77, 57, 0, 0, 0, 0, 0, 0, 0},
+	{false, 133, 18, 181, 57, 0, 0, 0, 0, 0, 0, 1},
+	{false, 241, 18, 289, 57, 0, 0, 0, 0, 0, 0, 2},
+};
+
+const OnceUpon::MenuButton OnceUpon::kSectionButtons[4] = {
+	{false,  27, 121,  91, 179,   0, 0,   0,  0,   0,   0,  0},
+	{ true,  95, 121, 159, 179,   4, 1,  56, 49, 100, 126,  2},
+	{ true, 163, 121, 227, 179,  64, 1, 120, 49, 168, 126,  6},
+	{ true, 231, 121, 295, 179, 128, 1, 184, 49, 236, 126, 10}
+};
+
+const OnceUpon::MenuButton OnceUpon::kIngameButtons[3] = {
+	{true, 108, 83, 139, 116,   0,   0,  31,  34, 108,  83, 0},
+	{true, 144, 83, 175, 116,  36,   0,  67,  34, 144,  83, 1},
+	{true, 180, 83, 211, 116,  72,   0, 103,  34, 180,  83, 2}
+};
+
+
 OnceUpon::OnceUpon(GobEngine *vm) : PreGob(vm), _jeudak(0), _lettre(0), _plettre(0), _glettre(0),
-	_openedArchives(false) {
+	_openedArchives(false), _animalsButton(0) {
 
 }
 
@@ -267,6 +287,9 @@ void OnceUpon::init() {
 		      "Thanks", _vm->getLangDesc(_vm->_global->_language));
 
 	initScreen();
+
+	_difficulty = kDifficultyMAX;
+	_section    = 0;
 }
 
 void OnceUpon::deinit() {
@@ -289,6 +312,10 @@ void OnceUpon::deinit() {
 	_openedArchives = false;
 }
 
+void OnceUpon::setAnimalsButton(const MenuButton *animalsButton) {
+	_animalsButton = animalsButton;
+}
+
 void OnceUpon::setCopyProtectionPalette() {
 	setPalette(kCopyProtectionPalette, kPaletteSize);
 }
@@ -300,6 +327,14 @@ void OnceUpon::setGamePalette(uint palette) {
 	setPalette(kGamePalettes[palette], kPaletteSize);
 }
 
+void OnceUpon::setGameCursor() {
+	Surface cursor(320, 16, 1);
+
+	_vm->_video->drawPackedSprite("icon.cmp", cursor);
+
+	setCursor(cursor, 105, 0, 120, 15, 0, 0);
+}
+
 enum CopyProtectionState {
 	kCPStateSetup,     // Set up the screen
 	kCPStateWaitUser,  // Waiting for the user to pick a shape
@@ -489,12 +524,12 @@ void OnceUpon::setAnimState(ANIObject &ani, uint16 state, bool once, bool pause)
 	ani.setPosition();
 }
 
-void OnceUpon::showWait() {
+void OnceUpon::showWait(uint palette) {
 	// Show the loading floppy
 
 	fadeOut();
 	clearScreen();
-	setGamePalette(10);
+	setGamePalette(palette);
 
 	Surface wait(320, 43, 1);
 
@@ -510,7 +545,7 @@ void OnceUpon::showIntro() {
 	// Show all intro parts
 
 	// "Loading"
-	showWait();
+	showWait(10);
 	if (_vm->shouldQuit())
 		return;
 
@@ -530,7 +565,7 @@ void OnceUpon::showIntro() {
 		return;
 
 	// "Loading"
-	showWait();
+	showWait(17);
 }
 
 void OnceUpon::showQuote() {
@@ -667,6 +702,364 @@ void OnceUpon::showChapter(int chapter) {
 	fadeOut();
 }
 
+OnceUpon::MenuAction OnceUpon::doMenu(MenuType type) {
+	bool cursorVisible = isCursorVisible();
+
+	// Set the cursor
+	addCursor();
+	setGameCursor();
+
+	// Backup the screen
+	Surface screenBackup(320, 200, 1);
+	screenBackup.blit(*_vm->_draw->_backSurface);
+
+	// Handle the specific menu
+	MenuAction action;
+	if      (type == kMenuTypeMainStart)
+		action = doMenuMainStart();
+	else if (type == kMenuTypeMainIngame)
+		action = doMenuMainIngame();
+	else if (type == kMenuTypeIngame)
+		action = doMenuIngame();
+	else
+		error("OnceUpon::doMenu(): No such menu %d", type);
+
+	if (_vm->shouldQuit())
+		return action;
+
+	// The ingame menu cleans itself up in a special way
+	if (type == kMenuTypeIngame)
+		clearMenuIngame(screenBackup);
+
+	// The main menus fade out
+	if ((type == kMenuTypeMainStart) || (type == kMenuTypeMainIngame))
+		fadeOut();
+
+	// Restore the screen
+	_vm->_draw->_backSurface->blit(screenBackup);
+	_vm->_draw->forceBlit();
+
+	// Restore the cursor
+	if (!cursorVisible)
+		hideCursor();
+	removeCursor();
+
+	return action;
+}
+
+OnceUpon::MenuAction OnceUpon::doMenuMainStart() {
+	fadeOut();
+	drawMenuMainStart();
+	showCursor();
+	fadeIn();
+
+	MenuAction action = kMenuActionNone;
+	while (!_vm->shouldQuit() && (action == kMenuActionNone)) {
+		endFrame(true);
+
+		// Check user input
+
+		int16 mouseX, mouseY;
+		MouseButtons mouseButtons;
+
+		int16 key = checkInput(mouseX, mouseY, mouseButtons);
+		if (key == kKeyEscape)
+			// ESC -> Quit
+			return kMenuActionQuit;
+
+		if (mouseButtons != kMouseButtonsLeft)
+			continue;
+
+		// If we clicked on a difficulty button, show the selected difficulty and start the game
+		Difficulty difficulty = checkDifficultyButton(mouseX, mouseY);
+		if (difficulty < kDifficultyMAX) {
+			_difficulty = difficulty;
+			action      = kMenuActionPlay;
+
+			drawMenuMainStart();
+			_vm->_util->longDelay(1000);
+		}
+
+		if (checkAnimalsButton(mouseX, mouseY))
+			action = kMenuActionAnimals;
+
+	}
+
+	return action;
+}
+
+OnceUpon::MenuAction OnceUpon::doMenuMainIngame() {
+	fadeOut();
+	drawMenuMainIngame();
+	showCursor();
+	fadeIn();
+
+	MenuAction action = kMenuActionNone;
+	while (!_vm->shouldQuit() && (action == kMenuActionNone)) {
+		endFrame(true);
+
+		// Check user input
+
+		int16 mouseX, mouseY;
+		MouseButtons mouseButtons;
+
+		int16 key = checkInput(mouseX, mouseY, mouseButtons);
+		if (key == kKeyEscape)
+			// ESC -> Quit
+			return kMenuActionQuit;
+
+		if (mouseButtons != kMouseButtonsLeft)
+			continue;
+
+		// If we clicked on a difficulty button, change the current difficulty level
+		Difficulty difficulty = checkDifficultyButton(mouseX, mouseY);
+		if ((difficulty < kDifficultyMAX) && (_difficulty != difficulty)) {
+			_difficulty = difficulty;
+
+			drawMenuMainIngame();
+		}
+
+		// If we clicked on a section button, restart the game from this section
+		int8 section = checkSectionButton(mouseX, mouseY);
+		if (section >= 0) {
+			_section = section;
+			action   = kMenuActionRestart;
+		}
+
+	}
+
+	return action;
+}
+
+OnceUpon::MenuAction OnceUpon::doMenuIngame() {
+	drawMenuIngame();
+	showCursor();
+
+	MenuAction action = kMenuActionNone;
+	while (!_vm->shouldQuit() && (action == kMenuActionNone)) {
+		endFrame(true);
+
+		// Check user input
+
+		int16 mouseX, mouseY;
+		MouseButtons mouseButtons;
+
+		int16 key = checkInput(mouseX, mouseY, mouseButtons);
+		if ((key == kKeyEscape) || (mouseButtons == kMouseButtonsRight))
+			// ESC or right mouse button -> Dismiss the menu
+			action = kMenuActionPlay;
+
+		if (mouseButtons != kMouseButtonsLeft)
+			continue;
+
+		// Check if we've pressed one of the buttons
+		int8 button = checkIngameButton(mouseX, mouseY);
+		if      (button == 0)
+			action = kMenuActionQuit;
+		else if (button == 1)
+			action = kMenuActionMainMenu;
+		else if (button == 2)
+			action = kMenuActionPlay;
+
+	}
+
+	return action;
+}
+
+void OnceUpon::drawMenuMainStart() {
+	// Draw the background
+	_vm->_video->drawPackedSprite("menu2.cmp", *_vm->_draw->_backSurface);
+
+	// Draw the "Listen to animal names" button
+	if (_animalsButton) {
+		Surface elements(320, 38, 1);
+		_vm->_video->drawPackedSprite("elemenu.cmp", elements);
+		_vm->_draw->_backSurface->fillRect(_animalsButton->left , _animalsButton->top,
+		                                   _animalsButton->right, _animalsButton->bottom, 0);
+		_vm->_draw->_backSurface->blit(elements,
+		                               _animalsButton->srcLeft , _animalsButton->srcTop,
+		                               _animalsButton->srcRight, _animalsButton->srcBottom,
+		                               _animalsButton->dstX    , _animalsButton->dstY);
+	}
+
+	// Highlight the current difficulty
+	drawMenuDifficulty();
+
+	_vm->_draw->forceBlit();
+}
+
+void OnceUpon::drawMenuMainIngame() {
+	// Draw the background
+	_vm->_video->drawPackedSprite("menu.cmp", *_vm->_draw->_backSurface);
+
+	// Highlight the current difficulty
+	drawMenuDifficulty();
+
+	// Draw the section buttons
+	Surface elements(320, 200, 1);
+	_vm->_video->drawPackedSprite("elemenu.cmp", elements);
+
+	for (uint i = 0; i < ARRAYSIZE(kSectionButtons); i++) {
+		const MenuButton &button = kSectionButtons[i];
+
+		if (!button.needDraw)
+			continue;
+
+		if (_section >= (uint)button.id)
+			_vm->_draw->_backSurface->blit(elements, button.srcLeft, button.srcTop, button.srcRight, button.srcBottom,
+			                               button.dstX, button.dstY);
+	}
+
+	_vm->_draw->forceBlit();
+}
+
+void OnceUpon::drawMenuIngame() {
+	Surface menu(320, 34, 1);
+	_vm->_video->drawPackedSprite("icon.cmp", menu);
+
+	// Draw the menu in a special way
+	for (uint i = 0; i < ARRAYSIZE(kIngameButtons); i++) {
+		const MenuButton &button = kIngameButtons[i];
+
+		drawLineByLine(menu, button.srcLeft, button.srcTop, button.srcRight, button.srcBottom,
+		               button.dstX, button.dstY);
+	}
+
+	_vm->_draw->forceBlit();
+	_vm->_video->retrace();
+}
+
+void OnceUpon::drawMenuDifficulty() {
+	if (_difficulty == kDifficultyMAX)
+		return;
+
+	TXTFile *difficulties = loadTXT(getLocFile("diffic.tx"), TXTFile::kFormatStringPositionColor);
+
+	// Draw the difficulty name
+	difficulties->draw((uint) _difficulty, *_vm->_draw->_backSurface, &_plettre, 1);
+
+	// Draw a border around the current difficulty
+	_vm->_draw->_backSurface->drawRect(kMainMenuDifficultyButton[_difficulty].left,
+	                                   kMainMenuDifficultyButton[_difficulty].top,
+	                                   kMainMenuDifficultyButton[_difficulty].right,
+	                                   kMainMenuDifficultyButton[_difficulty].bottom,
+	                                   difficulties->getLines()[_difficulty].color);
+
+	delete difficulties;
+}
+
+void OnceUpon::clearMenuIngame(const Surface &background) {
+	// Find the area encompassing the whole ingame menu
+
+	int16 left   = 0x7FFF;
+	int16 top    = 0x7FFF;
+	int16 right  = 0x0000;
+	int16 bottom = 0x0000;
+
+	for (uint i = 0; i < ARRAYSIZE(kIngameButtons); i++) {
+		const MenuButton &button = kIngameButtons[i];
+
+		if (!button.needDraw)
+			continue;
+
+		left   = MIN<int16>(left  , button.dstX);
+		top    = MIN<int16>(top   , button.dstY);
+		right  = MAX<int16>(right , button.dstX + (button.srcRight  - button.srcLeft + 1) - 1);
+		bottom = MAX<int16>(bottom, button.dstY + (button.srcBottom - button.srcTop  + 1) - 1);
+	}
+
+	if ((left > right) || (top > bottom))
+		return;
+
+	// Clear it line by line
+	drawLineByLine(background, left, top, right, bottom, left, top);
+}
+
+OnceUpon::Difficulty OnceUpon::checkDifficultyButton(int16 x, int16 y) const {
+	for (uint i = 0; i < ARRAYSIZE(kMainMenuDifficultyButton); i++) {
+		const MenuButton &button = kMainMenuDifficultyButton[i];
+
+		if ((x >= button.left) && (x <= button.right) && (y >= button.top) && (y <= button.bottom))
+			return (Difficulty) button.id;
+	}
+
+	return kDifficultyMAX;
+}
+
+bool OnceUpon::checkAnimalsButton(int16 x, int16 y) const {
+	if (!_animalsButton)
+		return false;
+
+	return (x >= _animalsButton->left) && (x <= _animalsButton->right) &&
+	       (y >= _animalsButton->top)  && (y <= _animalsButton->bottom);
+}
+
+int8 OnceUpon::checkSectionButton(int16 x, int16 y) const {
+	for (uint i = 0; i < ARRAYSIZE(kSectionButtons); i++) {
+		const MenuButton &button = kSectionButtons[i];
+
+		if ((uint)button.id > _section)
+			continue;
+
+		if ((x >= button.left) && (x <= button.right) && (y >= button.top) && (y <= button.bottom))
+			return (int8)button.id;
+	}
+
+	return -1;
+}
+
+int8 OnceUpon::checkIngameButton(int16 x, int16 y) const {
+	for (uint i = 0; i < ARRAYSIZE(kIngameButtons); i++) {
+		const MenuButton &button = kIngameButtons[i];
+
+		if ((x >= button.left) && (x <= button.right) && (y >= button.top) && (y <= button.bottom))
+			return (int8)button.id;
+	}
+
+	return -1;
+}
+
+void OnceUpon::drawLineByLine(const Surface &src, int16 left, int16 top, int16 right, int16 bottom,
+                              int16 x, int16 y) const {
+
+	// A special way of drawing something:
+	// Draw every other line "downwards", wait a bit after each line
+	// Then, draw the remaining lines "upwards" and again wait a bit after each line.
+
+	if (_vm->shouldQuit())
+		return;
+
+	const int16 width  = right  - left + 1;
+	const int16 height = bottom - top  + 1;
+
+	if ((width <= 0) || (height <= 0))
+		return;
+
+	for (int16 i = 0; i < height; i += 2) {
+		if (_vm->shouldQuit())
+			return;
+
+		_vm->_draw->_backSurface->blit(src, left, top + i, right, top + i, x, y + i);
+
+		_vm->_draw->dirtiedRect(_vm->_draw->_backSurface, x, y + i, x + width - 1, y + 1);
+		_vm->_draw->blitInvalidated();
+
+		_vm->_util->longDelay(1);
+	}
+
+	for (int16 i = (height & 1) ? height : (height - 1); i >= 0; i -= 2) {
+		if (_vm->shouldQuit())
+			return;
+
+		_vm->_draw->_backSurface->blit(src, left, top + i, right, top + i, x, y + i);
+
+		_vm->_draw->dirtiedRect(_vm->_draw->_backSurface, x, y + i, x + width - 1, y + 1);
+		_vm->_draw->blitInvalidated();
+
+		_vm->_util->longDelay(1);
+	}
+}
+
 } // End of namespace OnceUpon
 
 } // End of namespace Gob
diff --git a/engines/gob/pregob/onceupon/onceupon.h b/engines/gob/pregob/onceupon/onceupon.h
index 968c70e..640e613 100644
--- a/engines/gob/pregob/onceupon/onceupon.h
+++ b/engines/gob/pregob/onceupon/onceupon.h
@@ -42,18 +42,59 @@ public:
 	~OnceUpon();
 
 protected:
+	enum MenuType {
+		kMenuTypeMainStart  = 0, ///< The big main menu at game start.
+		kMenuTypeMainIngame,     ///< The big main menu during the game.
+		kMenuTypeIngame          ///< The small popup menu during the game.
+	};
+
+	enum MenuAction {
+		kMenuActionNone = 0, ///< No action.
+		kMenuActionAnimals , ///< Do the animal names.
+		kMenuActionPlay    , ///< Play the game.
+		kMenuActionRestart , ///< Restart the section.
+		kMenuActionMainMenu, ///< Go to the main menu.
+		kMenuActionQuit      ///< Quit the game.
+	};
+
+	enum Difficulty {
+		kDifficultyBeginner     = 0,
+		kDifficultyIntermediate = 1,
+		kDifficultyAdvanced     = 2,
+		kDifficultyMAX
+	};
+
+	struct MenuButton {
+		bool needDraw;
+		int16 left, top, right, bottom;
+		int16 srcLeft, srcTop, srcRight, srcBottom;
+		int16 dstX, dstY;
+		int id;
+	};
+
+	static const uint kSectionCount = 15;
+
+
 	void init();
 	void deinit();
 
+	void setAnimalsButton(const MenuButton *animalsButton);
+
 	void setGamePalette(uint palette);
+	void setGameCursor();
 
 	bool doCopyProtection(const uint8 colors[7], const uint8 shapes[7 * 20], const uint8 obfuscate[4]);
 
-	void showWait();  ///< Show the wait / loading screen.
-	void showIntro(); ///< Show the whole intro.
+	void showWait(uint palette = 0xFFFF);  ///< Show the wait / loading screen.
+	void showIntro();                      ///< Show the whole intro.
 
 	void showChapter(int chapter); ///< Show a chapter intro text.
 
+	MenuAction doMenu(MenuType type);
+
+	void drawLineByLine(const Surface &src, int16 left, int16 top, int16 right, int16 bottom,
+	                    int16 x, int16 y) const;
+
 
 	// Fonts
 	Font *_jeudak;
@@ -61,7 +102,14 @@ protected:
 	Font *_plettre;
 	Font *_glettre;
 
+	Difficulty _difficulty;
+	uint8      _section;
+
 private:
+	static const MenuButton kMainMenuDifficultyButton[3];
+	static const MenuButton kSectionButtons[4];
+	static const MenuButton kIngameButtons[3];
+
 	void setCopyProtectionPalette();
 
 	void setAnimState(ANIObject &ani, uint16 state, bool once, bool pause) const;
@@ -82,8 +130,27 @@ private:
 	void playTitleMusicAtariST();
 	void stopTitleMusic();
 
+	// Menu helpers
+	MenuAction doMenuMainStart();
+	MenuAction doMenuMainIngame();
+	MenuAction doMenuIngame();
+
+	void drawMenuMainStart();
+	void drawMenuMainIngame();
+	void drawMenuIngame();
+	void drawMenuDifficulty();
+
+	void clearMenuIngame(const Surface &background);
+
+	Difficulty checkDifficultyButton(int16 x, int16 y) const;
+	bool       checkAnimalsButton   (int16 x, int16 y) const;
+	int8       checkSectionButton   (int16 x, int16 y) const;
+	int8       checkIngameButton    (int16 x, int16 y) const;
+
 
 	bool _openedArchives;
+
+	const MenuButton *_animalsButton;
 };
 
 } // End of namespace OnceUpon


Commit: 34cf81a4b614dee5f2657bf24d9f867165e6ced9
    https://github.com/scummvm/scummvm/commit/34cf81a4b614dee5f2657bf24d9f867165e6ced9
Author: Sven Hesse (drmccoy at users.sourceforge.net)
Date: 2012-07-29T16:44:44-07:00

Commit Message:
GOB: Add some PreGob sound utility functions

Changed paths:
    engines/gob/pregob/onceupon/onceupon.cpp
    engines/gob/pregob/onceupon/onceupon.h
    engines/gob/pregob/pregob.cpp
    engines/gob/pregob/pregob.h



diff --git a/engines/gob/pregob/onceupon/onceupon.cpp b/engines/gob/pregob/onceupon/onceupon.cpp
index 67004d2..ad6befa 100644
--- a/engines/gob/pregob/onceupon/onceupon.cpp
+++ b/engines/gob/pregob/onceupon/onceupon.cpp
@@ -246,6 +246,10 @@ const OnceUpon::MenuButton OnceUpon::kIngameButtons[3] = {
 	{true, 180, 83, 211, 116,  72,   0, 103,  34, 180,  83, 2}
 };
 
+const char *OnceUpon::kSound[kSoundMAX] = {
+	"diamant.snd"
+};
+
 
 OnceUpon::OnceUpon(GobEngine *vm) : PreGob(vm), _jeudak(0), _lettre(0), _plettre(0), _glettre(0),
 	_openedArchives(false), _animalsButton(0) {
@@ -286,6 +290,8 @@ void OnceUpon::init() {
 		      "please contact the ScummVM team with details about this version.\n"
 		      "Thanks", _vm->getLangDesc(_vm->_global->_language));
 
+	loadSounds(kSound, kSoundMAX);
+
 	initScreen();
 
 	_difficulty = kDifficultyMAX;
@@ -293,6 +299,8 @@ void OnceUpon::init() {
 }
 
 void OnceUpon::deinit() {
+	freeSounds();
+
 	delete _jeudak;
 	delete _lettre;
 	delete _plettre;
@@ -671,7 +679,7 @@ void OnceUpon::stopTitleMusic() {
 	_vm->_sound->blasterStopComposition();
 	_vm->_sound->protrackerStop();
 
-	for (int i = 0; i < Sound::kSoundsCount; i++)
+	for (int i = 0; i < ::Gob::Sound::kSoundsCount; i++)
 		_vm->_sound->sampleFree(_vm->_sound->sampleGetBySlot(i));
 }
 
diff --git a/engines/gob/pregob/onceupon/onceupon.h b/engines/gob/pregob/onceupon/onceupon.h
index 640e613..9ad5639 100644
--- a/engines/gob/pregob/onceupon/onceupon.h
+++ b/engines/gob/pregob/onceupon/onceupon.h
@@ -64,6 +64,11 @@ protected:
 		kDifficultyMAX
 	};
 
+	enum Sound {
+		kSoundClick = 0,
+		kSoundMAX
+	};
+
 	struct MenuButton {
 		bool needDraw;
 		int16 left, top, right, bottom;
@@ -110,6 +115,9 @@ private:
 	static const MenuButton kSectionButtons[4];
 	static const MenuButton kIngameButtons[3];
 
+	static const char *kSound[kSoundMAX];
+
+
 	void setCopyProtectionPalette();
 
 	void setAnimState(ANIObject &ani, uint16 state, bool once, bool pause) const;
diff --git a/engines/gob/pregob/pregob.cpp b/engines/gob/pregob/pregob.cpp
index 582ebc6..9c6cfb7 100644
--- a/engines/gob/pregob/pregob.cpp
+++ b/engines/gob/pregob/pregob.cpp
@@ -32,6 +32,8 @@
 #include "gob/video.h"
 #include "gob/aniobject.h"
 
+#include "gob/sound/sound.h"
+
 #include "gob/pregob/pregob.h"
 
 static char kLanguageSuffix[5] = { 't', 'g', 'a', 'e', 'i' };
@@ -141,6 +143,39 @@ bool PreGob::isCursorVisible() const {
 	return CursorMan.isVisible();
 }
 
+void PreGob::loadSounds(const char * const *sounds, uint soundCount) {
+	freeSounds();
+
+	_sounds.resize(soundCount);
+
+	for (uint i = 0; i < soundCount; i++) {
+		int32 size;
+		byte *data = _vm->_dataIO->getFile(sounds[i], size);
+
+		if (!data || !_sounds[i].load(SOUND_SND, data, size)) {
+			delete data;
+
+			warning("PreGob::loadSounds(): Failed to load sound \"%s\"", sounds[i]);
+			continue;
+		}
+	}
+}
+
+void PreGob::freeSounds() {
+	_sounds.clear();
+}
+
+void PreGob::playSound(uint sound, int16 frequency, int16 repCount) {
+	if (sound >= _sounds.size())
+		return;
+
+	_vm->_sound->blasterPlay(&_sounds[sound], repCount, frequency);
+}
+
+void PreGob::stopSound() {
+	_vm->_sound->blasterStop(0);
+}
+
 void PreGob::endFrame(bool doInput) {
 	_vm->_draw->blitInvalidated();
 	_vm->_util->waitEndFrame();
diff --git a/engines/gob/pregob/pregob.h b/engines/gob/pregob/pregob.h
index 902a7c4..b917588 100644
--- a/engines/gob/pregob/pregob.h
+++ b/engines/gob/pregob/pregob.h
@@ -24,9 +24,12 @@
 #define GOB_PREGOB_PREGOB_H
 
 #include "common/str.h"
+#include "common/array.h"
 
 #include "gob/util.h"
 
+#include "gob/sound/sounddesc.h"
+
 #include "gob/pregob/txtfile.h"
 
 namespace Gob {
@@ -70,6 +73,12 @@ protected:
 
 	bool isCursorVisible() const;
 
+	void loadSounds(const char * const *sounds, uint soundCount);
+	void freeSounds();
+
+	void playSound(uint sound, int16 frequency = 0, int16 repCount = 0);
+	void stopSound();
+
 	void endFrame(bool doInput);
 
 	int16 checkInput(int16 &mouseX, int16 &mouseY, MouseButtons &mouseButtons);
@@ -89,6 +98,8 @@ protected:
 
 private:
 	bool _fadedOut; ///< Did we fade out?
+
+	Common::Array<SoundDesc> _sounds;
 };
 
 } // End of namespace Gob


Commit: a98ba5f038c536a2b492b816433f4283e9d1ae26
    https://github.com/scummvm/scummvm/commit/a98ba5f038c536a2b492b816433f4283e9d1ae26
Author: Sven Hesse (drmccoy at users.sourceforge.net)
Date: 2012-07-29T16:44:44-07:00

Commit Message:
GOB: Play a click sound in the Once Upon A Time menus

Changed paths:
    engines/gob/pregob/onceupon/onceupon.cpp



diff --git a/engines/gob/pregob/onceupon/onceupon.cpp b/engines/gob/pregob/onceupon/onceupon.cpp
index ad6befa..49516a5 100644
--- a/engines/gob/pregob/onceupon/onceupon.cpp
+++ b/engines/gob/pregob/onceupon/onceupon.cpp
@@ -778,6 +778,8 @@ OnceUpon::MenuAction OnceUpon::doMenuMainStart() {
 		if (mouseButtons != kMouseButtonsLeft)
 			continue;
 
+		playSound(kSoundClick);
+
 		// If we clicked on a difficulty button, show the selected difficulty and start the game
 		Difficulty difficulty = checkDifficultyButton(mouseX, mouseY);
 		if (difficulty < kDifficultyMAX) {
@@ -819,6 +821,8 @@ OnceUpon::MenuAction OnceUpon::doMenuMainIngame() {
 		if (mouseButtons != kMouseButtonsLeft)
 			continue;
 
+		playSound(kSoundClick);
+
 		// If we clicked on a difficulty button, change the current difficulty level
 		Difficulty difficulty = checkDifficultyButton(mouseX, mouseY);
 		if ((difficulty < kDifficultyMAX) && (_difficulty != difficulty)) {


Commit: e477b7d2b996bb4a93b3d95fb5b08e01d64e3b03
    https://github.com/scummvm/scummvm/commit/e477b7d2b996bb4a93b3d95fb5b08e01d64e3b03
Author: Sven Hesse (drmccoy at users.sourceforge.net)
Date: 2012-07-29T16:44:44-07:00

Commit Message:
GOB: Move the Once Upon A Time palettes into their own file

Changed paths:
  A engines/gob/pregob/onceupon/palettes.h
    engines/gob/pregob/onceupon/onceupon.cpp



diff --git a/engines/gob/pregob/onceupon/onceupon.cpp b/engines/gob/pregob/onceupon/onceupon.cpp
index 49516a5..c304219 100644
--- a/engines/gob/pregob/onceupon/onceupon.cpp
+++ b/engines/gob/pregob/onceupon/onceupon.cpp
@@ -33,139 +33,7 @@
 #include "gob/sound/sound.h"
 
 #include "gob/pregob/onceupon/onceupon.h"
-
-static const  int kPaletteSize  = 16;
-static const uint kPaletteCount = 20;
-
-static const byte kCopyProtectionPalette[3 * kPaletteSize] = {
-	0x00, 0x00, 0x00, 0x19, 0x00, 0x19, 0x00, 0x3F, 0x00, 0x00, 0x2A, 0x2A,
-	0x2A, 0x00, 0x00, 0x2A, 0x00, 0x2A, 0x2A, 0x15, 0x00, 0x00, 0x19, 0x12,
-	0x00, 0x00, 0x00, 0x15, 0x15, 0x3F, 0x15, 0x3F, 0x15, 0x00, 0x20, 0x3F,
-	0x3F, 0x00, 0x00, 0x3F, 0x00, 0x20, 0x3F, 0x3F, 0x00, 0x3F, 0x3F, 0x3F
-};
-
-static const byte kGamePalettes[kPaletteCount][3 * kPaletteSize] = {
-	{
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x18, 0x00, 0x00, 0x3C,
-		0x1C, 0x28, 0x00, 0x10, 0x18, 0x00, 0x1C, 0x1C, 0x20, 0x14, 0x14, 0x14,
-		0x14, 0x20, 0x04, 0x00, 0x00, 0x24, 0x3C, 0x3C, 0x3C, 0x00, 0x00, 0x00,
-		0x3C, 0x2C, 0x00, 0x3C, 0x18, 0x00, 0x3C, 0x04, 0x00, 0x1C, 0x00, 0x00
-	},
-	{
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x3C, 0x3C, 0x3C, 0x14, 0x20, 0x04,
-		0x3C, 0x2C, 0x00, 0x02, 0x00, 0x18, 0x3C, 0x04, 0x00, 0x1C, 0x00, 0x00,
-		0x14, 0x20, 0x04, 0x00, 0x00, 0x24, 0x3C, 0x3C, 0x3C, 0x00, 0x00, 0x00,
-		0x3C, 0x2C, 0x00, 0x3C, 0x18, 0x00, 0x3C, 0x04, 0x00, 0x1C, 0x00, 0x00
-	},
-	{
-		0x00, 0x00, 0x00, 0x38, 0x20, 0x3C, 0x2C, 0x10, 0x30, 0x20, 0x08, 0x28,
-		0x14, 0x00, 0x1C, 0x20, 0x20, 0x38, 0x18, 0x18, 0x2C, 0x10, 0x10, 0x24,
-		0x14, 0x20, 0x04, 0x00, 0x00, 0x24, 0x3C, 0x3C, 0x3C, 0x00, 0x00, 0x00,
-		0x3C, 0x2C, 0x00, 0x3C, 0x18, 0x00, 0x3C, 0x04, 0x00, 0x1C, 0x00, 0x00
-	},
-	{
-		0x00, 0x00, 0x00, 0x3C, 0x20, 0x20, 0x24, 0x14, 0x14, 0x1C, 0x10, 0x10,
-		0x14, 0x0C, 0x0C, 0x1C, 0x1C, 0x1C, 0x18, 0x18, 0x18, 0x10, 0x10, 0x10,
-		0x14, 0x20, 0x04, 0x00, 0x00, 0x24, 0x3C, 0x3C, 0x3C, 0x00, 0x00, 0x00,
-		0x3C, 0x2C, 0x00, 0x3C, 0x18, 0x00, 0x3C, 0x04, 0x00, 0x1C, 0x00, 0x00
-	},
-	{
-		0x00, 0x00, 0x00, 0x10, 0x28, 0x1C, 0x10, 0x1C, 0x10, 0x10, 0x14, 0x0C,
-		0x1C, 0x1C, 0x3C, 0x24, 0x24, 0x3C, 0x18, 0x18, 0x24, 0x10, 0x10, 0x18,
-		0x14, 0x20, 0x04, 0x00, 0x00, 0x24, 0x3C, 0x3C, 0x3C, 0x00, 0x00, 0x00,
-		0x3C, 0x2C, 0x00, 0x3C, 0x18, 0x00, 0x3C, 0x04, 0x00, 0x1C, 0x00, 0x00
-	},
-	{
-		0x00, 0x00, 0x00, 0x3F, 0x26, 0x3F, 0x36, 0x1C, 0x36, 0x2C, 0x12, 0x2A,
-		0x27, 0x0C, 0x24, 0x22, 0x07, 0x1E, 0x1D, 0x03, 0x18, 0x16, 0x00, 0x10,
-		0x14, 0x20, 0x04, 0x00, 0x00, 0x24, 0x3C, 0x3C, 0x3A, 0x00, 0x00, 0x00,
-		0x3C, 0x2C, 0x00, 0x3C, 0x18, 0x00, 0x3C, 0x04, 0x00, 0x1C, 0x00, 0x00
-	},
-	{
-		0x00, 0x00, 0x00, 0x3F, 0x39, 0x26, 0x38, 0x34, 0x1C, 0x30, 0x2F, 0x13,
-		0x27, 0x29, 0x0C, 0x1D, 0x22, 0x07, 0x14, 0x1B, 0x03, 0x0C, 0x14, 0x00,
-		0x14, 0x20, 0x04, 0x00, 0x00, 0x24, 0x3C, 0x3C, 0x3A, 0x00, 0x00, 0x00,
-		0x3C, 0x2C, 0x00, 0x3C, 0x18, 0x00, 0x3C, 0x04, 0x00, 0x1C, 0x00, 0x00
-	},
-	{
-		0x00, 0x00, 0x00, 0x24, 0x3C, 0x3C, 0x1C, 0x34, 0x38, 0x14, 0x2C, 0x30,
-		0x0C, 0x20, 0x2C, 0x08, 0x18, 0x28, 0x04, 0x10, 0x20, 0x00, 0x08, 0x1C,
-		0x14, 0x20, 0x04, 0x00, 0x00, 0x24, 0x3C, 0x3C, 0x38, 0x00, 0x00, 0x00,
-		0x3C, 0x2C, 0x00, 0x3C, 0x18, 0x00, 0x3C, 0x04, 0x00, 0x1C, 0x00, 0x00
-	},
-	{
-		0x00, 0x00, 0x00, 0x3C, 0x2C, 0x24, 0x38, 0x24, 0x1C, 0x30, 0x1C, 0x14,
-		0x28, 0x18, 0x0C, 0x20, 0x10, 0x04, 0x1C, 0x0C, 0x00, 0x14, 0x08, 0x00,
-		0x14, 0x20, 0x04, 0x00, 0x00, 0x24, 0x3C, 0x3C, 0x38, 0x00, 0x00, 0x00,
-		0x3C, 0x2C, 0x00, 0x3C, 0x18, 0x00, 0x3C, 0x04, 0x00, 0x1C, 0x00, 0x00
-	},
-	{
-		0x00, 0x00, 0x00, 0x3C, 0x34, 0x24, 0x38, 0x2C, 0x1C, 0x30, 0x24, 0x14,
-		0x2C, 0x1C, 0x10, 0x30, 0x30, 0x3C, 0x1C, 0x1C, 0x38, 0x0C, 0x0C, 0x38,
-		0x14, 0x20, 0x04, 0x00, 0x00, 0x24, 0x3C, 0x3C, 0x3C, 0x00, 0x00, 0x00,
-		0x3C, 0x2C, 0x00, 0x3C, 0x18, 0x00, 0x3C, 0x04, 0x00, 0x1C, 0x00, 0x00
-	},
-	{
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x02, 0x03, 0x14, 0x07, 0x07, 0x1D,
-		0x0E, 0x0E, 0x25, 0x17, 0x17, 0x2E, 0x21, 0x22, 0x36, 0x2F, 0x2F, 0x3F,
-		0x3F, 0x3F, 0x3F, 0x3F, 0x3B, 0x0D, 0x3A, 0x31, 0x0A, 0x35, 0x28, 0x07,
-		0x30, 0x21, 0x04, 0x2B, 0x19, 0x02, 0x26, 0x12, 0x01, 0x16, 0x0B, 0x00
-	},
-	{
-		0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x21, 0x01, 0x00, 0x2A, 0x02, 0x00,
-		0x33, 0x03, 0x00, 0x3D, 0x06, 0x00, 0x2A, 0x19, 0x05, 0x15, 0x14, 0x14,
-		0x22, 0x1F, 0x1E, 0x2F, 0x2C, 0x28, 0x3F, 0x3C, 0x29, 0x3F, 0x38, 0x0B,
-		0x3B, 0x30, 0x0A, 0x37, 0x29, 0x08, 0x33, 0x23, 0x07, 0x2F, 0x1D, 0x06
-	},
-	{
-		0x00, 0x00, 0x00, 0x00, 0x1C, 0x38, 0x34, 0x30, 0x28, 0x2C, 0x24, 0x1C,
-		0x24, 0x18, 0x10, 0x1C, 0x10, 0x08, 0x14, 0x04, 0x04, 0x10, 0x00, 0x00,
-		0x14, 0x20, 0x04, 0x00, 0x00, 0x24, 0x3C, 0x3C, 0x38, 0x00, 0x00, 0x00,
-		0x3C, 0x2C, 0x00, 0x3C, 0x18, 0x00, 0x3C, 0x04, 0x00, 0x1C, 0x00, 0x00
-	},
-	{
-		0x00, 0x00, 0x00, 0x00, 0x1C, 0x38, 0x34, 0x30, 0x28, 0x2C, 0x24, 0x1C,
-		0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
-		0x14, 0x20, 0x04, 0x00, 0x00, 0x24, 0x3C, 0x3C, 0x38, 0x00, 0x00, 0x00,
-		0x3C, 0x2C, 0x00, 0x3C, 0x18, 0x00, 0x3C, 0x04, 0x00, 0x1C, 0x00, 0x00
-	},
-	{
-		0x00, 0x00, 0x00, 0x1A, 0x30, 0x37, 0x14, 0x28, 0x31, 0x10, 0x20, 0x2C,
-		0x0C, 0x19, 0x27, 0x08, 0x12, 0x21, 0x05, 0x0C, 0x1C, 0x03, 0x07, 0x16,
-		0x01, 0x03, 0x11, 0x00, 0x00, 0x0C, 0x3C, 0x3C, 0x3C, 0x00, 0x00, 0x00,
-		0x3C, 0x2C, 0x00, 0x3C, 0x18, 0x00, 0x3C, 0x04, 0x00, 0x1C, 0x00, 0x00
-	},
-	{
-		0x00, 0x00, 0x00, 0x34, 0x30, 0x34, 0x30, 0x24, 0x30, 0x28, 0x1C, 0x28,
-		0x24, 0x14, 0x24, 0x1C, 0x0C, 0x1C, 0x18, 0x08, 0x18, 0x14, 0x04, 0x14,
-		0x0C, 0x04, 0x0C, 0x08, 0x00, 0x08, 0x3C, 0x3C, 0x3C, 0x00, 0x00, 0x00,
-		0x3C, 0x2C, 0x00, 0x3C, 0x18, 0x00, 0x3C, 0x04, 0x00, 0x1C, 0x00, 0x00
-	},
-	{
-		0x00, 0x00, 0x00, 0x2C, 0x24, 0x0C, 0x34, 0x34, 0x28, 0x2C, 0x2C, 0x1C,
-		0x24, 0x24, 0x10, 0x1C, 0x18, 0x08, 0x14, 0x14, 0x08, 0x10, 0x10, 0x04,
-		0x0C, 0x0C, 0x04, 0x00, 0x00, 0x24, 0x3C, 0x3C, 0x38, 0x00, 0x00, 0x00,
-		0x3C, 0x2C, 0x00, 0x3C, 0x18, 0x00, 0x3C, 0x04, 0x00, 0x1C, 0x00, 0x00
-	},
-	{
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x28, 0x31, 0x10, 0x20, 0x2C,
-		0x0C, 0x19, 0x27, 0x08, 0x12, 0x21, 0x05, 0x0C, 0x1C, 0x03, 0x07, 0x16,
-		0x01, 0x03, 0x11, 0x00, 0x3C, 0x00, 0x3C, 0x3C, 0x3C, 0x00, 0x00, 0x00,
-		0x3C, 0x2C, 0x00, 0x3C, 0x18, 0x00, 0x3C, 0x04, 0x00, 0x1C, 0x00, 0x00
-	},
-	{
-		0x00, 0x00, 0x00, 0x10, 0x28, 0x1C, 0x10, 0x1C, 0x10, 0x10, 0x14, 0x0C,
-		0x1C, 0x1C, 0x3C, 0x24, 0x24, 0x3C, 0x18, 0x18, 0x24, 0x10, 0x10, 0x18,
-		0x14, 0x20, 0x04, 0x00, 0x00, 0x24, 0x3C, 0x3C, 0x3C, 0x00, 0x00, 0x00,
-		0x3C, 0x2C, 0x00, 0x3C, 0x18, 0x00, 0x3C, 0x04, 0x00, 0x1C, 0x00, 0x00
-	},
-	{
-		0x00, 0x00, 0x00, 0x10, 0x28, 0x1C, 0x10, 0x1C, 0x10, 0x10, 0x14, 0x0C,
-		0x1C, 0x1C, 0x3C, 0x24, 0x24, 0x3C, 0x18, 0x18, 0x24, 0x10, 0x10, 0x18,
-		0x14, 0x20, 0x04, 0x00, 0x00, 0x24, 0x3C, 0x3C, 0x3C, 0x00, 0x00, 0x00,
-		0x3C, 0x2C, 0x00, 0x3C, 0x18, 0x00, 0x3C, 0x04, 0x00, 0x1C, 0x00, 0x00
-	}
-};
+#include "gob/pregob/onceupon/palettes.h"
 
 static const uint kLanguageCount = 5;
 
diff --git a/engines/gob/pregob/onceupon/palettes.h b/engines/gob/pregob/onceupon/palettes.h
new file mode 100644
index 0000000..9525810
--- /dev/null
+++ b/engines/gob/pregob/onceupon/palettes.h
@@ -0,0 +1,411 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef GOB_PREGOB_ONCEUPON_PALETTES_H
+#define GOB_PREGOB_ONCEUPON_PALETTES_H
+
+static const  int kPaletteSize  = 16;
+static const uint kPaletteCount = 20;
+
+static const byte kCopyProtectionPalette[3 * kPaletteSize] = {
+	0x00, 0x00, 0x00,
+	0x19, 0x00, 0x19,
+	0x00, 0x3F, 0x00,
+	0x00, 0x2A, 0x2A,
+	0x2A, 0x00, 0x00,
+	0x2A, 0x00, 0x2A,
+	0x2A, 0x15, 0x00,
+	0x00, 0x19, 0x12,
+	0x00, 0x00, 0x00,
+	0x15, 0x15, 0x3F,
+	0x15, 0x3F, 0x15,
+	0x00, 0x20, 0x3F,
+	0x3F, 0x00, 0x00,
+	0x3F, 0x00, 0x20,
+	0x3F, 0x3F, 0x00,
+	0x3F, 0x3F, 0x3F
+};
+
+static const byte kGamePalettes[kPaletteCount][3 * kPaletteSize] = {
+	{
+		0x00, 0x00, 0x00,
+		0x00, 0x00, 0x10,
+		0x00, 0x00, 0x18,
+		0x00, 0x00, 0x3C,
+		0x1C, 0x28, 0x00,
+		0x10, 0x18, 0x00,
+		0x1C, 0x1C, 0x20,
+		0x14, 0x14, 0x14,
+		0x14, 0x20, 0x04,
+		0x00, 0x00, 0x24,
+		0x3C, 0x3C, 0x3C,
+		0x00, 0x00, 0x00,
+		0x3C, 0x2C, 0x00,
+		0x3C, 0x18, 0x00,
+		0x3C, 0x04, 0x00,
+		0x1C, 0x00, 0x00
+	},
+	{
+		0x00, 0x00, 0x00,
+		0x00, 0x00, 0x24,
+		0x3C, 0x3C, 0x3C,
+		0x14, 0x20, 0x04,
+		0x3C, 0x2C, 0x00,
+		0x02, 0x00, 0x18,
+		0x3C, 0x04, 0x00,
+		0x1C, 0x00, 0x00,
+		0x14, 0x20, 0x04,
+		0x00, 0x00, 0x24,
+		0x3C, 0x3C, 0x3C,
+		0x00, 0x00, 0x00,
+		0x3C, 0x2C, 0x00,
+		0x3C, 0x18, 0x00,
+		0x3C, 0x04, 0x00,
+		0x1C, 0x00, 0x00
+	},
+	{
+		0x00, 0x00, 0x00,
+		0x38, 0x20, 0x3C,
+		0x2C, 0x10, 0x30,
+		0x20, 0x08, 0x28,
+		0x14, 0x00, 0x1C,
+		0x20, 0x20, 0x38,
+		0x18, 0x18, 0x2C,
+		0x10, 0x10, 0x24,
+		0x14, 0x20, 0x04,
+		0x00, 0x00, 0x24,
+		0x3C, 0x3C, 0x3C,
+		0x00, 0x00, 0x00,
+		0x3C, 0x2C, 0x00,
+		0x3C, 0x18, 0x00,
+		0x3C, 0x04, 0x00,
+		0x1C, 0x00, 0x00
+	},
+	{
+		0x00, 0x00, 0x00,
+		0x3C, 0x20, 0x20,
+		0x24, 0x14, 0x14,
+		0x1C, 0x10, 0x10,
+		0x14, 0x0C, 0x0C,
+		0x1C, 0x1C, 0x1C,
+		0x18, 0x18, 0x18,
+		0x10, 0x10, 0x10,
+		0x14, 0x20, 0x04,
+		0x00, 0x00, 0x24,
+		0x3C, 0x3C, 0x3C,
+		0x00, 0x00, 0x00,
+		0x3C, 0x2C, 0x00,
+		0x3C, 0x18, 0x00,
+		0x3C, 0x04, 0x00,
+		0x1C, 0x00, 0x00
+	},
+	{
+		0x00, 0x00, 0x00,
+		0x10, 0x28, 0x1C,
+		0x10, 0x1C, 0x10,
+		0x10, 0x14, 0x0C,
+		0x1C, 0x1C, 0x3C,
+		0x24, 0x24, 0x3C,
+		0x18, 0x18, 0x24,
+		0x10, 0x10, 0x18,
+		0x14, 0x20, 0x04,
+		0x00, 0x00, 0x24,
+		0x3C, 0x3C, 0x3C,
+		0x00, 0x00, 0x00,
+		0x3C, 0x2C, 0x00,
+		0x3C, 0x18, 0x00,
+		0x3C, 0x04, 0x00,
+		0x1C, 0x00, 0x00
+	},
+	{
+		0x00, 0x00, 0x00,
+		0x3F, 0x26, 0x3F,
+		0x36, 0x1C, 0x36,
+		0x2C, 0x12, 0x2A,
+		0x27, 0x0C, 0x24,
+		0x22, 0x07, 0x1E,
+		0x1D, 0x03, 0x18,
+		0x16, 0x00, 0x10,
+		0x14, 0x20, 0x04,
+		0x00, 0x00, 0x24,
+		0x3C, 0x3C, 0x3A,
+		0x00, 0x00, 0x00,
+		0x3C, 0x2C, 0x00,
+		0x3C, 0x18, 0x00,
+		0x3C, 0x04, 0x00,
+		0x1C, 0x00, 0x00
+	},
+	{
+		0x00, 0x00, 0x00,
+		0x3F, 0x39, 0x26,
+		0x38, 0x34, 0x1C,
+		0x30, 0x2F, 0x13,
+		0x27, 0x29, 0x0C,
+		0x1D, 0x22, 0x07,
+		0x14, 0x1B, 0x03,
+		0x0C, 0x14, 0x00,
+		0x14, 0x20, 0x04,
+		0x00, 0x00, 0x24,
+		0x3C, 0x3C, 0x3A,
+		0x00, 0x00, 0x00,
+		0x3C, 0x2C, 0x00,
+		0x3C, 0x18, 0x00,
+		0x3C, 0x04, 0x00,
+		0x1C, 0x00, 0x00
+	},
+	{
+		0x00, 0x00, 0x00,
+		0x24, 0x3C, 0x3C,
+		0x1C, 0x34, 0x38,
+		0x14, 0x2C, 0x30,
+		0x0C, 0x20, 0x2C,
+		0x08, 0x18, 0x28,
+		0x04, 0x10, 0x20,
+		0x00, 0x08, 0x1C,
+		0x14, 0x20, 0x04,
+		0x00, 0x00, 0x24,
+		0x3C, 0x3C, 0x38,
+		0x00, 0x00, 0x00,
+		0x3C, 0x2C, 0x00,
+		0x3C, 0x18, 0x00,
+		0x3C, 0x04, 0x00,
+		0x1C, 0x00, 0x00
+	},
+	{
+		0x00, 0x00, 0x00,
+		0x3C, 0x2C, 0x24,
+		0x38, 0x24, 0x1C,
+		0x30, 0x1C, 0x14,
+		0x28, 0x18, 0x0C,
+		0x20, 0x10, 0x04,
+		0x1C, 0x0C, 0x00,
+		0x14, 0x08, 0x00,
+		0x14, 0x20, 0x04,
+		0x00, 0x00, 0x24,
+		0x3C, 0x3C, 0x38,
+		0x00, 0x00, 0x00,
+		0x3C, 0x2C, 0x00,
+		0x3C, 0x18, 0x00,
+		0x3C, 0x04, 0x00,
+		0x1C, 0x00, 0x00
+	},
+	{
+		0x00, 0x00, 0x00,
+		0x3C, 0x34, 0x24,
+		0x38, 0x2C, 0x1C,
+		0x30, 0x24, 0x14,
+		0x2C, 0x1C, 0x10,
+		0x30, 0x30, 0x3C,
+		0x1C, 0x1C, 0x38,
+		0x0C, 0x0C, 0x38,
+		0x14, 0x20, 0x04,
+		0x00, 0x00, 0x24,
+		0x3C, 0x3C, 0x3C,
+		0x00, 0x00, 0x00,
+		0x3C, 0x2C, 0x00,
+		0x3C, 0x18, 0x00,
+		0x3C, 0x04, 0x00,
+		0x1C, 0x00, 0x00
+	},
+	{
+		0x00, 0x00, 0x00,
+		0x00, 0x00, 0x0C,
+		0x02, 0x03, 0x14,
+		0x07, 0x07, 0x1D,
+		0x0E, 0x0E, 0x25,
+		0x17, 0x17, 0x2E,
+		0x21, 0x22, 0x36,
+		0x2F, 0x2F, 0x3F,
+		0x3F, 0x3F, 0x3F,
+		0x3F, 0x3B, 0x0D,
+		0x3A, 0x31, 0x0A,
+		0x35, 0x28, 0x07,
+		0x30, 0x21, 0x04,
+		0x2B, 0x19, 0x02,
+		0x26, 0x12, 0x01,
+		0x16, 0x0B, 0x00
+	},
+	{
+		0x00, 0x00, 0x00,
+		0x18, 0x00, 0x00,
+		0x21, 0x01, 0x00,
+		0x2A, 0x02, 0x00,
+		0x33, 0x03, 0x00,
+		0x3D, 0x06, 0x00,
+		0x2A, 0x19, 0x05,
+		0x15, 0x14, 0x14,
+		0x22, 0x1F, 0x1E,
+		0x2F, 0x2C, 0x28,
+		0x3F, 0x3C, 0x29,
+		0x3F, 0x38, 0x0B,
+		0x3B, 0x30, 0x0A,
+		0x37, 0x29, 0x08,
+		0x33, 0x23, 0x07,
+		0x2F, 0x1D, 0x06
+	},
+	{
+		0x00, 0x00, 0x00,
+		0x00, 0x1C, 0x38,
+		0x34, 0x30, 0x28,
+		0x2C, 0x24, 0x1C,
+		0x24, 0x18, 0x10,
+		0x1C, 0x10, 0x08,
+		0x14, 0x04, 0x04,
+		0x10, 0x00, 0x00,
+		0x14, 0x20, 0x04,
+		0x00, 0x00, 0x24,
+		0x3C, 0x3C, 0x38,
+		0x00, 0x00, 0x00,
+		0x3C, 0x2C, 0x00,
+		0x3C, 0x18, 0x00,
+		0x3C, 0x04, 0x00,
+		0x1C, 0x00, 0x00
+	},
+	{
+		0x00, 0x00, 0x00,
+		0x00, 0x1C, 0x38,
+		0x34, 0x30, 0x28,
+		0x2C, 0x24, 0x1C,
+		0x3F, 0x3F, 0x3F,
+		0x3F, 0x3F, 0x3F,
+		0x3F, 0x3F, 0x3F,
+		0x3F, 0x3F, 0x3F,
+		0x14, 0x20, 0x04,
+		0x00, 0x00, 0x24,
+		0x3C, 0x3C, 0x38,
+		0x00, 0x00, 0x00,
+		0x3C, 0x2C, 0x00,
+		0x3C, 0x18, 0x00,
+		0x3C, 0x04, 0x00,
+		0x1C, 0x00, 0x00
+	},
+	{
+		0x00, 0x00, 0x00,
+		0x1A, 0x30, 0x37,
+		0x14, 0x28, 0x31,
+		0x10, 0x20, 0x2C,
+		0x0C, 0x19, 0x27,
+		0x08, 0x12, 0x21,
+		0x05, 0x0C, 0x1C,
+		0x03, 0x07, 0x16,
+		0x01, 0x03, 0x11,
+		0x00, 0x00, 0x0C,
+		0x3C, 0x3C, 0x3C,
+		0x00, 0x00, 0x00,
+		0x3C, 0x2C, 0x00,
+		0x3C, 0x18, 0x00,
+		0x3C, 0x04, 0x00,
+		0x1C, 0x00, 0x00
+	},
+	{
+		0x00, 0x00, 0x00,
+		0x34, 0x30, 0x34,
+		0x30, 0x24, 0x30,
+		0x28, 0x1C, 0x28,
+		0x24, 0x14, 0x24,
+		0x1C, 0x0C, 0x1C,
+		0x18, 0x08, 0x18,
+		0x14, 0x04, 0x14,
+		0x0C, 0x04, 0x0C,
+		0x08, 0x00, 0x08,
+		0x3C, 0x3C, 0x3C,
+		0x00, 0x00, 0x00,
+		0x3C, 0x2C, 0x00,
+		0x3C, 0x18, 0x00,
+		0x3C, 0x04, 0x00,
+		0x1C, 0x00, 0x00
+	},
+	{
+		0x00, 0x00, 0x00,
+		0x2C, 0x24, 0x0C,
+		0x34, 0x34, 0x28,
+		0x2C, 0x2C, 0x1C,
+		0x24, 0x24, 0x10,
+		0x1C, 0x18, 0x08,
+		0x14, 0x14, 0x08,
+		0x10, 0x10, 0x04,
+		0x0C, 0x0C, 0x04,
+		0x00, 0x00, 0x24,
+		0x3C, 0x3C, 0x38,
+		0x00, 0x00, 0x00,
+		0x3C, 0x2C, 0x00,
+		0x3C, 0x18, 0x00,
+		0x3C, 0x04, 0x00,
+		0x1C, 0x00, 0x00
+	},
+	{
+		0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00,
+		0x14, 0x28, 0x31,
+		0x10, 0x20, 0x2C,
+		0x0C, 0x19, 0x27,
+		0x08, 0x12, 0x21,
+		0x05, 0x0C, 0x1C,
+		0x03, 0x07, 0x16,
+		0x01, 0x03, 0x11,
+		0x00, 0x3C, 0x00,
+		0x3C, 0x3C, 0x3C,
+		0x00, 0x00, 0x00,
+		0x3C, 0x2C, 0x00,
+		0x3C, 0x18, 0x00,
+		0x3C, 0x04, 0x00,
+		0x1C, 0x00, 0x00
+	},
+	{
+		0x00, 0x00, 0x00,
+		0x10, 0x28, 0x1C,
+		0x10, 0x1C, 0x10,
+		0x10, 0x14, 0x0C,
+		0x1C, 0x1C, 0x3C,
+		0x24, 0x24, 0x3C,
+		0x18, 0x18, 0x24,
+		0x10, 0x10, 0x18,
+		0x14, 0x20, 0x04,
+		0x00, 0x00, 0x24,
+		0x3C, 0x3C, 0x3C,
+		0x00, 0x00, 0x00,
+		0x3C, 0x2C, 0x00,
+		0x3C, 0x18, 0x00,
+		0x3C, 0x04, 0x00,
+		0x1C, 0x00, 0x00
+	},
+	{
+		0x00, 0x00, 0x00,
+		0x10, 0x28, 0x1C,
+		0x10, 0x1C, 0x10,
+		0x10, 0x14, 0x0C,
+		0x1C, 0x1C, 0x3C,
+		0x24, 0x24, 0x3C,
+		0x18, 0x18, 0x24,
+		0x10, 0x10, 0x18,
+		0x14, 0x20, 0x04,
+		0x00, 0x00, 0x24,
+		0x3C, 0x3C, 0x3C,
+		0x00, 0x00, 0x00,
+		0x3C, 0x2C, 0x00,
+		0x3C, 0x18, 0x00,
+		0x3C, 0x04, 0x00,
+		0x1C, 0x00, 0x00
+	}
+};
+
+#endif // GOB_PREGOB_ONCEUPON_PALETTES_H


Commit: 4663ab2373ac3230ccb95cc2accee87ddd1682b8
    https://github.com/scummvm/scummvm/commit/4663ab2373ac3230ccb95cc2accee87ddd1682b8
Author: Sven Hesse (drmccoy at users.sourceforge.net)
Date: 2012-07-29T16:44:44-07:00

Commit Message:
GOB: Fix some broken German text in Once Upon A Time

Changed paths:
  A engines/gob/pregob/onceupon/brokenstrings.h
    engines/gob/pregob/onceupon/onceupon.cpp
    engines/gob/pregob/onceupon/onceupon.h
    engines/gob/pregob/pregob.cpp
    engines/gob/pregob/pregob.h



diff --git a/engines/gob/pregob/onceupon/brokenstrings.h b/engines/gob/pregob/onceupon/brokenstrings.h
new file mode 100644
index 0000000..86c0603
--- /dev/null
+++ b/engines/gob/pregob/onceupon/brokenstrings.h
@@ -0,0 +1,51 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef GOB_PREGOB_ONCEUPON_BROKENSTRINGS_H
+#define GOB_PREGOB_ONCEUPON_BROKENSTRINGS_H
+
+struct BrokenString {
+	const char *wrong;
+	const char *correct;
+};
+
+struct BrokenStringLanguage {
+	const BrokenString *strings;
+	uint count;
+};
+
+static const BrokenString kBrokenStringsGerman[] = {
+	{ "Zeichungen von Kaki,"         , "Zeichnungen von Kaki,"        },
+	{ "die es in seine Wachtr\204ume", "die es in seine Tagtr\204ume" },
+	{ "   Spielerfahrung"            , "    Spielerfahren"            },
+	{ "  Fortgeschrittene"           , "  Fortgeschritten"            }
+};
+
+static const BrokenStringLanguage kBrokenStrings[kLanguageCount] = {
+	{                    0,                               0 }, // French
+	{ kBrokenStringsGerman, ARRAYSIZE(kBrokenStringsGerman) }, // German
+	{                    0,                               0 }, // English
+	{                    0,                               0 }, // Spanish
+	{                    0,                               0 }, // Italian
+};
+
+#endif // GOB_PREGOB_ONCEUPON_BROKENSTRINGS_H
diff --git a/engines/gob/pregob/onceupon/onceupon.cpp b/engines/gob/pregob/onceupon/onceupon.cpp
index c304219..c20ca2a 100644
--- a/engines/gob/pregob/onceupon/onceupon.cpp
+++ b/engines/gob/pregob/onceupon/onceupon.cpp
@@ -211,6 +211,24 @@ void OnceUpon::setGameCursor() {
 	setCursor(cursor, 105, 0, 120, 15, 0, 0);
 }
 
+void OnceUpon::fixTXTStrings(TXTFile &txt) const {
+	TXTFile::LineArray &lines = txt.getLines();
+	for (uint i = 0; i < lines.size(); i++)
+		lines[i].text = fixString(lines[i].text);
+}
+
+#include "gob/pregob/onceupon/brokenstrings.h"
+Common::String OnceUpon::fixString(const Common::String &str) const {
+	const BrokenStringLanguage &broken = kBrokenStrings[_vm->_global->_language];
+
+	for (uint i = 0; i < broken.count; i++) {
+		if (str == broken.strings[i].wrong)
+			return broken.strings[i].correct;
+	}
+
+	return str;
+}
+
 enum CopyProtectionState {
 	kCPStateSetup,     // Set up the screen
 	kCPStateWaitUser,  // Waiting for the user to pick a shape
diff --git a/engines/gob/pregob/onceupon/onceupon.h b/engines/gob/pregob/onceupon/onceupon.h
index 9ad5639..efc2710 100644
--- a/engines/gob/pregob/onceupon/onceupon.h
+++ b/engines/gob/pregob/onceupon/onceupon.h
@@ -88,6 +88,9 @@ protected:
 	void setGamePalette(uint palette);
 	void setGameCursor();
 
+	Common::String fixString(const Common::String &str) const;
+	void fixTXTStrings(TXTFile &txt) const;
+
 	bool doCopyProtection(const uint8 colors[7], const uint8 shapes[7 * 20], const uint8 obfuscate[4]);
 
 	void showWait(uint palette = 0xFFFF);  ///< Show the wait / loading screen.
diff --git a/engines/gob/pregob/pregob.cpp b/engines/gob/pregob/pregob.cpp
index 9c6cfb7..f94f990 100644
--- a/engines/gob/pregob/pregob.cpp
+++ b/engines/gob/pregob/pregob.cpp
@@ -256,7 +256,12 @@ TXTFile *PreGob::loadTXT(const Common::String &txtFile, TXTFile::Format format)
 
 	delete txtStream;
 
+	fixTXTStrings(*txt);
+
 	return txt;
 }
 
+void PreGob::fixTXTStrings(TXTFile &txt) const {
+}
+
 } // End of namespace Gob
diff --git a/engines/gob/pregob/pregob.h b/engines/gob/pregob/pregob.h
index b917588..0a40ed6 100644
--- a/engines/gob/pregob/pregob.h
+++ b/engines/gob/pregob/pregob.h
@@ -93,6 +93,8 @@ protected:
 	Common::String getLocFile(const Common::String &file) const;
 	TXTFile *loadTXT(const Common::String &txtFile, TXTFile::Format format) const;
 
+	virtual void fixTXTStrings(TXTFile &txt) const;
+
 
 	GobEngine *_vm;
 


Commit: 9e997fea1be0c3f7cd8af7ee0f145879d5c49882
    https://github.com/scummvm/scummvm/commit/9e997fea1be0c3f7cd8af7ee0f145879d5c49882
Author: Sven Hesse (drmccoy at users.sourceforge.net)
Date: 2012-07-29T16:44:44-07:00

Commit Message:
GOB: Add "long" PreGob language suffixes

Changed paths:
    engines/gob/pregob/pregob.cpp
    engines/gob/pregob/pregob.h



diff --git a/engines/gob/pregob/pregob.cpp b/engines/gob/pregob/pregob.cpp
index f94f990..f39a7a1 100644
--- a/engines/gob/pregob/pregob.cpp
+++ b/engines/gob/pregob/pregob.cpp
@@ -36,10 +36,13 @@
 
 #include "gob/pregob/pregob.h"
 
-static char kLanguageSuffix[5] = { 't', 'g', 'a', 'e', 'i' };
 
 namespace Gob {
 
+const char  PreGob::kLanguageSuffixShort[5] = { 't',  'g',  'a',  'e',  'i'};
+const char *PreGob::kLanguageSuffixLong [5] = {"fr", "al", "an", "it", "es"};
+
+
 PreGob::PreGob(GobEngine *vm) : _vm(vm), _fadedOut(false) {
 }
 
@@ -241,10 +244,10 @@ void PreGob::redrawAnim(ANIObject &ani) {
 }
 
 Common::String PreGob::getLocFile(const Common::String &file) const {
-	if (_vm->_global->_language >= ARRAYSIZE(kLanguageSuffix))
+	if (_vm->_global->_language >= ARRAYSIZE(kLanguageSuffixShort))
 		return file;
 
-	return file + kLanguageSuffix[_vm->_global->_language];
+	return file + kLanguageSuffixShort[_vm->_global->_language];
 }
 
 TXTFile *PreGob::loadTXT(const Common::String &txtFile, TXTFile::Format format) const {
diff --git a/engines/gob/pregob/pregob.h b/engines/gob/pregob/pregob.h
index 0a40ed6..477aec6 100644
--- a/engines/gob/pregob/pregob.h
+++ b/engines/gob/pregob/pregob.h
@@ -47,6 +47,10 @@ public:
 	virtual void run() = 0;
 
 protected:
+	static const char  kLanguageSuffixShort[5];
+	static const char *kLanguageSuffixLong [5];
+
+
 	void initScreen(); ///< Initialize the game screen.
 
 	void fadeOut(); ///< Fade to black.


Commit: 9d564ecd268781d8b92ca7a5895aa10aea6b4e52
    https://github.com/scummvm/scummvm/commit/9d564ecd268781d8b92ca7a5895aa10aea6b4e52
Author: Sven Hesse (drmccoy at users.sourceforge.net)
Date: 2012-07-29T16:44:44-07:00

Commit Message:
GOB: Implement the animal names bit Once Upon A Time

Changed paths:
    engines/gob/pregob/onceupon/abracadabra.cpp
    engines/gob/pregob/onceupon/abracadabra.h
    engines/gob/pregob/onceupon/babayaga.cpp
    engines/gob/pregob/onceupon/babayaga.h
    engines/gob/pregob/onceupon/brokenstrings.h
    engines/gob/pregob/onceupon/onceupon.cpp
    engines/gob/pregob/onceupon/onceupon.h
    engines/gob/pregob/pregob.cpp
    engines/gob/pregob/pregob.h



diff --git a/engines/gob/pregob/onceupon/abracadabra.cpp b/engines/gob/pregob/onceupon/abracadabra.cpp
index 696e4d9..781d683 100644
--- a/engines/gob/pregob/onceupon/abracadabra.cpp
+++ b/engines/gob/pregob/onceupon/abracadabra.cpp
@@ -52,6 +52,32 @@ const OnceUpon::MenuButton Abracadabra::kAnimalsButtons = {
 	true, 131, 127, 183, 164, 193, 0, 243, 35, 132, 128, 0
 };
 
+const OnceUpon::MenuButton Abracadabra::kAnimalButtons[] = {
+	{false,  37,  89,  95, 127,  37,  89,  95, 127, 131, 25, 0},
+	{false, 114,  65, 172, 111, 114,  65, 172, 111, 131, 25, 1},
+	{false, 186,  72, 227,  96, 186,  72, 227,  96, 139, 25, 2},
+	{false, 249,  87, 282, 112, 249,  87, 282, 112, 143, 25, 3},
+	{false, 180, 102, 234, 138, 180, 102, 234, 138, 133, 25, 4},
+	{false, 197, 145, 242, 173, 197, 145, 242, 173, 137, 25, 5},
+	{false, 113, 151, 171, 176, 113, 151, 171, 176, 131, 25, 6},
+	{false, 114, 122, 151, 150, 114, 122, 151, 150, 141, 25, 7},
+	{false,  36, 136,  94, 176,  36, 136,  94, 176, 131, 25, 8},
+	{false, 243, 123, 295, 155, 243, 123, 295, 155, 136, 25, 9}
+};
+
+const char *Abracadabra::kAnimalNames[] = {
+	"loup",
+	"drag",
+	"arai",
+	"crap",
+	"crab",
+	"mous",
+	"saut",
+	"guep",
+	"rhin",
+	"scor"
+};
+
 
 Abracadabra::Abracadabra(GobEngine *vm) : OnceUpon(vm) {
 	setAnimalsButton(&kAnimalsButtons);
@@ -91,7 +117,7 @@ void Abracadabra::mainLoop() {
 		else if (action == kMenuActionRestart)
 			warning("Abracadabra::mainLoop(): TODO: Restart");
 		else if (action == kMenuActionAnimals)
-			warning("Abracadabra::mainLoop(): TODO: Animals");
+			doAnimalNames(ARRAYSIZE(kAnimalButtons), kAnimalButtons, kAnimalNames);
 		else if (action == kMenuActionQuit)
 			break;
 	}
diff --git a/engines/gob/pregob/onceupon/abracadabra.h b/engines/gob/pregob/onceupon/abracadabra.h
index 64deaf4..5f3a1ba 100644
--- a/engines/gob/pregob/onceupon/abracadabra.h
+++ b/engines/gob/pregob/onceupon/abracadabra.h
@@ -39,6 +39,9 @@ public:
 private:
 	static const MenuButton kAnimalsButtons;
 
+	static const MenuButton kAnimalButtons[];
+	static const char *kAnimalNames[];
+
 
 	void mainLoop();
 };
diff --git a/engines/gob/pregob/onceupon/babayaga.cpp b/engines/gob/pregob/onceupon/babayaga.cpp
index b752bb0..34f6741 100644
--- a/engines/gob/pregob/onceupon/babayaga.cpp
+++ b/engines/gob/pregob/onceupon/babayaga.cpp
@@ -52,6 +52,32 @@ const OnceUpon::MenuButton BabaYaga::kAnimalsButtons = {
 	true, 131, 127, 183, 164, 193, 0, 245, 37, 131, 127, 0
 };
 
+const OnceUpon::MenuButton BabaYaga::kAnimalButtons[] = {
+	{false,  34,  84,  92, 127,  34,  84,  92, 127, 131, 25, 0},
+	{false, 114,  65, 172, 111, 114,  65, 172, 111, 131, 25, 1},
+	{false, 186,  72, 227,  96, 186,  72, 227,  96, 139, 25, 2},
+	{false, 249,  87, 282, 112, 249,  87, 282, 112, 143, 25, 3},
+	{false, 180,  97, 234, 138, 180,  97, 234, 138, 133, 25, 4},
+	{false, 197, 145, 242, 173, 197, 145, 242, 173, 137, 25, 5},
+	{false, 113, 156, 171, 176, 113, 156, 171, 176, 131, 25, 6},
+	{false, 114, 127, 151, 150, 114, 127, 151, 150, 141, 25, 7},
+	{false,  36, 136,  94, 176,  36, 136,  94, 176, 131, 25, 8},
+	{false, 245, 123, 293, 155, 245, 123, 293, 155, 136, 25, 9}
+};
+
+const char *BabaYaga::kAnimalNames[] = {
+	"vaut",
+	"drag",
+	"arai",
+	"gren",
+	"fauc",
+	"abei",
+	"serp",
+	"tort",
+	"sang",
+	"rena"
+};
+
 
 BabaYaga::BabaYaga(GobEngine *vm) : OnceUpon(vm) {
 	setAnimalsButton(&kAnimalsButtons);
@@ -91,7 +117,7 @@ void BabaYaga::mainLoop() {
 		else if (action == kMenuActionRestart)
 			warning("BabaYaga::mainLoop(): TODO: Restart");
 		else if (action == kMenuActionAnimals)
-			warning("BabaYaga::mainLoop(): TODO: Animals");
+			doAnimalNames(ARRAYSIZE(kAnimalButtons), kAnimalButtons, kAnimalNames);
 		else if (action == kMenuActionQuit)
 			break;
 	}
diff --git a/engines/gob/pregob/onceupon/babayaga.h b/engines/gob/pregob/onceupon/babayaga.h
index 98d4524..de42f8e 100644
--- a/engines/gob/pregob/onceupon/babayaga.h
+++ b/engines/gob/pregob/onceupon/babayaga.h
@@ -39,6 +39,9 @@ public:
 private:
 	static const MenuButton kAnimalsButtons;
 
+	static const MenuButton kAnimalButtons[];
+	static const char *kAnimalNames[];
+
 
 	void mainLoop();
 };
diff --git a/engines/gob/pregob/onceupon/brokenstrings.h b/engines/gob/pregob/onceupon/brokenstrings.h
index 86c0603..98dcb72 100644
--- a/engines/gob/pregob/onceupon/brokenstrings.h
+++ b/engines/gob/pregob/onceupon/brokenstrings.h
@@ -37,7 +37,10 @@ static const BrokenString kBrokenStringsGerman[] = {
 	{ "Zeichungen von Kaki,"         , "Zeichnungen von Kaki,"        },
 	{ "die es in seine Wachtr\204ume", "die es in seine Tagtr\204ume" },
 	{ "   Spielerfahrung"            , "    Spielerfahren"            },
-	{ "  Fortgeschrittene"           , "  Fortgeschritten"            }
+	{ "  Fortgeschrittene"           , "  Fortgeschritten"            },
+	{ "die Vespe"                    , "die Wespe"                    },
+	{ "das Rhinoceros"               , "das Rhinozeros"               },
+	{ "die Heusschrecke"             , "die Heuschrecke"              }
 };
 
 static const BrokenStringLanguage kBrokenStrings[kLanguageCount] = {
diff --git a/engines/gob/pregob/onceupon/onceupon.cpp b/engines/gob/pregob/onceupon/onceupon.cpp
index c20ca2a..b7bf2c3 100644
--- a/engines/gob/pregob/onceupon/onceupon.cpp
+++ b/engines/gob/pregob/onceupon/onceupon.cpp
@@ -39,7 +39,7 @@ static const uint kLanguageCount = 5;
 
 static const uint kCopyProtectionHelpStringCount = 3;
 
-static const char *kCopyProtectionHelpStrings[kLanguageCount][kCopyProtectionHelpStringCount] = {
+static const char *kCopyProtectionHelpStrings[Gob::OnceUpon::OnceUpon::kLanguageCount][kCopyProtectionHelpStringCount] = {
 	{ // French
 		"Consulte le livret des animaux, rep\212re la",
 		"page correspondant \205 la couleur de l\'\202cran",
@@ -67,7 +67,7 @@ static const char *kCopyProtectionHelpStrings[kLanguageCount][kCopyProtectionHel
 	}
 };
 
-static const char *kCopyProtectionWrongStrings[kLanguageCount] = {
+static const char *kCopyProtectionWrongStrings[Gob::OnceUpon::OnceUpon::kLanguageCount] = {
 	"Tu t\'es tromp\202, dommage...", // French
 	"Schade, du hast dich geirrt."  , // German
 	"You are wrong, what a pity!"   , // English
@@ -95,25 +95,38 @@ namespace Gob {
 
 namespace OnceUpon {
 
-const OnceUpon::MenuButton OnceUpon::kMainMenuDifficultyButton[3] = {
-	{false,  29, 18,  77, 57, 0, 0, 0, 0, 0, 0, 0},
-	{false, 133, 18, 181, 57, 0, 0, 0, 0, 0, 0, 1},
-	{false, 241, 18, 289, 57, 0, 0, 0, 0, 0, 0, 2},
+const OnceUpon::MenuButton OnceUpon::kMainMenuDifficultyButton[] = {
+	{false,  29, 18,  77, 57, 0, 0, 0, 0, 0, 0, (int)kDifficultyBeginner},
+	{false, 133, 18, 181, 57, 0, 0, 0, 0, 0, 0, (int)kDifficultyIntermediate},
+	{false, 241, 18, 289, 57, 0, 0, 0, 0, 0, 0, (int)kDifficultyAdvanced},
 };
 
-const OnceUpon::MenuButton OnceUpon::kSectionButtons[4] = {
+const OnceUpon::MenuButton OnceUpon::kSectionButtons[] = {
 	{false,  27, 121,  91, 179,   0, 0,   0,  0,   0,   0,  0},
 	{ true,  95, 121, 159, 179,   4, 1,  56, 49, 100, 126,  2},
 	{ true, 163, 121, 227, 179,  64, 1, 120, 49, 168, 126,  6},
 	{ true, 231, 121, 295, 179, 128, 1, 184, 49, 236, 126, 10}
 };
 
-const OnceUpon::MenuButton OnceUpon::kIngameButtons[3] = {
+const OnceUpon::MenuButton OnceUpon::kIngameButtons[] = {
 	{true, 108, 83, 139, 116,   0,   0,  31,  34, 108,  83, 0},
 	{true, 144, 83, 175, 116,  36,   0,  67,  34, 144,  83, 1},
 	{true, 180, 83, 211, 116,  72,   0, 103,  34, 180,  83, 2}
 };
 
+const OnceUpon::MenuButton OnceUpon::kAnimalNamesBack = {
+	true, 19, 13, 50, 46, 36, 0, 67, 34, 19, 13, 1
+};
+
+const OnceUpon::MenuButton OnceUpon::kLanguageButtons[] = {
+	{true,  43,  80,  93, 115,   0, 55,  50, 90,  43,  80, 0},
+	{true, 132,  80, 182, 115,  53, 55, 103, 90, 132,  80, 1},
+	{true, 234,  80, 284, 115, 106, 55, 156, 90, 234,  80, 2},
+	{true,  43, 138,  93, 173, 159, 55, 209, 90,  43, 138, 3},
+	{true, 132, 138, 182, 173, 212, 55, 262, 90, 132, 138, 4},
+	{true, 234, 138, 284, 173, 265, 55, 315, 90, 234, 138, 2}
+};
+
 const char *OnceUpon::kSound[kSoundMAX] = {
 	"diamant.snd"
 };
@@ -643,6 +656,7 @@ OnceUpon::MenuAction OnceUpon::doMenu(MenuType type) {
 
 OnceUpon::MenuAction OnceUpon::doMenuMainStart() {
 	fadeOut();
+	setGamePalette(17);
 	drawMenuMainStart();
 	showCursor();
 	fadeIn();
@@ -667,16 +681,16 @@ OnceUpon::MenuAction OnceUpon::doMenuMainStart() {
 		playSound(kSoundClick);
 
 		// If we clicked on a difficulty button, show the selected difficulty and start the game
-		Difficulty difficulty = checkDifficultyButton(mouseX, mouseY);
-		if (difficulty < kDifficultyMAX) {
-			_difficulty = difficulty;
+		int diff = checkButton(kMainMenuDifficultyButton, ARRAYSIZE(kMainMenuDifficultyButton), mouseX, mouseY);
+		if (diff >= 0) {
+			_difficulty = (Difficulty)diff;
 			action      = kMenuActionPlay;
 
 			drawMenuMainStart();
 			_vm->_util->longDelay(1000);
 		}
 
-		if (checkAnimalsButton(mouseX, mouseY))
+		if (_animalsButton && (checkButton(_animalsButton, 1, mouseX, mouseY) != -1))
 			action = kMenuActionAnimals;
 
 	}
@@ -686,6 +700,7 @@ OnceUpon::MenuAction OnceUpon::doMenuMainStart() {
 
 OnceUpon::MenuAction OnceUpon::doMenuMainIngame() {
 	fadeOut();
+	setGamePalette(17);
 	drawMenuMainIngame();
 	showCursor();
 	fadeIn();
@@ -710,16 +725,16 @@ OnceUpon::MenuAction OnceUpon::doMenuMainIngame() {
 		playSound(kSoundClick);
 
 		// If we clicked on a difficulty button, change the current difficulty level
-		Difficulty difficulty = checkDifficultyButton(mouseX, mouseY);
-		if ((difficulty < kDifficultyMAX) && (_difficulty != difficulty)) {
-			_difficulty = difficulty;
+		int diff = checkButton(kMainMenuDifficultyButton, ARRAYSIZE(kMainMenuDifficultyButton), mouseX, mouseY);
+		if ((diff >= 0) && (diff != (int)_difficulty)) {
+			_difficulty = (Difficulty)diff;
 
 			drawMenuMainIngame();
 		}
 
 		// If we clicked on a section button, restart the game from this section
-		int8 section = checkSectionButton(mouseX, mouseY);
-		if (section >= 0) {
+		int section = checkButton(kSectionButtons, ARRAYSIZE(kSectionButtons), mouseX, mouseY);
+		if ((section >= 0) && (section <= _section)) {
 			_section = section;
 			action   = kMenuActionRestart;
 		}
@@ -750,8 +765,7 @@ OnceUpon::MenuAction OnceUpon::doMenuIngame() {
 		if (mouseButtons != kMouseButtonsLeft)
 			continue;
 
-		// Check if we've pressed one of the buttons
-		int8 button = checkIngameButton(mouseX, mouseY);
+		int button = checkButton(kIngameButtons, ARRAYSIZE(kIngameButtons), mouseX, mouseY);
 		if      (button == 0)
 			action = kMenuActionQuit;
 		else if (button == 1)
@@ -774,10 +788,7 @@ void OnceUpon::drawMenuMainStart() {
 		_vm->_video->drawPackedSprite("elemenu.cmp", elements);
 		_vm->_draw->_backSurface->fillRect(_animalsButton->left , _animalsButton->top,
 		                                   _animalsButton->right, _animalsButton->bottom, 0);
-		_vm->_draw->_backSurface->blit(elements,
-		                               _animalsButton->srcLeft , _animalsButton->srcTop,
-		                               _animalsButton->srcRight, _animalsButton->srcBottom,
-		                               _animalsButton->dstX    , _animalsButton->dstY);
+		drawButton(*_vm->_draw->_backSurface, elements, *_animalsButton);
 	}
 
 	// Highlight the current difficulty
@@ -804,8 +815,7 @@ void OnceUpon::drawMenuMainIngame() {
 			continue;
 
 		if (_section >= (uint)button.id)
-			_vm->_draw->_backSurface->blit(elements, button.srcLeft, button.srcTop, button.srcRight, button.srcBottom,
-			                               button.dstX, button.dstY);
+			drawButton(*_vm->_draw->_backSurface, elements, button);
 	}
 
 	_vm->_draw->forceBlit();
@@ -873,48 +883,205 @@ void OnceUpon::clearMenuIngame(const Surface &background) {
 	drawLineByLine(background, left, top, right, bottom, left, top);
 }
 
-OnceUpon::Difficulty OnceUpon::checkDifficultyButton(int16 x, int16 y) const {
-	for (uint i = 0; i < ARRAYSIZE(kMainMenuDifficultyButton); i++) {
-		const MenuButton &button = kMainMenuDifficultyButton[i];
+int OnceUpon::checkButton(const MenuButton *buttons, uint count, int16 x, int16 y, int failValue) const {
+	for (uint i = 0; i < count; i++) {
+		const MenuButton &button = buttons[i];
 
 		if ((x >= button.left) && (x <= button.right) && (y >= button.top) && (y <= button.bottom))
-			return (Difficulty) button.id;
+			return (int)button.id;
 	}
 
-	return kDifficultyMAX;
+	return failValue;
 }
 
-bool OnceUpon::checkAnimalsButton(int16 x, int16 y) const {
-	if (!_animalsButton)
-		return false;
-
-	return (x >= _animalsButton->left) && (x <= _animalsButton->right) &&
-	       (y >= _animalsButton->top)  && (y <= _animalsButton->bottom);
+void OnceUpon::drawButton(Surface &dest, const Surface &src, const MenuButton &button) const {
+	dest.blit(src, button.srcLeft, button.srcTop, button.srcRight, button.srcBottom, button.dstX, button.dstY);
 }
 
-int8 OnceUpon::checkSectionButton(int16 x, int16 y) const {
-	for (uint i = 0; i < ARRAYSIZE(kSectionButtons); i++) {
-		const MenuButton &button = kSectionButtons[i];
+void OnceUpon::drawButtons(Surface &dest, const Surface &src, const MenuButton *buttons, uint count) const {
+	for (uint i = 0; i < count; i++) {
+		const MenuButton &button = buttons[i];
 
-		if ((uint)button.id > _section)
+		if (!button.needDraw)
 			continue;
 
-		if ((x >= button.left) && (x <= button.right) && (y >= button.top) && (y <= button.bottom))
-			return (int8)button.id;
+		drawButton(dest, src, button);
 	}
+}
 
-	return -1;
+void OnceUpon::drawButtonBorder(const MenuButton &button, uint8 color) {
+	_vm->_draw->_backSurface->drawRect(button.left, button.top, button.right, button.bottom, color);
+	_vm->_draw->dirtiedRect(_vm->_draw->_backSurface, button.left, button.top, button.right, button.bottom);
 }
 
-int8 OnceUpon::checkIngameButton(int16 x, int16 y) const {
-	for (uint i = 0; i < ARRAYSIZE(kIngameButtons); i++) {
-		const MenuButton &button = kIngameButtons[i];
+enum AnimalNamesState {
+	kANStateChoose,
+	kANStateNames,
+	kANStateFinish
+};
 
-		if ((x >= button.left) && (x <= button.right) && (y >= button.top) && (y <= button.bottom))
-			return (int8)button.id;
+void OnceUpon::doAnimalNames(uint count, const MenuButton *buttons, const char * const *names) {
+	fadeOut();
+	clearScreen();
+	setGamePalette(19);
+
+	bool cursorVisible = isCursorVisible();
+
+	// Set the cursor
+	addCursor();
+	setGameCursor();
+
+	anSetupChooser();
+
+	int8 _animal = -1;
+
+	AnimalNamesState state = kANStateChoose;
+	while (!_vm->shouldQuit() && (state != kANStateFinish)) {
+		showCursor();
+		fadeIn();
+
+		endFrame(true);
+
+		// Check user input
+
+		int16 mouseX, mouseY;
+		MouseButtons mouseButtons;
+
+		checkInput(mouseX, mouseY, mouseButtons);
+
+		// If we moused over an animal button, draw a border around it
+		int animal = checkButton(buttons, count, mouseX, mouseY);
+		if ((state == kANStateChoose) && (animal != _animal)) {
+			// Erase the old border
+			if (_animal >= 0)
+				drawButtonBorder(buttons[_animal], 15);
+
+			_animal = animal;
+
+			// Draw the new border
+			if (_animal >= 0)
+				drawButtonBorder(buttons[_animal], 10);
+		}
+
+		if (mouseButtons != kMouseButtonsLeft)
+			continue;
+
+		playSound(kSoundClick);
+
+		// We clicked on a language button, play the animal name
+		int language = checkButton(kLanguageButtons, ARRAYSIZE(kLanguageButtons), mouseX, mouseY);
+		if ((state == kANStateNames) && (language >= 0))
+			anPlayAnimalName(names[_animal], language);
+
+		// We clicked on an animal
+		if ((state == kANStateChoose) && (_animal >= 0)) {
+			anSetupNames(buttons[_animal]);
+
+			state = kANStateNames;
+		}
+
+		// If we clicked on the back button, go back
+		if (checkButton(&kAnimalNamesBack, 1, mouseX, mouseY) != -1) {
+			if        (state == kANStateNames) {
+				anSetupChooser();
+
+				state = kANStateChoose;
+			} else if (state == kANStateChoose)
+				state = kANStateFinish;
+		}
 	}
 
-	return -1;
+	fadeOut();
+
+	// Restore the cursor
+	if (!cursorVisible)
+		hideCursor();
+	removeCursor();
+}
+
+void OnceUpon::anSetupChooser() {
+	fadeOut();
+
+	_vm->_video->drawPackedSprite("dico.cmp", *_vm->_draw->_backSurface);
+
+	// Draw the back button
+	Surface menu(320, 34, 1);
+	_vm->_video->drawPackedSprite("icon.cmp", menu);
+	drawButton(*_vm->_draw->_backSurface, menu, kAnimalNamesBack);
+
+	// "Choose an animal"
+	TXTFile *choose = loadTXT(getLocFile("choisi.tx"), TXTFile::kFormatStringPosition);
+	choose->draw(*_vm->_draw->_backSurface, &_plettre, 1, 14);
+	delete choose;
+
+	_vm->_draw->forceBlit();
+}
+
+void OnceUpon::anSetupNames(const MenuButton &animal) {
+	fadeOut();
+
+	Surface background(320, 200, 1);
+
+	_vm->_video->drawPackedSprite("dico.cmp", background);
+
+	// Draw the background and clear what we don't need
+	_vm->_draw->_backSurface->blit(background);
+	_vm->_draw->_backSurface->fillRect(19, 19, 302, 186, 15);
+
+	// Draw the back button
+	Surface menu(320, 34, 1);
+	_vm->_video->drawPackedSprite("icon.cmp", menu);
+	drawButton(*_vm->_draw->_backSurface, menu, kAnimalNamesBack);
+
+	// Draw the animal
+	drawButton(*_vm->_draw->_backSurface, background, animal);
+
+	// Draw the language buttons
+	Surface elements(320, 200, 1);
+	_vm->_video->drawPackedSprite("elemenu.cmp", elements);
+	drawButtons(*_vm->_draw->_backSurface, elements, kLanguageButtons, ARRAYSIZE(kLanguageButtons));
+
+	// Draw the language names
+	_plettre->drawString("Fran\207ais",  43,  70, 10, 15, true, *_vm->_draw->_backSurface);
+	_plettre->drawString("Deutsch"    , 136,  70, 10, 15, true, *_vm->_draw->_backSurface);
+	_plettre->drawString("English"    , 238,  70, 10, 15, true, *_vm->_draw->_backSurface);
+	_plettre->drawString("Italiano"   ,  43, 128, 10, 15, true, *_vm->_draw->_backSurface);
+	_plettre->drawString("Espa\244ol" , 136, 128, 10, 15, true, *_vm->_draw->_backSurface);
+	_plettre->drawString("English"    , 238, 128, 10, 15, true, *_vm->_draw->_backSurface);
+
+	_vm->_draw->forceBlit();
+}
+
+void OnceUpon::anPlayAnimalName(const Common::String &animal, uint language) {
+	// Sound file to play
+	Common::String soundFile = animal + "_" + kLanguageSuffixLong[language] + ".snd";
+
+	// Get the name of the animal
+	TXTFile *names = loadTXT(animal + ".anm", TXTFile::kFormatString);
+	Common::String name = names->getLines()[language].text;
+	delete names;
+
+	// It should be centered on the screen
+	const int nameX = 160 - (name.size() * _plettre->getCharWidth()) / 2;
+
+	// Backup the screen surface
+	Surface backup(162, 23, 1);
+	backup.blit(*_vm->_draw->_backSurface, 78, 123, 239, 145, 0, 0);
+
+	// Draw the name border
+	Surface nameBorder(162, 23, 1);
+	_vm->_video->drawPackedSprite("mot.cmp", nameBorder);
+	_vm->_draw->_backSurface->blit(nameBorder, 0, 0, 161, 22, 78, 123);
+
+	// Print the animal name
+	_plettre->drawString(name, nameX, 129, 10, 0, true, *_vm->_draw->_backSurface);
+	_vm->_draw->dirtiedRect(_vm->_draw->_backSurface, 78, 123, 239, 145);
+
+	playSoundFile(soundFile);
+
+	// Restore the screen
+	_vm->_draw->_backSurface->blit(backup, 0, 0, 161, 22, 78, 123);
+	_vm->_draw->dirtiedRect(_vm->_draw->_backSurface, 78, 123, 239, 145);
 }
 
 void OnceUpon::drawLineByLine(const Surface &src, int16 left, int16 top, int16 right, int16 bottom,
diff --git a/engines/gob/pregob/onceupon/onceupon.h b/engines/gob/pregob/onceupon/onceupon.h
index efc2710..ff7266e 100644
--- a/engines/gob/pregob/onceupon/onceupon.h
+++ b/engines/gob/pregob/onceupon/onceupon.h
@@ -38,6 +38,8 @@ namespace OnceUpon {
 
 class OnceUpon : public PreGob {
 public:
+	static const uint kLanguageCount = 5;
+
 	OnceUpon(GobEngine *vm);
 	~OnceUpon();
 
@@ -74,7 +76,7 @@ protected:
 		int16 left, top, right, bottom;
 		int16 srcLeft, srcTop, srcRight, srcBottom;
 		int16 dstX, dstY;
-		int id;
+		uint id;
 	};
 
 	static const uint kSectionCount = 15;
@@ -100,6 +102,8 @@ protected:
 
 	MenuAction doMenu(MenuType type);
 
+	void doAnimalNames(uint count, const MenuButton *buttons, const char * const *names);
+
 	void drawLineByLine(const Surface &src, int16 left, int16 top, int16 right, int16 bottom,
 	                    int16 x, int16 y) const;
 
@@ -114,9 +118,12 @@ protected:
 	uint8      _section;
 
 private:
-	static const MenuButton kMainMenuDifficultyButton[3];
-	static const MenuButton kSectionButtons[4];
-	static const MenuButton kIngameButtons[3];
+	static const MenuButton kMainMenuDifficultyButton[];
+	static const MenuButton kSectionButtons[];
+	static const MenuButton kIngameButtons[];
+
+	static const MenuButton kAnimalNamesBack;
+	static const MenuButton kLanguageButtons[];
 
 	static const char *kSound[kSoundMAX];
 
@@ -153,11 +160,15 @@ private:
 
 	void clearMenuIngame(const Surface &background);
 
-	Difficulty checkDifficultyButton(int16 x, int16 y) const;
-	bool       checkAnimalsButton   (int16 x, int16 y) const;
-	int8       checkSectionButton   (int16 x, int16 y) const;
-	int8       checkIngameButton    (int16 x, int16 y) const;
+	int checkButton(const MenuButton *buttons, uint count, int16 x, int16 y, int failValue = -1) const;
+	void drawButton(Surface &dest, const Surface &src, const MenuButton &button) const;
+	void drawButtons(Surface &dest, const Surface &src, const MenuButton *buttons, uint count) const;
+	void drawButtonBorder(const MenuButton &button, uint8 color);
 
+	// Animal names helpers
+	void anSetupChooser();
+	void anSetupNames(const MenuButton &animal);
+	void anPlayAnimalName(const Common::String &animal, uint language);
 
 	bool _openedArchives;
 
diff --git a/engines/gob/pregob/pregob.cpp b/engines/gob/pregob/pregob.cpp
index f39a7a1..6759580 100644
--- a/engines/gob/pregob/pregob.cpp
+++ b/engines/gob/pregob/pregob.cpp
@@ -151,23 +151,28 @@ void PreGob::loadSounds(const char * const *sounds, uint soundCount) {
 
 	_sounds.resize(soundCount);
 
-	for (uint i = 0; i < soundCount; i++) {
-		int32 size;
-		byte *data = _vm->_dataIO->getFile(sounds[i], size);
-
-		if (!data || !_sounds[i].load(SOUND_SND, data, size)) {
-			delete data;
-
-			warning("PreGob::loadSounds(): Failed to load sound \"%s\"", sounds[i]);
-			continue;
-		}
-	}
+	for (uint i = 0; i < soundCount; i++)
+		loadSound(_sounds[i], sounds[i]);
 }
 
 void PreGob::freeSounds() {
 	_sounds.clear();
 }
 
+bool PreGob::loadSound(SoundDesc &sound, const Common::String &file) const {
+	int32 size;
+	byte *data = _vm->_dataIO->getFile(file, size);
+
+	if (!data || !sound.load(SOUND_SND, data, size)) {
+		delete data;
+
+		warning("PreGob::loadSound(): Failed to load sound \"%s\"", file.c_str());
+		return false;
+	}
+
+	return true;
+}
+
 void PreGob::playSound(uint sound, int16 frequency, int16 repCount) {
 	if (sound >= _sounds.size())
 		return;
@@ -179,6 +184,29 @@ void PreGob::stopSound() {
 	_vm->_sound->blasterStop(0);
 }
 
+void PreGob::playSoundFile(const Common::String &file, int16 frequency, int16 repCount, bool interruptible) {
+	stopSound();
+
+	SoundDesc sound;
+	if (!loadSound(sound, file))
+		return;
+
+	_vm->_sound->blasterPlay(&sound, repCount, frequency);
+
+	_vm->_util->forceMouseUp();
+
+	bool finished = false;
+	while (!_vm->shouldQuit() && !finished && _vm->_sound->blasterPlayingSound()) {
+		endFrame(true);
+
+		finished = hasInput();
+	}
+
+	_vm->_util->forceMouseUp();
+
+	stopSound();
+}
+
 void PreGob::endFrame(bool doInput) {
 	_vm->_draw->blitInvalidated();
 	_vm->_util->waitEndFrame();
diff --git a/engines/gob/pregob/pregob.h b/engines/gob/pregob/pregob.h
index 477aec6..a1a3d65 100644
--- a/engines/gob/pregob/pregob.h
+++ b/engines/gob/pregob/pregob.h
@@ -83,6 +83,8 @@ protected:
 	void playSound(uint sound, int16 frequency = 0, int16 repCount = 0);
 	void stopSound();
 
+	void playSoundFile(const Common::String &file, int16 frequency = 0, int16 repCount = 0, bool interruptible = true);
+
 	void endFrame(bool doInput);
 
 	int16 checkInput(int16 &mouseX, int16 &mouseY, MouseButtons &mouseButtons);
@@ -103,6 +105,9 @@ protected:
 	GobEngine *_vm;
 
 private:
+	bool loadSound(SoundDesc &sound, const Common::String &file) const;
+
+
 	bool _fadedOut; ///< Did we fade out?
 
 	Common::Array<SoundDesc> _sounds;


Commit: 24644c0012fb46bd77c6c24346f85c984418fb3b
    https://github.com/scummvm/scummvm/commit/24644c0012fb46bd77c6c24346f85c984418fb3b
Author: Sven Hesse (drmccoy at users.sourceforge.net)
Date: 2012-07-29T16:44:44-07:00

Commit Message:
GOB: Implement the Once Upon A Time "Bye Bye" screen

Changed paths:
    engines/gob/pregob/onceupon/abracadabra.cpp
    engines/gob/pregob/onceupon/babayaga.cpp
    engines/gob/pregob/onceupon/onceupon.cpp
    engines/gob/pregob/onceupon/onceupon.h



diff --git a/engines/gob/pregob/onceupon/abracadabra.cpp b/engines/gob/pregob/onceupon/abracadabra.cpp
index 781d683..5a5e407 100644
--- a/engines/gob/pregob/onceupon/abracadabra.cpp
+++ b/engines/gob/pregob/onceupon/abracadabra.cpp
@@ -102,7 +102,7 @@ void Abracadabra::run() {
 	mainLoop();
 
 	if (!_vm->shouldQuit())
-		warning("Abracadabra::run(): TODO: Show \"Bye Bye\"");
+		showByeBye();
 }
 
 void Abracadabra::mainLoop() {
diff --git a/engines/gob/pregob/onceupon/babayaga.cpp b/engines/gob/pregob/onceupon/babayaga.cpp
index 34f6741..9475ac4 100644
--- a/engines/gob/pregob/onceupon/babayaga.cpp
+++ b/engines/gob/pregob/onceupon/babayaga.cpp
@@ -102,7 +102,7 @@ void BabaYaga::run() {
 	mainLoop();
 
 	if (!_vm->shouldQuit())
-		warning("BabaYaga::run(): TODO: Show \"Bye Bye\"");
+		showByeBye();
 }
 
 void BabaYaga::mainLoop() {
diff --git a/engines/gob/pregob/onceupon/onceupon.cpp b/engines/gob/pregob/onceupon/onceupon.cpp
index b7bf2c3..6b90e9b 100644
--- a/engines/gob/pregob/onceupon/onceupon.cpp
+++ b/engines/gob/pregob/onceupon/onceupon.cpp
@@ -609,6 +609,22 @@ void OnceUpon::showChapter(int chapter) {
 	fadeOut();
 }
 
+void OnceUpon::showByeBye() {
+	fadeOut();
+	hideCursor();
+	clearScreen();
+	setGamePalette(1);
+
+	_plettre->drawString("Bye Bye....", 140, 80, 2, 0, true, *_vm->_draw->_backSurface);
+	_vm->_draw->forceBlit();
+
+	fadeIn();
+
+	_vm->_util->longDelay(1000);
+
+	fadeOut();
+}
+
 OnceUpon::MenuAction OnceUpon::doMenu(MenuType type) {
 	bool cursorVisible = isCursorVisible();
 
diff --git a/engines/gob/pregob/onceupon/onceupon.h b/engines/gob/pregob/onceupon/onceupon.h
index ff7266e..6f8b67a 100644
--- a/engines/gob/pregob/onceupon/onceupon.h
+++ b/engines/gob/pregob/onceupon/onceupon.h
@@ -100,6 +100,8 @@ protected:
 
 	void showChapter(int chapter); ///< Show a chapter intro text.
 
+	void showByeBye(); ///< Show the "bye bye" screen
+
 	MenuAction doMenu(MenuType type);
 
 	void doAnimalNames(uint count, const MenuButton *buttons, const char * const *names);


Commit: 305ab6847a6c3467ab02ea3f0798e300d82c89ed
    https://github.com/scummvm/scummvm/commit/305ab6847a6c3467ab02ea3f0798e300d82c89ed
Author: Sven Hesse (drmccoy at users.sourceforge.net)
Date: 2012-07-29T16:44:44-07:00

Commit Message:
GOB: Reorganize and clean up PreGob / Once Upon A Time

Changed paths:
    engines/gob/pregob/onceupon/abracadabra.cpp
    engines/gob/pregob/onceupon/abracadabra.h
    engines/gob/pregob/onceupon/babayaga.cpp
    engines/gob/pregob/onceupon/babayaga.h
    engines/gob/pregob/onceupon/onceupon.cpp
    engines/gob/pregob/onceupon/onceupon.h
    engines/gob/pregob/pregob.h



diff --git a/engines/gob/pregob/onceupon/abracadabra.cpp b/engines/gob/pregob/onceupon/abracadabra.cpp
index 5a5e407..2e4b5f2 100644
--- a/engines/gob/pregob/onceupon/abracadabra.cpp
+++ b/engines/gob/pregob/onceupon/abracadabra.cpp
@@ -80,7 +80,6 @@ const char *Abracadabra::kAnimalNames[] = {
 
 
 Abracadabra::Abracadabra(GobEngine *vm) : OnceUpon(vm) {
-	setAnimalsButton(&kAnimalsButtons);
 }
 
 Abracadabra::~Abracadabra() {
@@ -99,28 +98,13 @@ void Abracadabra::run() {
 	if (_vm->shouldQuit())
 		return;
 
-	mainLoop();
-
-	if (!_vm->shouldQuit())
-		showByeBye();
-}
+	// Handle the start menu
+	doStartMenu(&kAnimalsButtons, ARRAYSIZE(kAnimalButtons), kAnimalButtons, kAnimalNames);
+	if (_vm->shouldQuit())
+		return;
 
-void Abracadabra::mainLoop() {
-	clearScreen();
-
-	MenuType mainMenu = kMenuTypeMainStart;
-
-	while (!_vm->shouldQuit()) {
-		MenuAction action = doMenu(mainMenu);
-		if      (action == kMenuActionPlay)
-			warning("Abracadabra::mainLoop(): TODO: Play");
-		else if (action == kMenuActionRestart)
-			warning("Abracadabra::mainLoop(): TODO: Restart");
-		else if (action == kMenuActionAnimals)
-			doAnimalNames(ARRAYSIZE(kAnimalButtons), kAnimalButtons, kAnimalNames);
-		else if (action == kMenuActionQuit)
-			break;
-	}
+	// Play the actual game
+	playGame();
 }
 
 } // End of namespace OnceUpon
diff --git a/engines/gob/pregob/onceupon/abracadabra.h b/engines/gob/pregob/onceupon/abracadabra.h
index 5f3a1ba..f2075fc 100644
--- a/engines/gob/pregob/onceupon/abracadabra.h
+++ b/engines/gob/pregob/onceupon/abracadabra.h
@@ -37,13 +37,13 @@ public:
 	void run();
 
 private:
+	/** Definition of the menu button that leads to the animal names screen. */
 	static const MenuButton kAnimalsButtons;
 
+	/** Definition of the buttons that make up the animals in the animal names screen. */
 	static const MenuButton kAnimalButtons[];
+	/** File prefixes for the name of each animal. */
 	static const char *kAnimalNames[];
-
-
-	void mainLoop();
 };
 
 } // End of namespace OnceUpon
diff --git a/engines/gob/pregob/onceupon/babayaga.cpp b/engines/gob/pregob/onceupon/babayaga.cpp
index 9475ac4..6f27f46 100644
--- a/engines/gob/pregob/onceupon/babayaga.cpp
+++ b/engines/gob/pregob/onceupon/babayaga.cpp
@@ -80,7 +80,6 @@ const char *BabaYaga::kAnimalNames[] = {
 
 
 BabaYaga::BabaYaga(GobEngine *vm) : OnceUpon(vm) {
-	setAnimalsButton(&kAnimalsButtons);
 }
 
 BabaYaga::~BabaYaga() {
@@ -99,28 +98,13 @@ void BabaYaga::run() {
 	if (_vm->shouldQuit())
 		return;
 
-	mainLoop();
-
-	if (!_vm->shouldQuit())
-		showByeBye();
-}
+	// Handle the start menu
+	doStartMenu(&kAnimalsButtons, ARRAYSIZE(kAnimalButtons), kAnimalButtons, kAnimalNames);
+	if (_vm->shouldQuit())
+		return;
 
-void BabaYaga::mainLoop() {
-	clearScreen();
-
-	MenuType mainMenu = kMenuTypeMainStart;
-
-	while (!_vm->shouldQuit()) {
-		MenuAction action = doMenu(mainMenu);
-		if      (action == kMenuActionPlay)
-			warning("BabaYaga::mainLoop(): TODO: Play");
-		else if (action == kMenuActionRestart)
-			warning("BabaYaga::mainLoop(): TODO: Restart");
-		else if (action == kMenuActionAnimals)
-			doAnimalNames(ARRAYSIZE(kAnimalButtons), kAnimalButtons, kAnimalNames);
-		else if (action == kMenuActionQuit)
-			break;
-	}
+	// Play the actual game
+	playGame();
 }
 
 } // End of namespace OnceUpon
diff --git a/engines/gob/pregob/onceupon/babayaga.h b/engines/gob/pregob/onceupon/babayaga.h
index de42f8e..181b6f4 100644
--- a/engines/gob/pregob/onceupon/babayaga.h
+++ b/engines/gob/pregob/onceupon/babayaga.h
@@ -37,13 +37,13 @@ public:
 	void run();
 
 private:
+	/** Definition of the menu button that leads to the animal names screen. */
 	static const MenuButton kAnimalsButtons;
 
+	/** Definition of the buttons that make up the animals in the animal names screen. */
 	static const MenuButton kAnimalButtons[];
+	/** File prefixes for the name of each animal. */
 	static const char *kAnimalNames[];
-
-
-	void mainLoop();
 };
 
 } // End of namespace OnceUpon
diff --git a/engines/gob/pregob/onceupon/onceupon.cpp b/engines/gob/pregob/onceupon/onceupon.cpp
index 6b90e9b..785d78b 100644
--- a/engines/gob/pregob/onceupon/onceupon.cpp
+++ b/engines/gob/pregob/onceupon/onceupon.cpp
@@ -132,8 +132,17 @@ const char *OnceUpon::kSound[kSoundMAX] = {
 };
 
 
-OnceUpon::OnceUpon(GobEngine *vm) : PreGob(vm), _jeudak(0), _lettre(0), _plettre(0), _glettre(0),
-	_openedArchives(false), _animalsButton(0) {
+OnceUpon::ScreenBackup::ScreenBackup() : palette(-1), changedCursor(false), cursorVisible(false) {
+	screen = new Surface(320, 200, 1);
+}
+
+OnceUpon::ScreenBackup::~ScreenBackup() {
+	delete screen;
+}
+
+
+OnceUpon::OnceUpon(GobEngine *vm) : PreGob(vm), _openedArchives(false),
+	_jeudak(0), _lettre(0), _plettre(0), _glettre(0) {
 
 }
 
@@ -144,6 +153,8 @@ OnceUpon::~OnceUpon() {
 void OnceUpon::init() {
 	deinit();
 
+	// Open data files
+
 	bool hasSTK1 = _vm->_dataIO->openArchive("stk1.stk", true);
 	bool hasSTK2 = _vm->_dataIO->openArchive("stk2.stk", true);
 	bool hasSTK3 = _vm->_dataIO->openArchive("stk3.stk", true);
@@ -153,6 +164,8 @@ void OnceUpon::init() {
 
 	_openedArchives = true;
 
+	// Open fonts
+
 	_jeudak  = _vm->_draw->loadFont("jeudak.let");
 	_lettre  = _vm->_draw->loadFont("lettre.let");
 	_plettre = _vm->_draw->loadFont("plettre.let");
@@ -162,6 +175,8 @@ void OnceUpon::init() {
 		error("OnceUpon::OnceUpon(): Failed to fonts (%d, %d, %d, %d)",
 		      _jeudak != 0, _lettre != 0, _plettre != 0, _glettre != 0);
 
+	// Verify the language
+
 	if (_vm->_global->_language == kLanguageAmerican)
 		_vm->_global->_language = kLanguageBritish;
 
@@ -171,17 +186,25 @@ void OnceUpon::init() {
 		      "please contact the ScummVM team with details about this version.\n"
 		      "Thanks", _vm->getLangDesc(_vm->_global->_language));
 
-	loadSounds(kSound, kSoundMAX);
+	// Load all our sounds and init the screen
 
+	loadSounds(kSound, kSoundMAX);
 	initScreen();
 
+	// We start with an invalid palette
+	_palette = -1;
+
+	// We start with no selected difficulty and at section 0
 	_difficulty = kDifficultyMAX;
 	_section    = 0;
 }
 
 void OnceUpon::deinit() {
+	// Free sounds
 	freeSounds();
 
+	// Free fonts
+
 	delete _jeudak;
 	delete _lettre;
 	delete _plettre;
@@ -192,6 +215,8 @@ void OnceUpon::deinit() {
 	_plettre = 0;
 	_glettre = 0;
 
+	// Close archives
+
 	if (_openedArchives) {
 		_vm->_dataIO->closeArchive(true);
 		_vm->_dataIO->closeArchive(true);
@@ -201,29 +226,115 @@ void OnceUpon::deinit() {
 	_openedArchives = false;
 }
 
-void OnceUpon::setAnimalsButton(const MenuButton *animalsButton) {
-	_animalsButton = animalsButton;
-}
-
-void OnceUpon::setCopyProtectionPalette() {
-	setPalette(kCopyProtectionPalette, kPaletteSize);
-}
-
 void OnceUpon::setGamePalette(uint palette) {
 	if (palette >= kPaletteCount)
 		return;
 
+	_palette = palette;
+
 	setPalette(kGamePalettes[palette], kPaletteSize);
 }
 
 void OnceUpon::setGameCursor() {
 	Surface cursor(320, 16, 1);
 
+	// Set the default game cursor
 	_vm->_video->drawPackedSprite("icon.cmp", cursor);
-
 	setCursor(cursor, 105, 0, 120, 15, 0, 0);
 }
 
+void OnceUpon::setAnimState(ANIObject &ani, uint16 state, bool once, bool pause) const {
+	ani.setAnimation(state);
+	ani.setMode(once ? ANIObject::kModeOnce : ANIObject::kModeContinuous);
+	ani.setPause(pause);
+	ani.setVisible(true);
+	ani.setPosition();
+}
+
+void OnceUpon::drawLineByLine(const Surface &src, int16 left, int16 top, int16 right, int16 bottom,
+                              int16 x, int16 y) const {
+
+	// A special way of drawing something:
+	// Draw every other line "downwards", wait a bit after each line
+	// Then, draw the remaining lines "upwards" and again wait a bit after each line.
+
+	if (_vm->shouldQuit())
+		return;
+
+	const int16 width  = right  - left + 1;
+	const int16 height = bottom - top  + 1;
+
+	if ((width <= 0) || (height <= 0))
+		return;
+
+	// Draw the even lines downwards
+	for (int16 i = 0; i < height; i += 2) {
+		if (_vm->shouldQuit())
+			return;
+
+		_vm->_draw->_backSurface->blit(src, left, top + i, right, top + i, x, y + i);
+
+		_vm->_draw->dirtiedRect(_vm->_draw->_backSurface, x, y + i, x + width - 1, y + 1);
+		_vm->_draw->blitInvalidated();
+
+		_vm->_util->longDelay(1);
+	}
+
+	// Draw the odd lines upwards
+	for (int16 i = (height & 1) ? height : (height - 1); i >= 0; i -= 2) {
+		if (_vm->shouldQuit())
+			return;
+
+		_vm->_draw->_backSurface->blit(src, left, top + i, right, top + i, x, y + i);
+
+		_vm->_draw->dirtiedRect(_vm->_draw->_backSurface, x, y + i, x + width - 1, y + 1);
+		_vm->_draw->blitInvalidated();
+
+		_vm->_util->longDelay(1);
+	}
+}
+
+void OnceUpon::backupScreen(ScreenBackup &backup, bool setDefaultCursor) {
+	// Backup the screen and palette
+	backup.screen->blit(*_vm->_draw->_backSurface);
+	backup.palette = _palette;
+
+	// Backup the cursor
+
+	backup.cursorVisible = isCursorVisible();
+
+	backup.changedCursor = false;
+	if (setDefaultCursor) {
+		backup.changedCursor = true;
+
+		addCursor();
+		setGameCursor();
+	}
+}
+
+void OnceUpon::restoreScreen(ScreenBackup &backup) {
+	if (_vm->shouldQuit())
+		return;
+
+	// Restore the screen
+	_vm->_draw->_backSurface->blit(*backup.screen);
+	_vm->_draw->forceBlit();
+
+	// Restore the palette
+	if (backup.palette >= 0)
+		setGamePalette(backup.palette);
+
+	// Restore the cursor
+
+	if (!backup.cursorVisible)
+		hideCursor();
+
+	if (backup.changedCursor)
+		removeCursor();
+
+	backup.changedCursor = false;
+}
+
 void OnceUpon::fixTXTStrings(TXTFile &txt) const {
 	TXTFile::LineArray &lines = txt.getLines();
 	for (uint i = 0; i < lines.size(); i++)
@@ -251,18 +362,22 @@ enum CopyProtectionState {
 
 bool OnceUpon::doCopyProtection(const uint8 colors[7], const uint8 shapes[7 * 20], const uint8 obfuscate[4]) {
 	fadeOut();
-	setCopyProtectionPalette();
+	setPalette(kCopyProtectionPalette, kPaletteSize);
 
+	// Load the copy protection sprites
 	Surface sprites[2] = {Surface(320, 200, 1), Surface(320, 200, 1)};
 
 	_vm->_video->drawPackedSprite("grille1.cmp", sprites[0]);
 	_vm->_video->drawPackedSprite("grille2.cmp", sprites[1]);
 
+	// Load the clown animation
 	ANIFile   ani  (_vm, "grille.ani", 320);
 	ANIObject clown(ani);
 
+	// Set the copy protection cursor
 	setCursor(sprites[1], 5, 110, 20, 134, 3, 0);
 
+	// We start with 2 tries left, not having a correct answer and the copy protection not set up yet
 	CopyProtectionState state = kCPStateSetup;
 
 	uint8 triesLeft   =  2;
@@ -423,31 +538,6 @@ void OnceUpon::cpWrong() {
 	clearScreen();
 }
 
-void OnceUpon::setAnimState(ANIObject &ani, uint16 state, bool once, bool pause) const {
-	ani.setAnimation(state);
-	ani.setMode(once ? ANIObject::kModeOnce : ANIObject::kModeContinuous);
-	ani.setPause(pause);
-	ani.setVisible(true);
-	ani.setPosition();
-}
-
-void OnceUpon::showWait(uint palette) {
-	// Show the loading floppy
-
-	fadeOut();
-	clearScreen();
-	setGamePalette(palette);
-
-	Surface wait(320, 43, 1);
-
-	_vm->_video->drawPackedSprite("wait.cmp", wait);
-	_vm->_draw->_backSurface->blit(wait, 0, 0, 72, 33, 122, 84);
-
-	_vm->_draw->forceBlit();
-
-	fadeIn();
-}
-
 void OnceUpon::showIntro() {
 	// Show all intro parts
 
@@ -475,6 +565,23 @@ void OnceUpon::showIntro() {
 	showWait(17);
 }
 
+void OnceUpon::showWait(uint palette) {
+	// Show the loading floppy
+
+	fadeOut();
+	clearScreen();
+	setGamePalette(palette);
+
+	Surface wait(320, 43, 1);
+
+	_vm->_video->drawPackedSprite("wait.cmp", wait);
+	_vm->_draw->_backSurface->blit(wait, 0, 0, 72, 33, 122, 84);
+
+	_vm->_draw->forceBlit();
+
+	fadeIn();
+}
+
 void OnceUpon::showQuote() {
 	// Show the quote about fairytales
 
@@ -534,6 +641,8 @@ void OnceUpon::showTitle() {
 }
 
 void OnceUpon::playTitleMusic() {
+	// Look at what platform this is and play the appropriate music type
+
 	if      (_vm->getPlatform() == Common::kPlatformPC)
 		playTitleMusicDOS();
 	else if (_vm->getPlatform() == Common::kPlatformAmiga)
@@ -571,6 +680,8 @@ void OnceUpon::playTitleMusicAtariST() {
 }
 
 void OnceUpon::stopTitleMusic() {
+	// Just stop everything
+
 	_vm->_sound->adlibSetRepeating(0);
 	_vm->_sound->blasterRepeatComposition(0);
 
@@ -625,55 +736,29 @@ void OnceUpon::showByeBye() {
 	fadeOut();
 }
 
-OnceUpon::MenuAction OnceUpon::doMenu(MenuType type) {
-	bool cursorVisible = isCursorVisible();
-
-	// Set the cursor
-	addCursor();
-	setGameCursor();
-
-	// Backup the screen
-	Surface screenBackup(320, 200, 1);
-	screenBackup.blit(*_vm->_draw->_backSurface);
-
-	// Handle the specific menu
-	MenuAction action;
-	if      (type == kMenuTypeMainStart)
-		action = doMenuMainStart();
-	else if (type == kMenuTypeMainIngame)
-		action = doMenuMainIngame();
-	else if (type == kMenuTypeIngame)
-		action = doMenuIngame();
-	else
-		error("OnceUpon::doMenu(): No such menu %d", type);
-
-	if (_vm->shouldQuit())
-		return action;
-
-	// The ingame menu cleans itself up in a special way
-	if (type == kMenuTypeIngame)
-		clearMenuIngame(screenBackup);
-
-	// The main menus fade out
-	if ((type == kMenuTypeMainStart) || (type == kMenuTypeMainIngame))
-		fadeOut();
-
-	// Restore the screen
-	_vm->_draw->_backSurface->blit(screenBackup);
-	_vm->_draw->forceBlit();
+void OnceUpon::doStartMenu(const MenuButton *animalsButton, uint animalCount,
+                           const MenuButton *animalButtons, const char * const *animalNames) {
+	clearScreen();
 
-	// Restore the cursor
-	if (!cursorVisible)
-		hideCursor();
-	removeCursor();
+	// Wait until we clicked on of the difficulty buttons and are ready to start playing
+	while (!_vm->shouldQuit()) {
+		MenuAction action = handleStartMenu(animalsButton);
+		if (action == kMenuActionPlay)
+			break;
 
-	return action;
+		// If we pressed the "listen to animal names" button, handle that screen
+		if (action == kMenuActionAnimals)
+			handleAnimalNames(animalCount, animalButtons, animalNames);
+	}
 }
 
-OnceUpon::MenuAction OnceUpon::doMenuMainStart() {
+OnceUpon::MenuAction OnceUpon::handleStartMenu(const MenuButton *animalsButton) {
+	ScreenBackup screenBackup;
+	backupScreen(screenBackup, true);
+
 	fadeOut();
 	setGamePalette(17);
-	drawMenuMainStart();
+	drawStartMenu(animalsButton);
 	showCursor();
 	fadeIn();
 
@@ -702,22 +787,28 @@ OnceUpon::MenuAction OnceUpon::doMenuMainStart() {
 			_difficulty = (Difficulty)diff;
 			action      = kMenuActionPlay;
 
-			drawMenuMainStart();
+			drawStartMenu(animalsButton);
 			_vm->_util->longDelay(1000);
 		}
 
-		if (_animalsButton && (checkButton(_animalsButton, 1, mouseX, mouseY) != -1))
+		if (animalsButton && (checkButton(animalsButton, 1, mouseX, mouseY) != -1))
 			action = kMenuActionAnimals;
 
 	}
 
+	fadeOut();
+	restoreScreen(screenBackup);
+
 	return action;
 }
 
-OnceUpon::MenuAction OnceUpon::doMenuMainIngame() {
+OnceUpon::MenuAction OnceUpon::handleMainMenu() {
+	ScreenBackup screenBackup;
+	backupScreen(screenBackup, true);
+
 	fadeOut();
 	setGamePalette(17);
-	drawMenuMainIngame();
+	drawMainMenu();
 	showCursor();
 	fadeIn();
 
@@ -745,7 +836,7 @@ OnceUpon::MenuAction OnceUpon::doMenuMainIngame() {
 		if ((diff >= 0) && (diff != (int)_difficulty)) {
 			_difficulty = (Difficulty)diff;
 
-			drawMenuMainIngame();
+			drawMainMenu();
 		}
 
 		// If we clicked on a section button, restart the game from this section
@@ -757,11 +848,17 @@ OnceUpon::MenuAction OnceUpon::doMenuMainIngame() {
 
 	}
 
+	fadeOut();
+	restoreScreen(screenBackup);
+
 	return action;
 }
 
-OnceUpon::MenuAction OnceUpon::doMenuIngame() {
-	drawMenuIngame();
+OnceUpon::MenuAction OnceUpon::handleIngameMenu() {
+	ScreenBackup screenBackup;
+	backupScreen(screenBackup, true);
+
+	drawIngameMenu();
 	showCursor();
 
 	MenuAction action = kMenuActionNone;
@@ -791,20 +888,23 @@ OnceUpon::MenuAction OnceUpon::doMenuIngame() {
 
 	}
 
+	clearIngameMenu(*screenBackup.screen);
+	restoreScreen(screenBackup);
+
 	return action;
 }
 
-void OnceUpon::drawMenuMainStart() {
+void OnceUpon::drawStartMenu(const MenuButton *animalsButton) {
 	// Draw the background
 	_vm->_video->drawPackedSprite("menu2.cmp", *_vm->_draw->_backSurface);
 
 	// Draw the "Listen to animal names" button
-	if (_animalsButton) {
+	if (animalsButton) {
 		Surface elements(320, 38, 1);
 		_vm->_video->drawPackedSprite("elemenu.cmp", elements);
-		_vm->_draw->_backSurface->fillRect(_animalsButton->left , _animalsButton->top,
-		                                   _animalsButton->right, _animalsButton->bottom, 0);
-		drawButton(*_vm->_draw->_backSurface, elements, *_animalsButton);
+		_vm->_draw->_backSurface->fillRect(animalsButton->left , animalsButton->top,
+		                                   animalsButton->right, animalsButton->bottom, 0);
+		drawButton(*_vm->_draw->_backSurface, elements, *animalsButton);
 	}
 
 	// Highlight the current difficulty
@@ -813,7 +913,7 @@ void OnceUpon::drawMenuMainStart() {
 	_vm->_draw->forceBlit();
 }
 
-void OnceUpon::drawMenuMainIngame() {
+void OnceUpon::drawMainMenu() {
 	// Draw the background
 	_vm->_video->drawPackedSprite("menu.cmp", *_vm->_draw->_backSurface);
 
@@ -837,11 +937,11 @@ void OnceUpon::drawMenuMainIngame() {
 	_vm->_draw->forceBlit();
 }
 
-void OnceUpon::drawMenuIngame() {
+void OnceUpon::drawIngameMenu() {
 	Surface menu(320, 34, 1);
 	_vm->_video->drawPackedSprite("icon.cmp", menu);
 
-	// Draw the menu in a special way
+	// Draw the menu in a special way, button by button
 	for (uint i = 0; i < ARRAYSIZE(kIngameButtons); i++) {
 		const MenuButton &button = kIngameButtons[i];
 
@@ -863,16 +963,15 @@ void OnceUpon::drawMenuDifficulty() {
 	difficulties->draw((uint) _difficulty, *_vm->_draw->_backSurface, &_plettre, 1);
 
 	// Draw a border around the current difficulty
-	_vm->_draw->_backSurface->drawRect(kMainMenuDifficultyButton[_difficulty].left,
-	                                   kMainMenuDifficultyButton[_difficulty].top,
-	                                   kMainMenuDifficultyButton[_difficulty].right,
-	                                   kMainMenuDifficultyButton[_difficulty].bottom,
-	                                   difficulties->getLines()[_difficulty].color);
+	drawButtonBorder(kMainMenuDifficultyButton[_difficulty], difficulties->getLines()[_difficulty].color);
 
 	delete difficulties;
 }
 
-void OnceUpon::clearMenuIngame(const Surface &background) {
+void OnceUpon::clearIngameMenu(const Surface &background) {
+	if (_vm->shouldQuit())
+		return;
+
 	// Find the area encompassing the whole ingame menu
 
 	int16 left   = 0x7FFF;
@@ -900,6 +999,8 @@ void OnceUpon::clearMenuIngame(const Surface &background) {
 }
 
 int OnceUpon::checkButton(const MenuButton *buttons, uint count, int16 x, int16 y, int failValue) const {
+	// Look through all buttons, and return the ID of the button we're in
+
 	for (uint i = 0; i < count; i++) {
 		const MenuButton &button = buttons[i];
 
@@ -907,6 +1008,7 @@ int OnceUpon::checkButton(const MenuButton *buttons, uint count, int16 x, int16
 			return (int)button.id;
 	}
 
+	// We're in none of these buttons, return the fail value
 	return failValue;
 }
 
@@ -931,12 +1033,12 @@ void OnceUpon::drawButtonBorder(const MenuButton &button, uint8 color) {
 }
 
 enum AnimalNamesState {
-	kANStateChoose,
-	kANStateNames,
-	kANStateFinish
+	kANStateChoose, // We're in the animal chooser
+	kANStateNames,  // We're in the language chooser
+	kANStateFinish  // We're finished
 };
 
-void OnceUpon::doAnimalNames(uint count, const MenuButton *buttons, const char * const *names) {
+void OnceUpon::handleAnimalNames(uint count, const MenuButton *buttons, const char * const *names) {
 	fadeOut();
 	clearScreen();
 	setGamePalette(19);
@@ -1100,45 +1202,8 @@ void OnceUpon::anPlayAnimalName(const Common::String &animal, uint language) {
 	_vm->_draw->dirtiedRect(_vm->_draw->_backSurface, 78, 123, 239, 145);
 }
 
-void OnceUpon::drawLineByLine(const Surface &src, int16 left, int16 top, int16 right, int16 bottom,
-                              int16 x, int16 y) const {
-
-	// A special way of drawing something:
-	// Draw every other line "downwards", wait a bit after each line
-	// Then, draw the remaining lines "upwards" and again wait a bit after each line.
-
-	if (_vm->shouldQuit())
-		return;
-
-	const int16 width  = right  - left + 1;
-	const int16 height = bottom - top  + 1;
-
-	if ((width <= 0) || (height <= 0))
-		return;
-
-	for (int16 i = 0; i < height; i += 2) {
-		if (_vm->shouldQuit())
-			return;
-
-		_vm->_draw->_backSurface->blit(src, left, top + i, right, top + i, x, y + i);
-
-		_vm->_draw->dirtiedRect(_vm->_draw->_backSurface, x, y + i, x + width - 1, y + 1);
-		_vm->_draw->blitInvalidated();
-
-		_vm->_util->longDelay(1);
-	}
-
-	for (int16 i = (height & 1) ? height : (height - 1); i >= 0; i -= 2) {
-		if (_vm->shouldQuit())
-			return;
-
-		_vm->_draw->_backSurface->blit(src, left, top + i, right, top + i, x, y + i);
-
-		_vm->_draw->dirtiedRect(_vm->_draw->_backSurface, x, y + i, x + width - 1, y + 1);
-		_vm->_draw->blitInvalidated();
-
-		_vm->_util->longDelay(1);
-	}
+void OnceUpon::playGame() {
+	warning("OnceUpon::playGame(): TODO");
 }
 
 } // End of namespace OnceUpon
diff --git a/engines/gob/pregob/onceupon/onceupon.h b/engines/gob/pregob/onceupon/onceupon.h
index 6f8b67a..08c8803 100644
--- a/engines/gob/pregob/onceupon/onceupon.h
+++ b/engines/gob/pregob/onceupon/onceupon.h
@@ -38,18 +38,67 @@ namespace OnceUpon {
 
 class OnceUpon : public PreGob {
 public:
+	/** Number of languages we support. */
 	static const uint kLanguageCount = 5;
 
+
 	OnceUpon(GobEngine *vm);
 	~OnceUpon();
 
+
 protected:
-	enum MenuType {
-		kMenuTypeMainStart  = 0, ///< The big main menu at game start.
-		kMenuTypeMainIngame,     ///< The big main menu during the game.
-		kMenuTypeIngame          ///< The small popup menu during the game.
+	/** A description of a menu button. */
+	struct MenuButton {
+		bool needDraw; ///< Does the button need drawing?
+
+		int16 left;   ///< Left   coordinate of the button.
+		int16 top;    ///< Top    coordinate of the button.
+		int16 right;  ///< Right  coordinate of the button.
+		int16 bottom; ///< Bottom coordinate of the button.
+
+		int16 srcLeft;   ///< Left  coordinate of the button's sprite.
+		int16 srcTop;    ///< Top   coordinate of the button's sprite.
+		int16 srcRight;  ///< Right coordinate of the button's sprite.
+		int16 srcBottom; ///< Right coordinate of the button's sprite.
+
+		int16 dstX; ///< Destination X coordinate of the button's sprite.
+		int16 dstY; ///< Destination Y coordinate of the button's sprite.
+
+		uint id; ///< The button's ID.
 	};
 
+
+	void init();
+	void deinit();
+
+	/** Handle the copy protection.
+	 *
+	 *  @param  colors    Colors the copy protection animals can be.
+	 *  @param  shapes    The shape that's the correct answer for each animal in each color.
+	 *  @param  obfuscate Extra obfuscate table. correctShape = shapes[colors][obfuscate[animal]].
+	 *  @return true if the user guessed the correct shape, false otherwise.
+	 */
+	bool doCopyProtection(const uint8 colors[7], const uint8 shapes[7 * 20], const uint8 obfuscate[4]);
+
+	/** Show the intro. */
+	void showIntro();
+
+	/** Handle the start menu.
+	 *
+	 *  @param animalsButton Definition of the menu button that leads to the animal names screen. Can be 0.
+	 *  @param animalCount   Number of animals in the animal names screen.
+	 *  @param animalButtons Definition of the buttons that make up the animals in the animal names screen.
+	 *  @param animalNames   File prefixes for the name of each animal.
+	 */
+	void doStartMenu(const MenuButton *animalsButton, uint animalCount,
+	                 const MenuButton *animalButtons, const char * const *animalNames);
+
+	/** Play the game proper. */
+	void playGame();
+
+
+private:
+	/** All actions a user can request in a menu. */
 	enum MenuAction {
 		kMenuActionNone = 0, ///< No action.
 		kMenuActionAnimals , ///< Do the animal names.
@@ -59,6 +108,7 @@ protected:
 		kMenuActionQuit      ///< Quit the game.
 	};
 
+	/** Difficulty levels. */
 	enum Difficulty {
 		kDifficultyBeginner     = 0,
 		kDifficultyIntermediate = 1,
@@ -66,115 +116,148 @@ protected:
 		kDifficultyMAX
 	};
 
+	/** The different sounds common in the game. */
 	enum Sound {
 		kSoundClick = 0,
 		kSoundMAX
 	};
 
-	struct MenuButton {
-		bool needDraw;
-		int16 left, top, right, bottom;
-		int16 srcLeft, srcTop, srcRight, srcBottom;
-		int16 dstX, dstY;
-		uint id;
-	};
+	/** A complete screen backup. */
+	struct ScreenBackup {
+		Surface *screen; ///< Screen contents.
+		int palette;     ///< Screen palette.
 
-	static const uint kSectionCount = 15;
+		bool changedCursor; ///< Did we change the cursor?
+		bool cursorVisible; ///< Was the cursor visible?
 
+		ScreenBackup();
+		~ScreenBackup();
+	};
 
-	void init();
-	void deinit();
 
-	void setAnimalsButton(const MenuButton *animalsButton);
+	/** The number of game sections. */
+	static const uint kSectionCount = 15;
 
-	void setGamePalette(uint palette);
-	void setGameCursor();
+	static const MenuButton kMainMenuDifficultyButton[]; ///< Difficulty buttons.
+	static const MenuButton kSectionButtons[];           ///< Section buttons.
 
-	Common::String fixString(const Common::String &str) const;
-	void fixTXTStrings(TXTFile &txt) const;
+	static const MenuButton kIngameButtons[];            ///< Ingame menu buttons.
 
-	bool doCopyProtection(const uint8 colors[7], const uint8 shapes[7 * 20], const uint8 obfuscate[4]);
+	static const MenuButton kAnimalNamesBack;   ///< "Back" button in the animal names screens.
+	static const MenuButton kLanguageButtons[]; ///< Language buttons in the animal names screen.
 
-	void showWait(uint palette = 0xFFFF);  ///< Show the wait / loading screen.
-	void showIntro();                      ///< Show the whole intro.
+	/** All general game sounds we know about. */
+	static const char *kSound[kSoundMAX];
 
-	void showChapter(int chapter); ///< Show a chapter intro text.
 
-	void showByeBye(); ///< Show the "bye bye" screen
+	// -- General helpers --
 
-	MenuAction doMenu(MenuType type);
+	void setGamePalette(uint palette); ///< Set a game palette.
+	void setGameCursor();              ///< Set the default game cursor.
 
-	void doAnimalNames(uint count, const MenuButton *buttons, const char * const *names);
+	/** Set the state of an ANIObject. */
+	void setAnimState(ANIObject &ani, uint16 state, bool once, bool pause) const;
 
+	/** Draw this sprite in a fancy, animated line-by-line way. */
 	void drawLineByLine(const Surface &src, int16 left, int16 top, int16 right, int16 bottom,
 	                    int16 x, int16 y) const;
 
+	/** Backup the screen contents. */
+	void backupScreen(ScreenBackup &backup, bool setDefaultCursor = false);
+	/** Restore the screen contents with a previously made backup. */
+	void restoreScreen(ScreenBackup &backup);
 
-	// Fonts
-	Font *_jeudak;
-	Font *_lettre;
-	Font *_plettre;
-	Font *_glettre;
+	Common::String fixString(const Common::String &str) const; ///< Fix a string if necessary.
+	void fixTXTStrings(TXTFile &txt) const;                    ///< Fix all strings in a TXT.
 
-	Difficulty _difficulty;
-	uint8      _section;
 
-private:
-	static const MenuButton kMainMenuDifficultyButton[];
-	static const MenuButton kSectionButtons[];
-	static const MenuButton kIngameButtons[];
+	// -- Copy protection helpers --
 
-	static const MenuButton kAnimalNamesBack;
-	static const MenuButton kLanguageButtons[];
+	/** Set up the copy protection. */
+	int8 cpSetup(const uint8 colors[7], const uint8 shapes[7 * 20],
+	             const uint8 obfuscate[4], const Surface sprites[2]);
+	/** Find the shape under these coordinates. */
+	int8 cpFindShape(int16 x, int16 y) const;
+	/** Display the "You are wrong" screen. */
+	void cpWrong();
 
-	static const char *kSound[kSoundMAX];
 
+	// -- Show different game screens --
 
-	void setCopyProtectionPalette();
+	void showWait(uint palette = 0xFFFF); ///< Show the wait / loading screen.
+	void showQuote();                     ///< Show the quote about fairytales.
+	void showTitle();                     ///< Show the Once Upon A Time title.
+	void showChapter(int chapter);        ///< Show a chapter intro text.
+	void showByeBye();                    ///< Show the "bye bye" screen.
 
-	void setAnimState(ANIObject &ani, uint16 state, bool once, bool pause) const;
+	/** Handle the "listen to animal names" part. */
+	void handleAnimalNames(uint count, const MenuButton *buttons, const char * const *names);
 
-	// Copy protection helpers
-	int8 cpSetup(const uint8 colors[7], const uint8 shapes[7 * 20], const uint8 obfuscate[4], const Surface sprites[2]);
-	int8 cpFindShape(int16 x, int16 y) const;
-	void cpWrong();
 
-	// Intro parts
-	void showQuote();
-	void showTitle();
-
-	// Title music
-	void playTitleMusic();
-	void playTitleMusicDOS();
-	void playTitleMusicAmiga();
-	void playTitleMusicAtariST();
-	void stopTitleMusic();
-
-	// Menu helpers
-	MenuAction doMenuMainStart();
-	MenuAction doMenuMainIngame();
-	MenuAction doMenuIngame();
-
-	void drawMenuMainStart();
-	void drawMenuMainIngame();
-	void drawMenuIngame();
+	// -- Title music helpers --
+
+	void playTitleMusic();        ///< Play the title music.
+	void playTitleMusicDOS();     ///< Play the title music of the DOS      version.
+	void playTitleMusicAmiga();   ///< Play the title music of the Amiga    version.
+	void playTitleMusicAtariST(); ///< Play the title music of the Atari ST version.
+	void stopTitleMusic();        ///< Stop the title music.
+
+
+	// -- Menu helpers --
+
+	MenuAction handleStartMenu(const MenuButton *animalsButton); ///< Handle the start  menu.
+	MenuAction handleMainMenu();                                 ///< Handle the main   menu.
+	MenuAction handleIngameMenu();                               ///< Handle the ingame menu.
+
+	void drawStartMenu(const MenuButton *animalsButton); ///< Draw the start  menu.
+	void drawMainMenu();                                 ///< Draw the main   menu.
+	void drawIngameMenu();                               ///< Draw the ingame menu.
+
+	/** Draw the difficulty label. */
 	void drawMenuDifficulty();
 
-	void clearMenuIngame(const Surface &background);
+	/** Clear the ingame menu in an animated way. */
+	void clearIngameMenu(const Surface &background);
+
 
+	// -- Menu button helpers --
+
+	/** Find the button under these coordinates. */
 	int checkButton(const MenuButton *buttons, uint count, int16 x, int16 y, int failValue = -1) const;
-	void drawButton(Surface &dest, const Surface &src, const MenuButton &button) const;
+
+	/** Draw a menu button. */
+	void drawButton (Surface &dest, const Surface &src, const MenuButton &button) const;
+	/** Draw multiple menu buttons. */
 	void drawButtons(Surface &dest, const Surface &src, const MenuButton *buttons, uint count) const;
+
+	/** Draw a border around a button. */
 	void drawButtonBorder(const MenuButton &button, uint8 color);
 
-	// Animal names helpers
+
+	// -- Animal names helpers --
+
+	/** Set up the animal chooser. */
 	void anSetupChooser();
+	/** Set up the language chooser for one animal. */
 	void anSetupNames(const MenuButton &animal);
+	/** Play / Display the name of an animal in one language. */
 	void anPlayAnimalName(const Common::String &animal, uint language);
 
+
+	/** Did we open the game archives? */
 	bool _openedArchives;
 
-	const MenuButton *_animalsButton;
+	// Fonts
+	Font *_jeudak;
+	Font *_lettre;
+	Font *_plettre;
+	Font *_glettre;
+
+	/** The current palette. */
+	int _palette;
+
+	Difficulty _difficulty; ///< The current difficulty.
+	uint8      _section;    ///< The current game section.
 };
 
 } // End of namespace OnceUpon
diff --git a/engines/gob/pregob/pregob.h b/engines/gob/pregob/pregob.h
index a1a3d65..e62a590 100644
--- a/engines/gob/pregob/pregob.h
+++ b/engines/gob/pregob/pregob.h
@@ -51,7 +51,10 @@ protected:
 	static const char *kLanguageSuffixLong [5];
 
 
-	void initScreen(); ///< Initialize the game screen.
+	// -- Graphics --
+
+	/** Initialize the game screen. */
+	void initScreen();
 
 	void fadeOut(); ///< Fade to black.
 	void fadeIn();  ///< Fade to the current palette.
@@ -65,51 +68,86 @@ protected:
 	 */
 	void setPalette(const byte *palette, uint16 size); ///< Change the palette
 
+	/** Add a new cursor that can be manipulated to the stack. */
 	void addCursor();
+	/** Remove the top-most cursor from the stack. */
 	void removeCursor();
 
+	/** Set the current cursor. */
 	void setCursor(Surface &sprite, int16 hotspotX, int16 hotspotY);
+	/** Set the current cursor. */
 	void setCursor(Surface &sprite, int16 left, int16 top, int16 right, int16 bottom,
 	               int16 hotspotX, int16 hotspotY);
 
+	/** Show the cursor. */
 	void showCursor();
+	/** Hide the cursor. */
 	void hideCursor();
 
+	/** Is the cursor currently visible? */
 	bool isCursorVisible() const;
 
+	/** Remove an animation from the screen. */
+	void clearAnim(ANIObject &ani);
+	/** Draw an animation to the screen, advancing it. */
+	void drawAnim(ANIObject &ani);
+	/** Clear and draw an animation to the screen, advancing it. */
+	void redrawAnim(ANIObject &ani);
+
+	/** Wait for the frame to end, handling screen updates and optionally update input. */
+	void endFrame(bool doInput);
+
+
+	// -- Sound --
+
+	/** Load all sounds that can be played interactively in the game. */
 	void loadSounds(const char * const *sounds, uint soundCount);
+	/** Free all loaded sound. */
 	void freeSounds();
 
+	/** Play a loaded sound. */
 	void playSound(uint sound, int16 frequency = 0, int16 repCount = 0);
+	/** Stop all sound playback. */
 	void stopSound();
 
+	/** Play a sound until it ends or is interrupted by a keypress. */
 	void playSoundFile(const Common::String &file, int16 frequency = 0, int16 repCount = 0, bool interruptible = true);
 
-	void endFrame(bool doInput);
 
+	// -- Input --
+
+	/** Check mouse and keyboard input. */
 	int16 checkInput(int16 &mouseX, int16 &mouseY, MouseButtons &mouseButtons);
+	/** Wait for mouse or keyboard input. */
 	int16 waitInput (int16 &mouseX, int16 &mouseY, MouseButtons &mouseButtons);
+	/** Wait for mouse or keyboard input, but don't care about what was done with the mouse. */
 	int16 waitInput();
+	/** Did we have mouse or keyboard input? */
 	bool  hasInput();
 
-	void clearAnim(ANIObject &ani);
-	void drawAnim(ANIObject &ani);
-	void redrawAnim(ANIObject &ani);
 
+	// -- TXT helpers --
+
+	/** Get the name of a localized file. */
 	Common::String getLocFile(const Common::String &file) const;
+	/** Open a TXT file. */
 	TXTFile *loadTXT(const Common::String &txtFile, TXTFile::Format format) const;
 
+	/** Called by loadTXT() to fix strings within the TXT file. */
 	virtual void fixTXTStrings(TXTFile &txt) const;
 
 
 	GobEngine *_vm;
 
 private:
+	/** Load a sound file. */
 	bool loadSound(SoundDesc &sound, const Common::String &file) const;
 
 
-	bool _fadedOut; ///< Did we fade out?
+	/** Did we fade out? */
+	bool _fadedOut;
 
+	/** All loaded sounds. */
 	Common::Array<SoundDesc> _sounds;
 };
 


Commit: 60f52ab9a0beccccca4958fbcf4d369e6dd22748
    https://github.com/scummvm/scummvm/commit/60f52ab9a0beccccca4958fbcf4d369e6dd22748
Author: Sven Hesse (drmccoy at users.sourceforge.net)
Date: 2012-07-29T16:44:44-07:00

Commit Message:
GOB: Add the frame for normal Once Upon A Time game play

Changed paths:
    engines/gob/pregob/onceupon/brokenstrings.h
    engines/gob/pregob/onceupon/onceupon.cpp
    engines/gob/pregob/onceupon/onceupon.h



diff --git a/engines/gob/pregob/onceupon/brokenstrings.h b/engines/gob/pregob/onceupon/brokenstrings.h
index 98dcb72..0a40493 100644
--- a/engines/gob/pregob/onceupon/brokenstrings.h
+++ b/engines/gob/pregob/onceupon/brokenstrings.h
@@ -40,7 +40,12 @@ static const BrokenString kBrokenStringsGerman[] = {
 	{ "  Fortgeschrittene"           , "  Fortgeschritten"            },
 	{ "die Vespe"                    , "die Wespe"                    },
 	{ "das Rhinoceros"               , "das Rhinozeros"               },
-	{ "die Heusschrecke"             , "die Heuschrecke"              }
+	{ "die Heusschrecke"             , "die Heuschrecke"              },
+	{ "Das, von Drachen gebrachte"   , "Das vom Drachen gebrachte"    },
+	{ "Am Waldesrand es sieht"       , "Am Waldesrand sieht es"       },
+	{ " das Kind den Palast."        , "das Kind den Palast."         },
+	{ "Am Waldessaum sieht"          , "Am Waldesrand sieht"          },
+	{ "tipp auf ESC!"                , "dr\201cke ESC!"               }
 };
 
 static const BrokenStringLanguage kBrokenStrings[kLanguageCount] = {
diff --git a/engines/gob/pregob/onceupon/onceupon.cpp b/engines/gob/pregob/onceupon/onceupon.cpp
index 785d78b..fb96295 100644
--- a/engines/gob/pregob/onceupon/onceupon.cpp
+++ b/engines/gob/pregob/onceupon/onceupon.cpp
@@ -131,6 +131,24 @@ const char *OnceUpon::kSound[kSoundMAX] = {
 	"diamant.snd"
 };
 
+const OnceUpon::SectionFunc OnceUpon::kSectionFuncs[kSectionCount] = {
+	&OnceUpon::sectionStork,
+	&OnceUpon::sectionChapter1,
+	&OnceUpon::section02,
+	&OnceUpon::sectionChapter2,
+	&OnceUpon::section04,
+	&OnceUpon::sectionChapter3,
+	&OnceUpon::section06,
+	&OnceUpon::sectionChapter4,
+	&OnceUpon::section08,
+	&OnceUpon::sectionChapter5,
+	&OnceUpon::section10,
+	&OnceUpon::sectionChapter6,
+	&OnceUpon::section12,
+	&OnceUpon::sectionChapter7,
+	&OnceUpon::sectionEnd
+};
+
 
 OnceUpon::ScreenBackup::ScreenBackup() : palette(-1), changedCursor(false), cursorVisible(false) {
 	screen = new Surface(320, 200, 1);
@@ -194,6 +212,9 @@ void OnceUpon::init() {
 	// We start with an invalid palette
 	_palette = -1;
 
+	// No quit requested at start
+	_quit = false;
+
 	// We start with no selected difficulty and at section 0
 	_difficulty = kDifficultyMAX;
 	_section    = 0;
@@ -930,7 +951,7 @@ void OnceUpon::drawMainMenu() {
 		if (!button.needDraw)
 			continue;
 
-		if (_section >= (uint)button.id)
+		if (_section >= (int)button.id)
 			drawButton(*_vm->_draw->_backSurface, elements, button);
 	}
 
@@ -998,6 +1019,41 @@ void OnceUpon::clearIngameMenu(const Surface &background) {
 	drawLineByLine(background, left, top, right, bottom, left, top);
 }
 
+OnceUpon::MenuAction OnceUpon::doIngameMenu() {
+	// Show the ingame menu
+	MenuAction action = handleIngameMenu();
+
+	if ((action == kMenuActionQuit) || _vm->shouldQuit()) {
+
+		// User pressed the quit button, or quit ScummVM
+		_quit = true;
+		return kMenuActionQuit;
+
+	} else if (action == kMenuActionPlay) {
+
+		// User pressed the return to game button
+		return kMenuActionPlay;
+
+	} else if (kMenuActionMainMenu) {
+
+		// User pressed the return to main menu button
+		return handleMainMenu();
+	}
+
+	return action;
+}
+
+OnceUpon::MenuAction OnceUpon::doIngameMenu(int16 key, MouseButtons mouseButtons) {
+	if ((key != kKeyEscape) && (mouseButtons != kMouseButtonsRight))
+		return kMenuActionNone;
+
+	MenuAction action = doIngameMenu();
+	if (action == kMenuActionPlay)
+		return kMenuActionNone;
+
+	return action;
+}
+
 int OnceUpon::checkButton(const MenuButton *buttons, uint count, int16 x, int16 y, int failValue) const {
 	// Look through all buttons, and return the ID of the button we're in
 
@@ -1203,7 +1259,101 @@ void OnceUpon::anPlayAnimalName(const Common::String &animal, uint language) {
 }
 
 void OnceUpon::playGame() {
-	warning("OnceUpon::playGame(): TODO");
+	while (!_vm->shouldQuit() && !_quit) {
+		// Play a section and advance to the next section if we finished it
+		if (playSection())
+			_section = MIN(_section + 1, kSectionCount - 1);
+	}
+
+	// If we quit through the game and not through ScummVM, show the "Bye Bye" screen
+	if (!_vm->shouldQuit())
+		showByeBye();
+}
+
+bool OnceUpon::playSection() {
+	if ((_section < 0) || (_section >= ARRAYSIZE(kSectionFuncs))) {
+		_quit = true;
+		return false;
+	}
+
+	return (this->*kSectionFuncs[_section])();
+}
+
+bool OnceUpon::sectionStork() {
+	warning("OnceUpon::sectionStork(): TODO");
+	return true;
+}
+
+bool OnceUpon::sectionChapter1() {
+	showChapter(1);
+	return true;
+}
+
+bool OnceUpon::section02() {
+	warning("OnceUpon::section02(): TODO");
+	return true;
+}
+
+bool OnceUpon::sectionChapter2() {
+	showChapter(2);
+	return true;
+}
+
+bool OnceUpon::section04() {
+	warning("OnceUpon::section04(): TODO");
+	return true;
+}
+
+bool OnceUpon::sectionChapter3() {
+	showChapter(3);
+	return true;
+}
+
+bool OnceUpon::section06() {
+	warning("OnceUpon::section06(): TODO");
+	return true;
+}
+
+bool OnceUpon::sectionChapter4() {
+	showChapter(4);
+	return true;
+}
+
+bool OnceUpon::section08() {
+	warning("OnceUpon::section08(): TODO");
+	return true;
+}
+
+bool OnceUpon::sectionChapter5() {
+	showChapter(5);
+	return true;
+}
+
+bool OnceUpon::section10() {
+	warning("OnceUpon::section10(): TODO");
+	return true;
+}
+
+bool OnceUpon::sectionChapter6() {
+	showChapter(6);
+	return true;
+}
+
+bool OnceUpon::section12() {
+	warning("OnceUpon::section12(): TODO");
+	return true;
+}
+
+bool OnceUpon::sectionChapter7() {
+	showChapter(7);
+	return true;
+}
+
+bool OnceUpon::sectionEnd() {
+	warning("OnceUpon::sectionEnd(): TODO");
+
+	_quit = true;
+	return false;
 }
 
 } // End of namespace OnceUpon
diff --git a/engines/gob/pregob/onceupon/onceupon.h b/engines/gob/pregob/onceupon/onceupon.h
index 08c8803..0cae369 100644
--- a/engines/gob/pregob/onceupon/onceupon.h
+++ b/engines/gob/pregob/onceupon/onceupon.h
@@ -136,7 +136,7 @@ private:
 
 
 	/** The number of game sections. */
-	static const uint kSectionCount = 15;
+	static const int kSectionCount = 15;
 
 	static const MenuButton kMainMenuDifficultyButton[]; ///< Difficulty buttons.
 	static const MenuButton kSectionButtons[];           ///< Section buttons.
@@ -149,6 +149,10 @@ private:
 	/** All general game sounds we know about. */
 	static const char *kSound[kSoundMAX];
 
+	/** Function pointer type for a section handler. */
+	typedef bool (OnceUpon::*SectionFunc)();
+	/** Section handler function. */
+	static const SectionFunc kSectionFuncs[kSectionCount];
 
 	// -- General helpers --
 
@@ -219,6 +223,11 @@ private:
 	/** Clear the ingame menu in an animated way. */
 	void clearIngameMenu(const Surface &background);
 
+	/** Handle the whole ingame menu. */
+	MenuAction doIngameMenu();
+	/** Handle the whole ingame menu if ESC or right mouse button was pressed. */
+	MenuAction doIngameMenu(int16 key, MouseButtons mouseButtons);
+
 
 	// -- Menu button helpers --
 
@@ -243,6 +252,26 @@ private:
 	/** Play / Display the name of an animal in one language. */
 	void anPlayAnimalName(const Common::String &animal, uint language);
 
+	// -- Game sections --
+
+	bool playSection();
+
+	bool sectionStork();
+	bool sectionChapter1();
+	bool section02();
+	bool sectionChapter2();
+	bool section04();
+	bool sectionChapter3();
+	bool section06();
+	bool sectionChapter4();
+	bool section08();
+	bool sectionChapter5();
+	bool section10();
+	bool sectionChapter6();
+	bool section12();
+	bool sectionChapter7();
+	bool sectionEnd();
+
 
 	/** Did we open the game archives? */
 	bool _openedArchives;
@@ -256,8 +285,10 @@ private:
 	/** The current palette. */
 	int _palette;
 
+	bool _quit; ///< Did the user request a normal game quit?
+
 	Difficulty _difficulty; ///< The current difficulty.
-	uint8      _section;    ///< The current game section.
+	int        _section;    ///< The current game section.
 };
 
 } // End of namespace OnceUpon


Commit: df18bc95834837f1f905bfe5613ffd43dfc908f9
    https://github.com/scummvm/scummvm/commit/df18bc95834837f1f905bfe5613ffd43dfc908f9
Author: Sven Hesse (drmccoy at users.sourceforge.net)
Date: 2012-07-29T16:44:44-07:00

Commit Message:
GOB: Implement parts of the Once Upon A Time end sequence

We don't yet support GCT files, so texts are still missing.

Changed paths:
    engines/gob/pregob/onceupon/onceupon.cpp
    engines/gob/pregob/onceupon/onceupon.h
    engines/gob/pregob/pregob.cpp
    engines/gob/pregob/pregob.h



diff --git a/engines/gob/pregob/onceupon/onceupon.cpp b/engines/gob/pregob/onceupon/onceupon.cpp
index fb96295..aed1b45 100644
--- a/engines/gob/pregob/onceupon/onceupon.cpp
+++ b/engines/gob/pregob/onceupon/onceupon.cpp
@@ -264,14 +264,6 @@ void OnceUpon::setGameCursor() {
 	setCursor(cursor, 105, 0, 120, 15, 0, 0);
 }
 
-void OnceUpon::setAnimState(ANIObject &ani, uint16 state, bool once, bool pause) const {
-	ani.setAnimation(state);
-	ani.setMode(once ? ANIObject::kModeOnce : ANIObject::kModeContinuous);
-	ani.setPause(pause);
-	ani.setVisible(true);
-	ani.setPosition();
-}
-
 void OnceUpon::drawLineByLine(const Surface &src, int16 left, int16 top, int16 right, int16 bottom,
                               int16 x, int16 y) const {
 
@@ -374,6 +366,18 @@ Common::String OnceUpon::fixString(const Common::String &str) const {
 	return str;
 }
 
+enum ClownAnimation {
+	kClownAnimationStand = 0,
+	kClownAnimationCheer = 1,
+	kClownAnimationCry   = 2
+};
+
+const PreGob::AnimProperties OnceUpon::kClownAnimations[] = {
+	{ 1, 0, ANIObject::kModeContinuous, true, false, false, 0, 0},
+	{ 0, 0, ANIObject::kModeOnce      , true, false, false, 0, 0},
+	{ 6, 0, ANIObject::kModeOnce      , true, false, false, 0, 0}
+};
+
 enum CopyProtectionState {
 	kCPStateSetup,     // Set up the screen
 	kCPStateWaitUser,  // Waiting for the user to pick a shape
@@ -392,8 +396,10 @@ bool OnceUpon::doCopyProtection(const uint8 colors[7], const uint8 shapes[7 * 20
 	_vm->_video->drawPackedSprite("grille2.cmp", sprites[1]);
 
 	// Load the clown animation
-	ANIFile   ani  (_vm, "grille.ani", 320);
-	ANIObject clown(ani);
+	ANIFile ani  (_vm, "grille.ani", 320);
+	ANIList anims;
+
+	loadAnims(anims, ani, 1, &kClownAnimations[kClownAnimationStand]);
 
 	// Set the copy protection cursor
 	setCursor(sprites[1], 5, 110, 20, 134, 3, 0);
@@ -406,20 +412,20 @@ bool OnceUpon::doCopyProtection(const uint8 colors[7], const uint8 shapes[7 * 20
 	bool  hasCorrect  = false;
 
 	while (!_vm->shouldQuit() && (state != kCPStateFinish)) {
-		clearAnim(clown);
+		clearAnim(anims);
 
 		// Set up the screen
 		if (state == kCPStateSetup) {
 			animalShape = cpSetup(colors, shapes, obfuscate, sprites);
 
-			setAnimState(clown, kClownAnimationClownStand, false, false);
+			setAnim(*anims[0], kClownAnimations[kClownAnimationStand]);
 			state = kCPStateWaitUser;
 		}
 
-		drawAnim(clown);
+		drawAnim(anims);
 
 		// If we're waiting for the clown and he finished, evaluate if we're finished
-		if (!clown.isVisible() && (state == kCPStateWaitClown))
+		if (!anims[0]->isVisible() && (state == kCPStateWaitClown))
 			state = (hasCorrect || (--triesLeft == 0)) ? kCPStateFinish : kCPStateSetup;
 
 		showCursor();
@@ -443,12 +449,14 @@ bool OnceUpon::doCopyProtection(const uint8 colors[7], const uint8 shapes[7 * 20
 				hasCorrect  = guessedShape == animalShape;
 				animalShape = -1;
 
-				setAnimState(clown, hasCorrect ? kClownAnimationClownCheer : kClownAnimationClownCry, true, false);
+				setAnim(*anims[0], kClownAnimations[hasCorrect ? kClownAnimationCheer : kClownAnimationCry]);
 				state = kCPStateWaitClown;
 			}
 		}
 	}
 
+	freeAnims(anims);
+
 	fadeOut();
 	hideCursor();
 	clearScreen();
@@ -625,6 +633,10 @@ void OnceUpon::showQuote() {
 	fadeOut();
 }
 
+const PreGob::AnimProperties OnceUpon::kTitleAnimation = {
+	8, 0, ANIObject::kModeContinuous, true, false, false, 0, 0
+};
+
 void OnceUpon::showTitle() {
 	// Show the Once Upon A Time title animation
 	// NOTE: This is currently only a mock-up. The real animation is in "ville.seq".
@@ -639,15 +651,15 @@ void OnceUpon::showTitle() {
 	_vm->_video->drawPackedSprite("ville.cmp", *_vm->_draw->_backSurface);
 	_vm->_draw->forceBlit();
 
-	ANIFile   ani  (_vm, "pres.ani", 320);
-	ANIObject title(ani);
+	ANIFile ani  (_vm, "pres.ani", 320);
+	ANIList anims;
 
-	setAnimState(title, 8, false, false);
+	loadAnims(anims, ani, 1, &kTitleAnimation);
 
 	playTitleMusic();
 
 	while (!_vm->shouldQuit()) {
-		redrawAnim(title);
+		redrawAnim(anims);
 
 		fadeIn();
 
@@ -657,6 +669,8 @@ void OnceUpon::showTitle() {
 			break;
 	}
 
+	freeAnims(anims);
+
 	fadeOut();
 	stopTitleMusic();
 }
@@ -1349,9 +1363,58 @@ bool OnceUpon::sectionChapter7() {
 	return true;
 }
 
+const PreGob::AnimProperties OnceUpon::kSectionEndAnimations[] = {
+	{ 0, 0, ANIObject::kModeContinuous, true, false, false, 0, 0},
+	{ 6, 0, ANIObject::kModeContinuous, true, false, false, 0, 0},
+	{ 9, 0, ANIObject::kModeContinuous, true, false, false, 0, 0},
+	{11, 0, ANIObject::kModeContinuous, true, false, false, 0, 0}
+};
+
 bool OnceUpon::sectionEnd() {
-	warning("OnceUpon::sectionEnd(): TODO");
+	fadeOut();
+	setGamePalette(9);
+
+	_vm->_video->drawPackedSprite("cadre.cmp", *_vm->_draw->_backSurface);
+
+	Surface endBackground(320, 200, 1);
+	_vm->_video->drawPackedSprite("fin.cmp", endBackground);
+
+	_vm->_draw->_backSurface->blit(endBackground, 0, 0, 288, 137, 16, 50);
+
+	ANIFile ani(_vm, "fin.ani", 320);
+	ANIList anims;
+
+	loadAnims(anims, ani, ARRAYSIZE(kSectionEndAnimations), kSectionEndAnimations);
+	drawAnim(anims);
+
+	_vm->_draw->forceBlit();
+
+	MenuAction action = kMenuActionNone;
+	while (!_vm->shouldQuit() && (action == kMenuActionNone)) {
+		redrawAnim(anims);
+
+		fadeIn();
+
+		endFrame(true);
+
+		int16 mouseX, mouseY;
+		MouseButtons mouseButtons;
+
+		int16 key = checkInput(mouseX, mouseY, mouseButtons);
+		if ((key != 0) && (key != kKeyEscape))
+			// Any key pressed => Quit
+			action = kMenuActionQuit;
+
+		action = doIngameMenu(key, mouseButtons);
+	}
+
+	freeAnims(anims);
+
+	// Restart requested
+	if (action == kMenuActionRestart)
+		return false;
 
+	// Last scene. Even if we didn't explicitly request a quit, the game ends here
 	_quit = true;
 	return false;
 }
diff --git a/engines/gob/pregob/onceupon/onceupon.h b/engines/gob/pregob/onceupon/onceupon.h
index 0cae369..caaf155 100644
--- a/engines/gob/pregob/onceupon/onceupon.h
+++ b/engines/gob/pregob/onceupon/onceupon.h
@@ -149,19 +149,23 @@ private:
 	/** All general game sounds we know about. */
 	static const char *kSound[kSoundMAX];
 
+
+	static const AnimProperties kClownAnimations[];
+	static const AnimProperties kTitleAnimation;
+	static const AnimProperties kSectionEndAnimations[];
+
+
 	/** Function pointer type for a section handler. */
 	typedef bool (OnceUpon::*SectionFunc)();
 	/** Section handler function. */
 	static const SectionFunc kSectionFuncs[kSectionCount];
 
+
 	// -- General helpers --
 
 	void setGamePalette(uint palette); ///< Set a game palette.
 	void setGameCursor();              ///< Set the default game cursor.
 
-	/** Set the state of an ANIObject. */
-	void setAnimState(ANIObject &ani, uint16 state, bool once, bool pause) const;
-
 	/** Draw this sprite in a fancy, animated line-by-line way. */
 	void drawLineByLine(const Surface &src, int16 left, int16 top, int16 right, int16 bottom,
 	                    int16 x, int16 y) const;
diff --git a/engines/gob/pregob/pregob.cpp b/engines/gob/pregob/pregob.cpp
index 6759580..4ee5430 100644
--- a/engines/gob/pregob/pregob.cpp
+++ b/engines/gob/pregob/pregob.cpp
@@ -251,24 +251,70 @@ bool PreGob::hasInput() {
 	return checkInput(mouseX, mouseY, mouseButtons) || (mouseButtons != kMouseButtonsNone);
 }
 
-void PreGob::clearAnim(ANIObject &ani) {
+void PreGob::clearAnim(ANIObject &anim) {
 	int16 left, top, right, bottom;
 
-	if (ani.clear(*_vm->_draw->_backSurface, left, top, right, bottom))
+	if (anim.clear(*_vm->_draw->_backSurface, left, top, right, bottom))
 		_vm->_draw->dirtiedRect(_vm->_draw->_backSurface, left, top, right, bottom);
 }
 
-void PreGob::drawAnim(ANIObject &ani) {
+void PreGob::drawAnim(ANIObject &anim) {
 	int16 left, top, right, bottom;
 
-	if (ani.draw(*_vm->_draw->_backSurface, left, top, right, bottom))
+	if (anim.draw(*_vm->_draw->_backSurface, left, top, right, bottom))
 		_vm->_draw->dirtiedRect(_vm->_draw->_backSurface, left, top, right, bottom);
-	ani.advance();
+	anim.advance();
 }
 
-void PreGob::redrawAnim(ANIObject &ani) {
-	clearAnim(ani);
-	drawAnim(ani);
+void PreGob::redrawAnim(ANIObject &anim) {
+	clearAnim(anim);
+	drawAnim(anim);
+}
+
+void PreGob::clearAnim(const ANIList &anims) {
+	for (int i = (anims.size() - 1); i >= 0; i--)
+		clearAnim(*anims[i]);
+}
+
+void PreGob::drawAnim(const ANIList &anims) {
+	for (ANIList::const_iterator a = anims.begin(); a != anims.end(); ++a)
+		drawAnim(**a);
+}
+
+void PreGob::redrawAnim(const ANIList &anims) {
+	clearAnim(anims);
+	drawAnim(anims);
+}
+
+void PreGob::loadAnims(ANIList &anims, ANIFile &ani, uint count, const AnimProperties *props) const {
+	freeAnims(anims);
+
+	anims.resize(count);
+	for (uint i = 0; i < count; i++) {
+		anims[i] = new ANIObject(ani);
+
+		setAnim(*anims[i], props[i]);
+	}
+}
+
+void PreGob::freeAnims(ANIList &anims) const {
+	for (ANIList::iterator a = anims.begin(); a != anims.end(); ++a)
+		delete *a;
+
+	anims.clear();
+}
+
+void PreGob::setAnim(ANIObject &anim, const AnimProperties &props) const {
+	anim.setAnimation(props.animation);
+	anim.setFrame(props.frame);
+	anim.setMode(props.mode);
+	anim.setPause(props.paused);
+	anim.setVisible(props.visible);
+
+	if (props.hasPosition)
+		anim.setPosition(props.x, props.y);
+	else
+		anim.setPosition();
 }
 
 Common::String PreGob::getLocFile(const Common::String &file) const {
diff --git a/engines/gob/pregob/pregob.h b/engines/gob/pregob/pregob.h
index e62a590..f172803 100644
--- a/engines/gob/pregob/pregob.h
+++ b/engines/gob/pregob/pregob.h
@@ -27,6 +27,7 @@
 #include "common/array.h"
 
 #include "gob/util.h"
+#include "gob/aniobject.h"
 
 #include "gob/sound/sounddesc.h"
 
@@ -37,8 +38,6 @@ namespace Gob {
 class GobEngine;
 class Surface;
 
-class ANIObject;
-
 class PreGob {
 public:
 	PreGob(GobEngine *vm);
@@ -46,7 +45,23 @@ public:
 
 	virtual void run() = 0;
 
+	struct AnimProperties {
+		uint16 animation;
+		uint16 frame;
+
+		ANIObject::Mode mode;
+
+		bool visible;
+		bool paused;
+
+		bool hasPosition;
+		int16 x;
+		int16 y;
+	};
+
 protected:
+	typedef Common::Array<ANIObject *> ANIList;
+
 	static const char  kLanguageSuffixShort[5];
 	static const char *kLanguageSuffixLong [5];
 
@@ -88,11 +103,23 @@ protected:
 	bool isCursorVisible() const;
 
 	/** Remove an animation from the screen. */
-	void clearAnim(ANIObject &ani);
+	void clearAnim(ANIObject &anim);
 	/** Draw an animation to the screen, advancing it. */
-	void drawAnim(ANIObject &ani);
+	void drawAnim(ANIObject &anim);
 	/** Clear and draw an animation to the screen, advancing it. */
-	void redrawAnim(ANIObject &ani);
+	void redrawAnim(ANIObject &anim);
+
+	/** Remove animations from the screen. */
+	void clearAnim(const ANIList &anims);
+	/** Draw animations to the screen, advancing them. */
+	void drawAnim(const ANIList &anims);
+	/** Clear and draw animations to the screen, advancing them. */
+	void redrawAnim(const ANIList &anims);
+
+	void loadAnims(ANIList &anims, ANIFile &ani, uint count, const AnimProperties *props) const;
+	void freeAnims(ANIList &anims) const;
+
+	void setAnim(ANIObject &anim, const AnimProperties &props) const;
 
 	/** Wait for the frame to end, handling screen updates and optionally update input. */
 	void endFrame(bool doInput);


Commit: a547633911afa31964c10ed0222410aa9e66db80
    https://github.com/scummvm/scummvm/commit/a547633911afa31964c10ed0222410aa9e66db80
Author: Sven Hesse (drmccoy at users.sourceforge.net)
Date: 2012-07-29T16:44:44-07:00

Commit Message:
GOB: ANIObject can now predict the position/size of future frames

Changed paths:
    engines/gob/aniobject.cpp
    engines/gob/aniobject.h



diff --git a/engines/gob/aniobject.cpp b/engines/gob/aniobject.cpp
index 8d3a689..7e3668a 100644
--- a/engines/gob/aniobject.cpp
+++ b/engines/gob/aniobject.cpp
@@ -101,7 +101,7 @@ void ANIObject::getPosition(int16 &x, int16 &y) const {
 	y = _y;
 }
 
-void ANIObject::getFramePosition(int16 &x, int16 &y) const {
+void ANIObject::getFramePosition(int16 &x, int16 &y, uint16 n) const {
 	// CMP "animations" have no specific frame positions
 	if (_cmp) {
 		getPosition(x, y);
@@ -115,11 +115,24 @@ void ANIObject::getFramePosition(int16 &x, int16 &y) const {
 	if (_frame >= animation.frameCount)
 		return;
 
-	x = _x + animation.frameAreas[_frame].left;
-	y = _y + animation.frameAreas[_frame].top;
+	// If we're paused, we don't advance any frames
+	if (_paused)
+		n = 0;
+
+	// Number of cycles run through after n frames
+	uint16 cycles = (_frame + n) / animation.frameCount;
+	// Frame position after n frames
+	uint16 frame  = (_frame + n) % animation.frameCount;
+
+	// Only doing one cycle?
+	if (_mode == kModeOnce)
+		cycles = MAX<uint16>(cycles, 1);
+
+	x = _x + animation.frameAreas[frame].left + cycles * animation.deltaX;
+	y = _y + animation.frameAreas[frame].top  + cycles * animation.deltaY;
 }
 
-void ANIObject::getFrameSize(int16 &width, int16 &height) const {
+void ANIObject::getFrameSize(int16 &width, int16 &height, uint16 n) const {
 	if (_cmp) {
 		width  = _cmp->getWidth (_animation);
 		height = _cmp->getHeight(_animation);
@@ -134,8 +147,15 @@ void ANIObject::getFrameSize(int16 &width, int16 &height) const {
 	if (_frame >= animation.frameCount)
 		return;
 
-	width  = animation.frameAreas[_frame].right  - animation.frameAreas[_frame].left + 1;
-	height = animation.frameAreas[_frame].bottom - animation.frameAreas[_frame].top  + 1;
+	// If we're paused, we don't advance any frames
+	if (_paused)
+		n = 0;
+
+	// Frame position after n frames
+	uint16 frame = (_frame + n) % animation.frameCount;
+
+	width  = animation.frameAreas[frame].right  - animation.frameAreas[frame].left + 1;
+	height = animation.frameAreas[frame].bottom - animation.frameAreas[frame].top  + 1;
 }
 
 bool ANIObject::isIn(int16 x, int16 y) const {
diff --git a/engines/gob/aniobject.h b/engines/gob/aniobject.h
index 3c374f7..d8c8edc 100644
--- a/engines/gob/aniobject.h
+++ b/engines/gob/aniobject.h
@@ -70,10 +70,10 @@ public:
 	/** Return the current position. */
 	void getPosition(int16 &x, int16 &y) const;
 
-	/** Return the current frame position. */
-	void getFramePosition(int16 &x, int16 &y) const;
-	/** Return the current frame size. */
-	void getFrameSize(int16 &width, int16 &height) const;
+	/** Return the frame position after another n frames. */
+	void getFramePosition(int16 &x, int16 &y, uint16 n = 0) const;
+	/** Return the current frame size after another n frames. */
+	void getFrameSize(int16 &width, int16 &height, uint16 n = 0) const;
 
 	/** Are there coordinates within the animation sprite? */
 	bool isIn(int16 x, int16 y) const;


Commit: 0b030dd341b00007b969805ff6d488a51a1a97c7
    https://github.com/scummvm/scummvm/commit/0b030dd341b00007b969805ff6d488a51a1a97c7
Author: Sven Hesse (drmccoy at users.sourceforge.net)
Date: 2012-07-29T16:44:45-07:00

Commit Message:
GOB: Implement parts of the Stork section in Once Upon A Time

No GCT texts yet ("The stork is bringing a sweet baby to $PLACE
where $PEOPLE live"), and the character creator is also still
missing.

Changed paths:
  A engines/gob/pregob/onceupon/stork.cpp
  A engines/gob/pregob/onceupon/stork.h
    engines/gob/module.mk
    engines/gob/pregob/onceupon/abracadabra.cpp
    engines/gob/pregob/onceupon/abracadabra.h
    engines/gob/pregob/onceupon/babayaga.cpp
    engines/gob/pregob/onceupon/babayaga.h
    engines/gob/pregob/onceupon/brokenstrings.h
    engines/gob/pregob/onceupon/onceupon.cpp
    engines/gob/pregob/onceupon/onceupon.h



diff --git a/engines/gob/module.mk b/engines/gob/module.mk
index f8b477b..1b3f400 100644
--- a/engines/gob/module.mk
+++ b/engines/gob/module.mk
@@ -83,6 +83,7 @@ MODULE_OBJS := \
 	pregob/onceupon/onceupon.o \
 	pregob/onceupon/abracadabra.o \
 	pregob/onceupon/babayaga.o \
+	pregob/onceupon/stork.o \
 	minigames/geisha/evilfish.o \
 	minigames/geisha/oko.o \
 	minigames/geisha/meter.o \
diff --git a/engines/gob/pregob/onceupon/abracadabra.cpp b/engines/gob/pregob/onceupon/abracadabra.cpp
index 2e4b5f2..0d644d9 100644
--- a/engines/gob/pregob/onceupon/abracadabra.cpp
+++ b/engines/gob/pregob/onceupon/abracadabra.cpp
@@ -78,6 +78,27 @@ const char *Abracadabra::kAnimalNames[] = {
 	"scor"
 };
 
+// The houses where the stork can drop a bundle
+const OnceUpon::MenuButton Abracadabra::kStorkHouses[] = {
+	{false,  16,  80,  87, 125, 0, 0, 0, 0, 0, 0, 0},
+	{false,  61, 123,  96, 149, 0, 0, 0, 0, 0, 0, 1},
+	{false, 199, 118, 226, 137, 0, 0, 0, 0, 0, 0, 2},
+	{false, 229,  91, 304, 188, 0, 0, 0, 0, 0, 0, 3}
+};
+
+// The stork bundle drop parameters
+const Stork::BundleDrop Abracadabra::kStorkBundleDrops[] = {
+	{ 14,  65, 127,  true },
+	{ 14,  76, 152,  true },
+	{ 14, 204, 137,  true },
+	{ 11, 275, 179, false }
+};
+
+// Parameters for the stork section.
+const OnceUpon::StorkParam Abracadabra::kStorkParam = {
+	"present.cmp", ARRAYSIZE(kStorkHouses), kStorkHouses, kStorkBundleDrops
+};
+
 
 Abracadabra::Abracadabra(GobEngine *vm) : OnceUpon(vm) {
 }
@@ -107,6 +128,10 @@ void Abracadabra::run() {
 	playGame();
 }
 
+const OnceUpon::StorkParam &Abracadabra::getStorkParameters() const {
+	return kStorkParam;
+}
+
 } // End of namespace OnceUpon
 
 } // End of namespace Gob
diff --git a/engines/gob/pregob/onceupon/abracadabra.h b/engines/gob/pregob/onceupon/abracadabra.h
index f2075fc..8048213 100644
--- a/engines/gob/pregob/onceupon/abracadabra.h
+++ b/engines/gob/pregob/onceupon/abracadabra.h
@@ -36,6 +36,9 @@ public:
 
 	void run();
 
+protected:
+	const StorkParam &getStorkParameters() const;
+
 private:
 	/** Definition of the menu button that leads to the animal names screen. */
 	static const MenuButton kAnimalsButtons;
@@ -44,6 +47,11 @@ private:
 	static const MenuButton kAnimalButtons[];
 	/** File prefixes for the name of each animal. */
 	static const char *kAnimalNames[];
+
+	// Parameters for the stork section.
+	static const MenuButton kStorkHouses[];
+	static const Stork::BundleDrop kStorkBundleDrops[];
+	static const struct StorkParam kStorkParam;
 };
 
 } // End of namespace OnceUpon
diff --git a/engines/gob/pregob/onceupon/babayaga.cpp b/engines/gob/pregob/onceupon/babayaga.cpp
index 6f27f46..6aa6031 100644
--- a/engines/gob/pregob/onceupon/babayaga.cpp
+++ b/engines/gob/pregob/onceupon/babayaga.cpp
@@ -78,6 +78,27 @@ const char *BabaYaga::kAnimalNames[] = {
 	"rena"
 };
 
+// The houses where the stork can drop a bundle
+const OnceUpon::MenuButton BabaYaga::kStorkHouses[] = {
+	{false,  16,  80,  87, 125, 0, 0, 0, 0, 0, 0, 0},
+	{false,  61, 123,  96, 149, 0, 0, 0, 0, 0, 0, 1},
+	{false, 199, 118, 226, 137, 0, 0, 0, 0, 0, 0, 2},
+	{false, 229,  91, 304, 188, 0, 0, 0, 0, 0, 0, 3}
+};
+
+// The stork bundle drop parameters
+const Stork::BundleDrop BabaYaga::kStorkBundleDrops[] = {
+	{ 14,  35, 129,  true },
+	{ 14,  70, 148,  true },
+	{ 14, 206, 136,  true },
+	{ 11, 260, 225, false }
+};
+
+// Parameters for the stork section.
+const OnceUpon::StorkParam BabaYaga::kStorkParam = {
+	"present2.cmp", ARRAYSIZE(kStorkHouses), kStorkHouses, kStorkBundleDrops
+};
+
 
 BabaYaga::BabaYaga(GobEngine *vm) : OnceUpon(vm) {
 }
@@ -107,6 +128,10 @@ void BabaYaga::run() {
 	playGame();
 }
 
+const OnceUpon::StorkParam &BabaYaga::getStorkParameters() const {
+	return kStorkParam;
+}
+
 } // End of namespace OnceUpon
 
 } // End of namespace Gob
diff --git a/engines/gob/pregob/onceupon/babayaga.h b/engines/gob/pregob/onceupon/babayaga.h
index 181b6f4..0241f78 100644
--- a/engines/gob/pregob/onceupon/babayaga.h
+++ b/engines/gob/pregob/onceupon/babayaga.h
@@ -36,6 +36,9 @@ public:
 
 	void run();
 
+protected:
+	const StorkParam &getStorkParameters() const;
+
 private:
 	/** Definition of the menu button that leads to the animal names screen. */
 	static const MenuButton kAnimalsButtons;
@@ -44,6 +47,11 @@ private:
 	static const MenuButton kAnimalButtons[];
 	/** File prefixes for the name of each animal. */
 	static const char *kAnimalNames[];
+
+	// Parameters for the stork section.
+	static const MenuButton kStorkHouses[];
+	static const Stork::BundleDrop kStorkBundleDrops[];
+	static const struct StorkParam kStorkParam;
 };
 
 } // End of namespace OnceUpon
diff --git a/engines/gob/pregob/onceupon/brokenstrings.h b/engines/gob/pregob/onceupon/brokenstrings.h
index 0a40493..89acb1c 100644
--- a/engines/gob/pregob/onceupon/brokenstrings.h
+++ b/engines/gob/pregob/onceupon/brokenstrings.h
@@ -45,7 +45,8 @@ static const BrokenString kBrokenStringsGerman[] = {
 	{ "Am Waldesrand es sieht"       , "Am Waldesrand sieht es"       },
 	{ " das Kind den Palast."        , "das Kind den Palast."         },
 	{ "Am Waldessaum sieht"          , "Am Waldesrand sieht"          },
-	{ "tipp auf ESC!"                , "dr\201cke ESC!"               }
+	{ "tipp auf ESC!"                , "dr\201cke ESC!"               },
+	{ "Wohin fliegt der Drachen?"    , "Wohin fliegt der Drache?"     }
 };
 
 static const BrokenStringLanguage kBrokenStrings[kLanguageCount] = {
diff --git a/engines/gob/pregob/onceupon/onceupon.cpp b/engines/gob/pregob/onceupon/onceupon.cpp
index aed1b45..aa08f6f 100644
--- a/engines/gob/pregob/onceupon/onceupon.cpp
+++ b/engines/gob/pregob/onceupon/onceupon.cpp
@@ -128,7 +128,8 @@ const OnceUpon::MenuButton OnceUpon::kLanguageButtons[] = {
 };
 
 const char *OnceUpon::kSound[kSoundMAX] = {
-	"diamant.snd"
+	"diamant.snd", // kSoundClick
+	"cigogne.snd"  // kSoundStork
 };
 
 const OnceUpon::SectionFunc OnceUpon::kSectionFuncs[kSectionCount] = {
@@ -1293,9 +1294,128 @@ bool OnceUpon::playSection() {
 	return (this->*kSectionFuncs[_section])();
 }
 
+const PreGob::AnimProperties OnceUpon::kSectionStorkAnimations[] = {
+	{ 0, 0, ANIObject::kModeContinuous, true, false, false, 0, 0},
+	{ 1, 0, ANIObject::kModeContinuous, true, false, false, 0, 0},
+	{ 2, 0, ANIObject::kModeContinuous, true, false, false, 0, 0},
+	{ 3, 0, ANIObject::kModeContinuous, true, false, false, 0, 0},
+	{ 4, 0, ANIObject::kModeContinuous, true, false, false, 0, 0},
+	{ 5, 0, ANIObject::kModeContinuous, true, false, false, 0, 0},
+	{ 6, 0, ANIObject::kModeContinuous, true, false, false, 0, 0},
+	{ 7, 0, ANIObject::kModeContinuous, true, false, false, 0, 0},
+	{ 8, 0, ANIObject::kModeContinuous, true, false, false, 0, 0},
+	{17, 0, ANIObject::kModeContinuous, true, false, false, 0, 0},
+	{16, 0, ANIObject::kModeContinuous, true, false, false, 0, 0},
+	{15, 0, ANIObject::kModeContinuous, true, false, false, 0, 0}
+};
+
+enum StorkState {
+	kStorkStateWaitUser,
+	kStorkStateWaitBundle,
+	kStorkStateFinish
+};
+
 bool OnceUpon::sectionStork() {
 	warning("OnceUpon::sectionStork(): TODO");
-	return true;
+
+	fadeOut();
+	hideCursor();
+	setGamePalette(0);
+	setGameCursor();
+
+	const StorkParam &param = getStorkParameters();
+
+	Surface backdrop(320, 200, 1);
+
+	// Draw the frame
+	_vm->_video->drawPackedSprite("cadre.cmp", *_vm->_draw->_backSurface);
+
+	// Draw the backdrop
+	_vm->_video->drawPackedSprite(param.backdrop, backdrop);
+	_vm->_draw->_backSurface->blit(backdrop, 0, 0, 288, 175, 16, 12);
+
+	// "Where does the stork go?"
+	TXTFile *whereStork = loadTXT(getLocFile("ouva.tx"), TXTFile::kFormatStringPositionColor);
+	whereStork->draw(*_vm->_draw->_backSurface, &_plettre, 1);
+
+	ANIFile ani(_vm, "present.ani", 320);
+	ANIList anims;
+
+	Stork *stork = new Stork(_vm, ani);
+
+	loadAnims(anims, ani, ARRAYSIZE(kSectionStorkAnimations), kSectionStorkAnimations);
+	anims.push_back(stork);
+
+	drawAnim(anims);
+
+	_vm->_draw->forceBlit();
+
+	int8 storkSoundWait = 0;
+
+	StorkState state  = kStorkStateWaitUser;
+	MenuAction action = kMenuActionNone;
+	while (!_vm->shouldQuit() && (state != kStorkStateFinish)) {
+		clearAnim(anims);
+
+		// Play the stork sound
+		if (--storkSoundWait == 0)
+			playSound(kSoundStork);
+		if (storkSoundWait <= 0)
+			storkSoundWait = 50 - _vm->_util->getRandom(30);
+
+		// Check if the bundle landed
+		if ((state == kStorkStateWaitBundle) && stork->hasBundleLanded())
+			state = kStorkStateFinish;
+
+		// Check user input
+
+		int16 mouseX, mouseY;
+		MouseButtons mouseButtons;
+
+		int16 key = checkInput(mouseX, mouseY, mouseButtons);
+
+		action = doIngameMenu(key, mouseButtons);
+		if (action != kMenuActionNone) {
+			state = kStorkStateFinish;
+			break;
+		}
+
+		if (mouseButtons == kMouseButtonsLeft) {
+			stopSound();
+			playSound(kSoundClick);
+
+			int house = checkButton(param.houses, param.houseCount, mouseX, mouseY);
+			if ((state == kStorkStateWaitUser) && (house >= 0)) {
+
+				stork->dropBundle(param.drops[house]);
+				state = kStorkStateWaitBundle;
+
+				// Remove the "Where does the stork go?" text
+				int16 left, top, right, bottom;
+				if (whereStork->clear(*_vm->_draw->_backSurface, left, top, right, bottom))
+					_vm->_draw->dirtiedRect(_vm->_draw->_backSurface, left, top, right, bottom);
+			}
+		}
+
+		drawAnim(anims);
+		showCursor();
+		fadeIn();
+
+		endFrame(true);
+	}
+
+	freeAnims(anims);
+	delete whereStork;
+
+	fadeOut();
+	hideCursor();
+
+	// Completed the section => move one
+	if (action == kMenuActionNone)
+		return true;
+
+	// Didn't complete the section
+	return false;
 }
 
 bool OnceUpon::sectionChapter1() {
diff --git a/engines/gob/pregob/onceupon/onceupon.h b/engines/gob/pregob/onceupon/onceupon.h
index caaf155..b9aef04 100644
--- a/engines/gob/pregob/onceupon/onceupon.h
+++ b/engines/gob/pregob/onceupon/onceupon.h
@@ -27,6 +27,8 @@
 
 #include "gob/pregob/pregob.h"
 
+#include "gob/pregob/onceupon/stork.h"
+
 namespace Gob {
 
 class Surface;
@@ -67,6 +69,15 @@ protected:
 		uint id; ///< The button's ID.
 	};
 
+	/** Parameters for the stork section. */
+	struct StorkParam {
+		const char *backdrop; ///< Backdrop image file.
+
+		uint  houseCount;         ///< Number of houses.
+		const MenuButton *houses; ///< House button definitions.
+
+		const Stork::BundleDrop *drops; ///< The bundle drop parameters.
+	};
 
 	void init();
 	void deinit();
@@ -97,6 +108,10 @@ protected:
 	void playGame();
 
 
+	/** Return the parameters for the stork section. */
+	virtual const StorkParam &getStorkParameters() const = 0;
+
+
 private:
 	/** All actions a user can request in a menu. */
 	enum MenuAction {
@@ -119,6 +134,7 @@ private:
 	/** The different sounds common in the game. */
 	enum Sound {
 		kSoundClick = 0,
+		kSoundStork    ,
 		kSoundMAX
 	};
 
@@ -146,12 +162,15 @@ private:
 	static const MenuButton kAnimalNamesBack;   ///< "Back" button in the animal names screens.
 	static const MenuButton kLanguageButtons[]; ///< Language buttons in the animal names screen.
 
+	static const MenuButton kSectionStorkHouses[];
+
 	/** All general game sounds we know about. */
 	static const char *kSound[kSoundMAX];
 
 
 	static const AnimProperties kClownAnimations[];
 	static const AnimProperties kTitleAnimation;
+	static const AnimProperties kSectionStorkAnimations[];
 	static const AnimProperties kSectionEndAnimations[];
 
 
diff --git a/engines/gob/pregob/onceupon/stork.cpp b/engines/gob/pregob/onceupon/stork.cpp
new file mode 100644
index 0000000..3c38037
--- /dev/null
+++ b/engines/gob/pregob/onceupon/stork.cpp
@@ -0,0 +1,234 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "common/str.h"
+
+#include "gob/gob.h"
+#include "gob/surface.h"
+#include "gob/anifile.h"
+#include "gob/video.h"
+
+#include "gob/pregob/onceupon/stork.h"
+
+enum Animation {
+	kAnimFlyNearWithBundle    =  9,
+	kAnimFlyFarWithBundle     = 12,
+	kAnimFlyNearWithoutBundle = 10,
+	kAnimFlyFarWithoutBundle  = 13,
+	kAnimBundleNear           = 11,
+	kAnimBundleFar            = 14
+};
+
+namespace Gob {
+
+namespace OnceUpon {
+
+Stork::Stork(GobEngine *vm, const ANIFile &ani) : ANIObject(ani), _shouldDrop(false) {
+	_frame = new Surface(320, 200, 1);
+	vm->_video->drawPackedSprite("cadre.cmp", *_frame);
+
+	_bundle = new ANIObject(ani);
+
+	_bundle->setVisible(false);
+	_bundle->setPause(true);
+
+	setState(kStateFlyNearWithBundle, kAnimFlyNearWithBundle, -80);
+}
+
+Stork::~Stork() {
+	delete _frame;
+
+	delete _bundle;
+}
+
+bool Stork::hasBundleLanded() const {
+	if (!_shouldDrop || !_bundle->isVisible() || _bundle->isPaused())
+		return false;
+
+	int16 x, y, width, height;
+	_bundle->getFramePosition(x, y);
+	_bundle->getFrameSize(width, height);
+
+	return (y + height) >= _bundleDrop.landY;
+}
+
+void Stork::dropBundle(const BundleDrop &drop) {
+	if (_shouldDrop)
+		return;
+
+	_shouldDrop = true;
+	_bundleDrop = drop;
+}
+
+bool Stork::draw(Surface &dest, int16 &left, int16 &top, int16 &right, int16 &bottom) {
+	left   = 0x7FFF;
+	top    = 0x7FFF;
+	right  = 0x0000;
+	bottom = 0x0000;
+
+	bool drawn = ANIObject::draw(dest, left, top, right, bottom);
+	if (drawn) {
+		// Left frame edge
+		if (left <= 15)
+			dest.blit(*_frame, left, top, MIN<int16>(15, right), bottom, left, top);
+
+		// Right frame edge
+		if (right >= 304)
+			dest.blit(*_frame, MAX<int16>(304, left), top, right, bottom, MAX<int16>(304, left), top);
+	}
+
+	int16 bLeft, bTop, bRight, bBottom;
+	if (_bundle->draw(dest, bLeft, bTop, bRight, bBottom)) {
+		// Bottom frame edge
+		if (bBottom >= 188)
+			dest.blit(*_frame, bLeft, MAX<int16>(188, bTop), bRight, bBottom, bLeft, MAX<int16>(188, bTop));
+
+		left   = MIN(left  , bLeft  );
+		top    = MIN(top   , bTop   );
+		right  = MAX(right , bRight );
+		bottom = MAX(bottom, bBottom);
+
+		drawn = true;
+	}
+
+	return drawn;
+}
+
+bool Stork::clear(Surface &dest, int16 &left, int16 &top, int16 &right, int16 &bottom) {
+	left   = 0x7FFF;
+	top    = 0x7FFF;
+	right  = 0x0000;
+	bottom = 0x0000;
+
+	bool cleared = _bundle->clear(dest, left, top, right, bottom);
+
+	int16 sLeft, sTop, sRight, sBottom;
+	if (ANIObject::clear(dest, sLeft, sTop, sRight, sBottom)) {
+		left   = MIN(left  , sLeft  );
+		top    = MIN(top   , sTop   );
+		right  = MAX(right , sRight );
+		bottom = MAX(bottom, sBottom);
+
+		cleared = true;
+	}
+
+	return cleared;
+}
+
+void Stork::advance() {
+	_bundle->advance();
+
+	ANIObject::advance();
+
+	int16 curX, curY, curWidth, curHeight;
+	getFramePosition(curX, curY, 0);
+	getFrameSize(curWidth, curHeight, 0);
+
+	const int16 curRight = curX + curWidth - 1;
+
+	int16 nextX, nextY, nextWidth, nextHeight;
+	getFramePosition(nextX, nextY, 1);
+	getFrameSize(nextWidth, nextHeight, 1);
+
+	const int16 nextRight = nextX + nextWidth - 1;
+
+	switch (_state) {
+	case kStateFlyNearWithBundle:
+		if (curX >= 330)
+			setState(kStateFlyFarWithBundle, kAnimFlyFarWithBundle, 330);
+
+		if ((curRight  <= _bundleDrop.dropX) &&
+		    (nextRight >= _bundleDrop.dropX) && _shouldDrop && !_bundleDrop.dropWhileFar)
+			dropBundle(kStateFlyNearWithoutBundle, kAnimFlyNearWithoutBundle);
+
+		break;
+
+	case kStateFlyFarWithBundle:
+		if (curX <= -80)
+			setState(kStateFlyNearWithBundle, kAnimFlyNearWithBundle, -80);
+
+		if ((curX  >= _bundleDrop.dropX) &&
+		    (nextX <= _bundleDrop.dropX) && _shouldDrop && _bundleDrop.dropWhileFar)
+			dropBundle(kStateFlyFarWithoutBundle, kAnimFlyFarWithoutBundle);
+
+		break;
+
+	case kStateFlyNearWithoutBundle:
+		if (curX >= 330)
+			setState(kStateFlyFarWithoutBundle, kAnimFlyFarWithoutBundle, 330);
+		break;
+
+	case kStateFlyFarWithoutBundle:
+		if (curX <= -80)
+			setState(kStateFlyNearWithoutBundle, kAnimFlyNearWithoutBundle, -80);
+		break;
+
+	default:
+		break;
+	}
+}
+
+void Stork::dropBundle(State state, uint16 anim) {
+	setState(state, anim);
+
+	int16 x, y, width, height;
+	getFramePosition(x, y);
+	getFrameSize(width, height);
+
+	_bundle->setAnimation(_bundleDrop.anim);
+	_bundle->setPause(false);
+	_bundle->setVisible(true);
+
+	int16 bWidth, bHeight;
+	_bundle->getFrameSize(bWidth, bHeight);
+
+	// Drop position
+	x = _bundleDrop.dropX;
+	y = y + height - bHeight;
+
+	// If the stork is flying near (from left to right), drop the bundle at the right edge
+	if (!_bundleDrop.dropWhileFar)
+		x = x - bWidth;
+
+	_bundle->setPosition(x, y);
+}
+
+void Stork::setState(State state, uint16 anim) {
+	setAnimation(anim);
+	setVisible(true);
+	setPause(false);
+
+	_state = state;
+}
+
+void Stork::setState(State state, uint16 anim, int16 x) {
+	setState(state, anim);
+	setPosition();
+
+	int16 pX, pY;
+	getPosition(pX, pY);
+	setPosition( x, pY);
+}
+
+} // End of namespace OnceUpon
+
+} // End of namespace Gob
diff --git a/engines/gob/pregob/onceupon/stork.h b/engines/gob/pregob/onceupon/stork.h
new file mode 100644
index 0000000..d26a887
--- /dev/null
+++ b/engines/gob/pregob/onceupon/stork.h
@@ -0,0 +1,103 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef GOB_PREGOB_ONCEUPON_STORK_H
+#define GOB_PREGOB_ONCEUPON_STORK_H
+
+#include "common/system.h"
+
+#include "gob/aniobject.h"
+
+namespace Common {
+	class String;
+}
+
+namespace Gob {
+
+class GobEngine;
+
+class Surface;
+class ANIFile;
+
+namespace OnceUpon {
+
+/** The stork in Baba Yaga / dragon in Abracadabra. */
+class Stork : public ANIObject {
+public:
+	/** Information on how to drop the bundle. */
+	struct BundleDrop {
+		int16 anim; ///< Animation of the bundle floating down
+
+		int16 dropX; ///< X position the stork drops the bundle
+		int16 landY; ///< Y position the bundle lands
+
+		bool dropWhileFar; ///< Does the stork drop the bundle while far instead of near?
+	};
+
+	Stork(GobEngine *vm, const ANIFile &ani);
+	~Stork();
+
+	/** Has the bundle landed? */
+	bool hasBundleLanded() const;
+
+	/** Drop the bundle. */
+	void dropBundle(const BundleDrop &drop);
+
+	/** Draw the current frame onto the surface and return the affected rectangle. */
+	bool draw(Surface &dest, int16 &left, int16 &top, int16 &right, int16 &bottom);
+	/** Draw the current frame from the surface and return the affected rectangle. */
+	bool clear(Surface &dest, int16 &left, int16 &top, int16 &right, int16 &bottom);
+
+	/** Advance the animation to the next frame. */
+	void advance();
+
+private:
+	enum State {
+		kStateFlyNearWithBundle    = 0,
+		kStateFlyFarWithBundle       ,
+		kStateFlyNearWithoutBundle   ,
+		kStateFlyFarWithoutBundle
+	};
+
+
+	void setState(State state, uint16 anim);
+	void setState(State state, uint16 anim, int16 x);
+
+	void dropBundle(State state, uint16 anim);
+
+
+	GobEngine *_vm;
+
+	Surface   *_frame;
+	ANIObject *_bundle;
+
+	State _state;
+
+	bool       _shouldDrop;
+	BundleDrop _bundleDrop;
+};
+
+} // End of namespace OnceUpon
+
+} // End of namespace Gob
+
+#endif // GOB_PREGOB_ONCEUPON_STORK_H


Commit: e17d4a5c0c66b890014efa62d207406fd5b887ef
    https://github.com/scummvm/scummvm/commit/e17d4a5c0c66b890014efa62d207406fd5b887ef
Author: Sven Hesse (drmccoy at users.sourceforge.net)
Date: 2012-07-29T16:44:45-07:00

Commit Message:
GOB: Implement GCT drawing

Changed paths:
  A engines/gob/pregob/gctfile.cpp
  A engines/gob/pregob/gctfile.h
    engines/gob/module.mk
    engines/gob/pregob/pregob.cpp
    engines/gob/pregob/pregob.h



diff --git a/engines/gob/module.mk b/engines/gob/module.mk
index 1b3f400..1535184 100644
--- a/engines/gob/module.mk
+++ b/engines/gob/module.mk
@@ -80,6 +80,7 @@ MODULE_OBJS := \
 	detection/detection.o \
 	pregob/pregob.o \
 	pregob/txtfile.o \
+	pregob/gctfile.o \
 	pregob/onceupon/onceupon.o \
 	pregob/onceupon/abracadabra.o \
 	pregob/onceupon/babayaga.o \
diff --git a/engines/gob/pregob/gctfile.cpp b/engines/gob/pregob/gctfile.cpp
new file mode 100644
index 0000000..08c32cd
--- /dev/null
+++ b/engines/gob/pregob/gctfile.cpp
@@ -0,0 +1,306 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "common/random.h"
+#include "common/stream.h"
+
+#include "gob/surface.h"
+#include "gob/video.h"
+
+#include "gob/pregob/gctfile.h"
+
+namespace Gob {
+
+GCTFile::Chunk::Chunk() : type(kChunkTypeNone) {
+}
+
+
+GCTFile::GCTFile(Common::SeekableReadStream &gct, Common::RandomSource &rnd) : _rnd(&rnd),
+	_areaLeft(0), _areaTop(0), _areaRight(0), _areaBottom(0), _currentItem(0xFFFF) {
+
+	load(gct);
+}
+
+GCTFile::~GCTFile() {
+}
+
+void GCTFile::load(Common::SeekableReadStream &gct) {
+	gct.skip(4); // Required buffer size
+	gct.skip(2); // Unknown
+
+	// Read the selector and line counts for each item
+	const uint16 itemCount = gct.readUint16LE();
+	_items.resize(itemCount);
+
+	for (Items::iterator i = _items.begin(); i != _items.end(); ++i) {
+		const uint16 selector  = gct.readUint16LE();
+		const uint16 lineCount = gct.readUint16LE();
+
+		i->selector = selector;
+		i->lines.resize(lineCount);
+	}
+
+	// Read all item lines
+	for (Items::iterator i = _items.begin(); i != _items.end(); ++i) {
+		for (Lines::iterator l = i->lines.begin(); l != i->lines.end(); ++l) {
+			const uint16 lineSize = gct.readUint16LE();
+
+			readLine(gct, *l, lineSize);
+		}
+	}
+
+	if (gct.err())
+		error("GCTFile::load(): Failed reading GCT");
+}
+
+void GCTFile::readLine(Common::SeekableReadStream &gct, Line &line, uint16 lineSize) const {
+	line.chunks.push_back(Chunk());
+
+	while (lineSize > 0) {
+		byte c = gct.readByte();
+		lineSize--;
+
+		if (c == 0) {
+			// Command byte
+
+			if (lineSize == 0)
+				break;
+
+			byte cmd = gct.readByte();
+			lineSize--;
+
+			// Line end command
+			if (cmd == 0)
+				break;
+
+			// Item reference command
+			if (cmd == 1) {
+				if (lineSize < 2) {
+					warning("GCTFile::readLine(): Item reference command is missing parameters");
+					break;
+				}
+
+				const uint32 itemRef = gct.readUint16LE();
+				lineSize -= 2;
+
+				line.chunks.push_back(Chunk());
+				line.chunks.back().type = kChunkTypeItem;
+				line.chunks.back().item = itemRef;
+
+				line.chunks.push_back(Chunk());
+				continue;
+			}
+
+			warning("GCTFile::readLine(): Invalid command 0x%02X", cmd);
+			break;
+		}
+
+		// Text
+		line.chunks.back().type = kChunkTypeString;
+		line.chunks.back().text += (char)c;
+	}
+
+	// Skip bytes we didn't read (because of errors)
+	gct.skip(lineSize);
+
+	// Remove empty chunks from the end of the list
+	while (!line.chunks.empty() && (line.chunks.back().type == kChunkTypeNone))
+		line.chunks.pop_back();
+}
+
+uint16 GCTFile::getLineCount(uint item) const {
+	if (item >= _items.size())
+		return 0;
+
+	return _items[item].lines.size();
+}
+
+void GCTFile::selectLine(uint item, uint16 line) {
+	if ((item >= _items.size()) && (item != kSelectorAll) && (item != kSelectorRandom))
+		return;
+
+	_items[item].selector = line;
+}
+
+void GCTFile::setText(uint item, uint16 line, const Common::String &text) {
+	if ((item >= _items.size()) || (line >= _items[item].lines.size()))
+		return;
+
+	_items[item].lines[line].chunks.clear();
+	_items[item].lines[line].chunks.push_back(Chunk());
+
+	_items[item].lines[line].chunks.back().type = kChunkTypeString;
+	_items[item].lines[line].chunks.back().text = text;
+}
+
+void GCTFile::setText(uint item, const Common::String &text) {
+	if (item >= _items.size())
+		return;
+
+	_items[item].selector = 0;
+
+	_items[item].lines.resize(1);
+
+	setText(item, 0, text);
+}
+
+void GCTFile::reset() {
+	_currentItem = 0xFFFF;
+	_currentText.clear();
+}
+
+Common::String GCTFile::getLineText(const Line &line) const {
+	Common::String text;
+
+	// Go over all chunks in this line
+	for (Chunks::const_iterator c = line.chunks.begin(); c != line.chunks.end(); ++c) {
+		// A chunk is either a direct string, or a reference to another item
+
+		if        (c->type == kChunkTypeItem) {
+			Common::List<Common::String> lines;
+
+			getItemText(c->item, lines);
+			if (lines.empty())
+				continue;
+
+			if (lines.size() > 1)
+				warning("GCTFile::getLineText(): Referenced item has multiple lines");
+
+			text += lines.front();
+		} else if (c->type == kChunkTypeString)
+			text += c->text;
+	}
+
+	return text;
+}
+
+void GCTFile::getItemText(uint item, Common::List<Common::String> &text) const {
+	text.clear();
+
+	if ((item >= _items.size()) || _items[item].lines.empty())
+		return;
+
+	uint16 line = _items[item].selector;
+
+	// Draw all lines
+	if (line == kSelectorAll) {
+		for (Lines::const_iterator l = _items[item].lines.begin(); l != _items[item].lines.end(); ++l)
+			text.push_back(getLineText(*l));
+
+		return;
+	}
+
+	// Draw random line
+	if (line == kSelectorRandom)
+		line = _rnd->getRandomNumber(_items[item].lines.size() - 1);
+
+	if (line >= _items[item].lines.size())
+		return;
+
+	text.push_back(getLineText(_items[item].lines[line]));
+}
+
+void GCTFile::setArea(int16 left, int16 top, int16 right, int16 bottom) {
+	trashBuffer();
+
+	_hasArea = false;
+
+	const int16 width  = right  - left + 1;
+	const int16 height = bottom - top  + 1;
+	if ((width <= 0) || (height <= 0))
+		return;
+
+	_areaLeft   = left;
+	_areaTop    = top;
+	_areaRight  = right;
+	_areaBottom = bottom;
+
+	_hasArea = true;
+
+	resizeBuffer(width, height);
+}
+
+bool GCTFile::clear(Surface &dest, int16 &left, int16 &top, int16 &right, int16 &bottom) {
+	return restoreScreen(dest, left, top, right, bottom);
+}
+
+bool GCTFile::fill(Surface &dest, uint8 color, int16 &left, int16 &top, int16 &right, int16 &bottom) {
+	left   = _areaLeft;
+	top    = _areaTop;
+	right  = _areaRight;
+	bottom = _areaBottom;
+
+	if (!hasSavedBackground())
+		saveScreen(dest, left, top, right, bottom);
+
+	dest.fillRect(left, top, right, bottom, color);
+
+	return true;
+}
+
+bool GCTFile::finished() const {
+	return (_currentItem != 0xFFFF) && _currentText.empty();
+}
+
+bool GCTFile::draw(Surface &dest, uint16 item, const Font &font, uint8 color,
+                   int16 &left, int16 &top, int16 &right, int16 &bottom) {
+
+	if ((item >= _items.size()) || !_hasArea)
+		return false;
+
+	left   = _areaLeft;
+	top    = _areaTop;
+	right  = _areaRight;
+	bottom = _areaBottom;
+
+	const int16 width  = right  - left + 1;
+	const int16 height = bottom - top  + 1;
+
+	const uint lineCount = height / font.getCharHeight();
+	if (lineCount == 0)
+		return false;
+
+	if (!hasSavedBackground())
+		saveScreen(dest, left, top, right, bottom);
+
+	if (item != _currentItem) {
+		_currentItem = item;
+
+		getItemText(_currentItem, _currentText);
+	}
+
+	if (_currentText.empty())
+		return false;
+
+	int16 y = top;
+	for (uint i = 0; (i < lineCount) && !_currentText.empty(); i++, y += font.getCharHeight()) {
+		const Common::String &line = _currentText.front();
+		const int16 x = left + ((width - (line.size() * font.getCharWidth())) / 2);
+
+		font.drawString(line, x, y, color, 0, true, dest);
+		_currentText.pop_front();
+	}
+
+	return true;
+}
+
+} // End of namespace Gob
diff --git a/engines/gob/pregob/gctfile.h b/engines/gob/pregob/gctfile.h
new file mode 100644
index 0000000..ed6351b
--- /dev/null
+++ b/engines/gob/pregob/gctfile.h
@@ -0,0 +1,149 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef GOB_PREGOB_GCTFILE_H
+#define GOB_PREGOB_GCTFILE_H
+
+#include "common/str.h"
+#include "common/array.h"
+#include "common/list.h"
+
+#include "gob/backbuffer.h"
+
+namespace Common {
+	class RandomSource;
+	class SeekableReadStream;
+}
+
+namespace Gob {
+
+class Surface;
+class Font;
+
+class GCTFile : public BackBuffer {
+public:
+	static const uint16 kSelectorAll    = 0xFFFE; ///< Print all lines.
+	static const uint16 kSelectorRandom = 0xFFFF; ///< Print a random line.
+
+
+	GCTFile(Common::SeekableReadStream &gct, Common::RandomSource &rnd);
+	~GCTFile();
+
+	/** Return the number of lines in an item. */
+	uint16 getLineCount(uint item) const;
+
+	/** Set the area the text will be printed in. */
+	void setArea(int16 left, int16 top, int16 right, int16 bottom);
+
+	/** Set which line of this item should be printed. */
+	void selectLine(uint item, uint16 line);
+
+	/** Change the text of an items' line. */
+	void setText(uint item, uint16 line, const Common::String &text);
+	/** Change the item into one one line and set that line's text. */
+	void setText(uint item, const Common::String &text);
+
+	/** Reset the item drawing state. */
+	void reset();
+
+	/** Clear the drawn text, restoring the original content. */
+	bool clear(Surface &dest, int16 &left, int16 &top, int16 &right, int16 &bottom);
+
+	/** Fill the text area with a color. */
+	bool fill(Surface &dest, uint8 color, int16 &left, int16 &top, int16 &right, int16 &bottom);
+
+	/** Draw an item onto the surface, until all text has been drawn or the area is filled. */
+	bool draw(Surface &dest, uint16 item, const Font &font, uint8 color,
+	          int16 &left, int16 &top, int16 &right, int16 &bottom);
+
+	/** Did we draw all text? */
+	bool finished() const;
+
+private:
+	/** The type of a chunk. */
+	enum ChunkType {
+		kChunkTypeNone   = 0, ///< Do nothing.
+		kChunkTypeString    , ///< A direct string.
+		kChunkTypeItem        ///< A reference to an item to print instead.
+	};
+
+	/** A chunk in an item text line. */
+	struct Chunk {
+		ChunkType type; ///< The type of the chunk.
+
+		Common::String text; ///< Text to print.
+
+		int item; ///< Item to print instead.
+
+		Chunk();
+	};
+
+	typedef Common::List<Chunk> Chunks;
+
+	/** A line in an item. */
+	struct Line {
+		Chunks chunks; ///< The chunks that make up the line.
+	};
+
+	typedef Common::Array<Line> Lines;
+
+	/** A GCT item. */
+	struct Item {
+		Lines  lines;    ///< The text lines in the item
+		uint16 selector; ///< Which line to print.
+	};
+
+	typedef Common::Array<Item> Items;
+
+
+	Common::RandomSource *_rnd;
+
+	Items _items; ///< All GCT items.
+
+	// The area on which to print
+	bool  _hasArea;
+	int16 _areaLeft;
+	int16 _areaTop;
+	int16 _areaRight;
+	int16 _areaBottom;
+
+	/** Index of the current item we're drawing. */
+	uint16 _currentItem;
+	/** Text left to draw. */
+	Common::List<Common::String> _currentText;
+
+
+	// -- Loading helpers --
+
+	void load(Common::SeekableReadStream &gct);
+	void readLine(Common::SeekableReadStream &gct, Line &line, uint16 lineSize) const;
+
+
+	// -- Draw helpers --
+
+	Common::String getLineText(const Line &line) const;
+	void getItemText(uint item, Common::List<Common::String> &text) const;
+};
+
+} // End of namespace Gob
+
+#endif // GOB_PREGOB_GCTFILE_H
diff --git a/engines/gob/pregob/pregob.cpp b/engines/gob/pregob/pregob.cpp
index 4ee5430..033eea8 100644
--- a/engines/gob/pregob/pregob.cpp
+++ b/engines/gob/pregob/pregob.cpp
@@ -35,6 +35,7 @@
 #include "gob/sound/sound.h"
 
 #include "gob/pregob/pregob.h"
+#include "gob/pregob/gctfile.h"
 
 
 namespace Gob {
@@ -341,4 +342,16 @@ TXTFile *PreGob::loadTXT(const Common::String &txtFile, TXTFile::Format format)
 void PreGob::fixTXTStrings(TXTFile &txt) const {
 }
 
+GCTFile *PreGob::loadGCT(const Common::String &gctFile) const {
+	Common::SeekableReadStream *gctStream = _vm->_dataIO->getFile(gctFile);
+	if (!gctStream)
+		error("PreGob::loadGCT(): Failed to open \"%s\"", gctFile.c_str());
+
+	GCTFile *gct = new GCTFile(*gctStream, _vm->_rnd);
+
+	delete gctStream;
+
+	return gct;
+}
+
 } // End of namespace Gob
diff --git a/engines/gob/pregob/pregob.h b/engines/gob/pregob/pregob.h
index f172803..686727b 100644
--- a/engines/gob/pregob/pregob.h
+++ b/engines/gob/pregob/pregob.h
@@ -38,6 +38,8 @@ namespace Gob {
 class GobEngine;
 class Surface;
 
+class GCTFile;
+
 class PreGob {
 public:
 	PreGob(GobEngine *vm);
@@ -164,6 +166,11 @@ protected:
 	virtual void fixTXTStrings(TXTFile &txt) const;
 
 
+	// -- GCT helpers --
+
+	GCTFile *loadGCT(const Common::String &gctFile) const;
+
+
 	GobEngine *_vm;
 
 private:


Commit: d7c81c27555ed49c70bb6d8b1e60e6a8b5065c70
    https://github.com/scummvm/scummvm/commit/d7c81c27555ed49c70bb6d8b1e60e6a8b5065c70
Author: Sven Hesse (drmccoy at users.sourceforge.net)
Date: 2012-07-29T16:44:45-07:00

Commit Message:
GOB: Implement GCT text drawing in the Stork section

The only thing missing in the stork section now is the character
creator.

Changed paths:
    engines/gob/pregob/onceupon/onceupon.cpp
    engines/gob/pregob/onceupon/onceupon.h



diff --git a/engines/gob/pregob/onceupon/onceupon.cpp b/engines/gob/pregob/onceupon/onceupon.cpp
index aa08f6f..f1b24c3 100644
--- a/engines/gob/pregob/onceupon/onceupon.cpp
+++ b/engines/gob/pregob/onceupon/onceupon.cpp
@@ -32,6 +32,9 @@
 
 #include "gob/sound/sound.h"
 
+#include "gob/pregob/txtfile.h"
+#include "gob/pregob/gctfile.h"
+
 #include "gob/pregob/onceupon/onceupon.h"
 #include "gob/pregob/onceupon/palettes.h"
 
@@ -1041,30 +1044,33 @@ OnceUpon::MenuAction OnceUpon::doIngameMenu() {
 	if ((action == kMenuActionQuit) || _vm->shouldQuit()) {
 
 		// User pressed the quit button, or quit ScummVM
-		_quit = true;
-		return kMenuActionQuit;
+		_quit  = true;
+		action = kMenuActionQuit;
 
 	} else if (action == kMenuActionPlay) {
 
 		// User pressed the return to game button
-		return kMenuActionPlay;
+		action = kMenuActionPlay;
 
 	} else if (kMenuActionMainMenu) {
 
 		// User pressed the return to main menu button
-		return handleMainMenu();
+		action = handleMainMenu();
 	}
 
 	return action;
 }
 
-OnceUpon::MenuAction OnceUpon::doIngameMenu(int16 key, MouseButtons mouseButtons) {
+OnceUpon::MenuAction OnceUpon::doIngameMenu(int16 &key, MouseButtons &mouseButtons) {
 	if ((key != kKeyEscape) && (mouseButtons != kMouseButtonsRight))
 		return kMenuActionNone;
 
+	key = 0;
+	mouseButtons = kMouseButtonsNone;
+
 	MenuAction action = doIngameMenu();
 	if (action == kMenuActionPlay)
-		return kMenuActionNone;
+		action = kMenuActionNone;
 
 	return action;
 }
@@ -1316,8 +1322,6 @@ enum StorkState {
 };
 
 bool OnceUpon::sectionStork() {
-	warning("OnceUpon::sectionStork(): TODO");
-
 	fadeOut();
 	hideCursor();
 	setGamePalette(0);
@@ -1338,6 +1342,10 @@ bool OnceUpon::sectionStork() {
 	TXTFile *whereStork = loadTXT(getLocFile("ouva.tx"), TXTFile::kFormatStringPositionColor);
 	whereStork->draw(*_vm->_draw->_backSurface, &_plettre, 1);
 
+	// Where the stork actually goes
+	GCTFile *thereStork = loadGCT(getLocFile("choix.gc"));
+	thereStork->setArea(17, 18, 303, 41);
+
 	ANIFile ani(_vm, "present.ani", 320);
 	ANIList anims;
 
@@ -1355,8 +1363,6 @@ bool OnceUpon::sectionStork() {
 	StorkState state  = kStorkStateWaitUser;
 	MenuAction action = kMenuActionNone;
 	while (!_vm->shouldQuit() && (state != kStorkStateFinish)) {
-		clearAnim(anims);
-
 		// Play the stork sound
 		if (--storkSoundWait == 0)
 			playSound(kSoundStork);
@@ -1380,6 +1386,8 @@ bool OnceUpon::sectionStork() {
 			break;
 		}
 
+		clearAnim(anims);
+
 		if (mouseButtons == kMouseButtonsLeft) {
 			stopSound();
 			playSound(kSoundClick);
@@ -1394,6 +1402,12 @@ bool OnceUpon::sectionStork() {
 				int16 left, top, right, bottom;
 				if (whereStork->clear(*_vm->_draw->_backSurface, left, top, right, bottom))
 					_vm->_draw->dirtiedRect(_vm->_draw->_backSurface, left, top, right, bottom);
+
+				// Print the text where the stork actually goes
+				thereStork->selectLine(3, house); // The house
+				thereStork->selectLine(4, house); // The house's inhabitants
+				if (thereStork->draw(*_vm->_draw->_backSurface, 2, *_plettre, 10, left, top, right, bottom))
+					_vm->_draw->dirtiedRect(_vm->_draw->_backSurface, left, top, right, bottom);
 			}
 		}
 
@@ -1405,14 +1419,17 @@ bool OnceUpon::sectionStork() {
 	}
 
 	freeAnims(anims);
+	delete thereStork;
 	delete whereStork;
 
 	fadeOut();
 	hideCursor();
 
 	// Completed the section => move one
-	if (action == kMenuActionNone)
+	if (action == kMenuActionNone) {
+		warning("OnceUpon::sectionStork(): TODO: Character creator");
 		return true;
+	}
 
 	// Didn't complete the section
 	return false;
diff --git a/engines/gob/pregob/onceupon/onceupon.h b/engines/gob/pregob/onceupon/onceupon.h
index b9aef04..7ae3a39 100644
--- a/engines/gob/pregob/onceupon/onceupon.h
+++ b/engines/gob/pregob/onceupon/onceupon.h
@@ -249,7 +249,7 @@ private:
 	/** Handle the whole ingame menu. */
 	MenuAction doIngameMenu();
 	/** Handle the whole ingame menu if ESC or right mouse button was pressed. */
-	MenuAction doIngameMenu(int16 key, MouseButtons mouseButtons);
+	MenuAction doIngameMenu(int16 &key, MouseButtons &mouseButtons);
 
 
 	// -- Menu button helpers --


Commit: 90415cf083d26e593ff05acb3a511c088a533b8b
    https://github.com/scummvm/scummvm/commit/90415cf083d26e593ff05acb3a511c088a533b8b
Author: Sven Hesse (drmccoy at users.sourceforge.net)
Date: 2012-07-29T16:44:45-07:00

Commit Message:
GOB: Implement GCT text drawing in the end section

The end section is now complete.

Changed paths:
    engines/gob/pregob/onceupon/onceupon.cpp
    engines/gob/pregob/onceupon/onceupon.h



diff --git a/engines/gob/pregob/onceupon/onceupon.cpp b/engines/gob/pregob/onceupon/onceupon.cpp
index f1b24c3..8c617e2 100644
--- a/engines/gob/pregob/onceupon/onceupon.cpp
+++ b/engines/gob/pregob/onceupon/onceupon.cpp
@@ -94,6 +94,9 @@ enum ClownAnimation {
 	kClownAnimationClownCry   = 6
 };
 
+// 12 seconds delay for one area full of GCT text
+static const uint32 kGCTDelay = 12000;
+
 namespace Gob {
 
 namespace OnceUpon {
@@ -222,6 +225,9 @@ void OnceUpon::init() {
 	// We start with no selected difficulty and at section 0
 	_difficulty = kDifficultyMAX;
 	_section    = 0;
+
+	// Default name
+	_name = "Nemo";
 }
 
 void OnceUpon::deinit() {
@@ -1518,6 +1524,10 @@ bool OnceUpon::sectionEnd() {
 
 	_vm->_draw->_backSurface->blit(endBackground, 0, 0, 288, 137, 16, 50);
 
+	GCTFile *endText = loadGCT(getLocFile("final.gc"));
+	endText->setArea(17, 18, 303, 41);
+	endText->setText(1, _name);
+
 	ANIFile ani(_vm, "fin.ani", 320);
 	ANIList anims;
 
@@ -1526,26 +1536,48 @@ bool OnceUpon::sectionEnd() {
 
 	_vm->_draw->forceBlit();
 
+	uint32 textStartTime = 0;
+
 	MenuAction action = kMenuActionNone;
 	while (!_vm->shouldQuit() && (action == kMenuActionNone)) {
-		redrawAnim(anims);
-
-		fadeIn();
-
-		endFrame(true);
+		// Check user input
 
 		int16 mouseX, mouseY;
 		MouseButtons mouseButtons;
 
 		int16 key = checkInput(mouseX, mouseY, mouseButtons);
-		if ((key != 0) && (key != kKeyEscape))
-			// Any key pressed => Quit
-			action = kMenuActionQuit;
 
 		action = doIngameMenu(key, mouseButtons);
+		if (action != kMenuActionNone)
+			break;
+
+		clearAnim(anims);
+
+		// Pressed a key or mouse button => Skip to next area-full of text
+		if ((mouseButtons == kMouseButtonsLeft) || (key != 0))
+			textStartTime = 0;
+
+		// Draw the next area-full of text
+		uint32 now = _vm->_util->getTimeKey();
+		if (!endText->finished() && ((textStartTime == 0) || (now >= (textStartTime + kGCTDelay)))) {
+			textStartTime = now;
+
+			int16 left, top, right, bottom;
+			if (endText->clear(*_vm->_draw->_backSurface, left, top, right, bottom))
+				_vm->_draw->dirtiedRect(_vm->_draw->_backSurface, left, top, right, bottom);
+
+			if (endText->draw(*_vm->_draw->_backSurface, 0, *_plettre, 10, left, top, right, bottom))
+				_vm->_draw->dirtiedRect(_vm->_draw->_backSurface, left, top, right, bottom);
+		}
+
+		drawAnim(anims);
+		fadeIn();
+
+		endFrame(true);
 	}
 
 	freeAnims(anims);
+	delete endText;
 
 	// Restart requested
 	if (action == kMenuActionRestart)
diff --git a/engines/gob/pregob/onceupon/onceupon.h b/engines/gob/pregob/onceupon/onceupon.h
index 7ae3a39..386d410 100644
--- a/engines/gob/pregob/onceupon/onceupon.h
+++ b/engines/gob/pregob/onceupon/onceupon.h
@@ -24,6 +24,7 @@
 #define GOB_PREGOB_ONCEUPON_ONCEUPON_H
 
 #include "common/system.h"
+#include "common/str.h"
 
 #include "gob/pregob/pregob.h"
 
@@ -312,6 +313,8 @@ private:
 
 	Difficulty _difficulty; ///< The current difficulty.
 	int        _section;    ///< The current game section.
+
+	Common::String _name; ///< The name of the child.
 };
 
 } // End of namespace OnceUpon


Commit: 75e7cca6921ae005cd5c4fa39b9cfa49be2a4cbb
    https://github.com/scummvm/scummvm/commit/75e7cca6921ae005cd5c4fa39b9cfa49be2a4cbb
Author: Sven Hesse (drmccoy at users.sourceforge.net)
Date: 2012-07-29T16:44:45-07:00

Commit Message:
GOB: Add support for entering non-ASCII CP850 characters

Changed paths:
    engines/gob/util.cpp
    engines/gob/util.h



diff --git a/engines/gob/util.cpp b/engines/gob/util.cpp
index 5d6ae78..e1c16c3 100644
--- a/engines/gob/util.cpp
+++ b/engines/gob/util.cpp
@@ -189,12 +189,27 @@ bool Util::getKeyFromBuffer(Common::KeyState &key) {
 	return true;
 }
 
+static const uint16 kLatin1ToCP850[] = {
+	0xFF, 0xAD, 0xBD, 0x9C, 0xCF, 0xBE, 0xDD, 0xF5, 0xF9, 0xB8, 0xA6, 0xAE, 0xAA, 0xF0, 0xA9, 0xEE,
+	0xF8, 0xF1, 0xFD, 0xFC, 0xEF, 0xE6, 0xF4, 0xFA, 0xF7, 0xFB, 0xA7, 0xAF, 0xAC, 0xAB, 0xF3, 0xA8,
+	0xB7, 0xB5, 0xB6, 0xC7, 0x8E, 0x8F, 0x92, 0x80, 0xD4, 0x90, 0xD2, 0xD3, 0xDE, 0xD6, 0xD7, 0xD8,
+	0xD1, 0xA5, 0xE3, 0xE0, 0xE2, 0xE5, 0x99, 0x9E, 0x9D, 0xEB, 0xE9, 0xEA, 0x9A, 0xED, 0xE8, 0xE1,
+	0x85, 0xA0, 0x83, 0xC6, 0x84, 0x86, 0x91, 0x87, 0x8A, 0x82, 0x88, 0x89, 0x8D, 0xA1, 0x8C, 0x8B,
+	0xD0, 0xA4, 0x95, 0xA2, 0x93, 0xE4, 0x94, 0xF6, 0x9B, 0x97, 0xA3, 0x96, 0x81, 0xEC, 0xE7, 0x98
+};
+
+int16 Util::toCP850(uint16 latin1) {
+	if ((latin1 < 0xA0) || ((latin1 - 0xA0) >= ARRAYSIZE(kLatin1ToCP850)))
+		return 0;
+
+	return kLatin1ToCP850[latin1 - 0xA0];
+}
+
 int16 Util::translateKey(const Common::KeyState &key) {
 	static struct keyS {
 		int16 from;
 		int16 to;
 	} keys[] = {
-		{Common::KEYCODE_INVALID,   kKeyNone     },
 		{Common::KEYCODE_BACKSPACE, kKeyBackspace},
 		{Common::KEYCODE_SPACE,     kKeySpace    },
 		{Common::KEYCODE_RETURN,    kKeyReturn   },
@@ -216,16 +231,18 @@ int16 Util::translateKey(const Common::KeyState &key) {
 		{Common::KEYCODE_F10,       kKeyF10      }
 	};
 
+	// Translate special keys
 	for (int i = 0; i < ARRAYSIZE(keys); i++)
 		if (key.keycode == keys[i].from)
 			return keys[i].to;
 
-	if ((key.keycode >= Common::KEYCODE_SPACE) &&
-	    (key.keycode <= Common::KEYCODE_DELETE)) {
-
-		// Used as a user input in Gobliins 2 notepad, in the save dialog, ...
+	// Return the ascii value, for text input
+	if ((key.ascii >= 32) && (key.ascii <= 127))
 		return key.ascii;
-	}
+
+	// Translate international characters into CP850 characters
+	if ((key.ascii >= 160) && (key.ascii <= 255))
+		return toCP850(key.ascii);
 
 	return 0;
 }
diff --git a/engines/gob/util.h b/engines/gob/util.h
index 30bff72..2e568ad 100644
--- a/engines/gob/util.h
+++ b/engines/gob/util.h
@@ -166,6 +166,7 @@ protected:
 	void addKeyToBuffer(const Common::KeyState &key);
 	bool getKeyFromBuffer(Common::KeyState &key);
 	int16 translateKey(const Common::KeyState &key);
+	int16 toCP850(uint16 latin1);
 	void checkJoystick();
 
 	void keyDown(const Common::Event &event);


Commit: 5b02192477cbdc9e8251bd48cac764d6fa61d024
    https://github.com/scummvm/scummvm/commit/5b02192477cbdc9e8251bd48cac764d6fa61d024
Author: Sven Hesse (drmccoy at users.sourceforge.net)
Date: 2012-07-29T16:44:45-07:00

Commit Message:
GOB: Add Font::hasChar()

Changed paths:
    engines/gob/video.cpp
    engines/gob/video.h



diff --git a/engines/gob/video.cpp b/engines/gob/video.cpp
index 62bb210..64af34c 100644
--- a/engines/gob/video.cpp
+++ b/engines/gob/video.cpp
@@ -84,6 +84,10 @@ uint16 Font::getCharCount() const {
 	return _endItem - _startItem + 1;
 }
 
+bool Font::hasChar(uint8 c) const {
+	return (c >= _startItem) && (c <= _endItem);
+}
+
 bool Font::isMonospaced() const {
 	return _charWidths == 0;
 }
diff --git a/engines/gob/video.h b/engines/gob/video.h
index a8c1480..122c1e4 100644
--- a/engines/gob/video.h
+++ b/engines/gob/video.h
@@ -41,6 +41,8 @@ public:
 	uint8  getCharWidth ()        const;
 	uint8  getCharHeight()        const;
 
+	bool hasChar(uint8 c) const;
+
 	bool isMonospaced() const;
 
 	void drawLetter(Surface &surf, uint8 c, uint16 x, uint16 y,


Commit: 10b9be285149dd21bc38710c1a685800fab75e01
    https://github.com/scummvm/scummvm/commit/10b9be285149dd21bc38710c1a685800fab75e01
Author: Sven Hesse (drmccoy at users.sourceforge.net)
Date: 2012-07-29T16:44:45-07:00

Commit Message:
GOB: Add Util::toCP850Lower() / toCP850Upper()

Changed paths:
    engines/gob/util.cpp
    engines/gob/util.h



diff --git a/engines/gob/util.cpp b/engines/gob/util.cpp
index e1c16c3..5ac4ef0 100644
--- a/engines/gob/util.cpp
+++ b/engines/gob/util.cpp
@@ -247,6 +247,72 @@ int16 Util::translateKey(const Common::KeyState &key) {
 	return 0;
 }
 
+static const uint8 kLowerToUpper[][2] = {
+	{0x81, 0x9A},
+	{0x82, 0x90},
+	{0x83, 0xB6},
+	{0x84, 0x8E},
+	{0x85, 0xB7},
+	{0x86, 0x8F},
+	{0x87, 0x80},
+	{0x88, 0xD2},
+	{0x89, 0xD3},
+	{0x8A, 0xD4},
+	{0x8B, 0xD8},
+	{0x8C, 0xD7},
+	{0x8D, 0xDE},
+	{0x91, 0x92},
+	{0x93, 0xE2},
+	{0x94, 0x99},
+	{0x95, 0xE3},
+	{0x96, 0xEA},
+	{0x97, 0xEB},
+	{0x95, 0xE3},
+	{0x96, 0xEA},
+	{0x97, 0xEB},
+	{0x9B, 0x9D},
+	{0xA0, 0xB5},
+	{0xA1, 0xD6},
+	{0xA2, 0xE0},
+	{0xA3, 0xE9},
+	{0xA4, 0xA5},
+	{0xC6, 0xC7},
+	{0xD0, 0xD1},
+	{0xE4, 0xE5},
+	{0xE7, 0xE8},
+	{0xEC, 0xED}
+};
+
+char Util::toCP850Lower(char cp850) {
+	const uint8 cp = (unsigned char)cp850;
+	if (cp <= 32)
+		return cp850;
+
+	if (cp <= 127)
+		return tolower(cp850);
+
+	for (uint i = 0; i < ARRAYSIZE(kLowerToUpper); i++)
+		if (cp == kLowerToUpper[i][1])
+			return (char)kLowerToUpper[i][0];
+
+	return cp850;
+}
+
+char Util::toCP850Upper(char cp850) {
+	const uint8 cp = (unsigned char)cp850;
+	if (cp <= 32)
+		return cp850;
+
+	if (cp <= 127)
+		return toupper(cp850);
+
+	for (uint i = 0; i < ARRAYSIZE(kLowerToUpper); i++)
+		if (cp == kLowerToUpper[i][0])
+			return (char)kLowerToUpper[i][1];
+
+	return cp850;
+}
+
 int16 Util::getKey() {
 	Common::KeyState key;
 
diff --git a/engines/gob/util.h b/engines/gob/util.h
index 2e568ad..a4984c6 100644
--- a/engines/gob/util.h
+++ b/engines/gob/util.h
@@ -143,6 +143,11 @@ public:
 	/** Read a constant-length string out of a stream. */
 	static Common::String readString(Common::SeekableReadStream &stream, int n);
 
+	/** Convert a character in CP850 encoding to the equivalent lower case character. */
+	static char toCP850Lower(char cp850);
+	/** Convert a character in CP850 encoding to the equivalent upper case character. */
+	static char toCP850Upper(char cp850);
+
 	Util(GobEngine *vm);
 
 protected:


Commit: 57b1b7ad2496be6f6c2545877576e3c818dc6ef6
    https://github.com/scummvm/scummvm/commit/57b1b7ad2496be6f6c2545877576e3c818dc6ef6
Author: Sven Hesse (drmccoy at users.sourceforge.net)
Date: 2012-07-29T16:44:45-07:00

Commit Message:
GOB: Implement the Once Upon A Time character generator

Still missing the little sprite bouncing around, though.

Changed paths:
    engines/gob/pregob/onceupon/onceupon.cpp
    engines/gob/pregob/onceupon/onceupon.h



diff --git a/engines/gob/pregob/onceupon/onceupon.cpp b/engines/gob/pregob/onceupon/onceupon.cpp
index 8c617e2..1d1bfd4 100644
--- a/engines/gob/pregob/onceupon/onceupon.cpp
+++ b/engines/gob/pregob/onceupon/onceupon.cpp
@@ -1095,18 +1095,18 @@ int OnceUpon::checkButton(const MenuButton *buttons, uint count, int16 x, int16
 	return failValue;
 }
 
-void OnceUpon::drawButton(Surface &dest, const Surface &src, const MenuButton &button) const {
-	dest.blit(src, button.srcLeft, button.srcTop, button.srcRight, button.srcBottom, button.dstX, button.dstY);
+void OnceUpon::drawButton(Surface &dest, const Surface &src, const MenuButton &button, int transp) const {
+	dest.blit(src, button.srcLeft, button.srcTop, button.srcRight, button.srcBottom, button.dstX, button.dstY, transp);
 }
 
-void OnceUpon::drawButtons(Surface &dest, const Surface &src, const MenuButton *buttons, uint count) const {
+void OnceUpon::drawButtons(Surface &dest, const Surface &src, const MenuButton *buttons, uint count, int transp) const {
 	for (uint i = 0; i < count; i++) {
 		const MenuButton &button = buttons[i];
 
 		if (!button.needDraw)
 			continue;
 
-		drawButton(dest, src, button);
+		drawButton(dest, src, button, transp);
 	}
 }
 
@@ -1431,16 +1431,355 @@ bool OnceUpon::sectionStork() {
 	fadeOut();
 	hideCursor();
 
-	// Completed the section => move one
-	if (action == kMenuActionNone) {
-		warning("OnceUpon::sectionStork(): TODO: Character creator");
+	// Didn't complete the section
+	if (action != kMenuActionNone)
+		return false;
+
+	// Move on to the character generator
+
+	CharGenAction charGenAction = kCharGenRestart;
+	while (charGenAction == kCharGenRestart)
+		charGenAction = characterGenerator();
+
+	// Did we successfully create a character?
+	return charGenAction == kCharGenDone;
+}
+
+const OnceUpon::MenuButton OnceUpon::kCharGenHeadButtons[] = {
+	{true, 106, 146, 152, 180,   0,  0,  47, 34, 106, 146, 0},
+	{true, 155, 146, 201, 180,  49,  0,  96, 34, 155, 146, 1},
+	{true, 204, 146, 250, 180,  98,  0, 145, 34, 204, 146, 2},
+	{true, 253, 146, 299, 180, 147,  0, 194, 34, 253, 146, 3}
+};
+
+const OnceUpon::MenuButton OnceUpon::kCharGenHeads[] = {
+	{true,   0,   0,   0,   0,  29,  4,  68, 31,  40,  51, 0},
+	{true,   0,   0,   0,   0,  83,  4, 113, 31,  45,  51, 1},
+	{true,   0,   0,   0,   0, 132,  4, 162, 31,  45,  51, 2},
+	{true,   0,   0,   0,   0, 182,  4, 211, 31,  45,  51, 3}
+};
+
+const OnceUpon::MenuButton OnceUpon::kCharGenHairButtons[] = {
+	{true, 105,  55, 124,  70, 271,  1, 289, 15, 105,  55, 0x04},
+	{true, 105,  74, 124,  89, 271, 20, 289, 34, 105,  74, 0x07}
+};
+
+const OnceUpon::MenuButton OnceUpon::kCharGenJacketButtons[] = {
+	{true, 105,  90, 124, 105, 271, 39, 289, 53, 105,  90, 0x06},
+	{true, 105, 109, 124, 124, 271, 58, 289, 72, 105, 109, 0x02}
+};
+
+const OnceUpon::MenuButton OnceUpon::kCharGenTrousersButtons[] = {
+	{true, 105, 140, 124, 155, 271, 77, 289,  91, 105, 140, 0x01},
+	{true, 105, 159, 124, 174, 271, 96, 289, 110, 105, 159, 0x03}
+};
+
+const OnceUpon::MenuButton OnceUpon::kCharGenNameEntry[] = {
+	{true, 0, 0, 0, 0,   0,  38,  54,  48, 140, 145, 0},
+	{true, 0, 0, 0, 0, 106,  38, 159,  48, 195, 145, 0},
+	{true, 0, 0, 0, 0,   0, 105,  54, 121, 140, 156, 0},
+	{true, 0, 0, 0, 0, 106, 105, 159, 121, 195, 156, 0}
+};
+
+enum CharGenState {
+	kCharGenStateHead     = 0, // Choose a head
+	kCharGenStateHair        , // Choose hair color
+	kCharGenStateJacket      , // Choose jacket color
+	kCharGenStateTrousers    , // Choose trousers color
+	kCharGenStateName        , // Choose name
+	kCharGenStateSure        , // "Are you sure?"
+	kCharGenStateStoryName   , // "We're going to tell the story of $NAME"
+	kCharGenStateFinish        // Finished
+};
+
+void OnceUpon::recolor(Surface &surface, uint8 from, uint8 to) {
+	for (Pixel p = surface.get(); p.isValid(); ++p)
+		if (p.get() == from)
+			p.set(to);
+}
+
+void OnceUpon::charGenSetup(uint stage) {
+	Surface choix(320, 200, 1), elchoix(320, 200, 1), paperDoll(65, 137, 1);
+
+	_vm->_video->drawPackedSprite("choix.cmp"  , choix);
+	_vm->_video->drawPackedSprite("elchoix.cmp", elchoix);
+
+	paperDoll.blit(choix, 200, 0, 264, 136, 0, 0);
+
+	GCTFile *text = loadGCT(getLocFile("choix.gc"));
+	text->setArea(17, 18, 303, 41);
+	text->setText(9, _name);
+
+	// Background
+	_vm->_video->drawPackedSprite("cadre.cmp", *_vm->_draw->_backSurface);
+	_vm->_draw->_backSurface->fillRect(16, 50, 303, 187, 5);
+
+	// Character sprite frame
+	_vm->_draw->_backSurface->blit(choix, 0, 38, 159, 121, 140, 54);
+
+	// Recolor the paper doll parts
+	if (_colorHair     != 0xFF)
+		recolor(elchoix  , 0x0C, _colorHair);
+	if (_colorJacket   != 0xFF)
+		recolor(paperDoll, 0x0A, _colorJacket);
+	if (_colorTrousers != 0xFF)
+		recolor(paperDoll, 0x09, _colorTrousers);
+
+	_vm->_draw->_backSurface->blit(paperDoll, 32, 51);
+
+	// Paper doll head
+	if (_head != 0xFF)
+		drawButton(*_vm->_draw->_backSurface, elchoix, kCharGenHeads[_head], 0);
+
+	if (stage == kCharGenStateHead) {
+		// Head buttons
+		drawButtons(*_vm->_draw->_backSurface, choix, kCharGenHeadButtons, ARRAYSIZE(kCharGenHeadButtons));
+
+		// "Choose a head"
+		int16 left, top, right, bottom;
+		text->draw(*_vm->_draw->_backSurface, 5, *_plettre, 10, left, top, right, bottom);
+
+	} else if (stage == kCharGenStateHair) {
+		// Hair color buttons
+		drawButtons(*_vm->_draw->_backSurface, choix, kCharGenHairButtons, ARRAYSIZE(kCharGenHairButtons));
+
+		// "What color is the hair?"
+		int16 left, top, right, bottom;
+		text->draw(*_vm->_draw->_backSurface, 6, *_plettre, 10, left, top, right, bottom);
+
+	} else if (stage == kCharGenStateJacket) {
+		// Jacket color buttons
+		drawButtons(*_vm->_draw->_backSurface, choix, kCharGenJacketButtons, ARRAYSIZE(kCharGenJacketButtons));
+
+		// "What color is the jacket?"
+		int16 left, top, right, bottom;
+		text->draw(*_vm->_draw->_backSurface, 7, *_plettre, 10, left, top, right, bottom);
+
+	} else if (stage == kCharGenStateTrousers) {
+		// Trousers color buttons
+		drawButtons(*_vm->_draw->_backSurface, choix, kCharGenTrousersButtons, ARRAYSIZE(kCharGenTrousersButtons));
+
+		// "What color are the trousers?"
+		int16 left, top, right, bottom;
+		text->draw(*_vm->_draw->_backSurface, 8, *_plettre, 10, left, top, right, bottom);
+
+	} else if (stage == kCharGenStateName) {
+		// Name entry field
+		drawButtons(*_vm->_draw->_backSurface, choix, kCharGenNameEntry, ARRAYSIZE(kCharGenNameEntry));
+
+		// "Enter name"
+		int16 left, top, right, bottom;
+		text->draw(*_vm->_draw->_backSurface, 10, *_plettre, 10, left, top, right, bottom);
+
+		charGenDrawName();
+	} else if (stage == kCharGenStateSure) {
+		// Name entry field
+		drawButtons(*_vm->_draw->_backSurface, choix, kCharGenNameEntry, ARRAYSIZE(kCharGenNameEntry));
+
+		// "Are you sure?"
+		TXTFile *sure = loadTXT(getLocFile("estu.tx"), TXTFile::kFormatStringPositionColor);
+		sure->draw(*_vm->_draw->_backSurface, &_plettre, 1);
+		delete sure;
+
+		charGenDrawName();
+	} else if (stage == kCharGenStateStoryName) {
+
+		// "We're going to tell the story of $NAME"
+		int16 left, top, right, bottom;
+		text->draw(*_vm->_draw->_backSurface, 11, *_plettre, 10, left, top, right, bottom);
+	}
+
+	delete text;
+}
+
+bool OnceUpon::enterString(Common::String &name, int16 key, uint maxLength, const Font &font) {
+	if (key == 0)
+		return true;
+
+	if (key == kKeyBackspace) {
+		name.deleteLastChar();
+		return true;
+	}
+
+	if ((key >= ' ') && (key <= 0xFF)) {
+		if (name.size() >= maxLength)
+			return false;
+
+		if (!font.hasChar(key))
+			return false;
+
+		name += (char) key;
 		return true;
 	}
 
-	// Didn't complete the section
 	return false;
 }
 
+void OnceUpon::charGenDrawName() {
+	_vm->_draw->_backSurface->fillRect(147, 151, 243, 166, 1);
+
+	const int16 nameY = 151 + ((166 - 151 + 1 -       _plettre->getCharHeight())  / 2);
+	const int16 nameX = 147 + ((243 - 147 + 1 - (15 * _plettre->getCharWidth ())) / 2);
+
+	_plettre->drawString(_name, nameX, nameY, 10, 0, true, *_vm->_draw->_backSurface);
+
+	const int16 cursorLeft   = nameX + _name.size() * _plettre->getCharWidth();
+	const int16 cursorTop    = nameY;
+	const int16 cursorRight  = cursorLeft + _plettre->getCharWidth() - 1;
+	const int16 cursorBottom = cursorTop + _plettre->getCharHeight() - 1;
+
+	_vm->_draw->_backSurface->fillRect(cursorLeft, cursorTop, cursorRight, cursorBottom, 10);
+
+	_vm->_draw->dirtiedRect(_vm->_draw->_backSurface, 147, 151, 243, 166);
+}
+
+OnceUpon::CharGenAction OnceUpon::characterGenerator() {
+	fadeOut();
+	hideCursor();
+	setGameCursor();
+
+	showWait(1);
+
+	_name.clear();
+
+	_head          = 0xFF;
+	_colorHair     = 0xFF;
+	_colorJacket   = 0xFF;
+	_colorTrousers = 0xFF;
+
+	CharGenState state = kCharGenStateHead;
+	charGenSetup(state);
+
+	fadeOut();
+	_vm->_draw->forceBlit();
+
+	CharGenAction action = kCharGenRestart;
+	while (!_vm->shouldQuit() && (state != kCharGenStateFinish)) {
+		// Check user input
+
+		int16 mouseX, mouseY;
+		MouseButtons mouseButtons;
+
+		int16 key = checkInput(mouseX, mouseY, mouseButtons);
+
+		MenuAction menuAction = doIngameMenu(key, mouseButtons);
+		if (menuAction != kMenuActionNone) {
+			state  = kCharGenStateFinish;
+			action = kCharGenAbort;
+			break;
+		}
+
+		// clearAnim(anims);
+
+		if (state == kCharGenStateStoryName) {
+			if ((mouseButtons != kMouseButtonsNone) || (key != 0)) {
+				state = kCharGenStateFinish;
+				action = kCharGenDone;
+				break;
+			}
+		}
+
+		if (state == kCharGenStateSure) {
+			// Not sure => restart
+			if ((key == 'N') || (key == 'n')) { // No / Nein / Non
+				state = kCharGenStateFinish;
+				action = kCharGenRestart;
+				break;
+			}
+
+			if ((key == 'Y') || (key == 'y') || // Yes
+			    (key == 'J') || (key == 'j') || // Ja
+			    (key == 'S') || (key == 's') || // Si
+			    (key == 'O') || (key == 'o')) { // Oui
+
+				state = kCharGenStateStoryName;
+				charGenSetup(state);
+				_vm->_draw->forceBlit();
+			}
+		}
+
+		if (state == kCharGenStateName) {
+			if (enterString(_name, key, 14, *_plettre)) {
+				_vm->_draw->_backSurface->fillRect(147, 151, 243, 166, 1);
+
+				const int16 nameY = 151 + ((166 - 151 + 1 -       _plettre->getCharHeight())  / 2);
+				const int16 nameX = 147 + ((243 - 147 + 1 - (15 * _plettre->getCharWidth ())) / 2);
+
+				_plettre->drawString(_name, nameX, nameY, 10, 0, true, *_vm->_draw->_backSurface);
+
+				const int16 cursorLeft   = nameX + _name.size() * _plettre->getCharWidth();
+				const int16 cursorTop    = nameY;
+				const int16 cursorRight  = cursorLeft + _plettre->getCharWidth() - 1;
+				const int16 cursorBottom = cursorTop + _plettre->getCharHeight() - 1;
+
+				_vm->_draw->_backSurface->fillRect(cursorLeft, cursorTop, cursorRight, cursorBottom, 10);
+
+				_vm->_draw->dirtiedRect(_vm->_draw->_backSurface, 147, 151, 243, 166);
+			}
+
+			if ((key == kKeyReturn) && !_name.empty()) {
+				_name.setChar(Util::toCP850Upper(_name[0]), 0);
+
+				state = kCharGenStateSure;
+				charGenSetup(state);
+				_vm->_draw->forceBlit();
+			}
+		}
+
+		if (mouseButtons == kMouseButtonsLeft) {
+			int trousers = checkButton(kCharGenTrousersButtons, ARRAYSIZE(kCharGenTrousersButtons), mouseX, mouseY);
+			if ((state == kCharGenStateTrousers) && (trousers >= 0)) {
+				_colorTrousers = trousers;
+
+				state = kCharGenStateName;
+				charGenSetup(state);
+				_vm->_draw->forceBlit();
+			}
+
+			int jacket = checkButton(kCharGenJacketButtons, ARRAYSIZE(kCharGenJacketButtons), mouseX, mouseY);
+			if ((state == kCharGenStateJacket) && (jacket >= 0)) {
+				_colorJacket = jacket;
+
+				state = kCharGenStateTrousers;
+				charGenSetup(state);
+				_vm->_draw->forceBlit();
+			}
+
+			int hair = checkButton(kCharGenHairButtons, ARRAYSIZE(kCharGenHairButtons), mouseX, mouseY);
+			if ((state == kCharGenStateHair) && (hair >= 0)) {
+				_colorHair = hair;
+
+				state = kCharGenStateJacket;
+				charGenSetup(state);
+				_vm->_draw->forceBlit();
+			}
+
+			int head = checkButton(kCharGenHeadButtons, ARRAYSIZE(kCharGenHeadButtons), mouseX, mouseY);
+			if ((state == kCharGenStateHead) && (head >= 0)) {
+				_head = head;
+
+				state = kCharGenStateHair;
+				charGenSetup(state);
+				_vm->_draw->forceBlit();
+			}
+		}
+
+		//drawAnim(anims);
+		showCursor();
+		fadeIn();
+
+		endFrame(true);
+	}
+
+	fadeOut();
+	hideCursor();
+
+	if (_vm->shouldQuit())
+		return kCharGenAbort;
+
+	return action;
+}
+
 bool OnceUpon::sectionChapter1() {
 	showChapter(1);
 	return true;
diff --git a/engines/gob/pregob/onceupon/onceupon.h b/engines/gob/pregob/onceupon/onceupon.h
index 386d410..3b924a1 100644
--- a/engines/gob/pregob/onceupon/onceupon.h
+++ b/engines/gob/pregob/onceupon/onceupon.h
@@ -139,6 +139,13 @@ private:
 		kSoundMAX
 	};
 
+	/** Action the character generation wants us to take. */
+	enum CharGenAction {
+		kCharGenDone    = 0, ///< Created a character, move on.
+		kCharGenAbort      , ///< Aborted the character generation.
+		kCharGenRestart      ///< Restart the character generation.
+	};
+
 	/** A complete screen backup. */
 	struct ScreenBackup {
 		Surface *screen; ///< Screen contents.
@@ -165,6 +172,13 @@ private:
 
 	static const MenuButton kSectionStorkHouses[];
 
+	static const MenuButton kCharGenHeadButtons[];
+	static const MenuButton kCharGenHeads[];
+	static const MenuButton kCharGenHairButtons[];
+	static const MenuButton kCharGenJacketButtons[];
+	static const MenuButton kCharGenTrousersButtons[];
+	static const MenuButton kCharGenNameEntry[];
+
 	/** All general game sounds we know about. */
 	static const char *kSound[kSoundMAX];
 
@@ -259,9 +273,9 @@ private:
 	int checkButton(const MenuButton *buttons, uint count, int16 x, int16 y, int failValue = -1) const;
 
 	/** Draw a menu button. */
-	void drawButton (Surface &dest, const Surface &src, const MenuButton &button) const;
+	void drawButton (Surface &dest, const Surface &src, const MenuButton &button, int transp = -1) const;
 	/** Draw multiple menu buttons. */
-	void drawButtons(Surface &dest, const Surface &src, const MenuButton *buttons, uint count) const;
+	void drawButtons(Surface &dest, const Surface &src, const MenuButton *buttons, uint count, int transp = -1) const;
 
 	/** Draw a border around a button. */
 	void drawButtonBorder(const MenuButton &button, uint8 color);
@@ -296,6 +310,13 @@ private:
 	bool sectionChapter7();
 	bool sectionEnd();
 
+	CharGenAction characterGenerator();
+	void charGenSetup(uint stage);
+	void charGenDrawName();
+
+	static void recolor(Surface &surface, uint8 from, uint8 to);
+	static bool enterString(Common::String &name, int16 key, uint maxLength, const Font &font);
+
 
 	/** Did we open the game archives? */
 	bool _openedArchives;
@@ -315,6 +336,11 @@ private:
 	int        _section;    ///< The current game section.
 
 	Common::String _name; ///< The name of the child.
+
+	uint8 _head;
+	uint8 _colorHair;
+	uint8 _colorJacket;
+	uint8 _colorTrousers;
 };
 
 } // End of namespace OnceUpon


Commit: baec4d87781d24786f0b76e83efee3bca7f9afea
    https://github.com/scummvm/scummvm/commit/baec4d87781d24786f0b76e83efee3bca7f9afea
Author: Sven Hesse (drmccoy at users.sourceforge.net)
Date: 2012-07-29T16:44:45-07:00

Commit Message:
GOB: Move recolor() into class Surface

Changed paths:
    engines/gob/pregob/onceupon/onceupon.cpp
    engines/gob/pregob/onceupon/onceupon.h
    engines/gob/surface.cpp
    engines/gob/surface.h



diff --git a/engines/gob/pregob/onceupon/onceupon.cpp b/engines/gob/pregob/onceupon/onceupon.cpp
index 1d1bfd4..53fa3bc 100644
--- a/engines/gob/pregob/onceupon/onceupon.cpp
+++ b/engines/gob/pregob/onceupon/onceupon.cpp
@@ -1492,12 +1492,6 @@ enum CharGenState {
 	kCharGenStateFinish        // Finished
 };
 
-void OnceUpon::recolor(Surface &surface, uint8 from, uint8 to) {
-	for (Pixel p = surface.get(); p.isValid(); ++p)
-		if (p.get() == from)
-			p.set(to);
-}
-
 void OnceUpon::charGenSetup(uint stage) {
 	Surface choix(320, 200, 1), elchoix(320, 200, 1), paperDoll(65, 137, 1);
 
@@ -1518,12 +1512,14 @@ void OnceUpon::charGenSetup(uint stage) {
 	_vm->_draw->_backSurface->blit(choix, 0, 38, 159, 121, 140, 54);
 
 	// Recolor the paper doll parts
-	if (_colorHair     != 0xFF)
-		recolor(elchoix  , 0x0C, _colorHair);
-	if (_colorJacket   != 0xFF)
-		recolor(paperDoll, 0x0A, _colorJacket);
+	if (_colorHair != 0xFF)
+		elchoix.recolor(0x0C, _colorHair);
+
+	if (_colorJacket != 0xFF)
+		paperDoll.recolor(0x0A, _colorJacket);
+
 	if (_colorTrousers != 0xFF)
-		recolor(paperDoll, 0x09, _colorTrousers);
+		paperDoll.recolor(0x09, _colorTrousers);
 
 	_vm->_draw->_backSurface->blit(paperDoll, 32, 51);
 
diff --git a/engines/gob/pregob/onceupon/onceupon.h b/engines/gob/pregob/onceupon/onceupon.h
index 3b924a1..80fcba3 100644
--- a/engines/gob/pregob/onceupon/onceupon.h
+++ b/engines/gob/pregob/onceupon/onceupon.h
@@ -314,7 +314,6 @@ private:
 	void charGenSetup(uint stage);
 	void charGenDrawName();
 
-	static void recolor(Surface &surface, uint8 from, uint8 to);
 	static bool enterString(Common::String &name, int16 key, uint maxLength, const Font &font);
 
 
diff --git a/engines/gob/surface.cpp b/engines/gob/surface.cpp
index 3eaf741..afbb7c3 100644
--- a/engines/gob/surface.cpp
+++ b/engines/gob/surface.cpp
@@ -684,6 +684,12 @@ void Surface::shadeRect(uint16 left, uint16 top, uint16 right, uint16 bottom,
 
 }
 
+void Surface::recolor(uint8 from, uint8 to) {
+	for (Pixel p = get(); p.isValid(); ++p)
+		if (p.get() == from)
+			p.set(to);
+}
+
 void Surface::putPixel(uint16 x, uint16 y, uint32 color) {
 	if ((x >= _width) || (y >= _height))
 		return;
diff --git a/engines/gob/surface.h b/engines/gob/surface.h
index 09be8d1..8f895a7 100644
--- a/engines/gob/surface.h
+++ b/engines/gob/surface.h
@@ -156,6 +156,8 @@ public:
 	void shadeRect(uint16 left, uint16 top, uint16 right, uint16 bottom,
 			uint32 color, uint8 strength);
 
+	void recolor(uint8 from, uint8 to);
+
 	void putPixel(uint16 x, uint16 y, uint32 color);
 	void drawLine(uint16 x0, uint16 y0, uint16 x1, uint16 y1, uint32 color);
 	void drawRect(uint16 left, uint16 top, uint16 right, uint16 bottom, uint32 color);


Commit: 20a96733a5f982e427a9143ded14e2af418ac6df
    https://github.com/scummvm/scummvm/commit/20a96733a5f982e427a9143ded14e2af418ac6df
Author: Sven Hesse (drmccoy at users.sourceforge.net)
Date: 2012-07-29T16:44:45-07:00

Commit Message:
GOB: Add CMPFile::recolor() and ANIFile::recolor()

Changed paths:
    engines/gob/anifile.cpp
    engines/gob/anifile.h
    engines/gob/cmpfile.cpp
    engines/gob/cmpfile.h



diff --git a/engines/gob/anifile.cpp b/engines/gob/anifile.cpp
index e6bf30f..085ac80 100644
--- a/engines/gob/anifile.cpp
+++ b/engines/gob/anifile.cpp
@@ -289,4 +289,9 @@ void ANIFile::drawLayer(Surface &dest, uint16 layer, uint16 part,
 	_layers[layer]->draw(dest, part, x, y, transp);
 }
 
+void ANIFile::recolor(uint8 from, uint8 to) {
+	for (LayerArray::iterator l = _layers.begin(); l != _layers.end(); ++l)
+		(*l)->recolor(from, to);
+}
+
 } // End of namespace Gob
diff --git a/engines/gob/anifile.h b/engines/gob/anifile.h
index b6d9c73..c930aaf 100644
--- a/engines/gob/anifile.h
+++ b/engines/gob/anifile.h
@@ -92,6 +92,9 @@ public:
 	/** Draw an animation frame. */
 	void draw(Surface &dest, uint16 animation, uint16 frame, int16 x, int16 y) const;
 
+	/** Recolor the animation sprites. */
+	void recolor(uint8 from, uint8 to);
+
 private:
 	typedef Common::Array<CMPFile *> LayerArray;
 	typedef Common::Array<Animation> AnimationArray;
diff --git a/engines/gob/cmpfile.cpp b/engines/gob/cmpfile.cpp
index 1cd1375..d304958 100644
--- a/engines/gob/cmpfile.cpp
+++ b/engines/gob/cmpfile.cpp
@@ -250,4 +250,9 @@ uint16 CMPFile::addSprite(uint16 left, uint16 top, uint16 right, uint16 bottom)
 	return _coordinates->add(left, top, right, bottom);
 }
 
+void CMPFile::recolor(uint8 from, uint8 to) {
+	if (_surface)
+		_surface->recolor(from, to);
+}
+
 } // End of namespace Gob
diff --git a/engines/gob/cmpfile.h b/engines/gob/cmpfile.h
index 2b669e4..9c85823 100644
--- a/engines/gob/cmpfile.h
+++ b/engines/gob/cmpfile.h
@@ -70,6 +70,8 @@ public:
 
 	uint16 addSprite(uint16 left, uint16 top, uint16 right, uint16 bottom);
 
+	void recolor(uint8 from, uint8 to);
+
 private:
 	GobEngine *_vm;
 


Commit: 6533047514d0ab1cc7273a0c071fa24b6c2f7b71
    https://github.com/scummvm/scummvm/commit/6533047514d0ab1cc7273a0c071fa24b6c2f7b71
Author: Sven Hesse (drmccoy at users.sourceforge.net)
Date: 2012-07-29T16:44:45-07:00

Commit Message:
GOB: Add the walking child in the character generator

Changed paths:
  A engines/gob/pregob/onceupon/chargenchild.cpp
  A engines/gob/pregob/onceupon/chargenchild.h
    engines/gob/module.mk
    engines/gob/pregob/onceupon/onceupon.cpp



diff --git a/engines/gob/module.mk b/engines/gob/module.mk
index 1535184..4858e97 100644
--- a/engines/gob/module.mk
+++ b/engines/gob/module.mk
@@ -85,6 +85,7 @@ MODULE_OBJS := \
 	pregob/onceupon/abracadabra.o \
 	pregob/onceupon/babayaga.o \
 	pregob/onceupon/stork.o \
+	pregob/onceupon/chargenchild.o \
 	minigames/geisha/evilfish.o \
 	minigames/geisha/oko.o \
 	minigames/geisha/meter.o \
diff --git a/engines/gob/pregob/onceupon/chargenchild.cpp b/engines/gob/pregob/onceupon/chargenchild.cpp
new file mode 100644
index 0000000..7150c69
--- /dev/null
+++ b/engines/gob/pregob/onceupon/chargenchild.cpp
@@ -0,0 +1,104 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "gob/surface.h"
+#include "gob/anifile.h"
+
+#include "gob/pregob/onceupon/chargenchild.h"
+
+enum Animation {
+	kAnimWalkLeft  =  0,
+	kAnimWalkRight =  1,
+	kAnimJumpLeft  =  2,
+	kAnimJumpRight =  3,
+	kAnimTapFoot   = 14
+};
+
+namespace Gob {
+
+namespace OnceUpon {
+
+CharGenChild::CharGenChild(const ANIFile &ani) : ANIObject(ani) {
+	setPosition(265, 110);
+	setAnimation(kAnimWalkLeft);
+	setVisible(true);
+	setPause(false);
+}
+
+CharGenChild::~CharGenChild() {
+}
+
+void CharGenChild::advance() {
+	bool wasLastFrame = lastFrame();
+
+	ANIObject::advance();
+
+	int16 x, y, left, top, width, height;
+	getPosition(x, y);
+	getFramePosition(left, top);
+	getFrameSize(width, height);
+
+	const int16 right = left + width - 1;
+
+	switch (getAnimation()) {
+	case kAnimWalkLeft:
+		if (left <= 147)
+			setAnimation(kAnimWalkRight);
+		break;
+
+	case kAnimWalkRight:
+		if (right >= 290) {
+			setAnimation(kAnimJumpLeft);
+
+			setPosition(x, y - 14);
+		}
+		break;
+
+	case kAnimJumpLeft:
+		if (wasLastFrame) {
+			setAnimation(kAnimTapFoot);
+
+			setPosition(x, y - 10);
+		}
+		break;
+
+	case kAnimTapFoot:
+		if (wasLastFrame) {
+			setAnimation(kAnimJumpRight);
+
+			setPosition(x, y + 10);
+		}
+		break;
+
+	case kAnimJumpRight:
+		if (wasLastFrame) {
+			setAnimation(kAnimWalkLeft);
+
+			setPosition(x, y + 14);
+		}
+		break;
+	}
+}
+
+} // End of namespace OnceUpon
+
+} // End of namespace Gob
diff --git a/engines/gob/pregob/onceupon/chargenchild.h b/engines/gob/pregob/onceupon/chargenchild.h
new file mode 100644
index 0000000..afbe3fd
--- /dev/null
+++ b/engines/gob/pregob/onceupon/chargenchild.h
@@ -0,0 +1,51 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef GOB_PREGOB_ONCEUPON_CHARGENCHILD_H
+#define GOB_PREGOB_ONCEUPON_CHARGENCHILD_H
+
+#include "common/system.h"
+
+#include "gob/aniobject.h"
+
+namespace Gob {
+
+class Surface;
+class ANIFile;
+
+namespace OnceUpon {
+
+/** The child running around on the character generator screen. */
+class CharGenChild : public ANIObject {
+public:
+	CharGenChild(const ANIFile &ani);
+	~CharGenChild();
+
+	/** Advance the animation to the next frame. */
+	void advance();
+};
+
+} // End of namespace OnceUpon
+
+} // End of namespace Gob
+
+#endif // GOB_PREGOB_ONCEUPON_CHARGENCHILD_H
diff --git a/engines/gob/pregob/onceupon/onceupon.cpp b/engines/gob/pregob/onceupon/onceupon.cpp
index 53fa3bc..7eef740 100644
--- a/engines/gob/pregob/onceupon/onceupon.cpp
+++ b/engines/gob/pregob/onceupon/onceupon.cpp
@@ -37,6 +37,7 @@
 
 #include "gob/pregob/onceupon/onceupon.h"
 #include "gob/pregob/onceupon/palettes.h"
+#include "gob/pregob/onceupon/chargenchild.h"
 
 static const uint kLanguageCount = 5;
 
@@ -1646,6 +1647,15 @@ OnceUpon::CharGenAction OnceUpon::characterGenerator() {
 	CharGenState state = kCharGenStateHead;
 	charGenSetup(state);
 
+	ANIFile ani(_vm, "ba.ani", 320);
+	ANIList anims;
+
+	anims.push_back(new CharGenChild(ani));
+
+	ani.recolor(0x0F, 0x0C);
+	ani.recolor(0x0E, 0x0A);
+	ani.recolor(0x08, 0x09);
+
 	fadeOut();
 	_vm->_draw->forceBlit();
 
@@ -1665,7 +1675,7 @@ OnceUpon::CharGenAction OnceUpon::characterGenerator() {
 			break;
 		}
 
-		// clearAnim(anims);
+		clearAnim(anims);
 
 		if (state == kCharGenStateStoryName) {
 			if ((mouseButtons != kMouseButtonsNone) || (key != 0)) {
@@ -1727,6 +1737,8 @@ OnceUpon::CharGenAction OnceUpon::characterGenerator() {
 			if ((state == kCharGenStateTrousers) && (trousers >= 0)) {
 				_colorTrousers = trousers;
 
+				ani.recolor(0x09, _colorTrousers);
+
 				state = kCharGenStateName;
 				charGenSetup(state);
 				_vm->_draw->forceBlit();
@@ -1736,6 +1748,8 @@ OnceUpon::CharGenAction OnceUpon::characterGenerator() {
 			if ((state == kCharGenStateJacket) && (jacket >= 0)) {
 				_colorJacket = jacket;
 
+				ani.recolor(0x0A, _colorJacket);
+
 				state = kCharGenStateTrousers;
 				charGenSetup(state);
 				_vm->_draw->forceBlit();
@@ -1745,6 +1759,8 @@ OnceUpon::CharGenAction OnceUpon::characterGenerator() {
 			if ((state == kCharGenStateHair) && (hair >= 0)) {
 				_colorHair = hair;
 
+				ani.recolor(0x0C, _colorHair);
+
 				state = kCharGenStateJacket;
 				charGenSetup(state);
 				_vm->_draw->forceBlit();
@@ -1760,7 +1776,7 @@ OnceUpon::CharGenAction OnceUpon::characterGenerator() {
 			}
 		}
 
-		//drawAnim(anims);
+		drawAnim(anims);
 		showCursor();
 		fadeIn();
 
@@ -1770,6 +1786,8 @@ OnceUpon::CharGenAction OnceUpon::characterGenerator() {
 	fadeOut();
 	hideCursor();
 
+	freeAnims(anims);
+
 	if (_vm->shouldQuit())
 		return kCharGenAbort;
 


Commit: 9c32fd2360d9fa18ceac6fefc571c6610965d361
    https://github.com/scummvm/scummvm/commit/9c32fd2360d9fa18ceac6fefc571c6610965d361
Author: Sven Hesse (drmccoy at users.sourceforge.net)
Date: 2012-07-29T16:44:46-07:00

Commit Message:
GOB: Add PreGob::beep()

Changed paths:
    engines/gob/pregob/pregob.cpp
    engines/gob/pregob/pregob.h



diff --git a/engines/gob/pregob/pregob.cpp b/engines/gob/pregob/pregob.cpp
index 033eea8..42b5a8f 100644
--- a/engines/gob/pregob/pregob.cpp
+++ b/engines/gob/pregob/pregob.cpp
@@ -208,6 +208,10 @@ void PreGob::playSoundFile(const Common::String &file, int16 frequency, int16 re
 	stopSound();
 }
 
+void PreGob::beep(int16 frequency, int32 length) {
+	_vm->_sound->speakerOn(frequency, length);
+}
+
 void PreGob::endFrame(bool doInput) {
 	_vm->_draw->blitInvalidated();
 	_vm->_util->waitEndFrame();
diff --git a/engines/gob/pregob/pregob.h b/engines/gob/pregob/pregob.h
index 686727b..da0de60 100644
--- a/engines/gob/pregob/pregob.h
+++ b/engines/gob/pregob/pregob.h
@@ -142,6 +142,9 @@ protected:
 	/** Play a sound until it ends or is interrupted by a keypress. */
 	void playSoundFile(const Common::String &file, int16 frequency = 0, int16 repCount = 0, bool interruptible = true);
 
+	/** Beep the PC speaker. */
+	void beep(int16 frequency, int32 length);
+
 
 	// -- Input --
 


Commit: 943c6af82af9e14062c1aa1940aea2f625121368
    https://github.com/scummvm/scummvm/commit/943c6af82af9e14062c1aa1940aea2f625121368
Author: Sven Hesse (drmccoy at users.sourceforge.net)
Date: 2012-07-29T16:44:46-07:00

Commit Message:
GOB: Add the sounds in the Once Upon A Time character generator

Changed paths:
    engines/gob/pregob/onceupon/chargenchild.cpp
    engines/gob/pregob/onceupon/chargenchild.h
    engines/gob/pregob/onceupon/onceupon.cpp
    engines/gob/pregob/onceupon/onceupon.h



diff --git a/engines/gob/pregob/onceupon/chargenchild.cpp b/engines/gob/pregob/onceupon/chargenchild.cpp
index 7150c69..ba099e4 100644
--- a/engines/gob/pregob/onceupon/chargenchild.cpp
+++ b/engines/gob/pregob/onceupon/chargenchild.cpp
@@ -99,6 +99,19 @@ void CharGenChild::advance() {
 	}
 }
 
+CharGenChild::Sound CharGenChild::shouldPlaySound() const {
+	const uint16 anim  = getAnimation();
+	const uint16 frame = getFrame();
+
+	if (((anim == kAnimWalkLeft) || (anim == kAnimWalkRight)) && ((frame == 1) || (frame == 6)))
+		return kSoundWalk;
+
+	if (((anim == kAnimJumpLeft) || (anim == kAnimJumpRight)) &&  (frame == 0))
+		return kSoundJump;
+
+	return kSoundNone;
+}
+
 } // End of namespace OnceUpon
 
 } // End of namespace Gob
diff --git a/engines/gob/pregob/onceupon/chargenchild.h b/engines/gob/pregob/onceupon/chargenchild.h
index afbe3fd..3b09ef1 100644
--- a/engines/gob/pregob/onceupon/chargenchild.h
+++ b/engines/gob/pregob/onceupon/chargenchild.h
@@ -37,11 +37,20 @@ namespace OnceUpon {
 /** The child running around on the character generator screen. */
 class CharGenChild : public ANIObject {
 public:
+	enum Sound {
+		kSoundNone = 0,
+		kSoundWalk    ,
+		kSoundJump
+	};
+
 	CharGenChild(const ANIFile &ani);
 	~CharGenChild();
 
 	/** Advance the animation to the next frame. */
 	void advance();
+
+	/** Should we play a sound right now? */
+	Sound shouldPlaySound() const;
 };
 
 } // End of namespace OnceUpon
diff --git a/engines/gob/pregob/onceupon/onceupon.cpp b/engines/gob/pregob/onceupon/onceupon.cpp
index 7eef740..f9e0933 100644
--- a/engines/gob/pregob/onceupon/onceupon.cpp
+++ b/engines/gob/pregob/onceupon/onceupon.cpp
@@ -136,7 +136,8 @@ const OnceUpon::MenuButton OnceUpon::kLanguageButtons[] = {
 
 const char *OnceUpon::kSound[kSoundMAX] = {
 	"diamant.snd", // kSoundClick
-	"cigogne.snd"  // kSoundStork
+	"cigogne.snd", // kSoundStork
+	"saute.snd"    // kSoundJump
 };
 
 const OnceUpon::SectionFunc OnceUpon::kSectionFuncs[kSectionCount] = {
@@ -1648,14 +1649,16 @@ OnceUpon::CharGenAction OnceUpon::characterGenerator() {
 	charGenSetup(state);
 
 	ANIFile ani(_vm, "ba.ani", 320);
-	ANIList anims;
-
-	anims.push_back(new CharGenChild(ani));
 
 	ani.recolor(0x0F, 0x0C);
 	ani.recolor(0x0E, 0x0A);
 	ani.recolor(0x08, 0x09);
 
+	CharGenChild *child = new CharGenChild(ani);
+
+	ANIList anims;
+	anims.push_back(child);
+
 	fadeOut();
 	_vm->_draw->forceBlit();
 
@@ -1733,6 +1736,9 @@ OnceUpon::CharGenAction OnceUpon::characterGenerator() {
 		}
 
 		if (mouseButtons == kMouseButtonsLeft) {
+			stopSound();
+			playSound(kSoundClick);
+
 			int trousers = checkButton(kCharGenTrousersButtons, ARRAYSIZE(kCharGenTrousersButtons), mouseX, mouseY);
 			if ((state == kCharGenStateTrousers) && (trousers >= 0)) {
 				_colorTrousers = trousers;
@@ -1777,6 +1783,16 @@ OnceUpon::CharGenAction OnceUpon::characterGenerator() {
 		}
 
 		drawAnim(anims);
+
+		// Play the child sounds
+		CharGenChild::Sound childSound = child->shouldPlaySound();
+		if        (childSound == CharGenChild::kSoundWalk) {
+			beep(50, 10);
+		} else if (childSound == CharGenChild::kSoundJump) {
+			stopSound();
+			playSound(kSoundJump);
+		}
+
 		showCursor();
 		fadeIn();
 
diff --git a/engines/gob/pregob/onceupon/onceupon.h b/engines/gob/pregob/onceupon/onceupon.h
index 80fcba3..d2e1feb 100644
--- a/engines/gob/pregob/onceupon/onceupon.h
+++ b/engines/gob/pregob/onceupon/onceupon.h
@@ -136,6 +136,7 @@ private:
 	enum Sound {
 		kSoundClick = 0,
 		kSoundStork    ,
+		kSoundJump     ,
 		kSoundMAX
 	};
 


Commit: 4bc80cd8810b4d328103e8bac75055a841b22d82
    https://github.com/scummvm/scummvm/commit/4bc80cd8810b4d328103e8bac75055a841b22d82
Author: Sven Hesse (drmccoy at users.sourceforge.net)
Date: 2012-07-29T16:44:46-07:00

Commit Message:
GOB: Allow spaces in the Once Upon A Time character generator

Changed paths:
    engines/gob/pregob/onceupon/onceupon.cpp



diff --git a/engines/gob/pregob/onceupon/onceupon.cpp b/engines/gob/pregob/onceupon/onceupon.cpp
index f9e0933..abee238 100644
--- a/engines/gob/pregob/onceupon/onceupon.cpp
+++ b/engines/gob/pregob/onceupon/onceupon.cpp
@@ -1599,6 +1599,9 @@ bool OnceUpon::enterString(Common::String &name, int16 key, uint maxLength, cons
 		return true;
 	}
 
+	if (key == kKeySpace)
+		key = ' ';
+
 	if ((key >= ' ') && (key <= 0xFF)) {
 		if (name.size() >= maxLength)
 			return false;
@@ -1727,6 +1730,7 @@ OnceUpon::CharGenAction OnceUpon::characterGenerator() {
 			}
 
 			if ((key == kKeyReturn) && !_name.empty()) {
+				_name.trim();
 				_name.setChar(Util::toCP850Upper(_name[0]), 0);
 
 				state = kCharGenStateSure;


Commit: 734329dcc10e5d22da716484034c78f8bea927c5
    https://github.com/scummvm/scummvm/commit/734329dcc10e5d22da716484034c78f8bea927c5
Author: Sven Hesse (drmccoy at users.sourceforge.net)
Date: 2012-07-29T16:44:46-07:00

Commit Message:
GOB: Name the Once Upon A Time frame a bit more

Changed paths:
    engines/gob/pregob/onceupon/onceupon.cpp
    engines/gob/pregob/onceupon/onceupon.h



diff --git a/engines/gob/pregob/onceupon/onceupon.cpp b/engines/gob/pregob/onceupon/onceupon.cpp
index abee238..7f59790 100644
--- a/engines/gob/pregob/onceupon/onceupon.cpp
+++ b/engines/gob/pregob/onceupon/onceupon.cpp
@@ -143,17 +143,17 @@ const char *OnceUpon::kSound[kSoundMAX] = {
 const OnceUpon::SectionFunc OnceUpon::kSectionFuncs[kSectionCount] = {
 	&OnceUpon::sectionStork,
 	&OnceUpon::sectionChapter1,
-	&OnceUpon::section02,
+	&OnceUpon::sectionParents,
 	&OnceUpon::sectionChapter2,
-	&OnceUpon::section04,
+	&OnceUpon::sectionForest0,
 	&OnceUpon::sectionChapter3,
-	&OnceUpon::section06,
+	&OnceUpon::sectionEvilCastle,
 	&OnceUpon::sectionChapter4,
-	&OnceUpon::section08,
+	&OnceUpon::sectionForest1,
 	&OnceUpon::sectionChapter5,
-	&OnceUpon::section10,
+	&OnceUpon::sectionBossFight,
 	&OnceUpon::sectionChapter6,
-	&OnceUpon::section12,
+	&OnceUpon::sectionForest2,
 	&OnceUpon::sectionChapter7,
 	&OnceUpon::sectionEnd
 };
@@ -230,6 +230,13 @@ void OnceUpon::init() {
 
 	// Default name
 	_name = "Nemo";
+
+	// Default character properties
+	_house         = 0;
+	_head          = 0;
+	_colorHair     = 0;
+	_colorJacket   = 0;
+	_colorTrousers = 0;
 }
 
 void OnceUpon::deinit() {
@@ -1403,6 +1410,8 @@ bool OnceUpon::sectionStork() {
 			int house = checkButton(param.houses, param.houseCount, mouseX, mouseY);
 			if ((state == kStorkStateWaitUser) && (house >= 0)) {
 
+				_house = house;
+
 				stork->dropBundle(param.drops[house]);
 				state = kStorkStateWaitBundle;
 
@@ -1819,8 +1828,8 @@ bool OnceUpon::sectionChapter1() {
 	return true;
 }
 
-bool OnceUpon::section02() {
-	warning("OnceUpon::section02(): TODO");
+bool OnceUpon::sectionParents() {
+	warning("OnceUpon::sectionParents(): TODO");
 	return true;
 }
 
@@ -1829,8 +1838,8 @@ bool OnceUpon::sectionChapter2() {
 	return true;
 }
 
-bool OnceUpon::section04() {
-	warning("OnceUpon::section04(): TODO");
+bool OnceUpon::sectionForest0() {
+	warning("OnceUpon::sectionForest0(): TODO");
 	return true;
 }
 
@@ -1839,8 +1848,8 @@ bool OnceUpon::sectionChapter3() {
 	return true;
 }
 
-bool OnceUpon::section06() {
-	warning("OnceUpon::section06(): TODO");
+bool OnceUpon::sectionEvilCastle() {
+	warning("OnceUpon::sectionEvilCastle(): TODO");
 	return true;
 }
 
@@ -1849,8 +1858,8 @@ bool OnceUpon::sectionChapter4() {
 	return true;
 }
 
-bool OnceUpon::section08() {
-	warning("OnceUpon::section08(): TODO");
+bool OnceUpon::sectionForest1() {
+	warning("OnceUpon::sectionForest1(): TODO");
 	return true;
 }
 
@@ -1859,8 +1868,8 @@ bool OnceUpon::sectionChapter5() {
 	return true;
 }
 
-bool OnceUpon::section10() {
-	warning("OnceUpon::section10(): TODO");
+bool OnceUpon::sectionBossFight() {
+	warning("OnceUpon::sectionBossFight(): TODO");
 	return true;
 }
 
@@ -1869,8 +1878,8 @@ bool OnceUpon::sectionChapter6() {
 	return true;
 }
 
-bool OnceUpon::section12() {
-	warning("OnceUpon::section12(): TODO");
+bool OnceUpon::sectionForest2() {
+	warning("OnceUpon::sectionForest2(): TODO");
 	return true;
 }
 
diff --git a/engines/gob/pregob/onceupon/onceupon.h b/engines/gob/pregob/onceupon/onceupon.h
index d2e1feb..2f25060 100644
--- a/engines/gob/pregob/onceupon/onceupon.h
+++ b/engines/gob/pregob/onceupon/onceupon.h
@@ -297,17 +297,17 @@ private:
 
 	bool sectionStork();
 	bool sectionChapter1();
-	bool section02();
+	bool sectionParents();
 	bool sectionChapter2();
-	bool section04();
+	bool sectionForest0();
 	bool sectionChapter3();
-	bool section06();
+	bool sectionEvilCastle();
 	bool sectionChapter4();
-	bool section08();
+	bool sectionForest1();
 	bool sectionChapter5();
-	bool section10();
+	bool sectionBossFight();
 	bool sectionChapter6();
-	bool section12();
+	bool sectionForest2();
 	bool sectionChapter7();
 	bool sectionEnd();
 
@@ -337,6 +337,8 @@ private:
 
 	Common::String _name; ///< The name of the child.
 
+	uint8 _house;
+
 	uint8 _head;
 	uint8 _colorHair;
 	uint8 _colorJacket;


Commit: f4cd726802732f7f0990eb213c2c9d16da217eec
    https://github.com/scummvm/scummvm/commit/f4cd726802732f7f0990eb213c2c9d16da217eec
Author: Sven Hesse (drmccoy at users.sourceforge.net)
Date: 2012-07-29T16:44:46-07:00

Commit Message:
GOB: Add a class handling simple SEQ files

Changed paths:
  A engines/gob/pregob/seqfile.cpp
  A engines/gob/pregob/seqfile.h
    engines/gob/module.mk



diff --git a/engines/gob/module.mk b/engines/gob/module.mk
index 4858e97..04e55dc 100644
--- a/engines/gob/module.mk
+++ b/engines/gob/module.mk
@@ -81,6 +81,7 @@ MODULE_OBJS := \
 	pregob/pregob.o \
 	pregob/txtfile.o \
 	pregob/gctfile.o \
+	pregob/seqfile.o \
 	pregob/onceupon/onceupon.o \
 	pregob/onceupon/abracadabra.o \
 	pregob/onceupon/babayaga.o \
diff --git a/engines/gob/pregob/seqfile.cpp b/engines/gob/pregob/seqfile.cpp
new file mode 100644
index 0000000..91973bb
--- /dev/null
+++ b/engines/gob/pregob/seqfile.cpp
@@ -0,0 +1,384 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "common/str.h"
+#include "common/stream.h"
+
+#include "gob/gob.h"
+#include "gob/dataio.h"
+#include "gob/draw.h"
+#include "gob/decfile.h"
+#include "gob/anifile.h"
+#include "gob/aniobject.h"
+
+#include "gob/pregob/seqfile.h"
+
+namespace Gob {
+
+SEQFile::SEQFile(GobEngine *vm, const Common::String &fileName) : _vm(vm) {
+	for (uint i = 0; i < kObjectCount; i++)
+		_objects[i].object = 0;
+
+	Common::SeekableReadStream *seq = _vm->_dataIO->getFile(Util::setExtension(fileName, ".SEQ"));
+	if (!seq) {
+		warning("SEQFile::SEQFile(): No such file \"%s\"", fileName.c_str());
+		return;
+	}
+
+	load(*seq);
+
+	delete seq;
+}
+
+SEQFile::~SEQFile() {
+	for (uint i = 0; i < kObjectCount; i++)
+		delete _objects[i].object;
+
+	for (Backgrounds::iterator b = _backgrounds.begin(); b != _backgrounds.end(); ++b)
+		delete *b;
+
+	for (Animations::iterator a = _animations.begin(); a != _animations.end(); ++a)
+		delete *a;
+}
+
+void SEQFile::load(Common::SeekableReadStream &seq) {
+	const uint16 decCount = (uint16)seq.readByte() + 1;
+	const uint16 aniCount = (uint16)seq.readByte() + 1;
+
+	// Load backgrounds
+	_backgrounds.reserve(decCount);
+	for (uint i = 0; i < decCount; i++) {
+		const Common::String dec = Util::readString(seq, 13);
+
+		if (!_vm->_dataIO->hasFile(dec)) {
+			warning("SEQFile::load(): No such background \"%s\"", dec.c_str());
+			return;
+		}
+
+		_backgrounds.push_back(new DECFile(_vm, dec, 320, 200));
+	}
+
+	// Load animations
+	_animations.reserve(aniCount);
+	for (uint i = 0; i < aniCount; i++) {
+		const Common::String ani = Util::readString(seq, 13);
+
+		if (!_vm->_dataIO->hasFile(ani)) {
+			warning("SEQFile::load(): No such animation \"%s\"", ani.c_str());
+			return;
+		}
+
+		_animations.push_back(new ANIFile(_vm, ani));
+	}
+
+	_frameRate = seq.readUint16LE();
+
+	// Load background change keys
+
+	const uint16 bgKeyCount = seq.readUint16LE();
+	_bgKeys.resize(bgKeyCount);
+
+	for (uint16 i = 0; i < bgKeyCount; i++) {
+		const uint16 frame = seq.readUint16LE();
+		const uint16 index = seq.readUint16LE();
+
+		_bgKeys[i].frame      = frame;
+		_bgKeys[i].background = index < _backgrounds.size() ? _backgrounds[index] : 0;
+	}
+
+	// Load animation keys for all 4 objects
+
+	for (uint i = 0; i < kObjectCount; i++) {
+		const uint16 animKeyCount = seq.readUint16LE();
+		_animKeys.reserve(_animKeys.size() + animKeyCount);
+
+		for (uint16 j = 0; j < animKeyCount; j++) {
+			_animKeys.push_back(AnimationKey());
+
+			const uint16 frame = seq.readUint16LE();
+			const uint16 index = seq.readUint16LE();
+
+			uint16 animation;
+			const ANIFile *ani = findANI(index, animation);
+
+			_animKeys.back().object    = i;
+			_animKeys.back().frame     = frame;
+			_animKeys.back().ani       = ani;
+			_animKeys.back().animation = animation;
+			_animKeys.back().x         = seq.readSint16LE();
+			_animKeys.back().y         = seq.readSint16LE();
+			_animKeys.back().order     = seq.readSint16LE();
+		}
+	}
+
+}
+
+const ANIFile *SEQFile::findANI(uint16 index, uint16 &animation) {
+	animation = 0xFFFF;
+
+	// 0xFFFF = remove animation
+	if (index == 0xFFFF)
+		return 0;
+
+	for (Animations::const_iterator a = _animations.begin(); a != _animations.end(); ++a) {
+		if (index < (*a)->getAnimationCount()) {
+			animation = index;
+			return *a;
+		}
+
+		index -= (*a)->getAnimationCount();
+	}
+
+	return 0;
+}
+
+void SEQFile::play(bool abortable, uint16 endFrame, uint16 frameRate) {
+	if (_bgKeys.empty() && _animKeys.empty())
+		// Nothing to do
+		return;
+
+	// Init
+
+	_frame = 0;
+	_abortPlay = false;
+
+	for (uint i = 0; i < kObjectCount; i++) {
+		delete _objects[i].object;
+
+		_objects[i].object = 0;
+		_objects[i].order  = 0;
+	}
+
+	for (Loops::iterator l = _loops.begin(); l != _loops.end(); ++l)
+		l->currentLoop = 0;
+
+	// Set the frame rate
+
+	int16 frameRateBack = _vm->_util->getFrameRate();
+
+	if (frameRate == 0)
+		frameRate = _frameRate;
+
+	_vm->_util->setFrameRate(frameRate);
+
+	_abortable = abortable;
+
+	while (!_vm->shouldQuit() && !_abortPlay) {
+		// Handle the frame contents
+		playFrame();
+
+		// Handle extra frame events
+		handleFrameEvent();
+
+		// Wait for the frame to end
+		_vm->_draw->blitInvalidated();
+		_vm->_util->waitEndFrame();
+
+		// Handle input
+
+		_vm->_util->processInput();
+
+		int16 key = _vm->_util->checkKey();
+
+		int16 mouseX, mouseY;
+		MouseButtons mouseButtons;
+		_vm->_util->getMouseState(&mouseX, &mouseY, &mouseButtons);
+		_vm->_util->forceMouseUp();
+
+		handleInput(key, mouseX, mouseY, mouseButtons);
+
+		// Loop
+
+		bool looped = false;
+		for (Loops::iterator l = _loops.begin(); l != _loops.end(); ++l) {
+			if ((l->endFrame == _frame) && (l->currentLoop < l->loopCount)) {
+				_frame = l->startFrame;
+
+				l->currentLoop++;
+				looped = true;
+			}
+		}
+
+		// If we didn't loop, advance the frame and look if we should end here
+
+		if (!looped) {
+			_frame++;
+			if (_frame >= endFrame)
+				break;
+		}
+	}
+
+	// Restore the frame rate
+	_vm->_util->setFrameRate(frameRateBack);
+}
+
+void SEQFile::playFrame() {
+	// Remove the current animation frames
+	clearAnims();
+
+	// Handle background keys, directly updating the background
+	for (BackgroundKeys::const_iterator b = _bgKeys.begin(); b != _bgKeys.end(); ++b) {
+		if (!b->background || (b->frame != _frame))
+			continue;
+
+		b->background->draw(*_vm->_draw->_backSurface);
+
+		_vm->_draw->dirtiedRect(_vm->_draw->_backSurface, 0, 0, 319, 199);
+	}
+
+	// Handle the animation keys, updating the objects
+	for (AnimationKeys::const_iterator a = _animKeys.begin(); a != _animKeys.end(); ++a) {
+		if (a->frame != _frame)
+			continue;
+
+		Object &object = _objects[a->object];
+
+		delete object.object;
+		object.object = 0;
+
+		// No valid animation => remove
+		if ((a->animation == 0xFFFF) || !a->ani)
+			continue;
+
+		// Change the animation
+
+		object.object = new ANIObject(*a->ani);
+
+		object.object->setAnimation(a->animation);
+		object.object->setPosition(a->x, a->y);
+		object.object->setVisible(true);
+		object.object->setPause(false);
+
+		object.order = a->order;
+	}
+
+	// Draw the animations
+	drawAnims();
+}
+
+// NOTE: This is really not at all efficient. However, since there's only a
+//       small number of objects, it should matter. We really do need a stable
+//       sort, though, so Common::sort() is out.
+SEQFile::Objects SEQFile::getOrderedObjects() {
+	int16 minOrder = (int16)0x7FFF;
+	int16 maxOrder = (int16)0x8000;
+
+	Objects objects;
+
+	// Find the span of order values
+	for (uint i = 0; i < kObjectCount; i++) {
+		if (!_objects[i].object)
+			continue;
+
+		minOrder = MIN(minOrder, _objects[i].order);
+		maxOrder = MAX(maxOrder, _objects[i].order);
+	}
+
+	// Stably sort the objects by order value
+	for (int16 o = minOrder; o <= maxOrder; o++)
+		for (uint i = 0; i < kObjectCount; i++)
+			if (_objects[i].object && (_objects[i].order == o))
+				objects.push_back(_objects[i]);
+
+	return objects;
+}
+
+void SEQFile::clearAnims() {
+	Objects objects = getOrderedObjects();
+
+	// Remove the animation frames, in reverse drawing order
+	for (Objects::iterator o = objects.reverse_begin(); o != objects.end(); --o) {
+		int16 left, top, right, bottom;
+
+		if (o->object->clear(*_vm->_draw->_backSurface, left, top, right, bottom))
+			_vm->_draw->dirtiedRect(_vm->_draw->_backSurface, left, top, right, bottom);
+	}
+}
+
+void SEQFile::drawAnims() {
+	Objects objects = getOrderedObjects();
+
+	// Draw the animation frames and advance the animation
+	for (Objects::iterator o = objects.begin(); o != objects.end(); ++o) {
+		int16 left, top, right, bottom;
+
+		if (o->object->draw(*_vm->_draw->_backSurface, left, top, right, bottom))
+			_vm->_draw->dirtiedRect(_vm->_draw->_backSurface, left, top, right, bottom);
+
+		o->object->advance();
+	}
+}
+
+uint16 SEQFile::getFrame() const {
+	return _frame;
+}
+
+void SEQFile::seekFrame(uint16 frame) {
+	_frame = frame;
+}
+
+uint SEQFile::addLoop(uint16 startFrame, uint16 endFrame, uint16 loopCount) {
+	_loops.resize(_loops.size() + 1);
+
+	_loops.back().startFrame  = startFrame;
+	_loops.back().endFrame    = endFrame;
+	_loops.back().loopCount   = loopCount;
+	_loops.back().currentLoop = 0;
+	_loops.back().empty       = false;
+
+	return _loops.size() - 1;
+}
+
+void SEQFile::skipLoop(uint loopID) {
+	if (loopID >= _loops.size())
+		return;
+
+	_loops[loopID].currentLoop = 0xFFFF;
+}
+
+void SEQFile::delLoop(uint loopID) {
+	if (loopID >= _loops.size())
+		return;
+
+	_loops[loopID].empty = true;
+
+	cleanLoops();
+}
+
+void SEQFile::cleanLoops() {
+	while (!_loops.empty() && _loops.back().empty)
+		_loops.pop_back();
+}
+
+void SEQFile::abortPlay() {
+	_abortPlay = true;
+}
+
+void SEQFile::handleFrameEvent() {
+}
+
+void SEQFile::handleInput(int16 key, int16 mouseX, int16 mouseY, MouseButtons mouseButtons) {
+	if (_abortable && ((key != 0) || (mouseButtons != kMouseButtonsNone)))
+		abortPlay();
+}
+
+} // End of namespace Gob
diff --git a/engines/gob/pregob/seqfile.h b/engines/gob/pregob/seqfile.h
new file mode 100644
index 0000000..5e12962
--- /dev/null
+++ b/engines/gob/pregob/seqfile.h
@@ -0,0 +1,193 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef GOB_PREGOB_SEQFILE_H
+#define GOB_PREGOB_SEQFILE_H
+
+#include "common/system.h"
+#include "common/array.h"
+#include "common/list.h"
+
+#include "gob/util.h"
+
+namespace Common {
+	class String;
+	class SeekableReadStream;
+}
+
+namespace Gob {
+
+class GobEngine;
+
+class DECFile;
+class ANIFile;
+class ANIObject;
+
+/** A SEQ file, describing a complex animation sequence.
+ *
+ *  Used in early hardcoded gob games.
+ *  The principle is similar to the Mult class (see mult.h), but instead
+ *  of depending on all the externally loaded animations, backgrounds and
+ *  objects, a SEQ file references animation and background directly by
+ *  filename.
+ */
+class SEQFile {
+public:
+	SEQFile(GobEngine *vm, const Common::String &fileName);
+	virtual ~SEQFile();
+
+	/** Play the SEQ.
+	 *
+	 *  @param abortable If true, end playback on any user input.
+	 *  @param endFrame  The frame on where to end, or 0xFFFF for infinite playback.
+	 *  @param frameRate The frame rate at which to play the SEQ, or 0 for playing at
+	 *                   the speed the SEQ itself wants to.
+	 */
+	void play(bool abortable = true, uint16 endFrame = 0xFFFF, uint16 frameRate = 0);
+
+
+protected:
+	GobEngine *_vm;
+
+
+	/** Returns the current frame number. */
+	uint16 getFrame() const;
+
+	/** Seek to a specific frame. */
+	void seekFrame(uint16 frame);
+
+	/** Add a frame loop. */
+	uint addLoop(uint16 startFrame, uint16 endFrame, uint16 loopCount);
+
+	/** Skip a frame loop. */
+	void skipLoop(uint loopID);
+
+	/** Delete a frame loop. */
+	void delLoop(uint loopID);
+
+	/** Ends SEQ playback. */
+	void abortPlay();
+
+	/** Callback for special frame events. */
+	virtual void handleFrameEvent();
+	/** Callback for special user input handling. */
+	virtual void handleInput(int16 key, int16 mouseX, int16 mouseY, MouseButtons mouseButtons);
+
+
+private:
+	/** Number of animation objects that are visible at the same time. */
+	static const uint kObjectCount = 4;
+
+	/** A key for changing the background. */
+	struct BackgroundKey {
+		uint16 frame; ///< Frame the change is to happen.
+
+		const DECFile *background; ///< The background to use.
+	};
+
+	/** A key for playing an object animation. */
+	struct AnimationKey {
+		uint object; ///< The object this key belongs to.
+
+		uint16 frame; ///< Frame the change is to happen.
+
+		const ANIFile *ani; ///< The ANI to use.
+
+		uint16 animation; ///< The animation to use.
+
+		int16 x; ///< X position of the animation.
+		int16 y; ///< Y position of the animation.
+
+		int16 order; ///< Used to determine in which order to draw the objects.
+	};
+
+	/** A managed animation object. */
+	struct Object {
+		ANIObject *object; ///< The actual animation object.
+
+		int16 order; ///< The current drawing order.
+	};
+
+	/** A frame loop. */
+	struct Loop {
+		uint16 startFrame;
+		uint16 endFrame;
+
+		uint16 loopCount;
+		uint16 currentLoop;
+
+		bool empty;
+	};
+
+	typedef Common::Array<DECFile *> Backgrounds;
+	typedef Common::Array<ANIFile *> Animations;
+
+	typedef Common::Array<BackgroundKey> BackgroundKeys;
+	typedef Common::Array<AnimationKey>  AnimationKeys;
+
+	typedef Common::List<Object> Objects;
+
+	typedef Common::Array<Loop> Loops;
+
+
+	uint16 _frame;     ///< The current frame.
+	bool   _abortPlay; ///< Was the end of the playback requested?
+
+	uint16 _frameRate;
+
+	Backgrounds _backgrounds; ///< All backgrounds in this SEQ.
+	Animations  _animations;  ///< All animations in this SEQ.
+
+	BackgroundKeys _bgKeys;   ///< The background change keyframes.
+	AnimationKeys  _animKeys; ///< The animation change keyframes.
+
+	Object _objects[kObjectCount]; ///< The managed animation objects.
+
+	Loops _loops;
+
+	/** Whether the playback should be abortable by user input. */
+	bool _abortable;
+
+
+	// -- Loading helpers --
+
+	void load(Common::SeekableReadStream &seq);
+
+	const ANIFile *findANI(uint16 index, uint16 &animation);
+
+	// -- Playback helpers --
+
+	void playFrame();
+
+	/** Get a list of objects ordered by drawing order. */
+	Objects getOrderedObjects();
+
+	void clearAnims(); ///< Remove all animation frames.
+	void drawAnims();  ///< Draw the animation frames.
+
+	/** Look if we can compact the loop array. */
+	void cleanLoops();
+};
+
+} // End of namespace Gob
+
+#endif // GOB_PREGOB_SEQFILE_H


Commit: 850472f21e73280c0bf35c76163419a7e280fea2
    https://github.com/scummvm/scummvm/commit/850472f21e73280c0bf35c76163419a7e280fea2
Author: Sven Hesse (drmccoy at users.sourceforge.net)
Date: 2012-07-29T16:44:46-07:00

Commit Message:
GOB: Implement the proper Once Upon A Time title sequence

Changed paths:
  A engines/gob/pregob/onceupon/title.cpp
  A engines/gob/pregob/onceupon/title.h
    engines/gob/module.mk
    engines/gob/pregob/onceupon/onceupon.cpp
    engines/gob/pregob/onceupon/onceupon.h



diff --git a/engines/gob/module.mk b/engines/gob/module.mk
index 04e55dc..489afe5 100644
--- a/engines/gob/module.mk
+++ b/engines/gob/module.mk
@@ -85,6 +85,7 @@ MODULE_OBJS := \
 	pregob/onceupon/onceupon.o \
 	pregob/onceupon/abracadabra.o \
 	pregob/onceupon/babayaga.o \
+	pregob/onceupon/title.o \
 	pregob/onceupon/stork.o \
 	pregob/onceupon/chargenchild.o \
 	minigames/geisha/evilfish.o \
diff --git a/engines/gob/pregob/onceupon/onceupon.cpp b/engines/gob/pregob/onceupon/onceupon.cpp
index 7f59790..6ee391e 100644
--- a/engines/gob/pregob/onceupon/onceupon.cpp
+++ b/engines/gob/pregob/onceupon/onceupon.cpp
@@ -37,6 +37,7 @@
 
 #include "gob/pregob/onceupon/onceupon.h"
 #include "gob/pregob/onceupon/palettes.h"
+#include "gob/pregob/onceupon/title.h"
 #include "gob/pregob/onceupon/chargenchild.h"
 
 static const uint kLanguageCount = 5;
@@ -657,94 +658,11 @@ const PreGob::AnimProperties OnceUpon::kTitleAnimation = {
 };
 
 void OnceUpon::showTitle() {
-	// Show the Once Upon A Time title animation
-	// NOTE: This is currently only a mock-up. The real animation is in "ville.seq".
-
 	fadeOut();
 	setGamePalette(10);
 
-	warning("OnceUpon::showTitle(): Actually play the SEQ");
-
-	clearScreen();
-
-	_vm->_video->drawPackedSprite("ville.cmp", *_vm->_draw->_backSurface);
-	_vm->_draw->forceBlit();
-
-	ANIFile ani  (_vm, "pres.ani", 320);
-	ANIList anims;
-
-	loadAnims(anims, ani, 1, &kTitleAnimation);
-
-	playTitleMusic();
-
-	while (!_vm->shouldQuit()) {
-		redrawAnim(anims);
-
-		fadeIn();
-
-		endFrame(true);
-
-		if (hasInput())
-			break;
-	}
-
-	freeAnims(anims);
-
-	fadeOut();
-	stopTitleMusic();
-}
-
-void OnceUpon::playTitleMusic() {
-	// Look at what platform this is and play the appropriate music type
-
-	if      (_vm->getPlatform() == Common::kPlatformPC)
-		playTitleMusicDOS();
-	else if (_vm->getPlatform() == Common::kPlatformAmiga)
-		playTitleMusicAmiga();
-	else if (_vm->getPlatform() == Common::kPlatformAtariST)
-		playTitleMusicAtariST();
-}
-
-void OnceUpon::playTitleMusicDOS() {
-	// Play an AdLib track
-
-	_vm->_sound->adlibLoadTBR("babayaga.tbr");
-	_vm->_sound->adlibLoadMDY("babayaga.mdy");
-	_vm->_sound->adlibSetRepeating(-1);
-	_vm->_sound->adlibPlay();
-}
-
-void OnceUpon::playTitleMusicAmiga() {
-	// Play a Protracker track
-
-	_vm->_sound->protrackerPlay("mod.babayaga");
-}
-
-void OnceUpon::playTitleMusicAtariST() {
-	// Play a Soundblaster composition
-
-	static const int16        titleMusic[21] = { 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 2, 0, 1, 0, 0, 0, 0, 0, -1};
-	static const char * const titleFiles[ 3] = {"baba1.snd", "baba2.snd", "baba3.snd"};
-
-	for (uint i = 0; i < ARRAYSIZE(titleFiles); i++)
-		_vm->_sound->sampleLoad(_vm->_sound->sampleGetBySlot(i), SOUND_SND, titleFiles[i]);
-
-	_vm->_sound->blasterPlayComposition(titleMusic, 0);
-	_vm->_sound->blasterRepeatComposition(-1);
-}
-
-void OnceUpon::stopTitleMusic() {
-	// Just stop everything
-
-	_vm->_sound->adlibSetRepeating(0);
-	_vm->_sound->blasterRepeatComposition(0);
-
-	_vm->_sound->adlibStop();
-	_vm->_sound->blasterStopComposition();
-	_vm->_sound->protrackerStop();
-
-	for (int i = 0; i < ::Gob::Sound::kSoundsCount; i++)
-		_vm->_sound->sampleFree(_vm->_sound->sampleGetBySlot(i));
+	Title title(_vm);
+	title.play();
 }
 
 void OnceUpon::showChapter(int chapter) {
diff --git a/engines/gob/pregob/onceupon/onceupon.h b/engines/gob/pregob/onceupon/onceupon.h
index 2f25060..41a2f56 100644
--- a/engines/gob/pregob/onceupon/onceupon.h
+++ b/engines/gob/pregob/onceupon/onceupon.h
@@ -237,15 +237,6 @@ private:
 	void handleAnimalNames(uint count, const MenuButton *buttons, const char * const *names);
 
 
-	// -- Title music helpers --
-
-	void playTitleMusic();        ///< Play the title music.
-	void playTitleMusicDOS();     ///< Play the title music of the DOS      version.
-	void playTitleMusicAmiga();   ///< Play the title music of the Amiga    version.
-	void playTitleMusicAtariST(); ///< Play the title music of the Atari ST version.
-	void stopTitleMusic();        ///< Stop the title music.
-
-
 	// -- Menu helpers --
 
 	MenuAction handleStartMenu(const MenuButton *animalsButton); ///< Handle the start  menu.
@@ -291,6 +282,7 @@ private:
 	/** Play / Display the name of an animal in one language. */
 	void anPlayAnimalName(const Common::String &animal, uint language);
 
+
 	// -- Game sections --
 
 	bool playSection();
diff --git a/engines/gob/pregob/onceupon/title.cpp b/engines/gob/pregob/onceupon/title.cpp
new file mode 100644
index 0000000..5163ff6
--- /dev/null
+++ b/engines/gob/pregob/onceupon/title.cpp
@@ -0,0 +1,117 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "gob/gob.h"
+#include "gob/global.h"
+#include "gob/palanim.h"
+#include "gob/draw.h"
+
+#include "gob/sound/sound.h"
+
+#include "gob/pregob/onceupon/title.h"
+
+namespace Gob {
+
+namespace OnceUpon {
+
+Title::Title(GobEngine *vm) : SEQFile(vm, "ville.seq") {
+}
+
+Title::~Title() {
+}
+
+void Title::play() {
+	SEQFile::play(true, 0xFFFF, 15);
+
+	// After playback, fade out and stop the music
+	if (!_vm->shouldQuit())
+		_vm->_palAnim->fade(0, 0, 0);
+
+	stopMusic();
+}
+
+void Title::handleFrameEvent() {
+	// On fame 0, start the music and fade in
+	if (getFrame() == 0) {
+		playMusic();
+
+		_vm->_draw->forceBlit();
+		_vm->_palAnim->fade(_vm->_global->_pPaletteDesc, 0, 0);
+	}
+}
+
+void Title::playMusic() {
+	// Look at what platform this is and play the appropriate music type
+
+	if      (_vm->getPlatform() == Common::kPlatformPC)
+		playMusicDOS();
+	else if (_vm->getPlatform() == Common::kPlatformAmiga)
+		playMusicAmiga();
+	else if (_vm->getPlatform() == Common::kPlatformAtariST)
+		playMusicAtariST();
+}
+
+void Title::playMusicDOS() {
+	// Play an AdLib track
+
+	_vm->_sound->adlibLoadTBR("babayaga.tbr");
+	_vm->_sound->adlibLoadMDY("babayaga.mdy");
+	_vm->_sound->adlibSetRepeating(-1);
+	_vm->_sound->adlibPlay();
+}
+
+void Title::playMusicAmiga() {
+	// Play a Protracker track
+
+	_vm->_sound->protrackerPlay("mod.babayaga");
+}
+
+void Title::playMusicAtariST() {
+	// Play a Soundblaster composition
+
+	static const int16        titleMusic[21] = { 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 2, 0, 1, 0, 0, 0, 0, 0, -1};
+	static const char * const titleFiles[ 3] = {"baba1.snd", "baba2.snd", "baba3.snd"};
+
+	for (uint i = 0; i < ARRAYSIZE(titleFiles); i++)
+		_vm->_sound->sampleLoad(_vm->_sound->sampleGetBySlot(i), SOUND_SND, titleFiles[i]);
+
+	_vm->_sound->blasterPlayComposition(titleMusic, 0);
+	_vm->_sound->blasterRepeatComposition(-1);
+}
+
+void Title::stopMusic() {
+	// Just stop everything
+
+	_vm->_sound->adlibSetRepeating(0);
+	_vm->_sound->blasterRepeatComposition(0);
+
+	_vm->_sound->adlibStop();
+	_vm->_sound->blasterStopComposition();
+	_vm->_sound->protrackerStop();
+
+	for (int i = 0; i < ::Gob::Sound::kSoundsCount; i++)
+		_vm->_sound->sampleFree(_vm->_sound->sampleGetBySlot(i));
+}
+
+} // End of namespace OnceUpon
+
+} // End of namespace Gob
diff --git a/engines/gob/pregob/onceupon/title.h b/engines/gob/pregob/onceupon/title.h
new file mode 100644
index 0000000..5e7ef76
--- /dev/null
+++ b/engines/gob/pregob/onceupon/title.h
@@ -0,0 +1,55 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef GOB_PREGOB_ONCEUPON_TITLE_H
+#define GOB_PREGOB_ONCEUPON_TITLE_H
+
+#include "gob/pregob/seqfile.h"
+
+namespace Gob {
+
+namespace OnceUpon {
+
+/** The Once Upon A Time title animation sequence. */
+class Title : public SEQFile {
+public:
+	Title(GobEngine *vm);
+	~Title();
+
+	void play();
+
+protected:
+	void handleFrameEvent();
+
+private:
+	void playMusic();        ///< Play the title music.
+	void playMusicDOS();     ///< Play the title music of the DOS      version.
+	void playMusicAmiga();   ///< Play the title music of the Amiga    version.
+	void playMusicAtariST(); ///< Play the title music of the Atari ST version.
+	void stopMusic();        ///< Stop the title music.
+};
+
+} // End of namespace OnceUpon
+
+} // End of namespace Gob
+
+#endif // GOB_PREGOB_ONCEUPON_TITLE_H


Commit: 3189729c972b5da1356497e82e08a21c94c8fbec
    https://github.com/scummvm/scummvm/commit/3189729c972b5da1356497e82e08a21c94c8fbec
Author: Sven Hesse (drmccoy at users.sourceforge.net)
Date: 2012-07-29T16:44:46-07:00

Commit Message:
GOB: Don't leak in sampleLoad() when loading fails

Changed paths:
    engines/gob/sound/sound.cpp
    engines/gob/sound/sound.h



diff --git a/engines/gob/sound/sound.cpp b/engines/gob/sound/sound.cpp
index 69a668e..63af6ae 100644
--- a/engines/gob/sound/sound.cpp
+++ b/engines/gob/sound/sound.cpp
@@ -109,7 +109,7 @@ int Sound::sampleGetNextFreeSlot() const {
 	return -1;
 }
 
-bool Sound::sampleLoad(SoundDesc *sndDesc, SoundType type, const char *fileName, bool tryExist) {
+bool Sound::sampleLoad(SoundDesc *sndDesc, SoundType type, const char *fileName) {
 	if (!sndDesc)
 		return false;
 
@@ -117,12 +117,15 @@ bool Sound::sampleLoad(SoundDesc *sndDesc, SoundType type, const char *fileName,
 
 	int32 size;
 	byte *data = _vm->_dataIO->getFile(fileName, size);
-	if (!data) {
-		warning("Can't open sample file \"%s\"", fileName);
+
+	if (!data || !sndDesc->load(type, data, size)) {
+		delete data;
+
+		warning("Sound::sampleLoad(): Failed to load sound \"%s\"", fileName);
 		return false;
 	}
 
-	return sndDesc->load(type, data, size);
+	return true;
 }
 
 void Sound::sampleFree(SoundDesc *sndDesc, bool noteAdLib, int index) {
diff --git a/engines/gob/sound/sound.h b/engines/gob/sound/sound.h
index 7beffb5..bbc182d 100644
--- a/engines/gob/sound/sound.h
+++ b/engines/gob/sound/sound.h
@@ -51,7 +51,7 @@ public:
 	const SoundDesc *sampleGetBySlot(int slot) const;
 	int sampleGetNextFreeSlot() const;
 
-	bool sampleLoad(SoundDesc *sndDesc, SoundType type, const char *fileName, bool tryExist = true);
+	bool sampleLoad(SoundDesc *sndDesc, SoundType type, const char *fileName);
 	void sampleFree(SoundDesc *sndDesc, bool noteAdLib = false, int index = -1);
 
 


Commit: 25bc7467b444d78c64300af9786f08842de81313
    https://github.com/scummvm/scummvm/commit/25bc7467b444d78c64300af9786f08842de81313
Author: Sven Hesse (drmccoy at users.sourceforge.net)
Date: 2012-07-29T16:44:46-07:00

Commit Message:
GOB: Use Sound::sampleLoad in PreGob

Changed paths:
    engines/gob/pregob/pregob.cpp



diff --git a/engines/gob/pregob/pregob.cpp b/engines/gob/pregob/pregob.cpp
index 42b5a8f..54eb3c6 100644
--- a/engines/gob/pregob/pregob.cpp
+++ b/engines/gob/pregob/pregob.cpp
@@ -161,17 +161,7 @@ void PreGob::freeSounds() {
 }
 
 bool PreGob::loadSound(SoundDesc &sound, const Common::String &file) const {
-	int32 size;
-	byte *data = _vm->_dataIO->getFile(file, size);
-
-	if (!data || !sound.load(SOUND_SND, data, size)) {
-		delete data;
-
-		warning("PreGob::loadSound(): Failed to load sound \"%s\"", file.c_str());
-		return false;
-	}
-
-	return true;
+	return _vm->_sound->sampleLoad(&sound, SOUND_SND, file.c_str());
 }
 
 void PreGob::playSound(uint sound, int16 frequency, int16 repCount) {


Commit: dd2768a2e47dd54f055cf65b2212ee9dca395c18
    https://github.com/scummvm/scummvm/commit/dd2768a2e47dd54f055cf65b2212ee9dca395c18
Author: Sven Hesse (drmccoy at users.sourceforge.net)
Date: 2012-07-29T16:44:46-07:00

Commit Message:
GOB: Reorder a few things

Changed paths:
    engines/gob/pregob/onceupon/onceupon.cpp
    engines/gob/pregob/onceupon/onceupon.h
    engines/gob/pregob/onceupon/stork.h
    engines/gob/pregob/pregob.h



diff --git a/engines/gob/pregob/onceupon/onceupon.cpp b/engines/gob/pregob/onceupon/onceupon.cpp
index 6ee391e..9d32eaa 100644
--- a/engines/gob/pregob/onceupon/onceupon.cpp
+++ b/engines/gob/pregob/onceupon/onceupon.cpp
@@ -135,7 +135,7 @@ const OnceUpon::MenuButton OnceUpon::kLanguageButtons[] = {
 	{true, 234, 138, 284, 173, 265, 55, 315, 90, 234, 138, 2}
 };
 
-const char *OnceUpon::kSound[kSoundMAX] = {
+const char *OnceUpon::kSound[kSoundCount] = {
 	"diamant.snd", // kSoundClick
 	"cigogne.snd", // kSoundStork
 	"saute.snd"    // kSoundJump
@@ -216,7 +216,7 @@ void OnceUpon::init() {
 
 	// Load all our sounds and init the screen
 
-	loadSounds(kSound, kSoundMAX);
+	loadSounds(kSound, kSoundCount);
 	initScreen();
 
 	// We start with an invalid palette
@@ -226,7 +226,7 @@ void OnceUpon::init() {
 	_quit = false;
 
 	// We start with no selected difficulty and at section 0
-	_difficulty = kDifficultyMAX;
+	_difficulty = kDifficultyCount;
 	_section    = 0;
 
 	// Default name
@@ -926,7 +926,7 @@ void OnceUpon::drawIngameMenu() {
 }
 
 void OnceUpon::drawMenuDifficulty() {
-	if (_difficulty == kDifficultyMAX)
+	if (_difficulty == kDifficultyCount)
 		return;
 
 	TXTFile *difficulties = loadTXT(getLocFile("diffic.tx"), TXTFile::kFormatStringPositionColor);
diff --git a/engines/gob/pregob/onceupon/onceupon.h b/engines/gob/pregob/onceupon/onceupon.h
index 41a2f56..66ef877 100644
--- a/engines/gob/pregob/onceupon/onceupon.h
+++ b/engines/gob/pregob/onceupon/onceupon.h
@@ -129,7 +129,7 @@ private:
 		kDifficultyBeginner     = 0,
 		kDifficultyIntermediate = 1,
 		kDifficultyAdvanced     = 2,
-		kDifficultyMAX
+		kDifficultyCount
 	};
 
 	/** The different sounds common in the game. */
@@ -137,7 +137,7 @@ private:
 		kSoundClick = 0,
 		kSoundStork    ,
 		kSoundJump     ,
-		kSoundMAX
+		kSoundCount
 	};
 
 	/** Action the character generation wants us to take. */
@@ -181,7 +181,7 @@ private:
 	static const MenuButton kCharGenNameEntry[];
 
 	/** All general game sounds we know about. */
-	static const char *kSound[kSoundMAX];
+	static const char *kSound[kSoundCount];
 
 
 	static const AnimProperties kClownAnimations[];
@@ -196,6 +196,33 @@ private:
 	static const SectionFunc kSectionFuncs[kSectionCount];
 
 
+	/** Did we open the game archives? */
+	bool _openedArchives;
+
+	// Fonts
+	Font *_jeudak;
+	Font *_lettre;
+	Font *_plettre;
+	Font *_glettre;
+
+	/** The current palette. */
+	int _palette;
+
+	bool _quit; ///< Did the user request a normal game quit?
+
+	Difficulty _difficulty; ///< The current difficulty.
+	int        _section;    ///< The current game section.
+
+	Common::String _name; ///< The name of the child.
+
+	uint8 _house;
+
+	uint8 _head;
+	uint8 _colorHair;
+	uint8 _colorJacket;
+	uint8 _colorTrousers;
+
+
 	// -- General helpers --
 
 	void setGamePalette(uint palette); ///< Set a game palette.
@@ -308,33 +335,6 @@ private:
 	void charGenDrawName();
 
 	static bool enterString(Common::String &name, int16 key, uint maxLength, const Font &font);
-
-
-	/** Did we open the game archives? */
-	bool _openedArchives;
-
-	// Fonts
-	Font *_jeudak;
-	Font *_lettre;
-	Font *_plettre;
-	Font *_glettre;
-
-	/** The current palette. */
-	int _palette;
-
-	bool _quit; ///< Did the user request a normal game quit?
-
-	Difficulty _difficulty; ///< The current difficulty.
-	int        _section;    ///< The current game section.
-
-	Common::String _name; ///< The name of the child.
-
-	uint8 _house;
-
-	uint8 _head;
-	uint8 _colorHair;
-	uint8 _colorJacket;
-	uint8 _colorTrousers;
 };
 
 } // End of namespace OnceUpon
diff --git a/engines/gob/pregob/onceupon/stork.h b/engines/gob/pregob/onceupon/stork.h
index d26a887..756f525 100644
--- a/engines/gob/pregob/onceupon/stork.h
+++ b/engines/gob/pregob/onceupon/stork.h
@@ -79,12 +79,6 @@ private:
 	};
 
 
-	void setState(State state, uint16 anim);
-	void setState(State state, uint16 anim, int16 x);
-
-	void dropBundle(State state, uint16 anim);
-
-
 	GobEngine *_vm;
 
 	Surface   *_frame;
@@ -94,6 +88,12 @@ private:
 
 	bool       _shouldDrop;
 	BundleDrop _bundleDrop;
+
+
+	void setState(State state, uint16 anim);
+	void setState(State state, uint16 anim, int16 x);
+
+	void dropBundle(State state, uint16 anim);
 };
 
 } // End of namespace OnceUpon
diff --git a/engines/gob/pregob/pregob.h b/engines/gob/pregob/pregob.h
index da0de60..632f85b 100644
--- a/engines/gob/pregob/pregob.h
+++ b/engines/gob/pregob/pregob.h
@@ -68,6 +68,9 @@ protected:
 	static const char *kLanguageSuffixLong [5];
 
 
+	GobEngine *_vm;
+
+
 	// -- Graphics --
 
 	/** Initialize the game screen. */
@@ -174,18 +177,16 @@ protected:
 	GCTFile *loadGCT(const Common::String &gctFile) const;
 
 
-	GobEngine *_vm;
-
 private:
-	/** Load a sound file. */
-	bool loadSound(SoundDesc &sound, const Common::String &file) const;
-
-
 	/** Did we fade out? */
 	bool _fadedOut;
 
 	/** All loaded sounds. */
 	Common::Array<SoundDesc> _sounds;
+
+
+	/** Load a sound file. */
+	bool loadSound(SoundDesc &sound, const Common::String &file) const;
 };
 
 } // End of namespace Gob


Commit: b001168658f57b845bae81df0ca85240c796e74e
    https://github.com/scummvm/scummvm/commit/b001168658f57b845bae81df0ca85240c796e74e
Author: Sven Hesse (drmccoy at users.sourceforge.net)
Date: 2012-07-29T16:48:40-07:00

Commit Message:
GOB: Implement the parents section in Once Upon A Time

The text lines are not drawn completely correct yet, because
apparently, GCTFile needs to wrap long lines.

Changed paths:
  A engines/gob/pregob/onceupon/parents.cpp
  A engines/gob/pregob/onceupon/parents.h
    engines/gob/module.mk
    engines/gob/pregob/onceupon/abracadabra.cpp
    engines/gob/pregob/onceupon/babayaga.cpp
    engines/gob/pregob/onceupon/onceupon.cpp



diff --git a/engines/gob/module.mk b/engines/gob/module.mk
index 489afe5..d5ee647 100644
--- a/engines/gob/module.mk
+++ b/engines/gob/module.mk
@@ -86,6 +86,7 @@ MODULE_OBJS := \
 	pregob/onceupon/abracadabra.o \
 	pregob/onceupon/babayaga.o \
 	pregob/onceupon/title.o \
+	pregob/onceupon/parents.o \
 	pregob/onceupon/stork.o \
 	pregob/onceupon/chargenchild.o \
 	minigames/geisha/evilfish.o \
diff --git a/engines/gob/pregob/onceupon/abracadabra.cpp b/engines/gob/pregob/onceupon/abracadabra.cpp
index 0d644d9..2cf6855 100644
--- a/engines/gob/pregob/onceupon/abracadabra.cpp
+++ b/engines/gob/pregob/onceupon/abracadabra.cpp
@@ -80,10 +80,10 @@ const char *Abracadabra::kAnimalNames[] = {
 
 // The houses where the stork can drop a bundle
 const OnceUpon::MenuButton Abracadabra::kStorkHouses[] = {
-	{false,  16,  80,  87, 125, 0, 0, 0, 0, 0, 0, 0},
-	{false,  61, 123,  96, 149, 0, 0, 0, 0, 0, 0, 1},
-	{false, 199, 118, 226, 137, 0, 0, 0, 0, 0, 0, 2},
-	{false, 229,  91, 304, 188, 0, 0, 0, 0, 0, 0, 3}
+	{false,  16,  80,  87, 125, 0, 0, 0, 0, 0, 0, 0}, // Castle , Lord & Lady
+	{false,  61, 123,  96, 149, 0, 0, 0, 0, 0, 0, 1}, // Cottage, Farmers
+	{false, 199, 118, 226, 137, 0, 0, 0, 0, 0, 0, 2}, // Hut    , Woodcutters
+	{false, 229,  91, 304, 188, 0, 0, 0, 0, 0, 0, 3}  // Palace , King & Queen
 };
 
 // The stork bundle drop parameters
diff --git a/engines/gob/pregob/onceupon/babayaga.cpp b/engines/gob/pregob/onceupon/babayaga.cpp
index 6aa6031..ef56b9d 100644
--- a/engines/gob/pregob/onceupon/babayaga.cpp
+++ b/engines/gob/pregob/onceupon/babayaga.cpp
@@ -80,10 +80,10 @@ const char *BabaYaga::kAnimalNames[] = {
 
 // The houses where the stork can drop a bundle
 const OnceUpon::MenuButton BabaYaga::kStorkHouses[] = {
-	{false,  16,  80,  87, 125, 0, 0, 0, 0, 0, 0, 0},
-	{false,  61, 123,  96, 149, 0, 0, 0, 0, 0, 0, 1},
-	{false, 199, 118, 226, 137, 0, 0, 0, 0, 0, 0, 2},
-	{false, 229,  91, 304, 188, 0, 0, 0, 0, 0, 0, 3}
+	{false,  16,  80,  87, 125, 0, 0, 0, 0, 0, 0, 0}, // Castle , Lord & Lady
+	{false,  61, 123,  96, 149, 0, 0, 0, 0, 0, 0, 1}, // Cottage, Farmers
+	{false, 199, 118, 226, 137, 0, 0, 0, 0, 0, 0, 2}, // Hut    , Woodcutters
+	{false, 229,  91, 304, 188, 0, 0, 0, 0, 0, 0, 3}  // Palace , King & Queen
 };
 
 // The stork bundle drop parameters
diff --git a/engines/gob/pregob/onceupon/onceupon.cpp b/engines/gob/pregob/onceupon/onceupon.cpp
index 9d32eaa..e4c2df3 100644
--- a/engines/gob/pregob/onceupon/onceupon.cpp
+++ b/engines/gob/pregob/onceupon/onceupon.cpp
@@ -38,6 +38,7 @@
 #include "gob/pregob/onceupon/onceupon.h"
 #include "gob/pregob/onceupon/palettes.h"
 #include "gob/pregob/onceupon/title.h"
+#include "gob/pregob/onceupon/parents.h"
 #include "gob/pregob/onceupon/chargenchild.h"
 
 static const uint kLanguageCount = 5;
@@ -1747,7 +1748,17 @@ bool OnceUpon::sectionChapter1() {
 }
 
 bool OnceUpon::sectionParents() {
-	warning("OnceUpon::sectionParents(): TODO");
+	fadeOut();
+	setGamePalette(14);
+	clearScreen();
+
+	const Common::String seq = ((_house == 1) || (_house == 2)) ? "parents.seq" : "parents2.seq";
+	const Common::String gct = getLocFile("mefait.gc");
+
+	Parents parents(_vm, seq, gct, _name, _house, *_plettre, kGamePalettes[14], kGamePalettes[13], kPaletteSize);
+	parents.play();
+
+	warning("OnceUpon::sectionParents(): TODO: Item search");
 	return true;
 }
 
diff --git a/engines/gob/pregob/onceupon/parents.cpp b/engines/gob/pregob/onceupon/parents.cpp
new file mode 100644
index 0000000..cdaee6a
--- /dev/null
+++ b/engines/gob/pregob/onceupon/parents.cpp
@@ -0,0 +1,217 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "gob/gob.h"
+#include "gob/global.h"
+#include "gob/dataio.h"
+#include "gob/palanim.h"
+#include "gob/draw.h"
+#include "gob/video.h"
+
+#include "gob/sound/sound.h"
+
+#include "gob/pregob/gctfile.h"
+
+#include "gob/pregob/onceupon/palettes.h"
+#include "gob/pregob/onceupon/parents.h"
+
+namespace Gob {
+
+namespace OnceUpon {
+
+const char *Parents::kSound[kSoundCount] = {
+	"rire.snd", // kSoundCackle
+	"tonn.snd"  // kSoundThunder
+};
+
+// So that every GCT line is displayed for 12 seconds
+const uint16 Parents::kLoop[kLoopCount][3] = {
+	{ 72,  77, 33},
+	{105, 109, 38},
+	{141, 145, 38},
+	{446, 454, 23},
+	{456, 464, 23},
+	{466, 474, 23},
+	{476, 484, 23}
+};
+
+
+Parents::Parents(GobEngine *vm, const Common::String &seq, const Common::String &gct,
+                 const Common::String &childName, uint8 house, const Font &font,
+                 const byte *normalPalette, const byte *brightPalette, uint paletteSize) :
+	SEQFile(vm, seq),
+	_gct(0), _house(house), _font(&font),
+	_paletteSize(paletteSize), _normalPalette(normalPalette), _brightPalette(brightPalette) {
+
+	// Load sounds
+	for (int i = 0; i < kSoundCount; i++)
+		_vm->_sound->sampleLoad(&_sounds[i], SOUND_SND, kSound[i]);
+
+	// Load GCT
+	Common::SeekableReadStream *gctStream = _vm->_dataIO->getFile(gct);
+	if (gctStream) {
+		_gct = new GCTFile(*gctStream, _vm->_rnd);
+
+		delete gctStream;
+	} else
+		error("Parents::Parents(): Failed to open \"%s\"", gct.c_str());
+
+	_gct->setArea(17, 18, 303, 41);
+	_gct->setText(1, childName);
+
+	_gct->selectLine(2, _house);
+	_gct->selectLine(4, _house);
+
+	for (uint i = 0; i < kLoopCount; i++)
+		_loopID[i] = addLoop(kLoop[i][0], kLoop[i][1], kLoop[i][2]);
+}
+
+Parents::~Parents() {
+	delete _gct;
+}
+
+void Parents::play() {
+	_currentLoop = 0;
+
+	SEQFile::play(true, 496, 15);
+
+	// After playback, fade out
+	if (!_vm->shouldQuit())
+		_vm->_palAnim->fade(0, 0, 0);
+}
+
+void Parents::handleFrameEvent() {
+	switch (getFrame()) {
+	case 0:
+		// On fame 0, fade in
+		_vm->_draw->forceBlit();
+		_vm->_palAnim->fade(_vm->_global->_pPaletteDesc, 0, 0);
+		break;
+
+	case 4:
+		drawGCT(0);
+		break;
+
+	case 55:
+		drawGCT(3, 0);
+		break;
+
+	case 79:
+		drawGCT(_house + 5, 1);
+		break;
+
+	case 110:
+		drawGCT(_house + 9, 2);
+		break;
+
+	case 146:
+		drawGCT(17);
+		break;
+
+	case 198:
+		drawGCT(13);
+		break;
+
+	case 445:
+		drawGCT(14, 3);
+		break;
+
+	case 455:
+		drawGCT(18, 4);
+		break;
+
+	case 465:
+		drawGCT(19, 5);
+		break;
+
+	case 475:
+		drawGCT(20, 6);
+		break;
+
+	case 188:
+	case 228:
+	case 237:
+	case 257:
+	case 275:
+	case 426:
+		lightningEffect();
+		break;
+
+	case 203:
+	case 243:
+	case 252:
+	case 272:
+	case 290:
+	case 441:
+		playSound(kSoundThunder);
+		break;
+
+	case 340:
+		playSound(kSoundCackle);
+		break;
+	}
+}
+
+void Parents::handleInput(int16 key, int16 mouseX, int16 mouseY, MouseButtons mouseButtons) {
+	if ((key == kKeyEscape) || (mouseButtons == kMouseButtonsRight))
+		abortPlay();
+
+	if (((key == kKeySpace) || (mouseButtons == kMouseButtonsLeft)) && (_currentLoop < kLoopCount))
+		skipLoop(_loopID[_currentLoop]);
+}
+
+void Parents::playSound(Sound sound) {
+	_vm->_sound->blasterStop(0);
+	_vm->_sound->blasterPlay(&_sounds[sound], 0, 0);
+}
+
+void Parents::lightningEffect() {
+	for (int i = 0; (i < 5) && !_vm->shouldQuit(); i++) {
+
+		setPalette(_brightPalette, _paletteSize);
+		_vm->_util->delay(5);
+
+		setPalette(_normalPalette, _paletteSize);
+		_vm->_util->delay(5);
+	}
+}
+
+void Parents::setPalette(const byte *palette, uint size) {
+	memcpy(_vm->_draw->_vgaPalette, palette, 3 * size);
+
+	_vm->_video->setFullPalette(_vm->_global->_pPaletteDesc);
+	_vm->_video->retrace();
+}
+
+void Parents::drawGCT(uint item, uint loop) {
+	int16 left, top, right, bottom;
+	if (_gct->clear(*_vm->_draw->_backSurface, left, top, right, bottom))
+		_vm->_draw->dirtiedRect(_vm->_draw->_backSurface, left, top, right, bottom);
+	if (_gct->draw(*_vm->_draw->_backSurface, item, *_font, 10, left, top, right, bottom))
+		_vm->_draw->dirtiedRect(_vm->_draw->_backSurface, left, top, right, bottom);
+
+	_currentLoop = loop;
+}
+
+} // End of namespace OnceUpon
+
+} // End of namespace Gob
diff --git a/engines/gob/pregob/onceupon/parents.h b/engines/gob/pregob/onceupon/parents.h
new file mode 100644
index 0000000..f5c8307
--- /dev/null
+++ b/engines/gob/pregob/onceupon/parents.h
@@ -0,0 +1,94 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef GOB_PREGOB_ONCEUPON_PARENTS_H
+#define GOB_PREGOB_ONCEUPON_PARENTS_H
+
+#include "gob/sound/sounddesc.h"
+
+#include "gob/pregob/seqfile.h"
+
+namespace Gob {
+
+class Font;
+
+class GCTFile;
+
+namespace OnceUpon {
+
+/** The home / parents animation sequence. */
+class Parents : public SEQFile {
+public:
+	Parents(GobEngine *vm, const Common::String &seq, const Common::String &gct,
+	        const Common::String &childName, uint8 house, const Font &font,
+	        const byte *normalPalette, const byte *brightPalette, uint paletteSize);
+	~Parents();
+
+	void play();
+
+protected:
+	void handleFrameEvent();
+	void handleInput(int16 key, int16 mouseX, int16 mouseY, MouseButtons mouseButtons);
+
+private:
+	static const uint kLoopCount = 7;
+
+	static const uint16 kLoop[kLoopCount][3];
+
+	enum Sound {
+		kSoundCackle  = 0,
+		kSoundThunder    ,
+		kSoundCount
+	};
+
+	static const char *kSound[kSoundCount];
+
+
+	uint8 _house;
+
+	const Font *_font;
+
+	uint _paletteSize;
+	const byte *_normalPalette;
+	const byte *_brightPalette;
+
+	SoundDesc _sounds[kSoundCount];
+
+	GCTFile *_gct;
+
+	uint _loopID[kLoopCount];
+	uint _currentLoop;
+
+
+	void lightningEffect();
+
+	void playSound(Sound sound);
+	void setPalette(const byte *palette, uint size);
+
+	void drawGCT(uint item, uint loop = 0xFFFF);
+};
+
+} // End of namespace OnceUpon
+
+} // End of namespace Gob
+
+#endif // GOB_PREGOB_ONCEUPON_PARENTS_H


Commit: d80d08128b2a030a65ce4f48776f5c63370ac598
    https://github.com/scummvm/scummvm/commit/d80d08128b2a030a65ce4f48776f5c63370ac598
Author: Sven Hesse (drmccoy at users.sourceforge.net)
Date: 2012-07-29T16:50:59-07:00

Commit Message:
Merge branch 'pregob' (WIP Once Upon A Time)

This is some in-progress work for supporting the mostly hard-coded
Once Upon A Time titles Abracadabra and Baba Yaga.

Changed paths:
  A engines/gob/backbuffer.cpp
  A engines/gob/backbuffer.h
  A engines/gob/detection/tables_onceupon.h
  A engines/gob/pregob/gctfile.cpp
  A engines/gob/pregob/gctfile.h
  A engines/gob/pregob/onceupon/abracadabra.cpp
  A engines/gob/pregob/onceupon/abracadabra.h
  A engines/gob/pregob/onceupon/babayaga.cpp
  A engines/gob/pregob/onceupon/babayaga.h
  A engines/gob/pregob/onceupon/brokenstrings.h
  A engines/gob/pregob/onceupon/chargenchild.cpp
  A engines/gob/pregob/onceupon/chargenchild.h
  A engines/gob/pregob/onceupon/onceupon.cpp
  A engines/gob/pregob/onceupon/onceupon.h
  A engines/gob/pregob/onceupon/palettes.h
  A engines/gob/pregob/onceupon/parents.cpp
  A engines/gob/pregob/onceupon/parents.h
  A engines/gob/pregob/onceupon/stork.cpp
  A engines/gob/pregob/onceupon/stork.h
  A engines/gob/pregob/onceupon/title.cpp
  A engines/gob/pregob/onceupon/title.h
  A engines/gob/pregob/pregob.cpp
  A engines/gob/pregob/pregob.h
  A engines/gob/pregob/seqfile.cpp
  A engines/gob/pregob/seqfile.h
  A engines/gob/pregob/txtfile.cpp
  A engines/gob/pregob/txtfile.h
    engines/gob/anifile.cpp
    engines/gob/anifile.h
    engines/gob/aniobject.cpp
    engines/gob/aniobject.h
    engines/gob/cmpfile.cpp
    engines/gob/cmpfile.h
    engines/gob/decfile.cpp
    engines/gob/detection/detection.cpp
    engines/gob/detection/tables.h
    engines/gob/detection/tables_ajworld.h
    engines/gob/detection/tables_fallback.h
    engines/gob/draw.cpp
    engines/gob/draw.h
    engines/gob/draw_fascin.cpp
    engines/gob/draw_playtoons.cpp
    engines/gob/draw_v2.cpp
    engines/gob/game.cpp
    engines/gob/gob.cpp
    engines/gob/gob.h
    engines/gob/init.cpp
    engines/gob/inter_bargon.cpp
    engines/gob/inter_v5.cpp
    engines/gob/minigames/geisha/penetration.cpp
    engines/gob/module.mk
    engines/gob/rxyfile.cpp
    engines/gob/rxyfile.h
    engines/gob/sound/sound.cpp
    engines/gob/sound/sound.h
    engines/gob/sound/soundblaster.cpp
    engines/gob/sound/soundblaster.h
    engines/gob/surface.cpp
    engines/gob/surface.h
    engines/gob/util.cpp
    engines/gob/util.h
    engines/gob/video.cpp
    engines/gob/video.h









More information about the Scummvm-git-logs mailing list