[Scummvm-git-logs] scummvm master -> b8a5483047b9a46e389d887ddd5029a81173f2c4

sev- sev at scummvm.org
Thu Dec 17 08:49:25 UTC 2020


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

Summary:
d92adc6f2c HADESCH: Transcribe and classify all the AIF files
937d5c4a98 HADESCH: Show subtitles for AIF files
0d39e96f55 COMMON: Make TranslationManager reusable.
b8a5483047 HADESCH: Use separate file for translations


Commit: d92adc6f2c76b9e60019014c69cf7b09f8089052
    https://github.com/scummvm/scummvm/commit/d92adc6f2c76b9e60019014c69cf7b09f8089052
Author: Vladimir Serbinenko (phcoder at google.com)
Date: 2020-12-17T09:49:18+01:00

Commit Message:
HADESCH: Transcribe and classify all the AIF files

This doesn't cover SMK files which would be a second effort

Changed paths:
    engines/hadesch/ambient.cpp
    engines/hadesch/ambient.h
    engines/hadesch/herobelt.cpp
    engines/hadesch/rooms/argo.cpp
    engines/hadesch/rooms/athena.cpp
    engines/hadesch/rooms/catacombs.cpp
    engines/hadesch/rooms/crete.cpp
    engines/hadesch/rooms/daedalus.cpp
    engines/hadesch/rooms/ferry.cpp
    engines/hadesch/rooms/hadesthrone.cpp
    engines/hadesch/rooms/medisle.cpp
    engines/hadesch/rooms/minos.cpp
    engines/hadesch/rooms/minotaur.cpp
    engines/hadesch/rooms/monster.cpp
    engines/hadesch/rooms/monster/cyclops.cpp
    engines/hadesch/rooms/monster/illusion.cpp
    engines/hadesch/rooms/monster/projectile.cpp
    engines/hadesch/rooms/monster/typhoon.cpp
    engines/hadesch/rooms/olympus.cpp
    engines/hadesch/rooms/options.cpp
    engines/hadesch/rooms/priam.cpp
    engines/hadesch/rooms/quiz.cpp
    engines/hadesch/rooms/riverstyx.cpp
    engines/hadesch/rooms/seriphos.cpp
    engines/hadesch/rooms/troy.cpp
    engines/hadesch/rooms/volcano.cpp
    engines/hadesch/rooms/walloffame.cpp
    engines/hadesch/video.cpp
    engines/hadesch/video.h


diff --git a/engines/hadesch/ambient.cpp b/engines/hadesch/ambient.cpp
index 74be4c7d78..c5bb1060ad 100644
--- a/engines/hadesch/ambient.cpp
+++ b/engines/hadesch/ambient.cpp
@@ -189,7 +189,7 @@ void AmbientAnim::play(bool reschedule) {
 		       _internal->_offset);		
 	
 	if (_internal->_descs[variant]._soundName != "")
-		room->playSound(_internal->_descs[variant]._soundName, -1);
+		room->playSFX(_internal->_descs[variant]._soundName, -1);
 }
 	
 void AmbientAnim::schedule() {
@@ -213,7 +213,7 @@ void AmbientAnim::start() {
 	schedule();
 }
 
-void AmbientAnimWeightedSet::readTableFilePriam(const TextTable &table) {
+void AmbientAnimWeightedSet::readTableFilePriamSFX(const TextTable &table) {
 	for (int row = 0; row < table.size(); row++) {
 		AmbientAnimWeightedSetElement el;
 		el.name = table.get(row, "name");
@@ -230,7 +230,7 @@ void AmbientAnimWeightedSet::readTableFilePriam(const TextTable &table) {
 	}
 }
 
-void AmbientAnimWeightedSet::readTableFile(const TextTable &table, AmbientAnim::PanType pan) {
+void AmbientAnimWeightedSet::readTableFileSFX(const TextTable &table, AmbientAnim::PanType pan) {
 	for (int row = 0; row < table.size(); row++) {
 		AmbientAnimWeightedSetElement el;
 		el.name = table.get(row, "anim");
@@ -334,12 +334,12 @@ void AnimClickables::playChosen(const Common::String &name, int counter, const E
 				Common::Point(_table.get(name, "smackerX", counter).asUint64(),
 					      _table.get(name, "smackerY", counter).asUint64()));
 	else if (anim != "")
-		room->playAnimWithSound(
-			anim, sound, zValue, PlayAnimParams::disappear(), event,
+		room->playAnimWithSpeech(
+			anim, TranscribedSound(sound.c_str(), _transcriptions[sound].c_str()), zValue, PlayAnimParams::disappear(), event,
 			Common::Point(_table.get(name, "X", counter).asUint64(),
 				      _table.get(name, "Y", counter).asUint64()));
 	else if (sound != "")
-		room->playSound(sound, event);
+		room->playSpeech(TranscribedSound(sound.c_str(), _transcriptions[sound].c_str()), event);
 	else
 		event();
 }
@@ -350,8 +350,12 @@ void AnimClickables::playNext(const Common::String &name, const EventHandlerWrap
 	_counters[name]++;
 }
 
-void AnimClickables::readTable(Common::SharedPtr<Hadesch::VideoRoom> room, const Common::String &name) {
+void AnimClickables::readTable(Common::SharedPtr<Hadesch::VideoRoom> room, const Common::String &name, const TranscribedSound *transcriptions) {
 	_table = TextTable(Common::SharedPtr<Common::SeekableReadStream>(room->openFile(name)), 14);
+
+	for (const TranscribedSound *t = transcriptions; t->soundName; t++) {
+		_transcriptions[t->soundName] = t->transcript;
+	}
 }
 
 }
diff --git a/engines/hadesch/ambient.h b/engines/hadesch/ambient.h
index 0c71f28ffe..5135d79aed 100644
--- a/engines/hadesch/ambient.h
+++ b/engines/hadesch/ambient.h
@@ -92,8 +92,8 @@ private:
 	
 class AmbientAnimWeightedSet {
 public:
-	void readTableFilePriam(const TextTable &table);
-	void readTableFile(const TextTable &table, AmbientAnim::PanType pan);
+	void readTableFilePriamSFX(const TextTable &table);
+	void readTableFileSFX(const TextTable &table, AmbientAnim::PanType pan);
 	void tick();
 	void firstFrame();
 	void pause(const Common::String &name);
@@ -119,10 +119,12 @@ public:
 		_table = table;
 	}
 	void readTable(Common::SharedPtr<Hadesch::VideoRoom> room,
-		       const Common::String &name);
+		       const Common::String &name,
+		       const TranscribedSound *transcriptionTable);
 
 private:
 	TextTable _table;
+	Common::HashMap<Common::String, Common::String> _transcriptions;
 	Common::HashMap<Common::String, int> _counters;
 };
 
diff --git a/engines/hadesch/herobelt.cpp b/engines/hadesch/herobelt.cpp
index 6fa041c2be..3182fdebd2 100644
--- a/engines/hadesch/herobelt.cpp
+++ b/engines/hadesch/herobelt.cpp
@@ -31,16 +31,26 @@
 #include "audio/decoders/aiff.h"
 #include "hadesch/pod_file.h"
 #include "hadesch/baptr.h"
+#include "common/translation.h"
 
 namespace Hadesch {
 
 static const int kHeroBeltMinY = 378;
 static const int kHeroBeltMaxY = 471;
 
-static const char *powerSounds[3][2] = {
-	{"g0280nc0", "g0280ng0"},
-	{"g0280nb0", "g0280nf0"},
-	{"g0280ne0", "g0280nh0"},
+static const TranscribedSound powerSounds[3][2] = {
+	{
+	    { "g0280nc0", _s("That's where hero power of strength will be stored when you earn it") },
+	    { "g0280ng0", _s("The power of strength will let you overcome obstacles but you'll need a complete set of hero powers to use it") }
+	},
+	{
+	    { "g0280nb0", _s("That's where hero power of stealth will be stored when you earn it") },
+	    { "g0280nf0", _s("The power of stealth allows you to sneak past things but you'll need a complete set of hero powers to use it") }
+	},
+	{
+	    { "g0280ne0", _s("That's where hero power of wisdom will be stored when you earn it") },
+	    { "g0280nh0", _s("The power of wisdom will let you outwit and avoid deception but you'll need a complete set of hero powers to use it") }
+	},
 };
 
 static Common::Array <PodImage> loadImageArray(const Common::String &name) {
@@ -422,7 +432,7 @@ void HeroBelt::clickPower(HeroPower pwr) {
 	if (persistent->_quest == kRescuePhilQuest)
 		return;
 
-	room->playSound(powerSounds[pwr][!!persistent->_powerLevel[pwr]]);
+	room->playSpeech(powerSounds[pwr][!!persistent->_powerLevel[pwr]]);
 }
 
 void HeroBelt::computeHighlight() {
diff --git a/engines/hadesch/rooms/argo.cpp b/engines/hadesch/rooms/argo.cpp
index 83ec2dd338..81fb452c72 100644
--- a/engines/hadesch/rooms/argo.cpp
+++ b/engines/hadesch/rooms/argo.cpp
@@ -23,6 +23,7 @@
  */
 #include "hadesch/hadesch.h"
 #include "hadesch/video.h"
+#include "common/translation.h"
 
 namespace Hadesch {
 
@@ -43,37 +44,37 @@ enum {
 
 static const struct island {
 	const char *hotname;
-	const char *mouseoverAnim; // not mapped
-	const char *nameSound; // not mapped
-	const char *sfxSound; // not mapped
+	const char *mouseoverAnim;
+	TranscribedSound nameSound;
+	const char *sfxSound;
 	RoomId roomId;
 	int zValue;
 } islands[] = {
-	{"Phils", "a1030bh0", "a1030nf0", "a1030ef0", kWallOfFameRoom, 901},
-	{"Medusa", "a1030bf0", "a1030nc0", "a1030ed0", kMedIsleRoom, 901},
-	{"Troy", "a1030bd0", "a1030na0", "a1030eb0", kTroyRoom, 901},
-	{"Seriphos", "a1030be0", "a1030nd0", "a1030ec0", kSeriphosRoom, 801},
-	{"Crete", "a1030bc0", "a1030nb0", "a1030ea0", kCreteRoom, 801},
-	{"Volcano", "a1030bg0", "a1030ne0", "a1030ee0", kVolcanoRoom, 801},
+	{"Phils", "a1030bh0", {"a1030nf0", _s("Phil's") }, "a1030ef0", kWallOfFameRoom, 901},
+	{"Medusa", "a1030bf0", {"a1030nc0", _s("Medusa Isle")}, "a1030ed0", kMedIsleRoom, 901},
+	{"Troy", "a1030bd0", {"a1030na0", _s("Troy")}, "a1030eb0", kTroyRoom, 901},
+	{"Seriphos", "a1030be0", {"a1030nd0", _s("Seriphos")}, "a1030ec0", kSeriphosRoom, 801},
+	{"Crete", "a1030bc0", {"a1030nb0", _s("Crete")}, "a1030ea0", kCreteRoom, 801},
+	{"Volcano", "a1030bg0", {"a1030ne0", _s("Volcano island")}, "a1030ee0", kVolcanoRoom, 801},
 };
 
-static const int nislands = sizeof(islands) / sizeof(islands[0]);
+static const int nislands = ARRAYSIZE(islands);
 
-static const char *intros[] = {
-	"a1150na0",
-	"a1150nb0",
-	"a1150nc0",
-	"a1150nd0",
-	"a1150ne0",
-	"a1150nf0"
+static const TranscribedSound intros[] = {
+	{ "a1150na0", _s("Aye, welcome onboard ladie") },
+	{ "a1150nb0", _s("So, are you hero yet?") },
+	{ "a1150nc0", _s("So, are you heroine yet?") },
+	{ "a1150nd0", _s("So, made it back, you did? Frankly, I'm surprised") },
+	{ "a1150ne0", _s("Glad I'm, you're still alive. I hate sailing alone") },
+	{ "a1150nf0", _s("So where will we be headed now?") }
 };
 
-static const char *defaultOutros[] = {
-	"a1170na0",
-	"a1170nb0",
-	"a1170nc0",
-	"a1170nd0",
-	"a1170ne0"
+static const TranscribedSound defaultOutros[] = {
+	{ "a1170na0", _s("Heave anchor") },
+	{ "a1170nb0", _s("Hurry, hoist the main") },
+	{ "a1170nc0", _s("All hands on deck. Man the sails") },
+	{ "a1170nd0", _s("Pull her to starboard and bring her around") },
+	{ "a1170ne0", _s("Pull back on that rudder. Hold her steady") }
 };
 
 enum {
@@ -86,7 +87,7 @@ enum {
 	kMastSoundFinished = 1027002
 };
 
-static Common::String
+static const TranscribedSound
 getOutroName(RoomId dest) {
 	Persistent *persistent = g_vm->getPersistent();
 	Quest quest = persistent->_quest;
@@ -94,49 +95,47 @@ getOutroName(RoomId dest) {
 	switch (dest) {
 	case kWallOfFameRoom:
 		if (!persistent->_argoSailedInQuest[dest][quest])
-			return "philsfirst";
+			return TranscribedSound("philsfirst", "That'd be where the grand heroes and heroines of the world go to train");
 		break;
 	case kSeriphosRoom:
-		if (quest == kCreteQuest && !persistent->_argoSailedInQuest[dest][quest])
-			return "seriphoscretetroy";
-		if (quest == kTroyQuest && !persistent->_argoSailedInQuest[dest][quest])
-			return "seriphoscretetroy";
+		if ((quest == kTroyQuest || quest == kCreteQuest) && !persistent->_argoSailedInQuest[dest][quest])
+			return TranscribedSound("seriphoscretetroy", "This place be ruled by the evil tyrant king Polydectes");
 		if (quest == kMedusaQuest && !persistent->_argoSailedInQuest[dest][quest])
-			return "seriphosperseus";
+			return TranscribedSound("seriphosperseus", "Arr, Perseus be in trouble deep. Could use a hand");
 		break;
 	case kMedIsleRoom:
 		if (quest == kMedusaQuest && !persistent->_argoSailedInQuest[dest][quest])
-			return "medusabeware";
+			return TranscribedSound("medusabeware", "Beware of Medusa. She be one scary looking lady. All her mirrors be made of shatter-proof glass");
 		break;
 	case kTroyRoom:
 		if (!persistent->isRoomVisited(kTroyRoom))
-			return "troytenyears";
+			return TranscribedSound("troytenyears", "For ten years now trojan and greek soldiers have been fighting that trojan war. Talk about job security");
 		if (quest == kTroyQuest && !persistent->_argoSailedInQuest[dest][quest])
-			return "troyregards";
+			return TranscribedSound("troyregards", "Send me regards to Odysseus");
 		if (quest > kTroyQuest && !persistent->_argoSaidTroyFinally) {
 			persistent->_argoSaidTroyFinally = true;
-			return "troyfinally";
+			return TranscribedSound("troyfinally", "Finally, the trojan war be over and Helen be back with Menelaus. Now those two can fight without an interruption");
 		}
 		break;
 	case kCreteRoom:
 		if (!persistent->isRoomVisited(kCreteRoom))
-			return "cretedaedalus";
+			return TranscribedSound("cretedaedalus", "This be where Daedalus, the inventor, lives");
 
 		if (quest != kCreteQuest && !persistent->_argoSaidCretePort)
-			return "creteport";
+			return TranscribedSound("creteport", "Crete, the famous international port of trade");
 		break;
 	case kVolcanoRoom:
 		if (!persistent->isRoomVisited(kVolcanoRoom))
-			return "volcanotopfirst";
+			return TranscribedSound("volcanotopfirst", "Know this: should you go down there, you may not come back");
 
 		if (quest == kRescuePhilQuest && !!persistent->_argoSailedInQuest[dest][quest])
-			return "volcanotopyoufirst";
+			return TranscribedSound("volcanotopyoufirst", "Hah, many are monsters down there. Very dangerous. You go first");
 		break;
 
 	default:
 		assert(0);
 	}
-	int rnd = g_vm->getRnd().getRandomNumberRng(0, sizeof(defaultOutros) / sizeof(defaultOutros[0]) - 1);
+	int rnd = g_vm->getRnd().getRandomNumberRng(0, ARRAYSIZE(defaultOutros) - 1);
 	debug("rnd = %d", rnd);
 	return defaultOutros[rnd];
 }
@@ -162,7 +161,10 @@ public:
 			room->disableMouse();
 			room->stopAnim("idlesound");
 			if (_destination == _prevId) {
-				playMastSound("currentlocation", kOutroFinished);
+				playMastSound(TranscribedSound(
+						  "currentlocation",
+						  "Here be your current location, matie."),
+					      kOutroFinished);
 				return;
 			}
 
@@ -170,13 +172,13 @@ public:
 			_cloudsMoving = true;
 			_cloudsMoveStart = g_vm->getCurrentTime();
 			playMastSound(getOutroName(_destination), kOutroFinishedCounter);
-			room->playAnimWithSound("wavesleft", "wavesleftSFX", kWavesLeftZ,
-						PlayAnimParams::disappear(),
-						kOutroFinishedCounter);
-			room->playAnimWithSound("wavesright", "wavesrightSFX", kWavesRightZ,
-						PlayAnimParams::disappear(),
-						kOutroFinishedCounter);
-			room->playSound("A1030eG0", kOutroFinishedCounter);
+			room->playAnimWithSFX("wavesleft", "wavesleftSFX", kWavesLeftZ,
+					      PlayAnimParams::disappear(),
+					      kOutroFinishedCounter);
+			room->playAnimWithSFX("wavesright", "wavesrightSFX", kWavesRightZ,
+					      PlayAnimParams::disappear(),
+					      kOutroFinishedCounter);
+			room->playSFX("A1030eG0", kOutroFinishedCounter);
 			persistent->_argoSailedInQuest[_destination][persistent->_quest] = true;
 		}
 	}
@@ -184,10 +186,13 @@ public:
 		Common::SharedPtr<VideoRoom> room = g_vm->getVideoRoom();
 		switch (eventId) {
 		case kPlayIntro2:
-			playMastSound("intro2", kPlayIntro3);
+			playMastSound(TranscribedSound("intro2", "Navigate by clicking on the island you want to go to"), kPlayIntro3);
 			break;
 		case kPlayIntro3:
-			playMastSound("intro3", kReturnToIdleEvent);
+			playMastSound(TranscribedSound(
+					      "intro3",
+					      "The map shall always show the location of the Argo in relation to the other islands in the region"),
+				      kReturnToIdleEvent);
 			break;
 		case kReturnToIdleEvent:
 			_mastHeadIsBusy = false;
@@ -205,12 +210,12 @@ public:
 			g_vm->addTimer(kIdleEvent, 30000);
 			if (_mastHeadIsBusy)
 				break;
-			playMastSound("idlesound", kMastSoundFinished);
+			playMastSound(TranscribedSound("idlesound", "And what course lies ahead for you, matie?"), kMastSoundFinished);
 			room->selectFrame(kMastHeadAnim, kMastHeadZ, 1);
 			break;
 		case 27301:
-			room->playAnimWithSound(kMastHeadAnim, _mastSoundName, kMastHeadZ,
-						PlayAnimParams::keepLastFrame().partial(8, 21), 27303);
+			room->playAnimWithSpeech(kMastHeadAnim, _mastSound, kMastHeadZ,
+						 PlayAnimParams::keepLastFrame().partial(8, 21), 27303);
 			break;
 		// 27302 was for event chaining and frame keeping
 		case 27303:
@@ -229,7 +234,7 @@ public:
 				room->selectFrame(kIslandNames, kIslandNamesZ, i);
 				room->playAnimKeepLastFrame(islands[i].mouseoverAnim, islands[i].zValue);
 				playMastSound(islands[i].nameSound);
-				room->playSoundLoop(islands[i].sfxSound);
+				room->playSFXLoop(islands[i].sfxSound);
 				return;
 			}
 		}
@@ -243,7 +248,7 @@ public:
 					room->stopAnim(kIslandNames);
 					room->stopAnim(islands[i].mouseoverAnim);
 				}
-				room->stopAnim(islands[i].nameSound);
+				room->stopAnim(islands[i].nameSound.soundName);
 				room->stopAnim(islands[i].sfxSound);
 				return;
 			}
@@ -292,26 +297,29 @@ public:
 			break;
 		}
 		room->addStaticLayer(sky, kSkyZ);
-		room->playSoundLoop(bgsound);
+		room->playMusicLoop(bgsound);
 
 		room->selectFrame("chesspiece", kChessPieceZ, chesspiece);
 
 		room->disableMouse();
 		// Originally event 4015
 		if (!persistent->isRoomVisited(kArgoRoom))
-			playMastSound("intro1", kPlayIntro2);
+			playMastSound(TranscribedSound(
+					      "intro1",
+					      "Sharpen up now, matie. You'll be on the Argo now. It's a hero of ships. It used to belong to Jason and his crew, the argonauts. And now it'll be here for you"),
+				      kPlayIntro2);
 		else {
-			int rnd = g_vm->getRnd().getRandomNumberRng(0, sizeof(intros) / sizeof(intros[0]) - 1);
+			int rnd = g_vm->getRnd().getRandomNumberRng(0, ARRAYSIZE(intros) - 1);
 			debug("rnd = %d", rnd);
 			if (rnd == 1 || rnd == 2)
 				rnd = persistent->_gender == kFemale ? 2 : 1;
 			playMastSound(intros[rnd], kReturnToIdleEvent);
 		}
 
-		room->playAnimWithSound("flags", "flagsSFX", kFlagsZ, PlayAnimParams::loop());
+		room->playAnimWithSFX("flags", "flagsSFX", kFlagsZ, PlayAnimParams::loop());
 		g_vm->addTimer(kIdleEvent, 30000);
 		g_vm->getHeroBelt()->setColour(HeroBelt::kCool);
-		room->playSound("intromusic");
+		room->playMusic("intromusic");
 		_cloudsMoving = false;
 		cloudMove(0);
 	}
@@ -331,9 +339,9 @@ public:
 	}
 	
 private:
-	void playMastSound(const Common::String &name, int event = kMastSoundFinished) {
+	void playMastSound(const TranscribedSound &sound, int event = kMastSoundFinished) {
 		Common::SharedPtr<VideoRoom> room = g_vm->getVideoRoom();
-		_mastSoundName = name;
+		_mastSound = sound;
 		_mastHeadEndEvent = event;
 		_mastHeadIsBusy = true;
 		room->playAnim(kMastHeadAnim, kMastHeadZ, PlayAnimParams::keepLastFrame().partial(1, 8), 27301);
@@ -346,7 +354,7 @@ private:
 	bool _cloudsMoving;
 	int _mastHeadEndEvent;
 	bool _mastHeadIsBusy;
-	Common::String _mastSoundName;
+	TranscribedSound _mastSound;
 };
 
 Common::SharedPtr<Hadesch::Handler> makeArgoHandler() {
diff --git a/engines/hadesch/rooms/athena.cpp b/engines/hadesch/rooms/athena.cpp
index 808f65411c..dbd3ef847f 100644
--- a/engines/hadesch/rooms/athena.cpp
+++ b/engines/hadesch/rooms/athena.cpp
@@ -24,6 +24,7 @@
 #include "hadesch/hadesch.h"
 #include "hadesch/video.h"
 #include "hadesch/ambient.h"
+#include "common/translation.h"
 
 namespace Hadesch {
 static const char *kAthenaAnim = "c8060ba0";
@@ -142,7 +143,11 @@ public:
 			room->stopAnim("c8130bf0");
 			room->disableHotzone("Sword");
 			room->disableMouse();
-			room->playSound("c8140wa0", 23026);
+			room->playSpeech(TranscribedSound(
+					     "c8140wa0",
+					     "The magic sword will never leave Perseus' hand, "
+					     "so he can successfully cut off Medusa's head"),
+					 23026);
 			return;
 		}
 
@@ -152,7 +157,11 @@ public:
 			room->stopAnim("c8130be0");
 			room->disableHotzone("Shield");
 			room->disableMouse();
-			room->playSound("c8150wa0", 23027);
+			room->playSpeech(TranscribedSound(
+					     "c8150wa0",
+					     "Medusa can only turn Perseus to stone if he looks directly at her. "
+					     "He'll use this shield to block her gaze"),
+					 23027);
 			return;
 		}
 
@@ -160,7 +169,7 @@ public:
 			room->disableMouse();
 			room->playAnimLoop("c8010oc0", 2101);
 			room->playVideo("c8080wa0", 0, 23043);
-			room->playSound("C8080eA1");
+			room->playSFX("C8080eA1");
 			return;
 		}
 
@@ -168,7 +177,7 @@ public:
 			room->disableMouse();
 			room->playAnimLoop("c8010ob0", 2101);
 			room->playVideo("c8070wa0", 0, 23044);
-			room->playSound("C8080eA1");
+			room->playSFX("C8080eA1");
 			return;
 		}
 	}
@@ -198,9 +207,9 @@ public:
 		case 23008:
 			room->playAnim("c8140ba0", 1101, PlayAnimParams::disappear(), 23015);
 			room->playAnim("c8150ba0", 1101, PlayAnimParams::disappear(), 23016);
-			room->playSound("c8130ma0", 23020);
-			room->playSound("c8130eb0");
-			room->playSound("c8130ec0");
+			room->playMusic("c8130ma0", 23020);
+			room->playSFX("c8130eb0");
+			room->playSFX("c8130ec0");
 			break;
 		case 23010:
 			if (persistent->_hintsAreEnabled && room->isMouseEnabled()) {
@@ -213,11 +222,11 @@ public:
 			break;
 		case 23015:
 			room->playAnimKeepLastFrame("c8130bf0", 1101, 23017);
-			room->playSound("c8130ef0");
+			room->playSFX("c8130ef0");
 			break;
 		case 23016:
 			room->playAnimKeepLastFrame("c8130be0", 1101, 23018);
-			room->playSound("c8130ee0");
+			room->playSFX("c8130ee0");
 			break;
 		case 23017:
 			room->enableHotzone("Sword");
@@ -232,11 +241,20 @@ public:
 			room->disableHeroBelt();
 			room->resetLayers();
 			room->addStaticLayer("c8180pa0", 9000);
-			room->playSound("g0261ma0", 23031);
-			room->playSound(persistent->_gender == kMale ? "c8180wa0" : "c8180wb0", 23029);
+			room->playSFX("g0261ma0", 23031);
+			room->playSpeech(persistent->_gender == kMale
+					? TranscribedSound(
+					    "c8180wa0",
+					    "Oh no. Why did I shine that light in Athena's temple. "
+					    "I was just trying to see what the hero was doing")
+					 : TranscribedSound(
+					     "c8180wb0",
+					     "Oh no. Why did I shine that light in Athena's temple. "
+					     "I was just trying to see what the heroine was doing"),
+					 23029);
 			break;
 		case 23029:
-			room->playSound("c8180wc0", 23030);
+			room->playSpeech(TranscribedSound("c8180wc0", "Well now you can see what I'm doing: tomato heads"), 23030);
 			break;
 		case 23030:
 			room->playVideo("c8180ba0", 0, 23032);
@@ -302,7 +320,7 @@ public:
 			room->playVideo(persistent->_gender == kMale ? "c8040wa0" : "c8040wb0",
 					1101, kIntroFinished);
 			room->playAnim(kAthenaAnim, 1101, PlayAnimParams::loop());
-			room->playSound("c8040ma0", 23013);
+			room->playMusic("c8040ma0", 23013);
 		}
 
 		if (!persistent->_athenaShieldTaken) {
@@ -385,11 +403,11 @@ private:
 			room->stopAnim("c8120bg1");
 
 		if (_isPuzzleLit[num] && _puzzleState[num])
-			room->playSound("c8120ea0");
+			room->playSFX("c8120ea0");
 
 		if (_isPuzzleWon) {
 			room->selectFrame(LayerId(kLights, 11, "internal"), kLightsZ, 11);
-			room->playSound("C8130eA0");
+			room->playSFX("C8130eA0");
 			g_vm->addTimer(23008, 1000);
 			room->disableHotzone("Athena's Sword");
 			room->disableHotzone("Athena's Shield");
@@ -399,7 +417,7 @@ private:
 			persistent->_athenaPuzzleSolved = true;
 		}
 
-		room->playSoundLoop(
+		room->playMusicLoop(
 			persistent->_quest != kMedusaQuest || persistent->_athenaPuzzleSolved
 			? "c8010ea0" : "c8110ea0");
 	}
diff --git a/engines/hadesch/rooms/catacombs.cpp b/engines/hadesch/rooms/catacombs.cpp
index 3525cb5ab6..ec3484e80c 100644
--- a/engines/hadesch/rooms/catacombs.cpp
+++ b/engines/hadesch/rooms/catacombs.cpp
@@ -24,6 +24,7 @@
 #include "hadesch/hadesch.h"
 #include "hadesch/video.h"
 #include "hadesch/ambient.h"
+#include "common/translation.h"
 
 namespace Hadesch {
 
@@ -57,16 +58,22 @@ static const char *musicNames[] = {
 	"MusicPainPanic"
 };
 
-static const char *painSounds[] = {
-	"SndPainBedtime",
-	"SndPanicBoneHead",
-	"SndPainRecognize"
+static const TranscribedSound painSounds[] = {
+	{"SndPainBedtime", _s("It's bed time")},
+	{"SndPanicBoneHead", _s("Hey there, bonehead")},
+	{"SndPainRecognize", _s("Recognize the jewel?")} // Unclear
 };
 
-static const char *painSounds2[] = {
-	"SndPanicLightsOut",
-	"SndPainByeBye",
-	"SndPanicMaybeHit"
+static const TranscribedSound painSounds2[] = {
+	{"SndPanicLightsOut", _s("He-he. Lights out") },
+	{"SndPainByeBye", _s("Bye-Bye")},
+	{"SndPanicMaybeHit", _s("Maybe it will hit ya")}
+};
+
+static const TranscribedSound guardSpeeches[] = {
+	{"T3220wA0", _s("Do you think we were going to let you just walk into Troy?")},
+	{"T3220wB0", _s("So sorry, noone is allowed in. So beat it")},
+	{"T3220wC0", _s("Hey, Troy is closed to all visitors. Take a hike")}
 };
 
 enum {
@@ -132,7 +139,7 @@ public:
 			renderDecoder();
 			if (!_philBangPlayed) {
 				_philBangPlayed = true;
-				room->playSound("SndBigBang", 22012);
+				room->playSFX("SndBigBang", 22012);
 			}
 			return;
 		}
@@ -202,26 +209,25 @@ public:
 			room->playVideo("PhilWowLowOnTroops", 0);
 			break;
 		case 22016:
-			room->playSound("SndGuardTrapDoorOpen", 22017);
+			room->playSFX("SndGuardTrapDoorOpen", 22017);
 			break;
 		case 22017:
-			room->playSound("SndGuardLaugh", 22018);
+			room->playSpeech(TranscribedSound("SndGuardLaugh", "[laughter]"), 22018);
 			break;
 		case 22018:
-			room->playSound(
-				Common::String::format("T3220w%c0",
-						       g_vm->getRnd().getRandomNumberRng('A', 'C')),
+			room->playSpeech(
+				guardSpeeches[g_vm->getRnd().getRandomNumberRng(0, ARRAYSIZE(guardSpeeches) - 1)],
 				22019);
 			break;
 		case 22019:
-			room->playSound("SndGuardTrapDoorClose", 22020);
+			room->playSFX("SndGuardTrapDoorClose", 22020);
 			break;
 		case 22020:
 			persistent->_catacombLevel = kCatacombLevelSign;
 			g_vm->moveToRoom(kTroyRoom);
 			break;
 		case 22022:
-			room->playSound(painSounds2[level], 22023);
+			room->playSpeech(painSounds2[level], 22023);
 			persistent->_catacombLevel = kCatacombLevelSign;
 			break;
 		case 22023:
@@ -268,19 +274,17 @@ public:
 
 		persistent->_catacombLastLevel = level;
 
-		room->playSoundLoop("T3010eA0");
-
 		if (persistent->_catacombPainAndPanic) {
 			persistent->_catacombPainAndPanic = false;
 			room->addStaticLayer("DeadEndBackground", 10001);
-			room->playSound("SndPainPanicStinger", 22022);
-			room->playSound(painSounds[persistent->_catacombLevel]);
+			room->playMusic("SndPainPanicStinger", 22022);
+			room->playSpeech(painSounds[persistent->_catacombLevel]);
 			return;
 		}
 		
 		if (level == 0)
 			room->loadHotZones("CaDecode.HOT", false);
-		room->playSoundLoop("T3010eA0");
+		room->playMusicLoop("T3010eA0");
 		// TODO: tremmors
 		// TODO: handle timer
 		g_vm->addTimer(22007, level == 2 ? 30000 : 40000, -1);
@@ -324,7 +328,7 @@ public:
 
 		switch (level) {
 		case 0:
-			room->playSound("IntroMusic");
+			room->playMusic("IntroMusic");
 			room->enableHotzone(skullHotzones[persistent->_catacombDecoderSkullPosition]);
 			room->selectFrame(
 				caVariantGet(persistent->_catacombDecoderSkullPosition, "SkullDecoder"), 450, 1);
@@ -353,7 +357,7 @@ public:
 			}
 			break;
 		case 2:
-			room->playSound("CollapseSnd", 22009);
+			room->playSFX("CollapseSnd", 22009);
 			for (CatacombsPosition side = kCatacombsLeft; side <= kCatacombsRight; side = (CatacombsPosition) (side + 1)) {
 				room->playAnimLoop(
 					caVariantGet(side, "TorchNormal"),
@@ -372,11 +376,12 @@ private:
 			room->stopAnim(musicNames[i]);
 	}
 
+	// TODO: how can we make tune challenge accessible to deaf people?
 	void playTune(CatacombsPosition side) {
 		Common::SharedPtr<VideoRoom> room = g_vm->getVideoRoom();
 		Persistent *persistent = g_vm->getPersistent();
 		stopTune();
-		room->playSoundLoop(musicNames[persistent->_catacombPaths[2][side]]);
+		room->playMusicLoop(musicNames[persistent->_catacombPaths[2][side]]);
 	}
 
 	void renderDecoder() {
@@ -448,7 +453,7 @@ private:
 			caVariantGet(side, isHelen ? "TorchLongBurst" : "TorchNormalBurst"),
 			caVariantGet(side, "TorchZ").asUint64(),
 			PlayAnimParams::disappear(), kL1TrochLitLeft + side - kCatacombsLeft);
-		room->playSound("SndTorchBurst");
+		room->playSFX("SndTorchBurst");
 		room->disableHotzone(torchHotzones[side]);
 	}
 
diff --git a/engines/hadesch/rooms/crete.cpp b/engines/hadesch/rooms/crete.cpp
index 2f69d4d30d..b120e92abc 100644
--- a/engines/hadesch/rooms/crete.cpp
+++ b/engines/hadesch/rooms/crete.cpp
@@ -24,6 +24,7 @@
 #include "hadesch/hadesch.h"
 #include "hadesch/video.h"
 #include "hadesch/ambient.h"
+#include "common/translation.h"
 
 namespace Hadesch {
 
@@ -470,7 +471,7 @@ public:
 					_vasePos[i] %= 4;
 				_vaseBusy[i] = true;
 				renderVase();
-				room->playSound(vaseSound[i], kSoundVaseSegment1Finished + i);
+				room->playSFX(vaseSound[i], kSoundVaseSegment1Finished + i);
 				return;
 			}
 		}
@@ -499,9 +500,9 @@ public:
 		if (name == "Latch") {
 			room->disableMouse();
 			persistent->_creteStrongBoxState = Persistent::BOX_OPEN;
-			room->playAnimWithSound("r2230bb0", "g0082ea0", 1000,
-						PlayAnimParams::keepLastFrame().partial(1, 3),
-						12402, kOffsetRightRoom);
+			room->playAnimWithSFX("r2230bb0", "g0082ea0", 1000,
+					      PlayAnimParams::keepLastFrame().partial(1, 3),
+					      12402, kOffsetRightRoom);
 			return;
 		}
 
@@ -527,7 +528,7 @@ public:
 
 		if (name == "ButtonC" && !strongBoxIsBusy()) {
 			g_vm->addTimer(12409, 250);
-			room->playSound("r2230ed0", 12412);
+			room->playSFX("r2230ed0", 12412);
 			for (int i = 0; i < 12; i++) {
 				int pos = _strongBoxTiles[i].getPosition();
 				if (pos == 1 || pos == 2 || pos == 5 || pos == 6) {
@@ -663,7 +664,12 @@ TODO:
 				break;
 			persistent->_cretePlayedZeusCheckOutThatBox = true;
 			room->disableMouse();
-			room->playAnimWithSound("r2230ba0", "r2230wa0", 4000, PlayAnimParams::keepLastFrame(), 12145,
+			room->playAnimWithSpeech("r2230ba0",
+						TranscribedSound("r2230wa0",
+								 "Hey, why don't you check out that box? Maybe it has something that can help"),
+						4000,
+						PlayAnimParams::keepLastFrame(),
+						12145,
 						kOffsetRightRoom);
 			break;
 		case kAtlantisBoatIntro2Finished:
@@ -709,7 +715,7 @@ TODO:
 			room->playAnim("r1220ba0", 500,
 				       PlayAnimParams::disappear().partial(0, 17), 12206);
 			room->playVideo("r1220mb0", 0);
-			room->playSound("r1220ea0");
+			room->playSFX("r1220ea0");
 			room->disableMouse();
 			break;
 		}
@@ -730,7 +736,7 @@ TODO:
 		case 12306:
 			room->disableMouse();
 			hideAtlantisPopupOverlays();
-			room->playAnimWithSound(kAtlantisOpening, "r1210eb0",kAtlantisOpeningZ,
+			room->playAnimWithSFX(kAtlantisOpening, "r1210eb0", kAtlantisOpeningZ,
 						PlayAnimParams::keepLastFrame().partial(0, 8),
 						kAtlantisDoorOpens);
 			break;
@@ -740,9 +746,11 @@ TODO:
 			// Fallthrough
 		case 12403:
 			room->disableMouse();
-			room->playAnimWithSound("r2230ba0", "r2230wb0", 4000,
-						PlayAnimParams::keepLastFrame(), 12404,
-						kOffsetRightRoom);
+			room->playAnimWithSpeech("r2230ba0",
+						 TranscribedSound("r2230wb0", "I think those buttons control the symbols"),
+						 4000,
+						 PlayAnimParams::keepLastFrame(), 12404,
+						 kOffsetRightRoom);
 			break;
 		case 12404:
 		case 12405:
@@ -760,9 +768,11 @@ TODO:
 			if (!room->isMouseEnabled())
 				break;
 			room->disableMouse();
-			room->playAnimWithSound("r2230ba0", "r2230wc0", 4000,
-						PlayAnimParams::keepLastFrame(), 12407,
-						kOffsetRightRoom);
+			room->playAnimWithSpeech("r2230ba0",
+						 TranscribedSound("r2230wc0", "Try to spell my name"),
+						 4000,
+						 PlayAnimParams::keepLastFrame(), 12407,
+						 kOffsetRightRoom);
 			break;
 		case 12409:
 			for (int i = 0; i < 12; i++) {
@@ -842,7 +852,9 @@ TODO:
 			room->selectFrame("r2035ba0", 1200, 0);
 
 			// Originally event 12123
-			room->playSound("r2035wa0", 12124);
+			room->playSpeech(TranscribedSound(
+						      "r2035wa0",
+						      "Seems the only thing I can count on you two for is target practice"), 12124);
 			persistent->_creteHadesPusnishesPainAndPanic = false;
 			return;
 		}
@@ -878,7 +890,7 @@ TODO:
 		if (quest == kMedusaQuest && !persistent->_creteAlchemistExploded) {
 			persistent->_creteAlchemistExploded = true;
 			room->disableMouse();
-			room->playAnimWithSound("r1190ba0", "r1190ea0", 1005, PlayAnimParams::disappear(), 12128);
+			room->playAnimWithSFX("r1190ba0", "r1190ea0", 1005, PlayAnimParams::disappear(), 12128);
 		}
 
 		if (quest == kRescuePhilQuest || quest == kMedusaQuest) {
@@ -886,7 +898,7 @@ TODO:
 		}
 
 		if (quest == kMedusaQuest) {
-			room->playAnimWithSound("r2220bb0", "r2220eb0", 4500, PlayAnimParams::loop(), -1, kOffsetRightRoom);
+			room->playAnimWithSFX("r2220bb0", "r2220eb0", 4500, PlayAnimParams::loop(), -1, kOffsetRightRoom);
 		}
 
 		showMiniStrongBox();
@@ -1179,7 +1191,7 @@ TODO:
 		if (persistent->_creteShowMerchant) {
 			room->addStaticLayer("r2010on0", kMerchantStandZ);
 			room->selectFrame(kMerchantAnim, kMerchantZ, 0);
-			room->playSound("G0261mA0");
+			room->playSFX("G0261mA0");
 			if (persistent->_creteShowHorned) {
 				room->addStaticLayer(kHorned, 1220);
 				room->enableHotzone(kHornedHotzone);
@@ -1271,7 +1283,7 @@ TODO:
 			room->addStaticLayer(bg1, 1000);
 		}
 
-		room->playSound("R1010eA0", true);
+		room->playMusicLoop("R1010eA0");
 
 		if (g_vm->getPreviousRoomId() == kMinosPalaceRoom) {
 			room->panRightInstant();
@@ -1388,12 +1400,13 @@ private:
 	}
 
 	AmbientAnim ambient(const Common::String &anim, const Common::String &sound,
-		     int zValue, int minint, int maxint,
-		     AmbientAnim::PanType pan,
-		     Common::Point offset = Common::Point(0,0),
-		     bool loop = true) {
+			    int zValue, int minint, int maxint,
+			    AmbientAnim::PanType pan,
+			    Common::Point offset = Common::Point(0,0),
+			    bool loop = true) {
 		AmbientAnim ret = AmbientAnim(anim, sound, zValue, minint * 1000, maxint * 1000,
-			    loop ? AmbientAnim::KEEP_LOOP : AmbientAnim::DISAPPEAR, offset, pan);
+					      loop ? AmbientAnim::KEEP_LOOP : AmbientAnim::DISAPPEAR,
+					      offset, pan);
 		ret.start();
 		return ret;
 	}
@@ -1413,7 +1426,7 @@ private:
 		Common::SharedPtr<VideoRoom> room = g_vm->getVideoRoom();
 		_atlantisBoatPosition[diskNum] = (_atlantisBoatPosition[diskNum] + 1) % 8;
 		renderAtlantisDisks();
-		room->playSound(Common::String::format("r1210e%c0", 'e' + diskNum), 12303 + diskNum);
+		room->playSFX(Common::String::format("r1210e%c0", 'e' + diskNum), 12303 + diskNum);
 	}
 
 	void hideAtlantisPopupOverlays() {
@@ -1443,7 +1456,7 @@ private:
 		// User already clicked, no need to play that anim
 		persistent->_cretePlayedZeusCheckOutThatBox = true;
 		room->pushHotZones("Box.Hot");
-		room->playSound("g0082ea0");
+		room->playSFX("g0082ea0");
 		redrawStrongBox();
 		_strongBoxPopup = true;
 		switch(persistent->_creteStrongBoxState) {
@@ -1565,14 +1578,15 @@ private:
 			room->disableHotzone("ButtonE");
 			room->disableHotzone("ButtonW");
 			room->disableHotzone("ButtonC");
-			room->playAnimWithSound("r2230bf0", "r2230ea0", 300, PlayAnimParams::keepLastFrame().partial(0, -2),
-						12414, kOffsetRightRoom);
+			room->playAnimWithSFX("r2230bf0", "r2230ea0", 300,
+					      PlayAnimParams::keepLastFrame().partial(0, -2),
+					      12414, kOffsetRightRoom);
 		}
 	}
 
 	void strongBoxMoveTiles(int p1, int p2, int p3, int p4) {
 		Common::SharedPtr<VideoRoom> room = g_vm->getVideoRoom();
-		room->playSound("r2230ee0");
+		room->playSFX("r2230ee0");
 		for (int i = 0; i < 12; i++) {
 			int pos = _strongBoxTiles[i].getPosition();
 			if (pos == p1)
diff --git a/engines/hadesch/rooms/daedalus.cpp b/engines/hadesch/rooms/daedalus.cpp
index b9455e7db0..0d1922b105 100644
--- a/engines/hadesch/rooms/daedalus.cpp
+++ b/engines/hadesch/rooms/daedalus.cpp
@@ -24,6 +24,7 @@
 #include "hadesch/hadesch.h"
 #include "hadesch/video.h"
 #include "hadesch/ambient.h"
+#include "common/translation.h"
 
 namespace Hadesch {
 
@@ -139,7 +140,7 @@ public:
 
 			renderCheckMarks();
 
-			room->playAnimWithSound("dust cloud", "dust cloud sound", 850, PlayAnimParams::disappear());
+			room->playAnimWithSFX("dust cloud", "dust cloud sound", 850, PlayAnimParams::disappear());
 
 			if (hasAll) 
 				playDaedalusVideo("daedalus exclaims", 13008, Common::Point(0, 2));
@@ -213,7 +214,7 @@ public:
 		case 13011: {
 			// TODO: use right algorithm
 			int roarNum = g_vm->getRnd().getRandomNumberRng(1, 5);
-			room->playSound(Common::String::format("ambient minotaur roar %d", roarNum), 13012);
+			room->playSFX(Common::String::format("ambient minotaur roar %d", roarNum), 13012);
 			break;
 		}
 		case 13012:
@@ -240,8 +241,8 @@ public:
 			break;
 		case 13902:
 			room->playAnim(kDaedalusAmbient, kDaedalusZ, PlayAnimParams::keepLastFrame().partial(35, -1), 13904);
-			room->playAnimWithSound(kLabyrinthWorkers, "labyrinth workers sound", kLabyrinthWorkersZ,
-						PlayAnimParams::keepLastFrame());
+			room->playAnimWithSFX(kLabyrinthWorkers, "labyrinth workers sound", kLabyrinthWorkersZ,
+					      PlayAnimParams::keepLastFrame());
 			break;
 		case 13903:
 			room->playAnim(kDaedalusAmbient, kDaedalusZ, PlayAnimParams::keepLastFrame().partial(57, -1), 13904);
@@ -280,8 +281,10 @@ public:
 				room->selectFrame("daedalus note", 800, 0);
 				room->selectFrame(persistent->_gender == kMale ? "daedalus note text male"
 						  : "daedalus note text female", 799, 0);
-				room->playSound(persistent->_gender == kMale ? "daedalus note vo male"
-						: "daedalus note vo female", 13004);
+				room->playSpeech(persistent->_gender == kMale ?
+						 TranscribedSound("daedalus note vo male", "Dear hero, now that we've brought peace to the people of Crete, I've used the wings that I've built for myself and my son Icarus to escape. I'm forever grateful for your help. Your friend, Daedalus") :
+						 TranscribedSound("daedalus note vo female", "Dear heroine, now that we've brought peace to the people of Crete, I've used the wings that I've built for myself and my son Icarus to escape. I'm forever grateful for your help. Your friend, Daedalus. Au revoir. Salaam. Good bye."),
+						 13004);
 			}
 		}
 
@@ -297,15 +300,15 @@ public:
 			persistent->_troyPlayAttack = true;
 			playDaedalusVideo("daedalus intro 1", kIntroStep1,
 					  Common::Point(50, 35));
-			room->playSoundLoop("theme music 1");
+			room->playMusicLoop("theme music 1");
 		} else if (quest == kCreteQuest &&
 			   (persistent->_daedalusLabItem[0] || persistent->isInInventory(kStone)) &&
 			   (persistent->_daedalusLabItem[1] || persistent->isInInventory(kBricks)) &&
 			   (persistent->_daedalusLabItem[2] || persistent->isInInventory(kWood)) &&
 			   (persistent->_daedalusLabItem[3] || persistent->isInInventory(kStraw))) {
-			room->playSoundLoop("theme music 2");
+			room->playMusicLoop("theme music 2");
 		} else {
-			room->playSoundLoop("R4010eA0");
+			room->playMusicLoop("R4010eA0");
 		}
 		AmbientAnim("mouse", "mouse sound", 900, 5000, 10000, AmbientAnim::KEEP_LOOP, Common::Point(0, 0),
 			    AmbientAnim::PAN_ANY).start();
@@ -347,7 +350,7 @@ private:
 	void daedalusWallMotion() {
 		Common::SharedPtr<VideoRoom> room = g_vm->getVideoRoom();
 		room->playAnim(kDaedalusAmbient, kDaedalusZ, PlayAnimParams::keepLastFrame().partial(0, 34), 13902);
-		room->playSound("daedalus ambient sound");
+		room->playSFX("daedalus ambient sound");
 		_daedalusIsBusy = true;
 	}
 
diff --git a/engines/hadesch/rooms/ferry.cpp b/engines/hadesch/rooms/ferry.cpp
index 96298c38ff..90fc945316 100644
--- a/engines/hadesch/rooms/ferry.cpp
+++ b/engines/hadesch/rooms/ferry.cpp
@@ -23,6 +23,7 @@
  */
 #include "hadesch/hadesch.h"
 #include "hadesch/video.h"
+#include "common/translation.h"
 
 namespace Hadesch {
 
@@ -188,117 +189,123 @@ static const ShadowInfo shadows[] = {
 
 static const struct {
 	const char *image;
-	const char *sound;
+	TranscribedSound sound;
 } thoughts[] = {
-	{ "V9140tA0", "V9140nA0" }, // 0
-	{ "V9140tB0", "V9140nB0" },
-	{ "V9140tC0", "V9140nC0" },
-	{ "V9140tD0", "V9140nD0" },
-	{ "V9140tE0", "V9140nE0" },
-	{ "V9140tF0", "V9140nF0" }, // 5
-	{ "V9140tG0", "V9140nG0" },
-	{ "V9140tH0", "V9140nH0" },
-	{ "V9140tI0", "V9140nI0" },
-	{ "V9140tJ0", "V9140nJ0" },
-	{ "V9140tK0", "V9140nK0" }, // 10
-	{ "V9140tL0", "V9140nL0" },
-	{ "V9140tM0", "V9140nM0" },
-	{ "V9140tN0", "V9140nN0" },
-	{ "V9140tO0", "V9140nO0" },
-	{ "V9140tP0", "V9140nP0" }, // 15
-	{ "V9140tQ0", "V9140nQ0" },
-	{ "V9140tR0", "V9140nR0" },
-	{ "V9140tS0", "V9140nS0" },
-	{ "V9140tT0", "V9140nT0" },
-	{ "V9140tU0", "V9140nU0" }, // 20
-	{ "V9140tV0", "V9140nV0" },
-	{ "V9140tW0", "V9140nW0" },
-	{ "V9160tA0", "V9160nA0" },
-	{ "V9160tB0", "V9160nB0" },
-	{ "V9160tC0", "V9160nC0" }, // 25
-	{ "V9160tD0", "V9160nD0" },
-	{ "V9160tE0", "V9160nE0" },
-	{ "V9160tF0", "V9160nF0" },
-	{ "V9160tG0", "V9160nG0" },
-	{ "V9160tH0", "V9160nH0" }, // 30
-	{ "V9160tI0", "V9160nI0" },
-	{ "V9160tJ0", "V9160nJ0" },
-	{ "V9160tK0", "V9160nK0" },
-	{ "V9160tL0", "V9160nL0" },
-	{ "V9170tA0", "V9170nA0" }, // 35
-	{ "V9170tB0", "V9170nB0" },
-	{ "V9170tC0", "V9170nC0" },
-	{ "V9170tD0", "V9170nD0" },
-	{ "V9170tE0", "V9170nE0" },
-	{ "V9170tF0", "V9170nF0" }, // 40
-	{ "V9170tG0", "V9170nG0" },
-	{ "V9170tH0", "V9170nH0" },
-	{ "V9170tI0", "V9170nI0" },
-	{ "V9170tJ0", "V9170nJ0" },
-	{ "V9170tK0", "V9170nK0" }, // 45
-	{ "V9170tL0", "V9170nL0" }, 
-	{ "V9170tM0", "V9170nM0" },
-	{ "V9170tN0", "V9170nN0" },
-	{ "V9170tO0", "V9170nO0" },
-	{ "V9170tP0", "V9170nP0" }, // 50
-	{ "V9170tQ0", "V9170nQ0" },
-	{ "V9170tR0", "V9170nR0" },
-	{ "V9170tS0", "V9170nS0" },
-	{ "V9170tT0", "V9170nT0" },
-	{ "V9170tU0", "V9170nU0" }, // 55
-	{ "V9170tV0", "V9170nV0" },
-	{ "V9170tY0", "V9170nY0" },
-	{ "V9200tA0", "V9200nA0" },
-	{ "V9200tB0", "V9200nB0" },
-	{ "V9200tC0", "V9200nC0" }, // 60
-	{ "V9200tD0", "V9200nD0" },
-	{ "V9200tE0", "V9200nE0" },
-	{ "V9200tF0", "V9200nF0" },
-	{ "V9200tG0", "V9200nG0" },
-	{ "V9200tH0", "V9200nH0" }, // 65
-	{ "V9200tI0", "V9200nI0" },
-	{ "V9200tJ0", "V9200nJ0" },
-	{ "V9200tK0", "V9200nK0" },
-	{ "V9200tL0", "V9200nL0" },
-	{ "V9200tM0", "V9200nM0" }, // 70
-	{ "V9200tN0", "V9200nN0" },
-	{ "V9200tO0", "V9200nO0" },
-	{ "V9240tA0", "V9240nA0" },
-	{ "V9210tA0", "V9210nA0" },
-	{ "V9210tB0", "V9210nB0" }, // 75
-	{ "V9210tC0", "V9210nC0" },
-	{ "V9210tD0", "V9210nD0" },
-	{ "V9220tA0", "V9220nA0" },
-	{ "V9220tB0", "V9220nB0" },
-	{ "V9220tC0", "V9220nC0" }, // 80
-	{ "V9220tD0", "V9220nD0" },
-        { "V9245tA0", "V9300nE0" }
+	{ "V9140tA0", {"V9140nA0", _s("He won't sit next to humans") } }, // 0
+	{ "V9140tB0", {"V9140nB0", _s("He won't sit next to animals") } },
+	{ "V9140tC0", {"V9140nC0", _s("He won't sit next to smoking beings") } },
+	{ "V9140tD0", {"V9140nD0", _s("He won't sit next to flat beings") } },
+	{ "V9140tE0", {"V9140nE0", _s("He won't sit next to weapon injuries") } },
+	{ "V9140tF0", {"V9140nF0", _s("He won't sit next to cats") } }, // 5
+	{ "V9140tG0", {"V9140nG0", _s("He won't sit next to two-headed beings") } },
+	{ "V9140tH0", {"V9140nH0", _s("He won't sit next to monsters") } },
+	{ "V9140tI0", {"V9140nI0", _s("He won't sit next to hot beings") } },
+	{ "V9140tJ0", {"V9140nJ0", _s("He won't sit next to headless beings") } },
+	{ "V9140tK0", {"V9140nK0", _s("He won't sit next to horned beings") } }, // 10
+	{ "V9140tL0", {"V9140nL0", _s("He won't sit next to flat monsters") } },
+	{ "V9140tM0", {"V9140nM0", _s("He won't sit next to beings with holes") } },
+	{ "V9140tN0", {"V9140nN0", _s("He won't sit next to pierced beings") } },
+	{ "V9140tO0", {"V9140nO0", _s("He won't sit next to fffreozen beings") } },
+	{ "V9140tP0", {"V9140nP0", _s("He won't sit next to wet beings") } }, // 15
+	{ "V9140tQ0", {"V9140nQ0", _s("He won't sit next to crushed dogs") } },
+	{ "V9140tR0", {"V9140nR0", _s("He won't sit next to dogs") } },
+	{ "V9140tS0", {"V9140nS0", _s("He won't sit next to headless dogs") } },
+	{ "V9140tT0", {"V9140nT0", _s("He won't sit next to dismembered beings") } },
+	{ "V9140tU0", {"V9140nU0", _s("He won't sit next to crushed humans") } }, // 20
+	{ "V9140tV0", {"V9140nV0", _s("He won't sit next to trident-injured beings. And I couldn't blame him") } },
+	{ "V9140tW0", {"V9140nW0", _s("He won't sit next to snake-killed beings") } },
+	{ "V9160tA0", {"V9160nA0", _s("He won't sit across from humans") } },
+	{ "V9160tB0", {"V9160nB0", _s("He won't sit across from animals") } },
+	{ "V9160tC0", {"V9160nC0", _s("He won't sit across from weapon injuries") } }, // 25
+	{ "V9160tD0", {"V9160nD0", _s("He won't sit across from cats") } },
+	{ "V9160tE0", {"V9160nE0", _s("He won't sit across from monsters") } },
+	{ "V9160tF0", {"V9160nF0", _s("He won't sit across from hot beings") } },
+	{ "V9160tG0", {"V9160nG0", _s("He won't sit across from headless beings") } },
+	{ "V9160tH0", {"V9160nH0", _s("He won't sit across from flat beings") } }, // 30
+	{ "V9160tI0", {"V9160nI0", _s("He won't sit across from head injuries") } },
+	{ "V9160tJ0", {"V9160nJ0", _s("He won't sit across from beings with holes") } },
+	{ "V9160tK0", {"V9160nK0", _s("He won't sit across from pierced beings") } },
+	{ "V9160tL0", {"V9160nL0", _s("He won't sit across from wet beings") } },
+	{ "V9170tA0", {"V9170nA0", _s("He simply must sit next to a dog") } }, // 35
+	{ "V9170tB0", {"V9170nB0", _s("He must sit next to a being with holes") } },
+	{ "V9170tC0", {"V9170nC0", _s("He must sit next to a pierced being") } },
+	{ "V9170tD0", {"V9170nD0", _s("He must sit next to a human") } },
+	{ "V9170tE0", {"V9170nE0", _s("He must sit next to a monster") } },
+	{ "V9170tF0", {"V9170nF0", _s("He must sit next to a monster with a head injury") } }, // 40
+	{ "V9170tG0", {"V9170nG0", _s("He must sit next to a dismembered being") } },
+	{ "V9170tH0", {"V9170nH0", _s("He must sit next to a flat human") } },
+	{ "V9170tI0", {"V9170nI0", _s("He must sit next to a smoking being") } },
+	{ "V9170tJ0", {"V9170nJ0", _s("He must sit next to a hot being") } },
+	{ "V9170tK0", {"V9170nK0", _s("He simply must sit next to a horned being") } }, // 45
+	{ "V9170tL0", {"V9170nL0", _s("He must sit next to a flat animal") } }, 
+	{ "V9170tM0", {"V9170nM0", _s("He must sit next to a flat being") } },
+	{ "V9170tN0", {"V9170nN0", _s("He must sit next to an animal") } },
+	{ "V9170tO0", {"V9170nO0", _s("He must sit next to a headless being") } },
+	{ "V9170tP0", {"V9170nP0", _s("He must sit next to a head being") } }, // 50
+	{ "V9170tQ0", {"V9170nQ0", _s("He must sit next to a weapon injury") } },
+	{ "V9170tR0", {"V9170nR0", _s("He must sit next to a cat") } },
+	{ "V9170tS0", {"V9170nS0", _s("He must sit next to a snake-killed being") } },
+	{ "V9170tT0", {"V9170nT0", _s("He must sit next to a smoking animal") } },
+	{ "V9170tU0", {"V9170nU0", _s("He must sit next to a wet being") } }, // 55
+	{ "V9170tV0", {"V9170nV0", _s("He must sit next to a c-c-cold being") } },
+	{ "V9170tY0", {"V9170nY0", _s("He must sit next to two humans") } },
+	{ "V9200tA0", {"V9200nA0", _s("He must sit across from a being with holes") } },
+	{ "V9200tB0", {"V9200nB0", _s("He must sit across from a pierced being") } },
+	{ "V9200tC0", {"V9200nC0", _s("He must sit across from a human") } }, // 60
+	{ "V9200tD0", {"V9200nD0", _s("He must sit across from a monster") } },
+	{ "V9200tE0", {"V9200nE0", _s("He must sit across from a monster with a head injury") } },
+	{ "V9200tF0", {"V9200nF0", _s("He must sit across from a dismembered injury") } },
+	{ "V9200tG0", {"V9200nG0", _s("He must sit across from a smoking being") } },
+	{ "V9200tH0", {"V9200nH0", _s("He must sit across from a hot being") } }, // 65
+	{ "V9200tI0", {"V9200nI0", _s("He must sit across from a horned being") } },
+	{ "V9200tJ0", {"V9200nJ0", _s("He must sit across from a flat being") } },
+	{ "V9200tK0", {"V9200nK0", _s("He must sit across from an animal") } },
+	{ "V9200tL0", {"V9200nL0", _s("He must sit across from a headless being") } },
+	{ "V9200tM0", {"V9200nM0", _s("He must sit across from the chariot wheel guy") } }, // 70
+	{ "V9200tN0", {"V9200nN0", _s("He must sit across from a head injury") } },
+	{ "V9200tO0", {"V9200nO0", _s("He must sit across from a weapon injury") } },
+	{ "V9240tA0", {"V9240nA0", _s("He must sit in the front or back") } },
+	{ "V9210tA0", {"V9210nA0", _s("He must sit next to and across from only monsters") } },
+	{ "V9210tB0", {"V9210nB0", _s("He must sit next to and across from only animals") } }, // 75
+	{ "V9210tC0", {"V9210nC0", _s("He must sit next to and across from only humans") } },
+	{ "V9210tD0", {"V9210nD0", _s("He must sit next to and across from only weapon injuries") } },
+	{ "V9220tA0", {"V9220nA0", _s("He must not sit next to or across from humans") } },
+	{ "V9220tB0", {"V9220nB0", _s("He must not sit next to or across from pierced beings") } },
+	{ "V9220tC0", {"V9220nC0", _s("He must not sit next to or across from monsters") } }, // 80
+	{ "V9220tD0", {"V9220nD0", _s("He must not sit next to or across from animals") } },
+        { "V9245tA0", {"V9300nE0", _s("Ha-ha-ha") } }
 };
 
 static const struct {
 	const char *image;
-	const char *sound;
+	const TranscribedSound sound;
 } charonRules[] = {
-	{ "V9250tA0", "V9250aA0" }, // 0
-	{ "V9250tB0", "V9250aB0" },
-	{ "V9250tC0", "V9250aC0" },
-	{ "V9250tD0", "V9250aD0" },
-	{ "V9260tA0", "V9260nA0" },
-	{ "V9260tB0", "V9260nB0" }, // 5
-	{ "V9260tC0", "V9260nC0" },
-	{ "V9260tD0", "V9260nD0" },
-	{ "V9260tE0", "V9260nE0" },
-	{ "V9260tF0", "V9260nF0" },
-	{ "V9260tG0", "V9260nG0" }, // 10
-	{ "V9260tJ0", "V9260nJ0" },
-	{ "V9270tA0", "XXXXXXXX" }
+	{ "V9250tA0", { "V9250aA0", _s("Charon must sit next to horned beings") } }, // 0
+	{ "V9250tB0", { "V9250aB0", _s("Charon must sit next to cats") } },
+	{ "V9250tC0", { "V9250aC0", _s("Charon must sit next to animals") } },
+	{ "V9250tD0", { "V9250aD0", _s("Charon must sit next to smoking beings") } },
+	{ "V9260tA0", { "V9260nA0", _s("Charon can't have any monsters at the head of the boat") } },
+	{ "V9260tB0", { "V9260nB0", _s("No animals at the head of the boat") } }, // 5
+	{ "V9260tC0", { "V9260nC0", _s("Charon wont sit next to two-headed beings") } },
+	{ "V9260tD0", { "V9260nD0", _s("Charon won't sit next to flat beings") } },
+	{ "V9260tE0", { "V9260nE0", _s("Charon won't sit next to horned beings") } },
+	{ "V9260tF0", { "V9260nF0", _s("Charon won't sit next to cats") } },
+	{ "V9260tG0", { "V9260nG0", _s("Charon won't sit next to smoking beings")  } }, // 10
+	{ "V9260tJ0", { "V9260nJ0", _s("Charon won't sit next to trident-injured beings") } },
+	{ "V9270tA0", { "XXXXXXXX", "" } }
 };
 
-static const char *charonFinishSounds[] = {
-	"V9300nA0",
-	"V9300nH0",
-	"V9300nI0"
-};		
+static const TranscribedSound charonFinishSounds[] = {
+	{"V9300nA0", _s("Well done")},
+	{"V9300nH0", _s("Deadly")},
+	{"V9300nI0", _s("Nice job")}
+};
+
+static const TranscribedSound charonNextLevel[] = {
+	{"V9280wA0", _s("Onto level two")},
+	{"V9280wB0", _s("Onto level three")},
+	{"V9280wC0", _s("You have mastered ferryman's folly")}
+};
 
 static const char *charonAnims[] = {
 	"V9140BA0",
@@ -306,6 +313,14 @@ static const char *charonAnims[] = {
 	"V9140BC0"
 };
 
+static TranscribedSound yuckSounds[] = {
+	{ "V9290nA0", _s("Eww!") },
+	{ "V9290nB0", _s("Yuck!") },
+	{ "V9290nC0", _s("Gross!") },
+	{ "V9290nD0", _s("As if!") },
+	{ "V9290nE0", _s("No way!") },
+};
+
 struct CharonIdleVideoInfo {
 	const char *name;
 	int offsetX;
@@ -555,7 +570,7 @@ public:
 					break;
 				}
 
-				playCharonSound(Common::String::format("V9280w%c0", 'A' + _levelL), 24020);
+				playCharonSound(charonNextLevel[_levelL], 24020);
 				_levelL++;
 				_levelS = 0;
 			}
@@ -592,21 +607,21 @@ public:
 			break;
 		}
 		case k24801_arg1:
-			playCharonSoundSMK("V9090NH0", k24801_arg2);
+			playCharonSoundSMK(TranscribedSound("V9090NH0", "When you click on a shade you can see and I'll tell you what they think of one another"), k24801_arg2);
 			_count24006 = 0;
 			g_vm->addTimer(24006, 1200);
 			break;
 		case k24801_arg2:
-			playCharonSoundSMK("V9090ND0", k24801_arg3);
+			playCharonSoundSMK(TranscribedSound("V9090ND0", "If you click on a shade you can drag it into a seat"), k24801_arg3);
 			break;
 		case k24801_arg3:
-			playCharonSoundSMK("V9090NE0", k24801_arg4);
+			playCharonSoundSMK(TranscribedSound("V9090NE0", "If they find a neighbour offensive, they'll return to the dark"), k24801_arg4);
 			break;
 		case k24801_arg4:
-			playCharonSoundSMK("V9090NI0", k24801_arg5);
+			playCharonSoundSMK(TranscribedSound("V9090NI0", "To remove the shade from the boat click and drag it to the dark"), k24801_arg5);
 			break;
 		case k24801_arg5:
-			playCharonSoundSMK("V9130NA0", k24801_arg6);
+			playCharonSoundSMK(TranscribedSound("V9130NA0", "Do try and discover what is bothering each of them"), k24801_arg6);
 			break;
 		case k24801_arg6:
 			room->enableMouse();
@@ -628,8 +643,8 @@ public:
 		room->playVideo("V9010xA0", 0, 24002);
 		room->loadHotZones("ff.hot", false);
 
-		room->playSoundLoop("V9010eA0");
-		room->playSoundLoop("V9300eA0");
+		room->playMusicLoop("V9010eA0");
+		room->playMusicLoop("V9300eA0");
 
 		_levelL = 1;
 		if (persistent->_quest == kRescuePhilQuest) {
@@ -653,7 +668,7 @@ public:
 		if (persistent->_quest == kRescuePhilQuest) {
 			room->disableMouse();
 			// originally 24800
-			playCharonSoundSMK("V9090NA0", k24801_arg1);
+			playCharonSoundSMK(TranscribedSound("V9090NA0", "Oh, the dead are a tiresome lot. Charon can't bear to weed through their assorted woes. If you assist Charon by loading the shades onto the boat, Charon will squeeze you in for the ride across"), k24801_arg1);
 		}
 	}
 
@@ -683,7 +698,7 @@ private:
 		PlayAnimParams params(PlayAnimParams::keepLastFrame().partial(startFrame, endFrame));
 		const char *snd = shadows[_shades[shade].shadowId].animSound;
 		if (snd && snd[0] != 0)
-			room->playAnimWithSound(sl, snd, z, params, k24018_arg0 + shade, getShadowPos(shade));
+			room->playAnimWithSFX(sl, snd, z, params, k24018_arg0 + shade, getShadowPos(shade));
 		else
 			room->playAnim(sl, z, params, k24018_arg0 + shade, getShadowPos(shade));
 	}
@@ -704,7 +719,7 @@ private:
 		_charonIsBusy = false;
 	}
 
-	void playCharonSound(const Common::String &sound,
+	void playCharonSound(const TranscribedSound &sound,
 			     EventHandlerWrapper ev = kCharonEndTalk, bool isSMK = false) {
 		Common::SharedPtr<VideoRoom> room = g_vm->getVideoRoom();
 		int selected = -2;
@@ -715,12 +730,12 @@ private:
 		_lastCharonAnim = selected;
 		room->playAnim(charonAnims[selected], kCharonZ, PlayAnimParams::loop());
 		if (isSMK)
-			room->playVideo(sound, 0, ev);
+			room->playVideo(sound.soundName, 0, ev);
 		else
-			room->playSound(sound, ev);
+			room->playSpeech(sound, ev);
 	}
 
-	void playCharonSoundSMK(const Common::String &sound,
+	void playCharonSoundSMK(const TranscribedSound &sound,
 				EventHandlerWrapper ev = kCharonEndTalk) {
 		playCharonSound(sound, ev, true);
 	}
@@ -755,7 +770,7 @@ private:
 			if (thoughtId >= 0)
 				playCharonSound(thoughts[thoughtId].sound);
 			else if (thoughtId == -1)
-				playCharonSound("V9150nA0");
+				playCharonSound(TranscribedSound("V9150nA0", "He won't move from that seat"));
 		}
 		room->selectFrame("V9090oA0", 112, 0, bubblePos);
 		room->selectFrame(shadows[_shades[id].shadowId].nameImage, 111, 0, bubblePos);
@@ -829,8 +844,8 @@ private:
 		if (_isPlayingYuck)
 			return;
 		_isPlayingYuck = true;
-		room->playSound(Common::String::format("V9290n%c0", g_vm->getRnd().getRandomNumberRng('A', 'E')),
-				24010);
+		room->playSpeech(yuckSounds[g_vm->getRnd().getRandomNumberRng(0, ARRAYSIZE(yuckSounds))],
+					  24010);
 	}
 
 	bool checkCombinationIsAllowed(int shadeId) {
diff --git a/engines/hadesch/rooms/hadesthrone.cpp b/engines/hadesch/rooms/hadesthrone.cpp
index 731678f1ad..29d863a562 100644
--- a/engines/hadesch/rooms/hadesthrone.cpp
+++ b/engines/hadesch/rooms/hadesthrone.cpp
@@ -52,7 +52,7 @@ public:
 		Common::SharedPtr<VideoRoom> room = g_vm->getVideoRoom();
 		room->playVideo("movie", 500, 29001);
 		room->disableHeroBelt();
-		room->playSoundLoop("V6010eA0");
+		room->playMusicLoop("V6010eA0");
 		room->disableMouse();
 	}
 };
diff --git a/engines/hadesch/rooms/medisle.cpp b/engines/hadesch/rooms/medisle.cpp
index 5c63a7920e..3fb54d5101 100644
--- a/engines/hadesch/rooms/medisle.cpp
+++ b/engines/hadesch/rooms/medisle.cpp
@@ -24,6 +24,7 @@
 #include "hadesch/hadesch.h"
 #include "hadesch/video.h"
 #include "hadesch/ambient.h"
+#include "common/translation.h"
 
 namespace Hadesch {
 
@@ -67,12 +68,12 @@ static const char *itemSounds[] = {
 	"m1230ea0"
 };
 
-static const char *itemClickSounds[] = {
-	"m1150ne0",
-	"m1150nd0",
-	"m1150na0",
-	"m1150nb0",
-	"m1150nc0"
+static const TranscribedSound itemClickSounds[] = {
+	{"m1150ne0", _s("If Perseus looks directly at Medusa he will be turned to stone. Using the shield from my temple, he can look at her reflection instead") },
+	{"m1150nd0", _s("The sword from my temple will cut off Medusa's head") },
+	{"m1150na0", _s("Medusa's head must be brough back inside this magic bag") },
+	{"m1150nb0", _s("When Perseus wears the dark helmet, he will be invisible") },
+	{"m1150nc0", _s("Putting on the winged sandals will allow you to fly above and move quickly") }
 };
 
 static const char *perseusItemAnims[] = {
@@ -83,12 +84,18 @@ static const char *perseusItemAnims[] = {
 	"m1230ba0"
 };
 
-static const char *perseusItemSounds[] = {
-	"m1190na0",
-	"m1180na0",
-	"m1220na0",
-	"m1210na0",
-	"m1230na0"
+static const TranscribedSound perseusItemSounds[] = {
+	{ "m1190na0", _s("Thanks. The shield is just what I needed") },
+	{ "m1180na0", _s("Yeah. The sword oughta do the trick") },
+	{ "m1220na0", _s("Alright. You've got the bag. Excellent") },
+	{ "m1210na0", _s("Yes, the helmet. You're doing great") },
+	{ "m1230na0", _s("Ok, you've found the sandals. I owe you big time") }
+};
+
+static const TranscribedSound eyeInsistSpeech[] = {
+	{"m2120wd0", _s("No, no. Where did he go?")},
+	{"m2120we0", _s("Feel around here. It's got to be near")},
+	{"m2120wf0", _s("If it's lost I'd cry but I don't have an eye")}
 };
 
 struct StatuePiece {
@@ -179,6 +186,31 @@ static const struct {
 	{ "m1280ba0", "m1280ea0", 5000, 50000, 1500, -200, false }
 };
 
+static const TranscribedSound kICanForetellTheFuture = {
+	"m2190wa0",
+	_s("I can foretell the future. You know, I always knew I was going to say that")
+};
+
+static const TranscribedSound kGiveMeEyeOrIllPunchYouInTheEye = {
+	"m2190wb0",
+	_s("Give me the eye or I'll punch you in the eye")
+};
+
+static const TranscribedSound kPunchingOwnEye = {
+	"m2190wc0",
+	_s("Oh yeah? Then you'll be punching your own eye")
+};
+
+static const TranscribedSound kIllTakeTheEyeYouCanHaveOneOfMyEars = {
+	"m2190wd0",
+	_s("I'll take the eye you can have one of my ears")
+};
+
+static const TranscribedSound kMedusaOnceBeauty = {
+	"m2210wa0",
+	_s("Medusa once was quite the beauty. Also vain and very snoody. Treated Athena awful bad and mad the goddess awfully mad. To snab the god is all it takes and now her hair is made of snakes")
+}; // unclear
+
 static const struct {
 	const char *image;
 	int minint, maxint;
@@ -243,7 +275,7 @@ public:
 			room->stopAnim(kStoneAnim);
 			g_vm->getHeroBelt()->placeToInventory(kStone, kStoneTaken);
 			room->disableHotzone(kStoneHotzone);
-			room->playSound("m1360ma0");
+			room->playMusic("m1360ma0");
 			persistent->_medisleStoneTaken = true;
 			room->disableMouse();
 			return;
@@ -258,7 +290,7 @@ public:
 			room->drag("m2010oa0", 0, Common::Point(21, 20));
 			room->stopAnim("m2010oa0");
 			room->disableMouse();
-			room->playSound("m2130ea0", 11027);
+			room->playSFX("m2130ea0", 11027);
 			_eyeIsPickedUp = true;
 			persistent->_medisleEyePosition = kNumFates;
 			return;
@@ -281,7 +313,7 @@ public:
 				if (name == fatesHotzoneNames[i]) {
 					persistent->_medisleEyePosition = i;
 					room->disableMouse();
-					room->playSound("m2130ee0", 11029);
+					room->playSFX("m2130ee0", 11029);
 					room->disableHotzone("Eyeball");
 					room->clearDrag();
 					_eyeIsGivenBack = true;
@@ -323,29 +355,29 @@ public:
 					return;
 				}
 
-				Common::Array <Common::String> hints;
+				Common::Array <TranscribedSound> hints;
 
 				switch (quest) {
 				case kCreteQuest:
-					hints.push_back("m2220wa0");
-					hints.push_back("m2220wb0");
-					hints.push_back("m2220wc0");
+					hints.push_back(TranscribedSound("m2220wa0", "The Minotaur's is where you need to be. Trapping him sets Daedalus free."));
+					hints.push_back(TranscribedSound("m2220wb0", "King Minos is the king of Crete. He's not the nicest man you meet."));
+					hints.push_back(TranscribedSound("m2220wc0", "The Minotaur is hard to beat. The one who's trying lives in Crete"));
 					break;
 				case kTroyQuest:
-					hints.push_back("m2230wa0");
-					hints.push_back("m2230wb0");
-					hints.push_back("m2230wc0");
+					hints.push_back(TranscribedSound("m2230wa0", "If Helen gets this note, our friend, the trojan war will quickly end."));
+					hints.push_back(TranscribedSound("m2230wb0", "Helen was a husband's joy but she's a prisonner inside Troy."));
+					hints.push_back(TranscribedSound("m2230wc0", "The trojan horse you cannot ride bust beware what's found inside"));
 					break;
 				case kMedusaQuest:
 					if (persistent->_medisleShowFates) {
-						hints.push_back("m2210wa0");
-						hints.push_back("m2250wa0");
-						hints.push_back("m2250wb0");
+						hints.push_back(kMedusaOnceBeauty);
+						hints.push_back(TranscribedSound("m2250wa0", "Medusa's curse is quite well known: she looks at you and you turn to stone"));
+						hints.push_back(TranscribedSound("m2250wb0", "So be forewarned, it isn't wise to gaze into Medusa's eyes."));
 					}
 					break;
 				case kRescuePhilQuest:
-					hints.push_back("m2240wa0");
-					hints.push_back("m2240wb0");
+					hints.push_back(TranscribedSound("m2240wa0", "To rescue Phil's an easy fix: just go across the river Styx"));
+					hints.push_back(TranscribedSound("m2240wb0", "You know Phil, he loves the ladies. He'd be best beware of the evil ladies"));
 					break;
 				// To silence warning
 				case kNoQuest:
@@ -357,41 +389,46 @@ public:
 				if (hints.empty()) {
 					playFatesLairBackupSound();
 				} else {
-					fatesShadowSound(hints[(_hintsCounter - 2) % hints.size()], 11632);
+					fatesShadowSpeech(hints[(_hintsCounter - 2) % hints.size()], 11632);
 				}
 				return;
 			}
 
+			// TODO: check this
+
 			if (showFate(kLachesis) && showFate(kAtropos) && !showFate(kClotho)) {
-				fatesShadowSound("m2210wd0", 11632);
+				fatesShadowSpeech(kIllTakeTheEyeYouCanHaveOneOfMyEars, 11632);
 			}
 
 			if (showFate(kLachesis) && !showFate(kAtropos) && showFate(kClotho)) {
-				fatesShadowSound("m2210wa0", 11632);
+				fatesShadowSpeech(kMedusaOnceBeauty, 11632);
 			}
 
 			if (showFate(kLachesis) && !showFate(kAtropos) && !showFate(kClotho)) {
-				fatesShadowSound("m2190wd0", 11632);
+				fatesShadowSpeech(_hintsCounter & 1 ? kIllTakeTheEyeYouCanHaveOneOfMyEars : kMedusaOnceBeauty, 11632);
 			}
 
 			if (!showFate(kLachesis) && showFate(kAtropos) && showFate(kClotho)) {
-				fatesShadowSound("m2190wa0", 11632);
+				fatesShadowSpeech(kICanForetellTheFuture, 11632);
 			}
 
 			if (!showFate(kLachesis) && showFate(kAtropos) && !showFate(kClotho)) {
-				fatesShadowSound(_hintsCounter & 1 ? "m2190wa0" : "m2190wd0", 11632);
+				fatesShadowSpeech(_hintsCounter & 1 ? kICanForetellTheFuture : kIllTakeTheEyeYouCanHaveOneOfMyEars, 11632);
 			}
 
 			if (!showFate(kLachesis) && !showFate(kAtropos) && showFate(kClotho)) {
-				switch (_hintsCounter % 3) {
+				switch (_hintsCounter % 4) {
 				case 0:
-					fatesShadowSound("m2190wb0", 11629);
+					fatesShadowSpeech(kGiveMeEyeOrIllPunchYouInTheEye, 11629);
 					return;
 				case 1:
-					fatesShadowSound("m2190wa0", 11632);
+					fatesShadowSpeech(kPunchingOwnEye, 11632);
 					return;
 				case 2:
-					fatesShadowSound("m2210wa0", 11632);
+					fatesShadowSpeech(kICanForetellTheFuture, 11632);
+					return;
+				case 3:
+					fatesShadowSpeech(kMedusaOnceBeauty, 11632);
 					return;
 				}
 			}
@@ -419,7 +456,7 @@ TODO (medusa quest):
 		if (name == "Perseus" && (
 			    item >= kShield && item <= kSandals)) {
 			room->disableMouse();
-			playPerseusAnim("m1240ba0", "m1240na0", 11053);
+			playPerseusAnimSpeech("m1240ba0", TranscribedSound("m1240na0", "No, you've got to put it in the frieze above me, hurry!"), 11053);
 		}
 
 		return false;
@@ -437,7 +474,10 @@ TODO (medusa quest):
 					Common::Point(640, 216));
 			break;
 		case 11003:
-			room->playSound("m2100wa0", 11004);
+			room->playSpeech(TranscribedSound(
+							  "m2100wa0",
+							  "Someone help! I'm over here"),
+						  11004);
 			room->enableMouse();
 			break;
 		case kStoneTaken:
@@ -449,24 +489,24 @@ TODO (medusa quest):
 				persistent->_medisleShowFates = true;
 				room->setPannable(false);
 				room->disableHotzone("Argo");
-				room->playSound("m2120ma0", 11642);
+				room->playMusic("m2120ma0", 11642);
 				g_vm->addTimer(11601, 6500);
 				room->disableMouse();
 				persistent->_medisleEyeballIsActive = true;
 			}
 			break;
 		case 11601:
-			fatesShadowSound("m2120wa0", 11602);
+			fatesShadowSpeech(TranscribedSound("m2120wa0", "Now it's time, the eyeball's mine"), 11602);
 			break;
 		case 11602:
-			fatesShadowSound("m2120wb0", 11603);
+			fatesShadowSpeech(TranscribedSound("m2120wb0", "I can't see, so give it to me"), 11603);
 			break;
 		case 11603:
-			fatesShadowSound("m2120wc0", 11604);
+			fatesShadowSpeech(TranscribedSound("m2120wc0", "You stupid lout. Let's go, look out"), 11604);
 			break;
 		case 11604:
-			fatesShadowSoundEnd();
-			room->playAnimWithSound("m2120ba0", "m2120ea0", 280, PlayAnimParams::disappear(), 11605, kOffsetRightRoom);
+			fatesShadowSpeechEnd();
+			room->playAnimWithSFX("m2120ba0", "m2120ea0", 280, PlayAnimParams::disappear(), 11605, kOffsetRightRoom);
 			break;
 		case 11605:
 			room->enableMouse();
@@ -478,11 +518,11 @@ TODO (medusa quest):
 		case 11606:
 			if (_eyeIsGivenBack || _eyeIsPickedUp)
 				break;
-			fatesShadowSound(Common::String::format("m2120w%c0", 'd' + (_eyeInsistCounter % 3)), 11608);
+			fatesShadowSpeech(eyeInsistSpeech[_eyeInsistCounter % 3], 11608);
 			_eyeInsistCounter++;
 			break;
 		case 11608:
-			fatesShadowSoundEnd();
+			fatesShadowSpeechEnd();
 			break;
 		case 11065: // Left pan
 			if (persistent->_seriphosPlayedMedusa && !persistent->_medislePlayedPerseusIntro) {
@@ -491,7 +531,12 @@ TODO (medusa quest):
 			}
 			break;
 		case 11005:
-			playPerseusAnim("m1140bb0", "m1140nb0", 11007);
+			playPerseusAnimSpeech("m1140bb0",
+					      TranscribedSound(
+						      "m1140nb0",
+						      "This is what happens when you don't follow instructions. "
+						      "I should have listened to Athena's warning"),
+					      11007);
 			persistent->_medislePlayedPerseusIntro = true;
 			break;
 		case 11006:
@@ -499,24 +544,27 @@ TODO (medusa quest):
 			room->enableMouse();
 			break;
 		case 11007:
-			playPerseusAnim("m1140bc0", "m1140nc0", 11008);
+			playPerseusAnimSpeech("m1140bc0", TranscribedSound(
+						      "m1140nc0",
+						      "Without that stuff, I'm gonna wind up as part of Medusa's latest rock collection"),
+					      11008);
 			break;
 		case 11008:
-			playPerseusAnim("m1140bd0", "m1140nd0", 11006);
+			playPerseusAnimSpeech("m1140bd0", TranscribedSound("m1140nd0", "You gotta help me"), 11006);
 			break;
 		case 11009:
-			room->playSound(itemClickSounds[_lastClickedItem], 11010);
+			room->playSpeech(itemClickSounds[_lastClickedItem], 11010);
 			break;
 		case 11010:
 			for (int i = 0; i < 5; i++)
 				room->stopAnim(itemImagesGlow[i]);
 			break;
 		case 11012:
-			room->playSound("m1210ma0", 11013);
+			room->playMusic("m1210ma0", 11013);
 			break;
 		case 11013:
-			playPerseusAnim(perseusItemAnims[_lastPlacedItem - kShield],
-					 perseusItemSounds[_lastPlacedItem - kShield], 11014);
+			playPerseusAnimSpeech(perseusItemAnims[_lastPlacedItem - kShield],
+					      perseusItemSounds[_lastPlacedItem - kShield], 11014);
 			break;
 		case 11014: {
 			finishPerseusAnim();
@@ -536,26 +584,26 @@ TODO (medusa quest):
 				event = 11024;
 				break;
 			case 5:
-				room->playAnimWithSound("m1170ba0",
-							"m1190ec1",
-							806,
-							PlayAnimParams::disappear(),
-							11021);
+				room->playAnimWithSFX("m1170ba0",
+						      "m1190ec1",
+						      806,
+						      PlayAnimParams::disappear(),
+						      11021);
 				return;
 			}
 			int snakeIdx = 4 - getNumberOfBroughtItems();
-			room->playAnimWithSound(snakes[snakeIdx],
-						"m1190ec1", 807 + snakeIdx,
-						PlayAnimParams::disappear(),
-						event);
+			room->playAnimWithSFX(snakes[snakeIdx],
+					      "m1190ec1", 807 + snakeIdx,
+					      PlayAnimParams::disappear(),
+					      event);
 		}
 			break;
 		case 11015:
 			renderPerseus();
 			if (_lastPlacedItem == kSword)
-				playPerseusAnim("m1180bc0", "m1180nb0", 11016);
+				playPerseusAnimSpeech("m1180bc0", TranscribedSound("m1180nb0", "Thanks for the sword. Did you bring anything else?"), 11016);
 			else
-				playPerseusAnim("m1190bc0", "m1190nb0", 11016);
+				playPerseusAnimSpeech("m1190bc0", TranscribedSound("m1190nb0", "Thanks for the shield. Did you bring anything else?"), 11016);
 			break;
 		case 11016:
 		case 11025:
@@ -565,7 +613,7 @@ TODO (medusa quest):
 			break;
 		case 11017:
 			renderPerseus();
-			playPerseusAnim("m1200ba0", "m1200na0", 11018);
+			playPerseusAnimSpeech("m1200ba0", TranscribedSound("m1200na0", "You're doing great but I still need three other weapons. The fates will know where they are. Go ask them. They're somewhere on the isle"), 11018);
 			break;
 		case 11018:
 			finishPerseusAnim();
@@ -599,11 +647,12 @@ TODO (medusa quest):
 			break;
 		case 11024:
 			renderPerseus();
-			playPerseusAnim("m1250bb0", "m1250nb0", 11025);
+			playPerseusAnimSpeech("m1250bb0", TranscribedSound("m1250nb0", "What about the last item?"), 11025);
 			break;
 		case 11020:
 			renderPerseus();
-			playPerseusAnim("m1250ba0", "m1250na0", 11025);
+			playPerseusAnimSpeech("m1250ba0",
+					      TranscribedSound("m1250na0", "What about the other items?"), 11025);
 			break;
 		case 11027:
 			room->playVideo("m2130ba0", kFatesZ, 11609, Common::Point(756, 0));
@@ -625,7 +674,7 @@ TODO (medusa quest):
 		case 11624:
 			if (persistent->_medisleBagPuzzleState < Persistent::BAG_STARTED)
 				persistent->_medisleBagPuzzleState = Persistent::BAG_STARTED;
-			room->playSound("m2200ea0");
+			room->playSFX("m2200ea0");
 			startBagPuzzle();
 			// Fallthrough
 		case 11625:
@@ -669,7 +718,7 @@ TODO (medusa quest):
 			FateId fate = (FateId) g_vm->getRnd().getRandomNumberRng(0, 2);
 
 			if (!showFate(fate) && fate == kLachesis) {
-				room->playSound(
+				room->playSFX(
 					g_vm->getRnd().getRandomBit() ? "m2160wb0" : "m2160wa0", 11616);
 				break;
 			}
@@ -712,22 +761,22 @@ TODO (medusa quest):
 			case kLachesis:
 				room->stopAnim("m2140od0");
 				if (g_vm->getRnd().getRandomBit()) {
-					room->playAnimWithSound("m2140ba0", "m2140ea0", 1500,
-								PlayAnimParams::disappear(), 11617, kOffsetRightRoom);
+					room->playAnimWithSFX("m2140ba0", "m2140ea0", 1500,
+							      PlayAnimParams::disappear(), 11617, kOffsetRightRoom);
 				} else {
-					room->playAnimWithSound("m2140be0", "m2140ee0", 1500,
-								PlayAnimParams::disappear(), 11617, kOffsetRightRoom);
+					room->playAnimWithSFX("m2140be0", "m2140ee0", 1500,
+							      PlayAnimParams::disappear(), 11617, kOffsetRightRoom);
 				}
 				break;
 			case kAtropos:
 				room->stopAnim("m2140oe0");
-				room->playAnimWithSound("m2140bg0", "m2140eg0", 1500,
-							PlayAnimParams::disappear(), 11617, kOffsetRightRoom);
+				room->playAnimWithSFX("m2140bg0", "m2140eg0", 1500,
+						      PlayAnimParams::disappear(), 11617, kOffsetRightRoom);
 				break;
 			case kClotho:
 				room->stopAnim("m2140of0");
-				room->playAnimWithSound("m2140bh0", "m2140eh0", 1500,
-							PlayAnimParams::disappear(), 11617, kOffsetRightRoom);
+				room->playAnimWithSFX("m2140bh0", "m2140eh0", 1500,
+						      PlayAnimParams::disappear(), 11617, kOffsetRightRoom);
 				break;
 			// To silence warning
 			case kNumFates:
@@ -740,25 +789,25 @@ TODO (medusa quest):
 			renderFatesAll();
 			break;
 		case 11629:
-			room->playSound("m2190wc0", 11630);
+			room->playSpeech(kPunchingOwnEye, 11630);
 			break;
 		case 11630:
 		case 11632:
 			room->enableMouse();
-			fatesShadowSoundEnd();
+			fatesShadowSpeechEnd();
 			break;
 		case kLoopFatesShadow:
 			room->playAnim("m2280bc0", 4000,
 				       PlayAnimParams::loop().partial(10, 49), -1, kOffsetRightRoom);
 			break;
 		case 11035:
-			room->playSound("m1270ea0", 11203);
+			room->playSFX("m1270ea0", 11203);
 			_statueDrag = -1;
 			renderStatue();
 			break;
 		case 11203:
 			if (isAllPlaced()) {
-				room->playAnimWithSound("m1270bc0", "m1270eb0", 500, PlayAnimParams::disappear(), 11038);
+				room->playAnimWithSFX("m1270bc0", "m1270eb0", 500, PlayAnimParams::disappear(), 11038);
 				room->disableMouse();
 			}
 			break;
@@ -769,7 +818,7 @@ TODO (medusa quest):
 			break;
 		case 11039:
 		case 11040:
-			playPerseusAnim("m1290ba0", "m1290na0", 11041);
+			playPerseusAnimSpeech("m1290ba0", TranscribedSound("m1290na0", "Hey, that's the magic bag. Put it in the frieze above me"), 11041);
 			break;
 		case 11041:
 			finishPerseusAnim();
@@ -809,7 +858,7 @@ TODO (medusa quest):
 
 		if (quest == kMedusaQuest && persistent->_seriphosPlayedMedusa) {
 			if (!persistent->_medislePlayedPerseusIntro) {
-				room->playSound("m1140ma0", 11056);
+				room->playMusic("m1140ma0", 11056);
 				g_vm->addTimer(11002, 5000);
 			}
 			renderPerseus();
@@ -839,7 +888,7 @@ TODO (medusa quest):
 				room->selectFrame(itemImages[i], 2000, 0);
 		}
 
-		room->playSoundLoop("m1010ea0");
+		room->playMusicLoop("m1010ea0");
 
 		if (persistent->_medisleShowFates) {
 			enforceEyeConsistency();
@@ -890,17 +939,17 @@ TODO (medusa quest):
 		room->playAnimLoop("m1040ba0", 450);
 	}
 private:
-	void fatesShadowSound(const Common::String &sound, int event) {
+	void fatesShadowSpeech(const TranscribedSound &sound, int event) {
 		Common::SharedPtr<VideoRoom> room = g_vm->getVideoRoom();
 		if (!_fatesShadowIsActive) {
 			room->playAnim("m2280bc0", 4000,
 				       PlayAnimParams::disappear().partial(0, 49), kLoopFatesShadow, kOffsetRightRoom);
 			_fatesShadowIsActive = true;
 		}
-		room->playSound(sound, event);
+		room->playSpeech(sound, event);
 	}
 
-	void fatesShadowSoundEnd() {
+	void fatesShadowSpeechEnd() {
 		Common::SharedPtr<VideoRoom> room = g_vm->getVideoRoom();
 		_fatesShadowIsActive = false;
 		room->playAnim("m2280bc0", 4000,
@@ -929,16 +978,10 @@ private:
 		}
 	}
 
-	void playPerseusAnim(const Common::String &anim, const Common::String &sound, int callback) {
-		Common::SharedPtr<VideoRoom> room = g_vm->getVideoRoom();
-		_perseusAnim.hide();
-		room->playAnimWithSound(anim, sound, 1200, PlayAnimParams::disappear(), callback);
-	}
-
-	void playPerseusAnimVideo(const Common::String &anim, const Common::String &sound, int callback) {
+	void playPerseusAnimSpeech(const Common::String &anim, const TranscribedSound &sound, int callback) {
 		Common::SharedPtr<VideoRoom> room = g_vm->getVideoRoom();
 		_perseusAnim.hide();
-		room->playAnimWithSound(anim, sound, 1200, PlayAnimParams::disappear(), callback);
+		room->playAnimWithSpeech(anim, sound, 1200, PlayAnimParams::disappear(), callback);
 	}
 
 	void finishPerseusAnim() {
@@ -958,7 +1001,7 @@ private:
 		g_vm->getHeroBelt()->removeFromInventory(item);
 		_lastPlacedItem = item;
 		room->selectFrame(itemImages[itemIdx], 2000, 0);
-		room->playSound(itemSounds[itemIdx], 11012);
+		room->playSFX(itemSounds[itemIdx], 11012);
 		room->disableMouse();
 	}
 
@@ -972,7 +1015,7 @@ private:
 		if (!persistent->_medislePlacedItems[itemIdx])
 			room->playAnimLoop(itemImagesGlow[itemIdx], 2000);
 		_lastClickedItem = itemIdx;
-		room->playSound("m1150ea0", 11009);
+		room->playSFX("m1150ea0", 11009);
 	}
 
 	void renderFatesExcept(FateId except1, FateId except2 = kNumFates) {
@@ -1082,7 +1125,7 @@ private:
 			transSound = "m2150ed0";
 		}
 
-		room->playAnimWithSound(transAnim, transSound, kFatesZ, PlayAnimParams::disappear(), event, kOffsetRightRoom);
+		room->playAnimWithSFX(transAnim, transSound, kFatesZ, PlayAnimParams::disappear(), event, kOffsetRightRoom);
 		persistent->_medisleEyePosition = newPos;
 		_fatesAreBusy = true;
 	}
@@ -1194,9 +1237,9 @@ private:
 
 	void playFatesLairBackupSound() {
 		if (g_vm->getRnd().getRandomBit())
-			fatesShadowSound("m2190wb0", 11629);
+			fatesShadowSpeech(kGiveMeEyeOrIllPunchYouInTheEye, 11629);
 		else
-			fatesShadowSound("m2190wd0", 11630);
+			fatesShadowSpeech(kIllTakeTheEyeYouCanHaveOneOfMyEars, 11630);
 	}
 
 	AmbientAnim _perseusAnim;
diff --git a/engines/hadesch/rooms/minos.cpp b/engines/hadesch/rooms/minos.cpp
index b2af5ef1b1..7e0b0d203e 100644
--- a/engines/hadesch/rooms/minos.cpp
+++ b/engines/hadesch/rooms/minos.cpp
@@ -95,11 +95,11 @@ public:
 
 		if (name == "Guard" && !_guardIsBusy) {
 			_guardIsBusy = true;
-			room->playAnimWithSound("AnimGuardGrunt",
-						"SndGuardGrunt",
-						kGuardZ,
-						PlayAnimParams::keepLastFrame(),
-						kGuardGruntCleanup);
+			room->playAnimWithSFX("AnimGuardGrunt",
+					      "SndGuardGrunt",
+					      kGuardZ,
+					      PlayAnimParams::keepLastFrame(),
+					      kGuardGruntCleanup);
 			room->stopAnim(kGuardLooking);
 			return;
 		}
@@ -142,7 +142,7 @@ public:
 				"R3160eC0",
 				"R3160eD0",
 			};
-			room->playSound(sounds[g_vm->getRnd().getRandomNumberRng(0, 3)]);
+			room->playSFX(sounds[g_vm->getRnd().getRandomNumberRng(0, 3)]);
 			if (item == kHornedStatue) {
 				g_vm->getHeroBelt()->removeFromInventory(item);
 //				room->selectFrame(kStatues, 0);
@@ -212,18 +212,18 @@ public:
 			break;
 		case kGuardPeriodic:
 			if (!_guardIsBusy)
-				room->playAnimWithSound(kGuardLooking,
-							"SndGuardLooking",
-							kGuardZ,
-							PlayAnimParams::keepLastFrame());
+				room->playAnimWithSFX(kGuardLooking,
+						      "SndGuardLooking",
+						      kGuardZ,
+						      PlayAnimParams::keepLastFrame());
 			g_vm->addTimer(kGuardPeriodic, g_vm->getRnd().getRandomNumberRng(5000, 10000));
 			break;
 		case kMinosPeriodic:
 			if (!_minosIsBusy)
-				room->playAnimWithSound(kAnimMinosEating,
-							"SndMinosEating",
-							kMinosZ,
-							PlayAnimParams::keepLastFrame());
+				room->playAnimWithSFX(kAnimMinosEating,
+						      "SndMinosEating",
+						      kMinosZ,
+						      PlayAnimParams::keepLastFrame());
 			g_vm->addTimer(kMinosPeriodic, g_vm->getRnd().getRandomNumberRng(5000, 10000));
 			break;
 		case kInstructionMovieCompleted:
@@ -295,7 +295,7 @@ public:
 			persistent->_creteShowHornless4 = true;
 		}
 
-		room->playSound(persistent->isInInventory(kHornedStatue)
+		room->playMusic(persistent->isInInventory(kHornedStatue)
 				? "HornedIntroMusic" : "NormalIntroMusic");
 
 		if (persistent->_creteDaedalusRoomAvailable) {
@@ -304,7 +304,7 @@ public:
 
 		TextTable miAmb = TextTable(
 			Common::SharedPtr<Common::SeekableReadStream>(room->openFile("MiAmb.txt")), 6);
-		_ambients.readTableFilePriam(miAmb);
+		_ambients.readTableFilePriamSFX(miAmb);
 		g_vm->addTimer(14006, 100, -1);
 		_ambients.firstFrame();
 	}
diff --git a/engines/hadesch/rooms/minotaur.cpp b/engines/hadesch/rooms/minotaur.cpp
index 878ad9c526..2028da9284 100644
--- a/engines/hadesch/rooms/minotaur.cpp
+++ b/engines/hadesch/rooms/minotaur.cpp
@@ -24,6 +24,7 @@
 #include "hadesch/hadesch.h"
 #include "hadesch/video.h"
 #include "hadesch/ambient.h"
+#include "common/translation.h"
 
 namespace Hadesch {
 static const char *kHighlightImage = "r6010ol0";
@@ -83,32 +84,35 @@ enum {
 	kRerenderLabyrinth = 1017001
 };
 
-static const char *daedalusSounds[] = {
+static const char *daedalusSoundSMK[] = {
 	"R6100nA0",
 	"R6100wA0",
 	"R6100nB0",
 	"R6100wC0",
 	"R6100nD0",
-	"R6100nH0",
-	"R6100nL0",
-	"R6100nG0",
-	"R6100nK0",
-	"R6170nA0",
-	"R6150nA0",
-	"R6150nB0",
-	"R6150nC0",
-	"R6150nD0",
-	"R6180nA0",
-	"R6180nC0",
-	"R6180nD0",
-	"R6170nC0",
-	"R6170nD0",
-	"R6170nE0",
-	"R6170nF0",
-	"R6160nA0",
-	"R6090eA0",
-	"R6190nA0",
-	"R6190nB0",
+};
+
+static const TranscribedSound daedalusSoundsAIF[] = {
+	{"R6100nH0", _s("Help us to move the walls so that they are strong enough to stop the minotaur")},
+	{"R6100nL0", _s("Click on a square to rotate the walls")},
+	{"R6100nG0", _s("Some walls are already locked in place and won't rotate")},
+	{"R6100nK0", _s("If you need help, refer to workman's equations")},
+	{"R6170nA0", _s("Careful, my friend. Some of the walls are not strong enough")},
+	{"R6150nA0", _s("You're a brave bullfighter, my friend")},
+	{"R6150nB0", _s("Keep it up. It looks like he's tiring")},
+	{"R6150nC0", _s("That's taking the bull by the horns")},
+	{"R6150nD0", _s("Don't give up. You can't beat him")},
+	{"R6180nA0", _s("You have beaten the Minotaur. You have the makings of a hero")},
+	{"R6180nC0", _s("You have beaten the beast at last")},
+	{"R6180nD0", _s("You have done it. The people of Crete are once again safe")},
+	{"R6170nC0", _s("Let's try again")},
+	{"R6170nD0", _s("Warn the people of Crete: the Minotaur has escaped. Workers, keep the Minotaur back in the labyrinth")},
+	{"R6170nE0", _s("I believe you and the Minotaur have not seen the last of one another")},
+	{"R6170nF0", _s("Ah that was a nobble effort, my friend")},
+	{"R6160nA0", _s("The Minotaur has broken though a critical wall. Workers, calm on the beast")},
+	{"R6090eA0", _s("Eh. Hm")},
+	{"R6190nA0", _s("Ok. Onto level two")},
+	{"R6190nB0", _s("Onto level three")},
 };
 
 struct Wall {
@@ -235,7 +239,10 @@ private:
 		// TODO: balance
 		_currentSound = index;
 		Common::SharedPtr<VideoRoom> room = g_vm->getVideoRoom();
-		room->playSound(daedalusSounds[index], 17953);
+		if (index < ARRAYSIZE(daedalusSoundSMK))
+			room->playVideo(daedalusSoundSMK[index], 17953);
+		else
+			room->playSpeech(daedalusSoundsAIF[index-ARRAYSIZE(daedalusSoundSMK)], 17953);
 	}
 
 	void playDaedalusSoundWrap() {
diff --git a/engines/hadesch/rooms/monster.cpp b/engines/hadesch/rooms/monster.cpp
index ca834c00f5..c470f9c3cb 100644
--- a/engines/hadesch/rooms/monster.cpp
+++ b/engines/hadesch/rooms/monster.cpp
@@ -24,6 +24,7 @@
 #include "hadesch/hadesch.h"
 #include "hadesch/video.h"
 #include "hadesch/rooms/monster.h"
+#include "common/translation.h"
 
 namespace Hadesch {
 enum {
@@ -36,6 +37,12 @@ enum {
 static const char *kZeusLight = "V7100BJ0";
 static const int kLightningCutoff = kVideoWidth / 2;
 
+TranscribedSound revitalisedSound() {
+	return g_vm->getRnd().getRandomBit()
+		? TranscribedSound("v7150wd0", "Your branch of life is revitalized")
+		: TranscribedSound("v7150we0", "You're back to full strength");
+}
+
 class MonsterHandler : public Handler {
 public:
 	MonsterHandler() {
@@ -76,7 +83,7 @@ public:
 			break;
 			
 		case 15351:
-			room->playAnimWithSound(kZeusLight, "G0260MA0", kZeusLightZ,
+			room->playAnimWithMusic(kZeusLight, "G0260MA0", kZeusLightZ,
 						PlayAnimParams::keepLastFrame().partial(0, 4),
 						15379); // 15379(anim), 15381(-1), 15359(sound)
 			break;
@@ -89,7 +96,10 @@ public:
 				       15358);
 			break;
 		case 15355:
-			room->playSkippableSound("V7100WC0", 15364);
+			room->playSpeech(TranscribedSound("V7100WC0",
+							  "I'm giving you these thunderbolts to "
+							  "use against Hades' monsters."),
+					 15364);
 			g_vm->getHeroBelt()->setThunderboltFrame(kLightning2);
 			g_vm->addTimer(526, 5000);
 			break;
@@ -97,9 +107,10 @@ public:
 			room->playVideo("V7180BB0", 0, 15361, Common::Point(0, 216));
 			break;
 		case 15357:
-			room->playSkippableSound(g_vm->getRnd().getRandomBit()
-						 ? "V7150WC0" : "V7150WB0",
-						 15353);
+			room->playSpeech(g_vm->getRnd().getRandomBit()
+					 ? TranscribedSound("V7150WC0", "Get back in there. Here is another branch")
+					 : TranscribedSound("V7150WB0", "Here's another branch. Keep going"),
+					 15353);
 			break;
 		case 15358:
 			switch (_battleground->_monsterNum) {
@@ -118,24 +129,44 @@ public:
 			g_vm->addTimer(15391, 100);
 			break;
 		case 15364:
-			room->playSkippableSound("V7100WD0", 15365);
+			room->playSpeech(TranscribedSound(
+					     "V7100WD0",
+					     "Ah, and this branch of life will let "
+					     "you to remain in the underworld until "
+					     "all of its leaves have fallen"),
+				15365);
 			_battleground->_leavesRemaining = 9;
 			g_vm->getHeroBelt()->setBranchOfLifeFrame(1);
 			g_vm->addTimer(524, 5000);
 			break;
 		case 15365:
-			room->playSkippableSound("V7100WE0", 15366);
+			room->playSpeech(TranscribedSound(
+						 "V7100WE0",
+						 "Use your thunderbolts and your hero powers "
+						 "to battle the monsters of the underworld"), 15366);
 			_countOfIntroLightning = 0;
 			introLightning();
 			break;
 		case 15366:
-			room->playSkippableSound("V7100WF0", 15367);
+			room->playSpeech(TranscribedSound(
+						 "V7100WF0",
+						 "Move your mouse to aim and click to fire your thunderbolts. "
+						 "And don't forget: you can now use your hero powers"),
+					 15367);
 			break;
 		case 15367:
-			room->playSkippableSound("V7100WH0", 15368);
+			room->playSpeech(TranscribedSound(
+						 "V7100WH0",
+						 "And remember to keep an eye on your branch. "
+						 "When the last leaf drops, you'll be "
+						 "banished from the underworld"),
+					 15368);
 			break;
 		case 15368:
-			room->playSkippableSound("V7100WI0", 15369);
+			room->playSpeech(TranscribedSound(
+						 "V7100WI0",
+						 "This is the ultimate test but I know you can do it"),
+					 15369);
 			break;
 		case 15369:
 			room->playAnim(kZeusLight, kZeusLightZ,
@@ -147,13 +178,12 @@ public:
 				introLightning();
 			break;
 		case 15374:
-			room->playAnimWithSound(kZeusLight, "G0260MA0", kZeusLightZ,
+			room->playAnimWithMusic(kZeusLight, "G0260MA0", kZeusLightZ,
 						PlayAnimParams::keepLastFrame().partial(0, 4),
 						15375);
 			break;
 		case 15375:
-			room->playSound(g_vm->getRnd().getRandomBit() ? "v7150wd0" : "v7150we0",
-				15376);
+			room->playSpeech(revitalisedSound(), 15376);
 			replenishPowers();
 			break;
 		case 15376:
@@ -168,8 +198,7 @@ public:
 			handleEvent(15390);
 			break;
 		case 15379:
-			room->playSound(g_vm->getRnd().getRandomBit() ? "v7150wd0" : "v7150we0",
-				15380);
+			room->playSpeech(revitalisedSound(), 15380);
 			replenishPowers();
 			break;
 		case 15380:
@@ -192,16 +221,57 @@ public:
 			}
 			break;
 		case 15386:
-			room->playSound(persistent->_gender == kMale ? "V7190WB0" : "V7190WC0", 15374);
+			// unclear
+			room->playSpeech(
+				persistent->_gender == kMale
+				? TranscribedSound(
+					"V7190WB0",
+					"One more word out of your goat-brain "
+					"and I'm gonna have your face for lambchops, alright? "
+					"This kid's gonna have to make it on his own, ok?")
+				: TranscribedSound(
+					"V7190WC0",
+					"One more word out of your goat-brain "
+					"and I'm gonna have your face for lambchops, ok? "
+					"This kid's gonna have to make it on her own."),
+				15374);
 			break;
 		case 15387:
-			room->playSound(persistent->_gender == kMale ? "V7210WB0" : "V7210WC0", 15378);
+			room->playSpeech(
+				persistent->_gender == kMale
+				? TranscribedSound(
+					"V7210WB0",
+					"Oh, you want to be a hero? "
+					"Well you're gonna die a hero's death. "
+					"Typhoon's gonna chew you up in little "
+					"pieces and spit you out like a meatgrinder, kid")
+				: TranscribedSound(
+					"V7210WC0",
+					"Oh, you want to be a heroine? "
+					"Well you're gonna die a gruesome death. "
+					"Typhoon's gonna chew you up in little "
+					"pieces and spit you out like a meatgrinder, little princess."),
+				15378);
 			break;
 		case 15388:
-			room->playSound("V7220WB1", 15382);
+			room->playSpeech(TranscribedSound(
+						 "V7220WB1",
+						 "You dare to think you can outwit me? "
+						 "You, my little friend, will be ripped to shreads and slowly digested for eternity "
+						 "inside a belly of a thousand hideous creatures. You will die a thousand agonizing "
+						 "deaths as I now bring down upon you all the forces of Hades."),
+				15382);
 			break;
 		case 15389:
-			room->playSound("V7180WB0", 15361);
+			// unclear
+			room->playSpeech(TranscribedSound(
+						 "V7180WB0",
+						 "Hey, there. Hi, there. Hoi, there. "
+						 "And welcome to my world. "
+						 "You know what they say: \"My world - my rules\". "
+						 "So here is the rule number one: No trespassing. "
+						 "My bouncer will show you the way out. Have a nice day"),
+					 15361);
 			break;
 		case 15390:
 			_typhoon->enterTyphoon(1);
@@ -222,7 +292,7 @@ public:
 			if (_battleground->_leavesRemaining <= 0) {
 				_battleground->stopFight();
 				room->disableMouse();
-				room->playAnimWithSound(kZeusLight, "G0260MA0", kZeusLightZ,
+				room->playAnimWithMusic(kZeusLight, "G0260MA0", kZeusLightZ,
 							PlayAnimParams::keepLastFrame().partial(0, 4),
 							15357);
 			}
@@ -239,7 +309,7 @@ public:
 
 		room->disableMouse();
 		_battleground->_monsterNum = kCyclops;
-		room->playAnimWithSound(kZeusLight, "G0260MA0", kZeusLightZ,
+		room->playAnimWithMusic(kZeusLight, "G0260MA0", kZeusLightZ,
 					PlayAnimParams::keepLastFrame().partial(0, 4),
 					15355);
 	}
@@ -268,16 +338,16 @@ public:
 		if (!_playingShootingSound) {
 			switch (hp) {
 			case kPowerStealth:
-				room->playSound("v7130ea0");
+				room->playSFX("v7130ea0");
 				break;
 			case kPowerStrength:
-				room->playSound("v7130eb0");
+				room->playSFX("v7130eb0");
 				break;
 			case kPowerWisdom:
-				room->playSound("v7130ec0");
+				room->playSFX("v7130ec0");
 				break;
 			case kPowerNone:
-				room->playSound("v7130ee0");
+				room->playSFX("v7130ee0");
 				break;
 			}
 			_playingShootingSound = true;
@@ -316,7 +386,7 @@ private:
 			room->playAnim("v7130ba1", 300, PlayAnimParams::disappear(), 15370,
 				       target - Common::Point(kLightningCutoff, 0));
 		}
-		room->playSound("v7130eb0");
+		room->playSFX("v7130eb0");
 	}
 
 	bool _playingShootingSound;
diff --git a/engines/hadesch/rooms/monster/cyclops.cpp b/engines/hadesch/rooms/monster/cyclops.cpp
index de7f856246..1a96e9d28d 100644
--- a/engines/hadesch/rooms/monster/cyclops.cpp
+++ b/engines/hadesch/rooms/monster/cyclops.cpp
@@ -91,7 +91,7 @@ void Cyclops::handleClick(Common::Point p) {
 		return;
 	room->disableMouse();
 	_battleground->stopFight();
-	room->playAnimWithSound("v7180bj0", "v7180xc0", 500, PlayAnimParams::disappear(), 15352);
+	room->playAnimWithSFX("v7180bj0", "v7180xc0", 500, PlayAnimParams::disappear(), 15352);
 }
 
 bool Cyclops::cyclopsIsHit(Common::Point p, int frame) {
@@ -122,16 +122,16 @@ void Cyclops::cyclopsState1() {
 	Common::SharedPtr<VideoRoom> room = g_vm->getVideoRoom();
 	_currentCyclopsState = 1;
 
-	room->playAnimWithSound("v7040ba0", "v7040ea0",
-				kCyclopsZ,
-				PlayAnimParams::disappear(),
-				15257);
+	room->playAnimWithSFX("v7040ba0", "v7040ea0",
+			      kCyclopsZ,
+			      PlayAnimParams::disappear(),
+			      15257);
 }
 
 void Cyclops::cyclopsState2() {
 	Common::SharedPtr<VideoRoom> room = g_vm->getVideoRoom();
 
-	room->playAnimWithSound(
+	room->playAnimWithSFX(
 		"v7180be0", "v7180ee0", kCyclopsZ,
 		PlayAnimParams::disappear()
 		.partial(0, 4), 15258);
@@ -147,20 +147,20 @@ void Cyclops::cyclopsState3() {
 void Cyclops::cyclopsState4() {
 	Common::SharedPtr<VideoRoom> room = g_vm->getVideoRoom();
 	_currentCyclopsState = 4;
-	room->playAnimWithSound("v7180bk0", "v7180sc0", kCyclopsZ, PlayAnimParams::disappear(), 15260);
+	room->playAnimWithSFX("v7180bk0", "v7180sc0", kCyclopsZ, PlayAnimParams::disappear(), 15260);
 }
 
 void Cyclops::cyclopsState5() {
 	Common::SharedPtr<VideoRoom> room = g_vm->getVideoRoom();
 	_currentCyclopsState = 5;
-	room->playAnimWithSound("v7180bi0", "v7180sa0", kCyclopsZ, PlayAnimParams::disappear().partial(0, 4), 15262);
+	room->playAnimWithSFX("v7180bi0", "v7180sa0", kCyclopsZ, PlayAnimParams::disappear().partial(0, 4), 15262);
 }
 
 void Cyclops::cyclopsState6() {
 	Common::SharedPtr<VideoRoom> room = g_vm->getVideoRoom();
 	_currentCyclopsState = 6;
 
-	room->playAnimWithSound("v7180bi0", "v7180ee0", kCyclopsZ, PlayAnimParams::disappear().partial(5, 11), 15264);
+	room->playAnimWithSFX("v7180bi0", "v7180ee0", kCyclopsZ, PlayAnimParams::disappear().partial(5, 11), 15264);
 }
 
 Cyclops::Cyclops(Common::SharedPtr<Battleground> battleground) {
@@ -170,9 +170,9 @@ Cyclops::Cyclops(Common::SharedPtr<Battleground> battleground) {
 void Cyclops::enterCyclops(int level) {
 	Common::SharedPtr<VideoRoom> room = g_vm->getVideoRoom();
 	room->playAnimKeepLastFrame("v7180oa0", 600);
-	room->playAnimWithSound("v7180ba0", "v7180ea0", kCyclopsZ,
-				PlayAnimParams::disappear(),
-				15252);
+	room->playAnimWithSFX("v7180ba0", "v7180ea0", kCyclopsZ,
+			      PlayAnimParams::disappear(),
+			      15252);
 	Typhoon::disableHotzones();
 	_cyclopsProximityCheckCountdown = 0;
 	_currentCyclopsState = 0;
@@ -371,7 +371,7 @@ void Cyclops::handleEvent(int eventId) {
 		for (int i = 0; i < _battleground->getNumOfProjectiles(); i++) {
 			_battleground->launchProjectile(50, Common::Point(60, 203), 0);
 		}
-		room->playSound("v7140eb0");
+		room->playSFX("v7140eb0");
 		break;
 	case kCyclopsShootingEyeClosedMidAnim:
 		room->playAnim(kCyclopsShootingEyeClosed, kCyclopsZ, PlayAnimParams::disappear().partial(12, -1), 15255);
diff --git a/engines/hadesch/rooms/monster/illusion.cpp b/engines/hadesch/rooms/monster/illusion.cpp
index e8303e9ab3..4e5d8dd90b 100644
--- a/engines/hadesch/rooms/monster/illusion.cpp
+++ b/engines/hadesch/rooms/monster/illusion.cpp
@@ -22,6 +22,7 @@
  *
  */
 
+#include "common/translation.h"
 #include "hadesch/hadesch.h"
 #include "hadesch/video.h"
 #include "hadesch/rooms/monster.h"
@@ -47,6 +48,14 @@ struct BirdInfo {
 	}
 };
 
+static const TranscribedSound fakePhilReplics[] = {
+	{"v7220xb0", _s("unclear utterance")}, // unclear
+	{"v7220xc0", _s("Hey, this was close, buddy")},
+	{"v7220xd0", _s("Get hold of thunderbolts")}, // unclear
+	{"v7220xe0", _s("Keep going, kid. You're doing great job")},
+	{"v7220xf0", _s("unclear utterance")} // unclear
+};
+
 static const BirdInfo birdInfo[] = {
 	{		
 		10,
@@ -136,7 +145,7 @@ void Bird::launch(int level) {
 	_isActive = true;
 	_level = level;
 	makeFlightParams();
-	room->playSound("v7220eb0");
+	room->playSFX("v7220eb0");
 	_flightStart = g_vm->getCurrentTime();
 }
 
@@ -263,10 +272,10 @@ void Bird::handleAbsoluteClick(Common::Point p) {
 	room->stopAnim(LayerId(birdInfo[_birdType]._shootAnim, _id, "bird"));
 	_isActive = false;
 	LayerId l = LayerId(birdInfo[_birdType]._interceptAnim, _id, "bird");
-	room->playAnimWithSound(l, "v7220ec0", 500, PlayAnimParams::disappear(),
-				EventHandlerWrapper(),
-				fp.centerPos - birdInfo[_birdType].getBirdSize()
-				* (fp.scale / 100.0));
+	room->playAnimWithSFX(l, "v7220ec0", 500, PlayAnimParams::disappear(),
+			      EventHandlerWrapper(),
+			      fp.centerPos - birdInfo[_birdType].getBirdSize()
+			      * (fp.scale / 100.0));
 }
 
 Illusion::Illusion(Common::SharedPtr<Battleground> battleground) {
@@ -306,10 +315,11 @@ void Illusion::enterIllusion(int level) {
 	Typhoon::disableHotzones();
 	for (unsigned i = 0; i < 6; i++)
 		room->enableHotzone(Common::String::format("Phil%d", i));
-	room->playAnimWithSound(Common::String::format("v7220bg%d", g_vm->getRnd().getRandomNumberRng(0, 5)),
-				"v7220xc1", 600,
-				PlayAnimParams::disappear(),
-				15306);
+	room->playAnimWithSpeech(Common::String::format("v7220bg%d", g_vm->getRnd().getRandomNumberRng(0, 5)),
+				 TranscribedSound("v7220xc1",
+						  "It's me, Phil. These beasts are all that stands between me and freedom"), 600, // unclear
+				 PlayAnimParams::disappear(),
+				 15306);
 	_battleground->_level = level;
 	_battleground->_leavesRemaining = 9;
 	_battleground->_monsterNum = kIllusion;
@@ -326,7 +336,7 @@ void Illusion::handleClick(const Common::String &name) {
 		_battleground->stopFight();
 		room->disableMouse();
 		room->playAnimKeepLastFrame(Common::String::format("v7220bv%d", _philPosition), 600);
-		room->playSound("v7220eg0", 15307);
+		room->playSFX("v7220eg0", 15307);
 		return;
 	}
 }
@@ -350,10 +360,10 @@ void Illusion::handleEvent(int eventId) {
 		launchBird();
 		break;
 	case 15307:
-		room->playSound("v7220wg0", 15308);
+		room->playSpeech(TranscribedSound("v7220wg0", "Oh no, we're gonna fry"), 15308);
 		break;
 	case 15308:
-		room->playSound("v7220wh0", 15309);
+		room->playSpeech(TranscribedSound("v7220wh0", "Let's get outta here"), 15309);
 		break;
 	case 15309:
 		g_vm->getCurrentHandler()->handleEvent(15383);
@@ -361,7 +371,7 @@ void Illusion::handleEvent(int eventId) {
 	case 15312:
 		if (!_battleground->_isInFight || _illusionIsKilled || _battleground->_monsterNum != kIllusion)
 			return;
-		room->playSound(Common::String::format("v7220x%c0", g_vm->getRnd().getRandomNumberRng('b', 'f')));
+		room->playSpeech(fakePhilReplics[g_vm->getRnd().getRandomNumberRng(0, ARRAYSIZE(fakePhilReplics) - 1)]);
 		g_vm->addTimer(15312, g_vm->getRnd().getRandomNumberRng(6000, 10000));
 		break;
 	case 15313:
diff --git a/engines/hadesch/rooms/monster/projectile.cpp b/engines/hadesch/rooms/monster/projectile.cpp
index 888754ef59..71ac44436b 100644
--- a/engines/hadesch/rooms/monster/projectile.cpp
+++ b/engines/hadesch/rooms/monster/projectile.cpp
@@ -272,9 +272,9 @@ bool Projectile::tick(Common::SharedPtr <Projectile> backRef) {
 		} else {
 			FlightPosition fp = getFlightPosition(_flightCounterMs / (double) _flightLengthMs);
 			LayerId l = LayerId(_hitAnim, _projectileId, "projectile");
-			room->playAnimWithSound(l, "v7130ea0", 400, PlayAnimParams::disappear(),
-						Common::SharedPtr<EventHandler>(new HandlerProjectile(backRef, 15053)),
-						fp.centerPos - Common::Point(182, 205));
+			room->playAnimWithSFX(l, "v7130ea0", 400, PlayAnimParams::disappear(),
+					      Common::SharedPtr<EventHandler>(new HandlerProjectile(backRef, 15053)),
+					      fp.centerPos - Common::Point(182, 205));
 			_pending = 1;
 			// TODO: fade to red, in 100 ms, callback 15055
 			// TODO: shake camera for 1s
@@ -296,9 +296,9 @@ void Projectile::handleAbsoluteClick(Common::SharedPtr <Projectile> backRef, Com
 	_isFlightFinished = true;
 	_pending = 1;
 	LayerId l = LayerId(_interceptAnim, _projectileId, "projectile");
-	room->playAnimWithSound(l, "v7130eg0", 400, PlayAnimParams::disappear(),
-				Common::SharedPtr<EventHandler>(new HandlerProjectile(backRef, 15054)),
-				fp.centerPos - Common::Point(186, 210) * (fp.scale / 100.0));
+	room->playAnimWithSFX(l, "v7130eg0", 400, PlayAnimParams::disappear(),
+			      Common::SharedPtr<EventHandler>(new HandlerProjectile(backRef, 15054)),
+			      fp.centerPos - Common::Point(186, 210) * (fp.scale / 100.0));
 }
 
 }
diff --git a/engines/hadesch/rooms/monster/typhoon.cpp b/engines/hadesch/rooms/monster/typhoon.cpp
index 427a180ac1..9583678d8e 100644
--- a/engines/hadesch/rooms/monster/typhoon.cpp
+++ b/engines/hadesch/rooms/monster/typhoon.cpp
@@ -88,7 +88,7 @@ void Typhoon::handleEvent(int eventId) {
 	case 15152:
 		room->enableMouse();
 		room->playAnimLoop("v7210bx0", 490);
-		room->playSound("v7210ed0");
+		room->playSFX("v7210ed0");
 		_battleground->_isInFight = true;
 		typhoonA();
 		for (unsigned i = 0; i < ARRAYSIZE(_headIsAlive); i++) {
@@ -104,7 +104,7 @@ void Typhoon::handleEvent(int eventId) {
 	case 15154:
 		if (!_battleground->_isInFight || _isKilled || _battleground->_monsterNum != kTyphoon)
 			return;
-		room->playSound("v7050ea0");
+		room->playSFX("v7050ea0");
 		schedule15154();
 		break;
 	case 15159:
@@ -126,8 +126,8 @@ void Typhoon::handleEvent(int eventId) {
 	case 15163:
 		if (!_battleground->_isInFight || _isKilled || _battleground->_monsterNum != kTyphoon)
 			return;
-		room->playSound(g_vm->getHeroBelt()->getSelectedStrength() == kPowerStrength
-				? "v7210eb0" : "v7210ea0");
+		room->playSFX(g_vm->getHeroBelt()->getSelectedStrength() == kPowerStrength
+			      ? "v7210eb0" : "v7210ea0");
 		g_vm->addTimer(15163, g_vm->getRnd().getRandomNumberRng(3000, 7000));
 		break;
 /*
@@ -146,7 +146,7 @@ void Typhoon::enterTyphoon(int level) {
 	room->playAnim("v7210ba0", kTyphoonZ,
 		       PlayAnimParams::disappear(),
 		       15152);
-	room->playSound("v7050eb0");
+	room->playSFX("v7050eb0");
 	for (unsigned i = 0; i < ARRAYSIZE(typhonHeadInfo); i++) {
 		room->enableHotzone(typhonHeadInfo[i]._hotZone);
 		room->setHotZoneOffset(typhonHeadInfo[i]._hotZone, typhonHeadInfo[i].getPosition());
@@ -183,11 +183,11 @@ void Typhoon::typhoonA() {
 		room->playAnim("v7050ba0", 500, PlayAnimParams::disappear(), 15153);
 	} else if (g_vm->getRnd().getRandomBit()) {
 		room->playAnim("v7210bi0", 500, PlayAnimParams::disappear().partial(0, 6), 15160);
-		room->playSound("v7140ec0");
+		room->playSFX("v7140ec0");
 	}
 	else {
 		room->playAnim("v7210bj0", 500, PlayAnimParams::disappear().partial(0, 6), 15159);
-		room->playSound("v7140ec0");
+		room->playSFX("v7140ec0");
 	}
 }
 
@@ -245,7 +245,7 @@ public:
 		_typhoon->_headIsAlive[_idx] = true;
 		if (!_typhoon->_playingTyphoonRespawnSound) {
 			_typhoon->_playingTyphoonRespawnSound = true;
-			room->playSound("v7050ed0", 15105);
+			room->playSFX("v7050ed0", 15105);
 		}
 		_typhoon->hideHead(_idx);
 		room->playAnim(LayerId(typhonHeadInfo[_idx]._animRespawn, _idx, "head"),
@@ -308,7 +308,7 @@ void Typhoon::hitTyphoonHead(Common::SharedPtr<Typhoon> backRef, int idx) {
 		return;
 
 	if (!_playingTyphoonDieSound) {
-		room->playSound("v7050ec0", 15104);
+		room->playSFX("v7050ec0", 15104);
 		_playingTyphoonDieSound = true;
 	}
 	_headIsAlive[idx] = false;
@@ -330,7 +330,7 @@ void Typhoon::hitTyphoonHead(Common::SharedPtr<Typhoon> backRef, int idx) {
 	_battleground->stopFight();
 
 	room->disableMouse();
-	room->playAnimWithSound("v7210bw0", "v7050ee0", 500, PlayAnimParams::disappear(), 15168);
+	room->playAnimWithSFX("v7210bw0", "v7050ee0", 500, PlayAnimParams::disappear(), 15168);
 }
 
 void Typhoon::stopAnims() {
diff --git a/engines/hadesch/rooms/olympus.cpp b/engines/hadesch/rooms/olympus.cpp
index bb5286f5ae..4cd52c8295 100644
--- a/engines/hadesch/rooms/olympus.cpp
+++ b/engines/hadesch/rooms/olympus.cpp
@@ -88,7 +88,7 @@ public:
 		Common::SharedPtr<VideoRoom> room = g_vm->getVideoRoom();
 		switch (eventId) {
 		case 21001:
-			room->playSound("o1010ea0");
+			room->playSFX("o1010ea0");
 			break;
 		case 21002:
 			room->enableMouse();
@@ -115,7 +115,7 @@ public:
 		room->addStaticLayer("background", kBackgroundZ);
 		room->disableMouse();
 		if (g_vm->getPreviousRoomId() == kOptionsRoom) {
-			room->playSound("o1010ea0", 21002);
+			room->playSFX("o1010ea0", 21002);
 		} else {
 			room->playVideo("movie", 201, 21002);
 			g_vm->addTimer(21001, 40000);
diff --git a/engines/hadesch/rooms/options.cpp b/engines/hadesch/rooms/options.cpp
index 316e7d4103..e0feda663b 100644
--- a/engines/hadesch/rooms/options.cpp
+++ b/engines/hadesch/rooms/options.cpp
@@ -383,7 +383,7 @@ public:
 
 			if (ucode == '\b' && _typedSlotName.size() > 0) {
 				_typedSlotName.deleteLastChar();
-				room->playSound("keyclick");
+				room->playSFX("keyclick");
 				renderSaveName();
 				return;
 			}
@@ -393,7 +393,7 @@ public:
 
 			if (_typedSlotName.size() < 11) {
 				_typedSlotName += ucode;
-				room->playSound("keyclick");
+				room->playSFX("keyclick");
 				renderSaveName();
 			}
 		}
diff --git a/engines/hadesch/rooms/priam.cpp b/engines/hadesch/rooms/priam.cpp
index 144030910c..2ed69dd693 100644
--- a/engines/hadesch/rooms/priam.cpp
+++ b/engines/hadesch/rooms/priam.cpp
@@ -161,7 +161,7 @@ public:
 			if (_specialPigeonIsDown) {
 				_specialPigeonCounter++;
 				if (_specialPigeonCounter > 2) {
-					room->playAnimWithSound(
+					room->playAnimWithSFX(
 						"AnimSpecialPigeonUp",
 						"SndSpecialPigeonUp",
 						500,
@@ -174,7 +174,7 @@ public:
 					return;
 				}
 			} else {
-				room->playAnimWithSound(
+				room->playAnimWithSFX(
 						"AnimSpecialPigeonDown",
 						"SndSpecialPigeonDown",
 						500,
@@ -194,7 +194,7 @@ public:
 			}
 			break;
 		case 20016:
-			room->playSound("HelenMusic", 20022);
+			room->playMusic("HelenMusic", 20022);
 			room->playAnimKeepLastFrame("AnimCrackedWallOverlay",
 						    999, 20011,
 						    Common::Point(-10, -10));
@@ -228,7 +228,7 @@ public:
 				       PlayAnimParams::disappear(), 20026);
 			room->playAnim("AnimCollapseR", 111,
 				       PlayAnimParams::disappear(), 20027);
-			room->playSound("BigCollapseSnd");
+			room->playSFX("BigCollapseSnd");
 			break;
 		case 20026:
 		case 20027:
@@ -245,11 +245,11 @@ public:
 		Common::SharedPtr<VideoRoom> room = g_vm->getVideoRoom();
 		room->loadHotZones("priam.HOT");
 		room->addStaticLayer("Background", 10000, Common::Point(-10, -10));
-		room->playSound("IntroMusic");
-		room->playSoundLoop("T4010eA0");
+		room->playMusic("IntroMusic");
+		room->playMusicLoop("T4010eA0");
 		TextTable prAmb = TextTable(
 			Common::SharedPtr<Common::SeekableReadStream>(room->openFile("PrAmb.txt")), 6);
-		_ambients.readTableFilePriam(prAmb);
+		_ambients.readTableFilePriamSFX(prAmb);
 		g_vm->addTimer(20001, 100, -1);
 		g_vm->addTimer(20014, 3000, -1);
 		_ambients.firstFrame();
@@ -257,7 +257,6 @@ public:
 		g_vm->getHeroBelt()->setColour(HeroBelt::kCool);
 		_specialPigeonIsDown = true;
 		_specialPigeonIsBusy = false;
-		room->playSoundLoop("T4010eA0");
 		room->playAnim("AnimPigeons", 600, PlayAnimParams::disappear(), kAnimPigeonsEnd);
 	}
 
diff --git a/engines/hadesch/rooms/quiz.cpp b/engines/hadesch/rooms/quiz.cpp
index 63e265bcd1..d12135044e 100644
--- a/engines/hadesch/rooms/quiz.cpp
+++ b/engines/hadesch/rooms/quiz.cpp
@@ -24,6 +24,7 @@
 #include "hadesch/hadesch.h"
 #include "hadesch/video.h"
 #include "hadesch/ambient.h"
+#include "common/translation.h"
 
 namespace Hadesch {
 
@@ -78,11 +79,12 @@ static const char *hadesIntroVideos[] = {
 	"H0020bF0"
 };
 
-static const char *h0090_names[] = {
-	"H0090wF0",
-	"H0090wA0",
-	"H0090wB0",
-	"H0090wE0"
+static const TranscribedSound h0090_names[] = {
+	{ "H0090wF0", _s("Congratulations. You've shown Mr Sour Grapes") },
+	{ "H0090wA0", _s("The enveloppe, please. And the winner is ... you. Hey, good job. That's showing him") },
+	{ "H0090wB0", _s("Way to go") },
+	// Difficult to hear. Please someone check after me
+	{ "H0090wE0", _s("You're amazing. Or Hades is hard under the gollar") }
 };
 
 static const int kNumQuestions = 4;
@@ -127,7 +129,7 @@ public:
 		Persistent *persistent = g_vm->getPersistent();
 		switch (eventId) {
 		case kBigItemSwitchToLoop:
-			room->playAnimWithSound(
+			room->playAnimWithSFX(
 				_bigItem, "SpinningItemSnd", kBigItemZ, PlayAnimParams::loop().partial(4, -1));
 			break;
 		case kZeusStingerFinished:
@@ -141,8 +143,8 @@ public:
 		case kHadesVideoFinished:
 			room->selectFrame(kQuestionBackground, kOverlayAnimZ, 0);
 			room->playAnimLoop("FlameAnim", kFlameAnimZ);
-			room->playSoundLoop("FlameSnd");
-			room->playSoundLoop("AmbientQuestionMusic");
+			room->playSFXLoop("FlameSnd");
+			room->playMusicLoop("AmbientQuestionMusic");
 			smallAnim();
 			playHadesVideo(hadesIntroVideos[g_vm->getRnd().getRandomNumberRng(0, 5)],
 					kFirstQuestion);
@@ -198,14 +200,15 @@ public:
 			break;
 
 		case kHadesFirstLaugh:
-			hadesAndZeus("ZeusNotFair", kHadesInstructions);
+			hadesAndZeus(TranscribedSound("ZeusNotFair", "Hold on, Hades. That's not fair. You've never explained the rules. That doesn't count"),
+				     kHadesInstructions);
 			_hadesIsFree = false;
 			break;
 
 		case kHadesInstructions:
 			hadesAndZeusEnd();
-			room->playAnimWithSound("FlameBurstAnim", "FlameBurstSnd", kFlameBurstAnimZ,
-						PlayAnimParams::disappear(), 30021);
+			room->playAnimWithSFX("FlameBurstAnim", "FlameBurstSnd", kFlameBurstAnimZ,
+					      PlayAnimParams::disappear(), 30021);
 			_shrinkLevel--;
 			break;
 
@@ -235,8 +238,8 @@ public:
 			break;
 
 		case kBuzzerFinished:
-			room->playAnimWithSound("FlameBurstAnim", "FlameBurstSnd", kFlameBurstAnimZ,
-						PlayAnimParams::disappear());
+			room->playAnimWithSFX("FlameBurstAnim", "FlameBurstSnd", kFlameBurstAnimZ,
+					      PlayAnimParams::disappear());
 			_shrinkLevel++;
 			if (_wrongAnswerCount == 0) {
 				playHadesVideo("HadesLaugh", kHadesFirstLaugh);
@@ -420,9 +423,9 @@ private:
 		_hadesIsFree = false;
 		room->selectFrame(kHadesEyes, kHadesEyesZ, 0);
 		if (selected == getRightAnswer())
-			room->playSound("DingSnd", kDingFinished);
+			room->playSFX("DingSnd", kDingFinished);
 		else
-			room->playSound("BuzzerSnd", kBuzzerFinished);
+			room->playSFX("BuzzerSnd", kBuzzerFinished);
 		memset(_frames, 0, sizeof (_frames));
 		for (int ansidx = 0; ansidx < kNumAnswers; ansidx++) {
 			_frames[ansidx] = 5;
@@ -434,9 +437,9 @@ private:
 		renderQuestion();
 	}
 
-	void hadesAndZeus(const Common::String &name, int event) {
+	void hadesAndZeus(const TranscribedSound &name, int event) {
 		Common::SharedPtr<VideoRoom> room = g_vm->getVideoRoom();
-		room->playAnimWithSound("HadesAndZeusAnim", name, kHadesAndZeusAnimZ,
+		room->playAnimWithSpeech("HadesAndZeusAnim", name, kHadesAndZeusAnimZ,
 					PlayAnimParams::keepLastFrame().partial(0, 5), event);
 		room->playAnim("ZeusLightAnim", kZeusLightAnimZ, PlayAnimParams::keepLastFrame());
 		_hadesIsFree = false;
diff --git a/engines/hadesch/rooms/riverstyx.cpp b/engines/hadesch/rooms/riverstyx.cpp
index 0e44d07978..6c6806d346 100644
--- a/engines/hadesch/rooms/riverstyx.cpp
+++ b/engines/hadesch/rooms/riverstyx.cpp
@@ -125,8 +125,8 @@ public:
 		Persistent *persistent = g_vm->getPersistent();
 		if (name == "volcano top") {
 			room->disableMouse();
-			room->playAnimWithSound("morphing gems", "morphing gems sound",
-						1000, PlayAnimParams::keepLastFrame().backwards(), 28018);
+			room->playAnimWithSFX("morphing gems", "morphing gems sound",
+					      1000, PlayAnimParams::keepLastFrame().backwards(), 28018);
 			return;
 		}
 
@@ -226,10 +226,10 @@ public:
 			playCharonTalk("charon says quite dead sound", 28004);
 			break;
 		case 28006:
-			room->playSound("charon glow sting", 28007);
+			room->playMusic("charon glow sting", 28007);
 			break;
 		case 28008:
-			room->playSound("charon accepts coin sting", 28009);
+			room->playMusic("charon accepts coin sting", 28009);
 			break;
 		case 28009:
 			if (persistent->_styxCharonUsedPotion && persistent->_styxCharonUsedCoin) {
@@ -299,7 +299,7 @@ public:
 			room->enableHotzone("charon");
 		}
 
-		room->playSoundLoop(quest == kRescuePhilQuest ? "V4010eB0" : "V4010eA0");
+		room->playMusicLoop(quest == kRescuePhilQuest ? "V4010eB0" : "V4010eA0");
 		_axHead = StyxShade("ax head", 800, 5000, 10000);
 		_axHead.addSound("ax head click sound 1");
 		_axHead.addSound("ax head click sound 2");
diff --git a/engines/hadesch/rooms/seriphos.cpp b/engines/hadesch/rooms/seriphos.cpp
index 42d65978bf..5e45328b48 100644
--- a/engines/hadesch/rooms/seriphos.cpp
+++ b/engines/hadesch/rooms/seriphos.cpp
@@ -24,6 +24,7 @@
 #include "hadesch/hadesch.h"
 #include "hadesch/video.h"
 #include "hadesch/ambient.h"
+#include "common/translation.h"
 
 namespace Hadesch {
 static const char *kApolloHighlight = "c7400ba0";
@@ -41,6 +42,33 @@ static const char *questHovelNames[] = {
 	"HovelsPhil"
 };
 
+// TODO: fill this
+static const TranscribedSound seClickTranscript[] = {
+	{"c7320wb0", _s("You know, you've got to say one thing for that Oedipus: he loved his mother")},
+	{"c7320wc0", _s("Did you ever wonder: if Atlas is holding up the world, what's the heck is he standing on?") },
+	{"c7320wd0", _s("Do you know ho many narcisses it takes to screw in an oil lamp? One. He holds the lamp and the world revolves around him") },
+	{"c7320we0", _s("My dear, these hovels are small. Even the mice are crammed") },
+	{"c7320wf0", _s("Happiness is seeing king Polydectes' picture on the side of a milk bucket") },
+	{"c7330xa0", _s("You know what would look really good on king Polydectes? A pitbull")}, // unclear: I'm unable to hear beginning of the utterance
+	{"c7330xc0", _s("That Perseus kid: brave, strong, steady as rock. And if he takes one look at Medusa and it's where he's gonna be. Yeah, well, keep your fingers crossed, he's all over in snakes right now.")},
+	{"c7340xa0", _s("Did you hear Daedalus is building a huge labyrinth to catch Minotaur? Works great except now he can't find his way out. I heard he's building some wings made of wax. He-he. Good luch getting that idea off the ground")},
+	{"c7340xc0", _s("Boy our king is mean. Did you know that when Oedipus went blind the king rearranged the furniture? But at least we're not as bad off as the Crete: they have a rotten king, the dangerous Minotaur and lousy parking. Good luck finding a place for your chariot")},
+	{"c7350xa0", _s("That beautiful Helen is still being held captive in Troy. How awful for her. They've got such a lousy shopping there. When is this trojan war going to be over? Then maybe we'll start peloponesean war.")},
+	{"c7350xc0", _s("Gee, Odysseus failed to get into the city. Helen is still a prisonner and morale is low. What else can go wrong? He's just found out his chariot needs new shocks. That's gonna be expensive")},
+	{"c7360xa0", _s("Oh, it's a good thing Perseus killed Medusa otherwise Polydectes would still be king. Perseus is a much better king than Polydectes was. Now that I think of it, my dog would be a much better king than Polydectes was")},
+//	"c7360wc0"
+//	"c7360wd0"
+//	"c7310xc0"
+//	"c7310xa0"
+//	"c7310xb0"
+//	"c7310xd0"
+//	"c7310xe0"
+//	"c7310xf0"
+//	"c7310xh0"
+//	"c7310xg0"
+	{ nullptr, nullptr }
+};
+
 enum {
 	kAnimationCompleted = 26007,
       	// 26008 is the end of statue animation that we handle as functor instead
@@ -124,7 +152,7 @@ public:
 		if (name == kStrawCartHotzone) {
 			room->selectFrame(kStrawCartEmpty, kCartZ, 0);
 			_seIdles.hide(kStrawCartFull);
-			room->playSound("c7380mb0");
+			room->playMusic("c7380mb0");
 			g_vm->getHeroBelt()->placeToInventory(kStraw, kStrawTaken);
 			room->disableHotzone(kStrawCartHotzone);
 			room->disableMouse();
@@ -159,7 +187,7 @@ public:
 			int genericidx = -1;
 			_hovelsCounter++;
 			room->disableMouse();
-			room->playAnimWithSound("c7320ba0", "C7320EA0", 3101, PlayAnimParams::loop());
+			room->playAnimWithSFX("c7320ba0", "C7320EA0", 3101, PlayAnimParams::loop());
 			switch(persistent->_quest) {
 			case kRescuePhilQuest:
 				if (_hovelsCounter == 1) {
@@ -196,11 +224,11 @@ public:
 			_ambients.tick();
 			break;
 		case 26009:
-			room->playSound("c7290ma0", 26012);
+			room->playMusic("c7290ma0", 26012);
 			room->playVideo("c7290ba0", 111, 26010, Common::Point(90, 76));
 			break;
 		case 26010:
-			room->playSound("c7160ea0", 26013);
+			room->playSFX("c7160ea0", 26013);
 			break;
 		case 26013:
 			room->playVideo("c7290bd0", 111, 26014, Common::Point(92, 76));
@@ -242,7 +270,7 @@ public:
 		Common::String seAmbFn = quest > kMedusaQuest ? "SeAmb2.txt" : "SeAmb.txt";
 		TextTable seAmb = TextTable(
 			Common::SharedPtr<Common::SeekableReadStream>(room->openFile(seAmbFn)), 9);
-		_ambients.readTableFile(seAmb, AmbientAnim::PAN_ANY);
+		_ambients.readTableFileSFX(seAmb, AmbientAnim::PAN_ANY);
 
 		if (quest == kMedusaQuest && !persistent->_seriphosPlayedMedusa) {
 			g_vm->addTimer(26009, 500, 1);
@@ -256,15 +284,15 @@ public:
 			room->playAnimLoop("c7320bb0", 1101);
 		}
 
-		room->playSoundLoop(quest > kMedusaQuest ? "c7010eb0" : "c7010ea0");
+		room->playMusicLoop(quest > kMedusaQuest ? "c7010eb0" : "c7010ea0");
 
-		_seClick.readTable(room, "SeClick.txt");
+		_seClick.readTable(room, "SeClick.txt", seClickTranscript);
 
 		g_vm->getHeroBelt()->setColour(quest > kMedusaQuest ? HeroBelt::kWarm : HeroBelt::kCool);
 
 		TextTable seIdles = TextTable(
 				Common::SharedPtr<Common::SeekableReadStream>(room->openFile("SeIdles.txt")), 14);
-		_seIdles.readTableFile(seIdles, AmbientAnim::PAN_ANY);
+		_seIdles.readTableFileSFX(seIdles, AmbientAnim::PAN_ANY);
 		_seIdles.firstFrame();
 
 		if (quest == kCreteQuest && !persistent->_seriphosStrawCartTaken) {
diff --git a/engines/hadesch/rooms/troy.cpp b/engines/hadesch/rooms/troy.cpp
index 608180ef98..1dc52ce61a 100644
--- a/engines/hadesch/rooms/troy.cpp
+++ b/engines/hadesch/rooms/troy.cpp
@@ -24,6 +24,7 @@
 #include "hadesch/hadesch.h"
 #include "hadesch/video.h"
 #include "hadesch/ambient.h"
+#include "common/translation.h"
 
 namespace Hadesch {
 
@@ -40,6 +41,11 @@ static const char *kKeyAndDecreePopup = "t2010of0";
 static const char *kMenelausImage = "t2070ba0";
 static const char *kHelenImage = "t1230ba0";
 
+// TODO: fill this
+static const TranscribedSound trClickTranscript[] = {
+	{ nullptr, nullptr }
+};
+
 enum {
 	kAnimationCompleted = 10011,
 	kPrisonerVideoCompleteted = 1010001,
@@ -151,7 +157,7 @@ public:
 		if (name == "Odysseus' Scroll") {
 			room->disableHotzone("Odysseus' Scroll");
 			room->disableHotzone("Background2");
-			room->playSound("T2150eA1", 10049);
+			room->playSFX("T2150eA1", 10049);
 			hideOdysseus();
 			showIdleOdysseus();
 			_philUseSecondInsistance = false;
@@ -164,7 +170,7 @@ public:
 			room->cancelVideo();
 			room->disableHotzone("Scroll PopUp");
 			room->disableHotzone("Background2");
-			room->playSound("T2150eB0");
+			room->playSFX("T2150eB0");
 			room->stopAnim("t2010oe0");
 			room->disableMouse();
 			g_vm->getHeroBelt()->placeToInventory(kMessage, 10052);
@@ -348,8 +354,8 @@ public:
 			if (item == kKey) {
 				room->disableMouse();
 				g_vm->getHeroBelt()->removeFromInventory(kKey);
-				room->playAnimWithSound("t1290bb0", "t1290xa0", 105, PlayAnimParams::keepLastFrame(),
-							10060);
+				room->playAnimWithSFX("t1290bb0", "t1290xa0", 105, PlayAnimParams::keepLastFrame(),
+						      10060);
 				persistent->_troyCatacombsUnlocked = true;
 				room->disableHotzone("Catacomb PopUp Grate");
 				room->enableHotzone("Link To Catacombs");
@@ -404,10 +410,10 @@ public:
 			break;
 		case 10022:
 			// Attack on castle
-			room->playAnimWithSound("t1250bb0",
-						"t1250eb0", 131,
-						PlayAnimParams::disappear(),
-						10027);
+			room->playAnimWithSFX("t1250bb0",
+					      "t1250eb0", 131,
+					      PlayAnimParams::disappear(),
+					      10027);
 			break;
 		case 10027:
 			room->selectFrame(kDamagedWall, kDamagedWallZ, 0);
@@ -468,7 +474,8 @@ public:
 			}
 			break;
 		case 10057:
-			room->playSound("T2240wA0", 10058);
+			room->playSpeech(
+				TranscribedSound("T2240wA0", "Official orders from king Priam: messenger is granted permissions to leave the city walls"), 10058);
 			break;
 		case 10058:
 			room->enableMouse();
@@ -484,11 +491,11 @@ public:
 				break;
 			/* Fallthrough */
 		case 10063:
-			room->playSound("t1350ec0", 10064);
+			room->playSFX("t1350ec0", 10064);
 			break;
 		case 10064:
 			room->playAnimKeepLastFrame("t1350bb0", 501, 10065);
-			room->playSound("t1350ed0", 10066);
+			room->playSFX("t1350ed0", 10066);
 			break;
 		case 10065:
 			room->playAnim("t1350bb0", 501, PlayAnimParams::loop().partial(8, 11));
@@ -550,7 +557,7 @@ public:
 		room->enableHotzone("Catacomb");
 		room->playAnimLoop("T1110BA0", 501);
 
-		_trClick.readTable(room, "TrClick.txt");
+		_trClick.readTable(room, "TrClick.txt", trClickTranscript);
 
 		if (persistent->_troyWallDamaged && quest == kCreteQuest) {
 			room->selectFrame(kDamagedWall, kDamagedWallZ, 0);
@@ -670,12 +677,12 @@ public:
 			}
 		}
 
-		room->playSoundLoop(persistent->_troyMessageIsDelivered || quest > kTroyQuest ? "t1010eb0" : "t1010ea0");
+		room->playMusicLoop(persistent->_troyMessageIsDelivered || quest > kTroyQuest ? "t1010eb0" : "t1010ea0");
 
 		if (quest <= kTroyQuest && !persistent->_troyPlayFinish) {
 			TextTable trLftAmb = TextTable(
 				Common::SharedPtr<Common::SeekableReadStream>(room->openFile("TrLftAmb.txt")), 9);
-			_leftAmbients.readTableFile(trLftAmb, AmbientAnim::PAN_LEFT);
+			_leftAmbients.readTableFileSFX(trLftAmb, AmbientAnim::PAN_LEFT);
 			g_vm->addTimer(2803, 10000, -1);
 			_leftAmbients.firstFrame();
 		}
@@ -713,7 +720,7 @@ public:
 			persistent->_troyPlayFinish = false;
 			room->disableMouse();
 			_horseCounter = 2;
-			room->playSound("T1350mA0", kHorseCounter);
+			room->playMusic("T1350mA0", kHorseCounter);
 			room->playVideo("t1350ba0", 501, kHorseCounter, Common::Point(288, 211));
 
 			room->playAnimLoop("t1090ba0", 501);
diff --git a/engines/hadesch/rooms/volcano.cpp b/engines/hadesch/rooms/volcano.cpp
index 734cd48d29..f25aa65852 100644
--- a/engines/hadesch/rooms/volcano.cpp
+++ b/engines/hadesch/rooms/volcano.cpp
@@ -64,8 +64,8 @@ public:
 			room->stopAnim("pain still");
 			room->stopAnim("panic still");
 			_boulder1Anim.hide();
-			room->playAnimWithSound("first boulder falls", "first boulder falls sound", 400,
-						PlayAnimParams::disappear(), 16023);
+			room->playAnimWithSFX("first boulder falls", "first boulder falls sound", 400,
+					      PlayAnimParams::disappear(), 16023);
 			return;
 		}
 
@@ -85,7 +85,7 @@ public:
 		if (name == "helmet") {
 			persistent->_volcanoPuzzleState = Persistent::VOLCANO_HELMET_SHOWN;
 			g_vm->getHeroBelt()->placeToInventory(kHelmet);
-			room->playSound("skeleton revealed sfx");
+			room->playSFX("skeleton revealed sfx");
 			room->playAnimKeepLastFrame("helmet", kHelmetZ);
 			return;
 		}
@@ -115,7 +115,7 @@ public:
 			break;
 		case 16007:
 			room->stopAnim("gem overlay");
-			room->playSound("morph music", 16009);
+			room->playMusic("morph music", 16009);
 			room->playVideo("morphing gems", 500, 16005, Common::Point(10, 10));
 			break;
 		case 16008:
@@ -137,8 +137,8 @@ public:
 			break;
 		case 16023:
 			squashedPanic();
-			room->playAnimWithSound("second boulder", "second boulder sound",
-						401, PlayAnimParams::keepLastFrame(), 16024);
+			room->playAnimWithSFX("second boulder", "second boulder sound",
+					      401, PlayAnimParams::keepLastFrame(), 16024);
 			persistent->_volcanoPuzzleState = Persistent::VOLCANO_SQUASHED_PANIC;
 			break;
 		case 16024:
@@ -149,7 +149,7 @@ public:
 			room->enableHotzone("second boulder");
 			break;
 		case 16025:
-			room->playSound("volcanic rumble", 16028);
+			room->playSFX("volcanic rumble", 16028);
 			room->selectFrame("volcano plug boulder", 400, 0);
 			g_vm->addTimer(16026, 500);
 			break;
@@ -158,7 +158,7 @@ public:
 			g_vm->addTimer(16030, 2500);
 			break;
 		case 16030:
-			room->playSound("explosion sound", 16033);
+			room->playSFX("explosion sound", 16033);
 			g_vm->addTimer(16031, 1000);
 			break;
 		case 16031:
@@ -171,8 +171,8 @@ public:
 			room->enableHotzone("helmet");
 			// TODO: 16035 timer
 			// TODO: Or is it "lava flow sound 1"
-			room->playAnimWithSound("final lava flow", "final lava flow sound", 500,
-						PlayAnimParams::loop());
+			room->playAnimWithSFX("final lava flow", "final lava flow sound", 500,
+					      PlayAnimParams::loop());
 			break;
 		}
 	}
@@ -208,9 +208,9 @@ public:
 
 		if (quest < kMedusaQuest || (quest == kMedusaQuest && persistent->_volcanoPuzzleState <= Persistent::VOLCANO_SQUASHED_PANIC)) {
 			for (int i = 1; i <= 3; i++) {
-				room->playAnimWithSound(Common::String::format("lava flow %d", i),
-							Common::String::format("lava flow sound %d", i),
-							500, PlayAnimParams::loop());
+				room->playAnimWithSFX(Common::String::format("lava flow %d", i),
+						      Common::String::format("lava flow sound %d", i),
+						      500, PlayAnimParams::loop());
 			}
 		}
 
@@ -228,15 +228,15 @@ public:
 			room->selectFrame("helmet", kHelmetZ, 0);
 			room->enableHotzone("helmet");
 			// TODO: Or is it "lava flow sound 1"
-			room->playAnimWithSound("final lava flow", "final lava flow sound", 500,
-						PlayAnimParams::loop());
+			room->playAnimWithSFX("final lava flow", "final lava flow sound", 500,
+					      PlayAnimParams::loop());
 			room->selectFrame("volcano plug boulder", 400, 0);
 		}
 
 		if (quest > kMedusaQuest || (quest == kMedusaQuest && persistent->_volcanoPuzzleState == Persistent::VOLCANO_HELMET_SHOWN)) {
 			room->selectFrame("helmet", kHelmetZ, -1);
-			room->playAnimWithSound("final lava flow", "final lava flow sound", 500,
-						PlayAnimParams::loop());
+			room->playAnimWithSFX("final lava flow", "final lava flow sound", 500,
+					      PlayAnimParams::loop());
 			room->selectFrame("volcano plug boulder", 400, 0);
 		}
 
@@ -247,9 +247,9 @@ public:
 		}
 
 		if (quest == kRescuePhilQuest) {
-			room->playSound("theme music");
+			room->playMusic("theme music");
 		} else {
-			room->playSoundLoop("W1010eA0");
+			room->playMusicLoop("W1010eA0");
 		}
 
 		room->playAnimLoop("waves", 900);
@@ -261,6 +261,7 @@ public:
 
 private:
 	void squashedPanic() {
+		// TODO: transcribe and change to speech sound type
 		_painAnim = AmbientAnim("squashed pain", "squashed pain sound", 425, 5000, 10000, AmbientAnim::KEEP_LOOP,
 					Common::Point(0, 0), AmbientAnim::PAN_ANY);
 		_panicAnim = AmbientAnim("squashed panic", "squashed panic sound", 425, 5000, 10000, AmbientAnim::KEEP_LOOP,
diff --git a/engines/hadesch/rooms/walloffame.cpp b/engines/hadesch/rooms/walloffame.cpp
index a7a8a11e80..630966f38d 100644
--- a/engines/hadesch/rooms/walloffame.cpp
+++ b/engines/hadesch/rooms/walloffame.cpp
@@ -243,7 +243,7 @@ public:
 		if (hotname == kApplicationHeroineHotzone) {
 			room->selectFrame(kApplicationHeroine, kApplicationButtonZ, 1);
 			room->selectFrame(kApplicationHero, kApplicationButtonZ, 0);
-			room->playSound(kApplicationChooseHeroineSound);
+			room->playSFX(kApplicationChooseHeroineSound);
 			_gender = kFemale;
 			computeEnter();
 			return;
@@ -251,7 +251,7 @@ public:
 		if (hotname == kApplicationHeroHotzone) {
 			room->selectFrame(kApplicationHeroine, kApplicationButtonZ, 0);
 			room->selectFrame(kApplicationHero, kApplicationButtonZ, 1);
-			room->playSound(kApplicationChooseHeroSound);
+			room->playSFX(kApplicationChooseHeroSound);
 			_gender = kMale;
 			computeEnter();
 			return;
@@ -270,7 +270,7 @@ public:
 			if (hotname == herculesRoomElements[i]) {
 				room->disableMouse();
 				room->playAnimKeepLastFrame(hotname + " glow", kGlowZ);
-				room->playSound("click");
+				room->playSFX("click");
 				room->playVideo("zeus " + hotname, kSoundOnlyZ, 1019026);
 				return;
 			}
@@ -278,9 +278,9 @@ public:
 		for (unsigned power = 0; power < ARRAYSIZE(powerLevelNames); power++) {
 			if (hotname.matchString(Common::String::format("%s#", powerLevelNames[power]))) {
 				Common::String pl(powerLevelNames[power]);
-				room->playSound("click");
+				room->playSFX("click");
 				if (strcmp(powerLevelNames[power], "thunderbolt") == 0)
-					room->playSound("thunder sound");
+					room->playSFX("thunder sound");
 				zeusCommentRight("zeus " + pl);
 				return;
 			}
@@ -288,13 +288,13 @@ public:
 
 		for (unsigned i = 0; i < sizeof (zeusComments) / sizeof(zeusComments[0]); i++)
 			if (hotname == zeusComments[i]) {
-				room->playSound("click");
+				room->playSFX("click");
 				zeusCommentRight(Common::String("zeus ") + hotname);
 				return;
 			}
 
 		if (hotname == "typhon") {
-			room->playSound("click");
+			room->playSFX("click");
 			zeusCommentRight(persistent->_gender == kFemale ? "zeus typhon heroine" : "zeus typhon hero");
 			return;
 		}
@@ -392,7 +392,7 @@ public:
 			room->playVideo(kZeusYooHoo, kSoundOnlyZ, 19701); // zeus yoo-hoo
 			break;
 		case 19005:
-			playPhilAnim(kPhilRollsOver, 1019001, Common::Point(-26, 2)); // state 1
+			playPhilAnimSFX(kPhilRollsOver, 1019001, Common::Point(-26, 2)); // state 1
 			break;
 		case 19011:
 			room->playVideo(kZeusVacationIsOver, kSoundOnlyZ, 19012);
@@ -423,13 +423,13 @@ public:
 			break;
 		case 1019001:
 			cancelAllPhils();
-			playPhilAnim(kPhilJumpsOffPillow, -1, Common::Point(-26, 2)); // state 4
+			playPhilAnimSFX(kPhilJumpsOffPillow, -1, Common::Point(-26, 2)); // state 4
 			room->playVideo(kZeusYellsPhil, kSoundOnlyZ, 19011);
 			break;
 		case 1019003:
 			room->setLayerEnabled(kRope, true);
 			displayPhilIdle();
-			room->playAnimWithSound(
+			room->playAnimWithSFX(
 				kApplicationUnfurls, kApplicationUnfurlsSound,
 				kApplicationZ, PlayAnimParams::disappear().speed(200), 1019004);
 			break;
@@ -466,7 +466,7 @@ public:
 			break;
 		case 1019011:
 			displayPhilYap();
-			room->playAnimWithSound(
+			room->playAnimWithSFX(
 				kHeroBelt, kHeroBeltUpSound, kHeroBeltZ,
 				PlayAnimParams::keepLastFrame().partial(0, 9),
 				19022, kOffsetRightRoom);
@@ -480,25 +480,25 @@ public:
 		case 1019013:
 			room->selectFrame(kHeroBelt, kHeroBeltZ, 10,
 					     kOffsetRightRoom);
-			room->playSound("hero belt items highlight sound");
+			room->playSFX("hero belt items highlight sound");
 			room->playVideo(kPhilClickAnItem, kPhilZ, 1019014); // state 15
 			break;
 		case 1019014:
 			room->selectFrame(kHeroBelt, kHeroBeltZ, 11,
 					     kOffsetRightRoom);
-			room->playSound("hero belt items highlight sound");
+			room->playSFX("hero belt items highlight sound");
 			room->playVideo(kPhilHeroPowers, kPhilZ, 1019015); // state 16
 			break;
 		case 1019015:
 			room->selectFrame(kHeroBelt, kHeroBeltZ, 12,
 					     kOffsetRightRoom);
-			room->playSound("hero belt items highlight sound");
+			room->playSFX("hero belt items highlight sound");
 			g_vm->addTimer(19029, 4000);
 			room->playVideo(kPhilRightNotches, kPhilZ, 1019016); // state 17
 			break;
 		case 1019016:
 			g_vm->cancelTimer(19029);
-			room->playAnimWithSound(
+			room->playAnimWithSFX(
 				kHeroBelt, kHeroBeltDownSound, kHeroBeltZ, PlayAnimParams::disappear().partial(9, 0),
 				1019017, kOffsetRightRoom);
 			break;
@@ -508,27 +508,27 @@ public:
 				      Common::Point(-8, 144)); // state 18
 			break;
 		case 1019018:
-			room->playSound(kPanicAndPainSting);
+			room->playSFX(kPanicAndPainSting);
 			playPhilVideo(kPhilBadNews, 1019019, Common::Point(14, 320)); // state 19
 			break;
 		case 1019019:
 			displayPhilIdle();
-			room->playAnimWithSound(kMugshot, kMugshotSound,
-						kMugshotZ, PlayAnimParams::keepLastFrame(),
-						19006, kOffsetRightRoom);
+			room->playAnimWithSFX(kMugshot, kMugshotSound,
+					      kMugshotZ, PlayAnimParams::keepLastFrame(),
+					      19006, kOffsetRightRoom);
 			break;
 		case 19006:
-			room->playAnimWithSound(kScroll, kScrollSound,
-						kScrollZ, PlayAnimParams::keepLastFrame(),
-						19009, kOffsetRightRoom);
+			room->playAnimWithSFX(kScroll, kScrollSound,
+					      kScrollZ, PlayAnimParams::keepLastFrame(),
+					      19009, kOffsetRightRoom);
 			break;
 		case 19009:
 			playPhilVideo(kPhilFirstQuest, kPhilNewQuestScroll, Common::Point(40, 324)); // state 21
 			break;
 		case kPhilNewQuestScroll:
 			room->selectFrame(kScroll, kScrollZ, 0, kOffsetRightRoom);
-			room->playSound("quest intro music");
-			playPhilAnim(kPhilTakesScroll, 1019021); // state 22
+			room->playMusic("quest intro music");
+			playPhilAnimSFX(kPhilTakesScroll, 1019021); // state 22
 			break;
 		case 1019021:
 			switch (quest) {
@@ -545,7 +545,7 @@ public:
 			}
 			break;
 		case 1019022:
-			playPhilAnim(kPhilDropsScroll, 1019023); // state 23
+			playPhilAnimSFX(kPhilDropsScroll, 1019023); // state 23
 			break;
 		case 1019023:
 			switch (quest) {
@@ -623,8 +623,8 @@ public:
 				}
 				_philWalkPhase++;
 				updatePhilHotzone();
-				playPhilAnim("phil walks left to center", kPhilJokeEventCleanup,
-					     Common::Point(-166, +2));
+				playPhilAnimSFX("phil walks left to center", kPhilJokeEventCleanup,
+						Common::Point(-166, +2));
 				break;
 			case 6:
 				// state 45, go left
@@ -634,29 +634,29 @@ public:
 				}
 				_philWalkPhase--;
 				updatePhilHotzone();
-				playPhilAnim(kPhilWalksCenterToLeft, kPhilJokeEventCleanup);
+				playPhilAnimSFX(kPhilWalksCenterToLeft, kPhilJokeEventCleanup);
 				break;
 			case 7:
 				// state 46
-				playPhilAnim("phil faces backward left", kPhilJokeEventCleanup, Common::Point(-640, 0));
+				playPhilAnimSFX("phil faces backward left", kPhilJokeEventCleanup, Common::Point(-640, 0));
 				break;
 			case 8:
 				// state 47
-				playPhilAnim(kPhilSighsLeft, kPhilJokeEventCleanup);
+				playPhilAnimSFX(kPhilSighsLeft, kPhilJokeEventCleanup);
 				break;
 			case 9:
 				// state 48
-				playPhilAnim(kPhilTapsFootLeft, kPhilJokeEventCleanup);
+				playPhilAnimSFX(kPhilTapsFootLeft, kPhilJokeEventCleanup);
 				break;
 			case 10:
 				// state 49, dusts
 				switch (_philWalkPhase) {
 				case 0:
-					playPhilAnim("phil dusts left", kPhilJokeEventCleanup);
+					playPhilAnimSFX("phil dusts left", kPhilJokeEventCleanup);
 					break;
 				case 1:
 				case 2:
-					playPhilAnim("phil dusts center", kPhilJokeEventCleanup, Common::Point(-166, 2));
+					playPhilAnimSFX("phil dusts center", kPhilJokeEventCleanup, Common::Point(-166, 2));
 					break;
 				case 3:
 					schedulePhilJoke();
@@ -669,7 +669,7 @@ public:
 		case 19029:
 			room->selectFrame(kHeroBelt, kHeroBeltZ, 13,
 					  kOffsetRightRoom);
-			room->playSound("hero belt items highlight sound");
+			room->playSFX("hero belt items highlight sound");
 			break;
 		case kPhilJokeEventCleanup:
 			schedulePhilJoke();
@@ -683,7 +683,7 @@ public:
 			room->enableMouse();
 			break;
 		case kPhilRereadDropScroll:
-			playPhilAnim(kPhilDropsScroll, 19047);
+			playPhilAnimSFX(kPhilDropsScroll, 19047);
 			break;
 		case 19047:
 			philBecomesIdle();
@@ -722,8 +722,8 @@ public:
 			room->setPannable(false);
 			room->addStaticLayer("black background", kBackgroundZ, kOffsetRightRoom);
 			room->playVideo("hades eye of fates", 0, 19054, kOffsetRightRoom);
-			room->playSound("herc laughs");
-			room->playSound("phil laughs");
+			room->playSFX("herc laughs");
+			room->playSFX("phil laughs");
 			break;
 		case 19054:
 			g_vm->moveToRoom(kCreditsRoom);
@@ -731,7 +731,7 @@ public:
 		case 1019031:
 			_philWalkPhase--;
 			updatePhilHotzone();
-			playPhilAnim(kPhilWalksCenterToLeft, 1019032);
+			playPhilAnimSFX(kPhilWalksCenterToLeft, 1019032);
 			break;
 		case 1019032:
 			playPhilVideo("phil lots more to do", kPhilNewQuestScroll, Common::Point(14, 312)); // state 28
@@ -749,7 +749,7 @@ public:
 		case 1019036:
 			_philWalkPhase--;
 			updatePhilHotzone();
-			playPhilAnim(kPhilWalksCenterToLeft, 1019037);
+			playPhilAnimSFX(kPhilWalksCenterToLeft, 1019037);
 			break;
 		case 1019037:
 			playPhilVideo("phil good work", kPhilNewQuestScroll, Common::Point(40, 324)); // state 35
@@ -784,7 +784,7 @@ public:
 			     || code == '.' || code == '-' || code == ' ')
 			    && room->computeStringWidth("application sign-in text", _heroName + code) <= 318) {
 				_heroName += code;
-				room->playSound("application click");
+				room->playSFX("application click");
 				renderNameInApplication();
 				computeEnter();
 				return;
@@ -792,7 +792,7 @@ public:
 
 			if (_heroName.size() > 0 && code == '\b') {
 				_heroName.deleteLastChar();
-				room->playSound("application click");
+				room->playSFX("application click");
 				renderNameInApplication();
 				computeEnter();
 				return;
@@ -872,7 +872,7 @@ public:
 		room->setPannable(true);
 		if (newGame) {
 			room->disableMouse();
-			room->playAnimWithSound(kPhilSnores, kPhilSnoresSound, kPhilZ, PlayAnimParams::loop()); //state 0
+			room->playAnimWithSFX(kPhilSnores, kPhilSnoresSound, kPhilZ, PlayAnimParams::loop()); //state 0
 			room->selectFrame(kMugshot, kMugshotZ, 0, kOffsetRightRoom);
 			g_vm->addSkippableTimer(19004, 4000);
 		} else if (persistent->_doQuestIntro) {
@@ -882,12 +882,12 @@ public:
 			case kTroyQuest:
 				_philWalkPhase = 1;
 				playPhilVideo("phil congrats trapped minotaur", 1019031, Common::Point(14, 320)); // state 27
-				room->playSound("done crete quest theme");
+				room->playMusic("done crete quest theme");
 				break;
 			case kMedusaQuest:
 				_philWalkPhase = 1;
 				playPhilVideo("phil dances", 1019035, Common::Point(36, 257)); // state 38
-				room->playSound("done troy quest theme");
+				room->playMusic("done troy quest theme");
 				break;
 			case kRescuePhilQuest:
 				g_vm->addTimer(19048, 5000, 1);
@@ -895,10 +895,10 @@ public:
 				room->disableHotzone("hades note popup background2");
 				room->setPannable(false);
 				room->enableMouse();
-				room->playAnimWithSound("hades note", "hades note sound", 150, PlayAnimParams::loop(),
-							EventHandlerWrapper(), kOffsetRightRoom);
+				room->playAnimWithSFX("hades note", "hades note sound", 150, PlayAnimParams::loop(),
+						      EventHandlerWrapper(), kOffsetRightRoom);
 				room->setHotzoneEnabled("argo", false);
-				room->playSound("done medusa quest theme");
+				room->playMusic("done medusa quest theme");
 				_endGameOutro = true;
 				break;
 
@@ -922,7 +922,7 @@ public:
 
 		renderLintel();
 
-		room->playSoundLoop("C1010eA0");
+		room->playMusicLoop("C1010eA0");
 
 		g_vm->getHeroBelt()->setColour(HeroBelt::kWarm);
 	}
@@ -974,7 +974,8 @@ private:
 			persistent->_gender = _gender;
 			persistent->_heroName = _heroName;
 			room->disableMouse();
-			room->playSound("hades evil intro theme");
+			// Or should it be music? Unclear to me
+			room->playSFX("hades evil intro theme");
 			room->playVideo(kHadesBurstsIn, kHadesVideoZ, 19016);
 		}
 	}
@@ -1008,13 +1009,13 @@ private:
 						videoOffset + getPhilBase());
 	}
 
-	void playPhilAnim(const Common::String &name,
-			  int callback, const Common::Point videoOffset = Common::Point(0, 0)) {
+	void playPhilAnimSFX(const Common::String &name,
+			     int callback, const Common::Point videoOffset = Common::Point(0, 0)) {
 		Persistent *persistent = g_vm->getPersistent();
 		cancelAllPhils();
 		if (persistent->_quest == kRescuePhilQuest)
 			return;
-		g_vm->getVideoRoom()->playAnimWithSound(
+		g_vm->getVideoRoom()->playAnimWithSFX(
 			name, name + " sound", kPhilZ, PlayAnimParams::keepLastFrame(), callback,
 			videoOffset + getPhilBase());
 	}
diff --git a/engines/hadesch/video.cpp b/engines/hadesch/video.cpp
index 9db8c63c1e..a08132ea95 100644
--- a/engines/hadesch/video.cpp
+++ b/engines/hadesch/video.cpp
@@ -789,7 +789,7 @@ Audio::RewindableAudioStream *VideoRoom::getAudioStream(const Common::String &so
 }
 
 void VideoRoom::playSoundInternal(const Common::String &soundName, EventHandlerWrapper callbackEvent, bool loop,
-				  bool skippable) {
+				  bool skippable, Audio::Mixer::SoundType soundType) {
 	Audio::RewindableAudioStream *rewSoundStream;
 	Audio::AudioStream *soundStream;
 	Animation anim;
@@ -801,29 +801,39 @@ void VideoRoom::playSoundInternal(const Common::String &soundName, EventHandlerW
 	anim._finished = false;
 	anim._keepLastFrame = false;
 	anim._skippable = skippable;
-	g_system->getMixer()->playStream(Audio::Mixer::kSFXSoundType, &anim._soundHandle, soundStream,
+	g_system->getMixer()->playStream(soundType, &anim._soundHandle, soundStream,
 					 -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::YES);
 	_anims.push_back(anim);
 }
 
-void VideoRoom::playSound(const Common::String &soundName, EventHandlerWrapper callbackEvent) {
-	playSoundInternal(soundName, callbackEvent, false, false);
+void VideoRoom::playSFX(const Common::String &soundName, EventHandlerWrapper callbackEvent) {
+	playSoundInternal(soundName, callbackEvent, false, false, Audio::Mixer::kSFXSoundType);
 }
 
-void VideoRoom::playSkippableSound(const Common::String &soundName, EventHandlerWrapper callbackEvent) {
-	playSoundInternal(soundName, callbackEvent, false, true);
+void VideoRoom::playMusic(const Common::String &soundName, EventHandlerWrapper callbackEvent) {
+	playSoundInternal(soundName, callbackEvent, false, false, Audio::Mixer::kMusicSoundType);
 }
 
-void VideoRoom::playSoundLoop(const Common::String &soundName) {
-	playSoundInternal(soundName, EventHandlerWrapper(), true, false);
+void VideoRoom::playSpeech(const TranscribedSound &sound,
+				    EventHandlerWrapper callbackEvent) {
+	playSoundInternal(sound.soundName, callbackEvent, false, true, Audio::Mixer::kSpeechSoundType);
 }
 
-void VideoRoom::playAnimWithSound(const LayerId &animName,
-				  const Common::String &soundName,
-				  int zValue,
-				  PlayAnimParams params,
-				  EventHandlerWrapper callbackEvent,
-				  Common::Point offset) {
+void VideoRoom::playSFXLoop(const Common::String &soundName) {
+	playSoundInternal(soundName, EventHandlerWrapper(), true, false, Audio::Mixer::kSFXSoundType);
+}
+
+void VideoRoom::playMusicLoop(const Common::String &soundName) {
+	playSoundInternal(soundName, EventHandlerWrapper(), true, false, Audio::Mixer::kMusicSoundType);
+}
+
+void VideoRoom::playAnimWithSoundInternal(const LayerId &animName,
+					  const Common::String &soundName,
+					  Audio::Mixer::SoundType soundType,
+					  int zValue,
+					  PlayAnimParams params,
+					  EventHandlerWrapper callbackEvent,
+					  Common::Point offset) {
 	Audio::AudioStream *soundStream;
 
 	if (!doesLayerExist(animName)) {
@@ -844,11 +854,38 @@ void VideoRoom::playAnimWithSound(const LayerId &animName,
 	anim._finished = false;
 	anim._keepLastFrame = params.getKeepLastFrame();
 	anim._skippable = false;
-	g_system->getMixer()->playStream(Audio::Mixer::kSFXSoundType, &anim._soundHandle, soundStream,
+	g_system->getMixer()->playStream(soundType, &anim._soundHandle, soundStream,
 					 -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::YES);
 	_anims.push_back(anim);
 }
 
+void VideoRoom::playAnimWithSpeech(const LayerId &animName,
+				   const TranscribedSound &sound,
+				   int zValue,
+				   PlayAnimParams params,
+				   EventHandlerWrapper callbackEvent,
+				   Common::Point offset) {
+	playAnimWithSoundInternal(animName, sound.soundName, Audio::Mixer::kSpeechSoundType, zValue, params, callbackEvent, offset);
+}
+
+void VideoRoom::playAnimWithSFX(const LayerId &animName,
+				const Common::String &soundName,
+				int zValue,
+				PlayAnimParams params,
+				EventHandlerWrapper callbackEvent,
+				Common::Point offset) {
+	playAnimWithSoundInternal(animName, soundName, Audio::Mixer::kSFXSoundType, zValue, params, callbackEvent, offset);
+}
+
+void VideoRoom::playAnimWithMusic(const LayerId &animName,
+				  const Common::String &soundName,
+				  int zValue,
+				  PlayAnimParams params,
+				  EventHandlerWrapper callbackEvent,
+				  Common::Point offset) {
+	playAnimWithSoundInternal(animName, soundName, Audio::Mixer::kMusicSoundType, zValue, params, callbackEvent, offset);
+}
+
 void VideoRoom::playAnim(const LayerId &animName, int zValue,
 			 PlayAnimParams params,
 			 EventHandlerWrapper callbackEvent,
diff --git a/engines/hadesch/video.h b/engines/hadesch/video.h
index 09a53f2b9c..830e9a5504 100644
--- a/engines/hadesch/video.h
+++ b/engines/hadesch/video.h
@@ -142,6 +142,21 @@ private:
 	int _msperframe;
 };
 
+struct TranscribedSound {
+	const char *soundName;
+	const char *transcript;
+
+	TranscribedSound(const char *s, const char *t) {
+		soundName = s;
+		transcript = t;
+	}
+
+	TranscribedSound() {
+		soundName = nullptr;
+		transcript = nullptr;
+	}
+};
+
 class VideoRoom {
 public:
 	VideoRoom(const Common::String &dir, const Common::String &pod,
@@ -185,7 +200,19 @@ public:
 	int getNumFrames(const LayerId &animName);
 
 	// Main animation API
-	void playAnimWithSound(const LayerId &animName,
+	void playAnimWithSpeech(const LayerId &animName,
+				const TranscribedSound &sound,
+				int zValue,
+				PlayAnimParams params,
+				EventHandlerWrapper callbackEvent = EventHandlerWrapper(),
+				Common::Point offset = Common::Point(0, 0));
+	void playAnimWithSFX(const LayerId &animName,
+			     const Common::String &soundName,
+			     int zValue,
+			     PlayAnimParams params,
+			     EventHandlerWrapper callbackEvent = EventHandlerWrapper(),
+			     Common::Point offset = Common::Point(0, 0));
+    	void playAnimWithMusic(const LayerId &animName,
 			       const Common::String &soundName,
 			       int zValue,
 			       PlayAnimParams params,
@@ -256,11 +283,14 @@ public:
 	int computeStringWidth(const Common::String &font, const Common::U32String &str, int fontDelta = 0);
 	
 	// Misc
-	void playSound(const Common::String &soundName,
+	void playSFX(const Common::String &soundName,
+		     EventHandlerWrapper callbackEvent = EventHandlerWrapper());
+	void playMusic(const Common::String &soundName,
 		       EventHandlerWrapper callbackEvent = EventHandlerWrapper());
-	void playSkippableSound(const Common::String &soundName,
-				EventHandlerWrapper callbackEvent = EventHandlerWrapper());
-	void playSoundLoop(const Common::String &soundName);
+	void playSFXLoop(const Common::String &soundName);
+	void playMusicLoop(const Common::String &soundName);
+	void playSpeech(const TranscribedSound &sound,
+				 EventHandlerWrapper callbackEvent = EventHandlerWrapper());
 	void playStatueSMK(StatueId id, const LayerId &animName, int zValue,
 			   const Common::Array<Common::String> &smkNames,
 			   int startOfLoop, int startOfEnd,
@@ -292,6 +322,13 @@ private:
 		int scale; // From 0 to 100
 	};
 
+	void playAnimWithSoundInternal(const LayerId &animName,
+				       const Common::String &soundName,
+				       Audio::Mixer::SoundType soundType,
+				       int zValue,
+				       PlayAnimParams params,
+				       EventHandlerWrapper callbackEvent = EventHandlerWrapper(),
+				       Common::Point offset = Common::Point(0, 0));
 	void addLayer(Renderable *renderable, const LayerId &name,
 		      int zValue,
 		      bool isEnabled = true, Common::Point offset = Common::Point(0, 0));
@@ -302,7 +339,7 @@ private:
 	Common::String mapAsset(const LayerId &name);
 	void addAnimLayerInternal(const LayerId &name, int zValue, Common::Point offset = Common::Point(0, 0));
 	void playSoundInternal(const Common::String &soundName, EventHandlerWrapper callbackEvent, bool loop,
-			       bool skippable);
+			       bool skippable, Audio::Mixer::SoundType soundType);
 	static int layerComparator (const Layer &a, const Layer &b);
 	void loadFontWidth(const Common::String &font);
 


Commit: 937d5c4a98e82ff7d327a7b9ecf78227dbcbe2f6
    https://github.com/scummvm/scummvm/commit/937d5c4a98e82ff7d327a7b9ecf78227dbcbe2f6
Author: Vladimir Serbinenko (phcoder at google.com)
Date: 2020-12-17T09:49:18+01:00

Commit Message:
HADESCH: Show subtitles for AIF files

Changed paths:
    engines/hadesch/gfx_context.cpp
    engines/hadesch/gfx_context.h
    engines/hadesch/hadesch.cpp
    engines/hadesch/hadesch.h
    engines/hadesch/video.cpp
    engines/hadesch/video.h


diff --git a/engines/hadesch/gfx_context.cpp b/engines/hadesch/gfx_context.cpp
index c4c467e390..63b7c201bc 100644
--- a/engines/hadesch/gfx_context.cpp
+++ b/engines/hadesch/gfx_context.cpp
@@ -26,6 +26,9 @@
 #include "hadesch/baptr.h"
 #include "common/system.h"
 #include "graphics/palette.h"
+#include "graphics/font.h"
+#include "graphics/fontman.h"
+#include "hadesch/hadesch.h"
 
 namespace Hadesch {
 
@@ -48,8 +51,8 @@ void blendVideo8To8(byte *targetPixels, int targetPitch, int targetW, int target
 void GfxContext8Bit::blitPodImage(byte *sourcePixels, int sourcePitch, int sourceW, int sourceH,
 				  byte *sourcePalette, size_t ncolours, Common::Point offset) {
 	
-	blendVideo8To8(_pixels.get(), _pitch,
-		       _w, _h, sourcePixels, sourceW, sourceH,
+	blendVideo8To8((byte *) surf.getPixels(), surf.pitch,
+		       surf.w, surf.h, sourcePixels, sourceW, sourceH,
 		       offset);
 	for (unsigned i = 0; i < ncolours; i++) {
 		int col = sourcePalette[4 * i] & 0xff;
@@ -63,7 +66,7 @@ void GfxContext8Bit::blitPodImage(byte *sourcePixels, int sourcePitch, int sourc
 
 void GfxContext8Bit::blitVideo(byte *sourcePixels, int sourcePitch, int sourceW, int sourceH,
 			       byte *sourcePalette, Common::Point offset) {
-	blendVideo8To8(_pixels.get(), _pitch, _w, _h, sourcePixels, sourceW, sourceH, offset);
+	blendVideo8To8((byte *) surf.getPixels(), surf.pitch, surf.w, surf.h, sourcePixels, sourceW, sourceH, offset);
 	for (int i = 0; i < 256; i++)
 		if (!_paletteUsed[i]) {
 			_palette[3 * i] = sourcePalette[3 * i];
@@ -81,18 +84,14 @@ void GfxContext8Bit::fade(int val) {
 }
 
 void GfxContext8Bit::clear() {
-	memset(_pixels.get(), 0, _w * _h);
+	surf.clearPalette();
+	surf.clear();
 	memset(_palette, 0, sizeof(_palette));
 	memset(_paletteUsed, 0, sizeof(_paletteUsed));
 }
 
-GfxContext8Bit::GfxContext8Bit(int canvasW, int canvasH) {
-	_w = canvasW;
-	_h = canvasH;
-	_pitch = _w;
-	_pixels = sharedPtrByteAlloc(_w * _h);
-	memset(_palette, 0, sizeof(_palette));
-	memset(_paletteUsed, 0, sizeof(_paletteUsed));
+GfxContext8Bit::GfxContext8Bit(int canvasW, int canvasH) : surf(canvasW, canvasH, Graphics::PixelFormat::createFormatCLUT8()) {
+	clear();
 }
 
 void GfxContext8Bit::renderToScreen(Common::Point viewPoint) {
@@ -100,8 +99,48 @@ void GfxContext8Bit::renderToScreen(Common::Point viewPoint) {
 		g_system->getPaletteManager()->setPalette(_palette, 0, 256);
 	}
 
-	g_system->copyRectToScreen(_pixels.get() + viewPoint.x + _pitch * viewPoint.y, _w, 0, 0,
+	g_system->copyRectToScreen(surf.getBasePtr(viewPoint.x, viewPoint.y), surf.w, 0, 0,
 				   kVideoWidth, kVideoHeight);
 }
 
+byte GfxContext8Bit::findColor(byte r, byte g, byte b) {
+	for (uint i = 1; i < 256; i++)
+		if (_paletteUsed[i] && _palette[3 * i] == r && _palette[3 * i + 1] == g && _palette[3 * i + 2] == b) {
+			return i;
+		}
+	for (uint i = 1; i < 256; i++)
+		if (!_paletteUsed[i]) {
+			_palette[3 * i] = r;
+			_palette[3 * i + 1] = g;
+			_palette[3 * i + 2] = b;
+			_paletteUsed[i] = true;
+			return i;
+		}
+	int diff = 0x40000; int c = 0;
+	for (uint i = 1; i < 256; i++) {
+		int cDiff = (_palette[3 * i] - r) * (_palette[3 * i] - r) + (_palette[3 * i + 1] - g) * (_palette[3 * i + 1] - g)
+			+ (_palette[3 * i + 2] - b) * (_palette[3 * i + 2] - b);
+		if (cDiff < diff) {
+			diff = cDiff;
+			c = i;
+		}
+	}
+
+	return c;
+}
+
+void GfxContext8Bit::renderSubtitle(Common::U32String const& line, Common::Point viewPoint) {
+	int fgColor = findColor(0xff, 0xff, 0xff);
+	int bgColor = findColor(0, 0, 0);
+	const Graphics::Font &font(*FontMan.getFontByUsage(Graphics::FontManager::kLocalizedFont));
+	Common::Rect rect(70 + viewPoint.x, 420 + viewPoint.y, 570 + viewPoint.x, 420 + viewPoint.y + font.getFontHeight());
+	surf.fillRect(rect, bgColor);
+	font.drawString(&surf, line, rect.left, rect.top, rect.width() - 10,
+			fgColor, Graphics::kTextAlignCenter);
+}
+
+void HadeschEngine::wrapSubtitles(const Common::U32String &str, Common::Array<Common::U32String> &lines) {
+	const Graphics::Font &font(*FontMan.getFontByUsage(Graphics::FontManager::kBigGUIFont));
+	font.wordWrapText(str, 500, lines);
+}
 }
diff --git a/engines/hadesch/gfx_context.h b/engines/hadesch/gfx_context.h
index 94e4780c78..9e886f1f15 100644
--- a/engines/hadesch/gfx_context.h
+++ b/engines/hadesch/gfx_context.h
@@ -26,6 +26,7 @@
 
 #include "common/ptr.h"
 #include "common/rect.h"
+#include "graphics/managed_surface.h"
 
 namespace Hadesch {
 class GfxContext {
@@ -36,12 +37,13 @@ public:
 	virtual void blitPodImage(byte *sourcePixels, int sourcePitch, int sourceW, int sourceH,
 				  byte *palette, size_t ncolours, Common::Point offset) = 0;
 	virtual void clear() = 0;
+	virtual void renderSubtitle(const Common::U32String &, Common::Point viewPoint) = 0;
 	virtual void fade(int val) = 0;
 	virtual void renderToScreen(Common::Point viewPoint) = 0;
 	virtual ~GfxContext() {}
 };
 
-class GfxContext8Bit : public GfxContext {
+class GfxContext8Bit : public GfxContext, Common::NonCopyable {
 public:
   	void blitVideo(byte *sourcePixels, int sourcePitch, int sourceW, int sourceH,
 		       byte *palette, Common::Point offset) override;
@@ -50,17 +52,16 @@ public:
 	void clear() override;
 	void fade(int val) override;
 	void renderToScreen(Common::Point viewPoint) override;
+	void renderSubtitle(const Common::U32String &, Common::Point viewPoint) override;
+	byte findColor(byte r, byte g, byte b);
 
 	GfxContext8Bit(int canvasW, int canvasH);
 	~GfxContext8Bit() {}
 
 private:
-	Common::SharedPtr<byte> _pixels;
+	Graphics::ManagedSurface surf;
 	byte _palette[256 * 4];
 	bool _paletteUsed[256];
-	int _pitch;
-	int _w;
-	int _h;
 };
 
 void blendVideo8To8(byte *targetPixels, int targetPitch, int targetW, int targetH,
diff --git a/engines/hadesch/hadesch.cpp b/engines/hadesch/hadesch.cpp
index fd3dced3b2..7f24a722c3 100644
--- a/engines/hadesch/hadesch.cpp
+++ b/engines/hadesch/hadesch.cpp
@@ -85,6 +85,8 @@ HadeschEngine::HadeschEngine(OSystem *system, const ADGameDescription *desc)
 	_isQuitting = false;
 	_isRestoring = false;
 
+	_subtitleID = 0;
+
 	debug("HadeschEngine::ctor");
 }
 
@@ -516,6 +518,22 @@ Common::Error HadeschEngine::run() {
 	_gfxContext = Common::SharedPtr<GfxContext8Bit>(new GfxContext8Bit(2 * kVideoWidth + 10, kVideoHeight + 50));
 	_isInOptions = false;
 
+	ConfMan.registerDefault("subtitles", "false");
+	ConfMan.registerDefault("sfx_volume", 192);
+	ConfMan.registerDefault("music_volume", 192);
+	ConfMan.registerDefault("speech_volume", 192);
+	ConfMan.registerDefault("mute", "false");
+	ConfMan.registerDefault("speech_mute", "false");
+	ConfMan.registerDefault("talkspeed", 60);
+	_mixer->setVolumeForSoundType(_mixer->kMusicSoundType, ConfMan.getInt("music_volume"));
+	_mixer->setVolumeForSoundType(_mixer->kSFXSoundType, ConfMan.getInt("sfx_volume"));
+	_mixer->setVolumeForSoundType(_mixer->kSpeechSoundType, ConfMan.getInt("speech_volume"));
+
+	if (!ConfMan.getBool("subtitles"))
+		_subtitleDelayPerChar = -1;
+	else
+		_subtitleDelayPerChar = 4500 / ConfMan.getInt("talkspeed");
+
 	debug("HadeschEngine: moving to main loop");
 	_nextRoom.clear();
 	int loadSlot = ConfMan.getInt("save_slot");
@@ -855,6 +873,10 @@ void HadeschEngine::moveToRoomReal(RoomId id) {
 	_persistent._roomVisited[id] = true;
 }
 
+int HadeschEngine::genSubtitleID() {
+	return _subtitleID++;
+}
+
 int HadeschEngine::firstAvailableSlot() {
 	for (unsigned slot = 3; ; slot++) {
 		SaveStateDescriptor desc = getMetaEngine().querySaveMetaInfos(_targetName.c_str(), slot);
@@ -926,4 +948,8 @@ bool EventHandlerWrapper::operator==(int b) const {
 	return _eventId == b;
 }
 
+uint32 HadeschEngine::getSubtitleDelayPerChar() const {
+	return _subtitleDelayPerChar;
+}
+
 } // End of namespace Hadesch
diff --git a/engines/hadesch/hadesch.h b/engines/hadesch/hadesch.h
index 54a7110c0a..dec8b319d4 100644
--- a/engines/hadesch/hadesch.h
+++ b/engines/hadesch/hadesch.h
@@ -173,6 +173,9 @@ public:
 
 	Common::Array<HadeschSaveDescriptor> getHadeschSavesList();
 	void deleteSave(int slot);
+	int genSubtitleID();
+	uint32 getSubtitleDelayPerChar() const;
+	void wrapSubtitles(const Common::U32String &str, Common::Array<Common::U32String> &lines);
 
 private:
 	void addTimer(EventHandlerWrapper event, int32 start_time, int period,
@@ -219,6 +222,8 @@ private:
 	Common::Array<RoomId> _nextRoom;
 	bool _isRestoring;
   	bool _isQuitting;
+	int _subtitleID;
+	int _subtitleDelayPerChar;
 
 	// For freeing purposes
 	Common::Array <Graphics::MacCursor *> _macCursors;
diff --git a/engines/hadesch/video.cpp b/engines/hadesch/video.cpp
index a08132ea95..ddc2b2cb1e 100644
--- a/engines/hadesch/video.cpp
+++ b/engines/hadesch/video.cpp
@@ -32,6 +32,7 @@
 #include "audio/decoders/aiff.h"
 #include "hadesch/pod_file.h"
 #include "hadesch/baptr.h"
+#include "common/translation.h"
 
 static const int kVideoMaxW = 1280;
 static const int kVideoMaxH = 480;
@@ -519,6 +520,19 @@ void VideoRoom::nextFrame(Common::SharedPtr<GfxContext> context, int time, bool
 			   layersIterator->colorScale, layersIterator->scale);
 	}
 
+	if (stopVideo) {
+		_subtitles.clear();
+		_countQueuedSubtitles.clear();
+	}
+
+	while (!_subtitles.empty() && time > _subtitles.front().maxTime) {
+		_countQueuedSubtitles[_subtitles.front().ID]--;
+		_subtitles.pop();
+	}
+
+	if (_subtitles.empty())
+		_countQueuedSubtitles.clear();
+
 	if (_videoDecoder && (_videoDecoder->endOfVideo() || (stopVideo && !_mouseEnabled))) {
 		debug("videoEnd: %s", _videoDecoderEndEvent.getDebugString().c_str());
 		_videoDecoder.reset();
@@ -532,6 +546,7 @@ void VideoRoom::nextFrame(Common::SharedPtr<GfxContext> context, int time, bool
 		bool soundFinished = !g_system->getMixer()->isSoundHandleActive(_anims[i]._soundHandle);
 		const LayerId &animName = _anims[i]._animName;
 		bool animFinished = isAnimationFinished(animName, time);
+		bool subFinished = (_countQueuedSubtitles.empty() || _countQueuedSubtitles[_anims[i]._subtitleID] == 0);
 		bool stopped = stopVideo && _anims[i]._skippable;
 
 		if (stopped) {
@@ -542,7 +557,7 @@ void VideoRoom::nextFrame(Common::SharedPtr<GfxContext> context, int time, bool
 						it->renderable->selectFrame(-1);
 		}
 
-		if ((soundFinished && animFinished) || stopped) {
+		if ((soundFinished && animFinished && subFinished) || stopped) {
 			_anims[i]._finished = true;
 			if (!_anims[i]._keepLastFrame)
 				setLayerEnabled(animName, false);
@@ -559,6 +574,9 @@ void VideoRoom::nextFrame(Common::SharedPtr<GfxContext> context, int time, bool
 	}
 
 	context->fade(_finalFade);
+	if (!_subtitles.empty())
+		context->renderSubtitle(_subtitles.front().line, viewPoint);
+	
 	context->renderToScreen(viewPoint);
 }
 
@@ -789,7 +807,7 @@ Audio::RewindableAudioStream *VideoRoom::getAudioStream(const Common::String &so
 }
 
 void VideoRoom::playSoundInternal(const Common::String &soundName, EventHandlerWrapper callbackEvent, bool loop,
-				  bool skippable, Audio::Mixer::SoundType soundType) {
+				  bool skippable, Audio::Mixer::SoundType soundType, int subtitleID) {
 	Audio::RewindableAudioStream *rewSoundStream;
 	Audio::AudioStream *soundStream;
 	Animation anim;
@@ -801,6 +819,7 @@ void VideoRoom::playSoundInternal(const Common::String &soundName, EventHandlerW
 	anim._finished = false;
 	anim._keepLastFrame = false;
 	anim._skippable = skippable;
+	anim._subtitleID = subtitleID;
 	g_system->getMixer()->playStream(soundType, &anim._soundHandle, soundStream,
 					 -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::YES);
 	_anims.push_back(anim);
@@ -816,7 +835,9 @@ void VideoRoom::playMusic(const Common::String &soundName, EventHandlerWrapper c
 
 void VideoRoom::playSpeech(const TranscribedSound &sound,
 				    EventHandlerWrapper callbackEvent) {
-	playSoundInternal(sound.soundName, callbackEvent, false, true, Audio::Mixer::kSpeechSoundType);
+	int subID = g_vm->genSubtitleID();
+	playSoundInternal(sound.soundName, callbackEvent, false, true, Audio::Mixer::kSpeechSoundType, subID);
+	playSubtitles(sound.transcript, subID);
 }
 
 void VideoRoom::playSFXLoop(const Common::String &soundName) {
@@ -833,7 +854,7 @@ void VideoRoom::playAnimWithSoundInternal(const LayerId &animName,
 					  int zValue,
 					  PlayAnimParams params,
 					  EventHandlerWrapper callbackEvent,
-					  Common::Point offset) {
+					  Common::Point offset, int subtitleID) {
 	Audio::AudioStream *soundStream;
 
 	if (!doesLayerExist(animName)) {
@@ -854,6 +875,7 @@ void VideoRoom::playAnimWithSoundInternal(const LayerId &animName,
 	anim._finished = false;
 	anim._keepLastFrame = params.getKeepLastFrame();
 	anim._skippable = false;
+	anim._subtitleID = subtitleID;
 	g_system->getMixer()->playStream(soundType, &anim._soundHandle, soundStream,
 					 -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::YES);
 	_anims.push_back(anim);
@@ -865,7 +887,9 @@ void VideoRoom::playAnimWithSpeech(const LayerId &animName,
 				   PlayAnimParams params,
 				   EventHandlerWrapper callbackEvent,
 				   Common::Point offset) {
-	playAnimWithSoundInternal(animName, sound.soundName, Audio::Mixer::kSpeechSoundType, zValue, params, callbackEvent, offset);
+	int subID = g_vm->genSubtitleID();
+	playAnimWithSoundInternal(animName, sound.soundName, Audio::Mixer::kSpeechSoundType, zValue, params, callbackEvent, offset, subID);
+	playSubtitles(sound.transcript, subID);
 }
 
 void VideoRoom::playAnimWithSFX(const LayerId &animName,
@@ -1068,4 +1092,23 @@ void VideoRoom::renderStringCentered(const Common::String &font, const Common::U
 	int width = computeStringWidth(font, str, fontDelta);
 	renderString(font, str, centerPos - Common::Point(width / 2, 0), zVal, fontDelta, extraId);
 }
+
+void VideoRoom::playSubtitles(const char *text, int subID) {
+	int delay = g_vm->getSubtitleDelayPerChar();
+	if (delay <= 0)
+		return;
+	Common::U32String s = _(text);
+	Common::Array<Common::U32String> lines;
+	int32 countTime = g_vm->getCurrentTime();
+	g_vm->wrapSubtitles(s, lines);
+	for (uint i = 0; i < lines.size(); i++) {
+		SubtitleLine l;
+		l.line = lines[i];
+		l.ID = subID;
+		countTime += delay * MAX<uint>(l.line.size(), 20);
+		l.maxTime = countTime;
+		_subtitles.push(l);
+		_countQueuedSubtitles[subID]++;
+	} 
+}
 }
diff --git a/engines/hadesch/video.h b/engines/hadesch/video.h
index 830e9a5504..eb6b026f17 100644
--- a/engines/hadesch/video.h
+++ b/engines/hadesch/video.h
@@ -39,6 +39,7 @@
 #include "hadesch/event.h"
 #include "hadesch/hotzone.h"
 #include "hadesch/table.h"
+#include "common/queue.h"
 
 namespace Video {
 class SmackerDecoder;
@@ -118,6 +119,7 @@ struct Animation {
 	bool _finished;
 	bool _keepLastFrame;
 	bool _skippable;
+	int _subtitleID;
 };
 
 class PlayAnimParams {
@@ -305,6 +307,7 @@ public:
 	void pause();
 	void unpause();
 	void finish();
+	void cancelAllSubtitles();
 	void setViewportOffset(Common::Point vp) {
 		_viewportOffset = vp;
 	}
@@ -322,13 +325,21 @@ private:
 		int scale; // From 0 to 100
 	};
 
+	struct SubtitleLine {
+		Common::U32String line;
+		int32 maxTime;
+		int ID;
+	};
+
 	void playAnimWithSoundInternal(const LayerId &animName,
 				       const Common::String &soundName,
 				       Audio::Mixer::SoundType soundType,
 				       int zValue,
 				       PlayAnimParams params,
-				       EventHandlerWrapper callbackEvent = EventHandlerWrapper(),
-				       Common::Point offset = Common::Point(0, 0));
+				       EventHandlerWrapper callbackEvent,
+				       Common::Point offset,
+				       int subID = -1);
+	void playSubtitles(const char *text, int subID);
 	void addLayer(Renderable *renderable, const LayerId &name,
 		      int zValue,
 		      bool isEnabled = true, Common::Point offset = Common::Point(0, 0));
@@ -339,7 +350,7 @@ private:
 	Common::String mapAsset(const LayerId &name);
 	void addAnimLayerInternal(const LayerId &name, int zValue, Common::Point offset = Common::Point(0, 0));
 	void playSoundInternal(const Common::String &soundName, EventHandlerWrapper callbackEvent, bool loop,
-			       bool skippable, Audio::Mixer::SoundType soundType);
+			       bool skippable, Audio::Mixer::SoundType soundType, int subtitleID = -1);
 	static int layerComparator (const Layer &a, const Layer &b);
 	void loadFontWidth(const Common::String &font);
 
@@ -383,6 +394,8 @@ private:
 	int _videoZ;
 	Common::SharedPtr<PodFile> _podFile;
 	Common::HashMap<Common::String, Common::Array<int> > _fontWidths;
+	Common::Queue<SubtitleLine> _subtitles;
+	Common::HashMap<int, int> _countQueuedSubtitles;
 	TextTable _assetMap;
 	bool _mouseEnabled;
 


Commit: 0d39e96f55604098b9cf4b00583c337686b2dfc3
    https://github.com/scummvm/scummvm/commit/0d39e96f55604098b9cf4b00583c337686b2dfc3
Author: Vladimir Serbinenko (phcoder at google.com)
Date: 2020-12-17T09:49:18+01:00

Commit Message:
COMMON: Make TranslationManager reusable.

This makes it possible to reuse TranslationManager with different
files.

Changed paths:
    base/main.cpp
    common/translation.cpp
    common/translation.h
    devtools/create_translations/create_translations.cpp
    po/module.mk


diff --git a/base/main.cpp b/base/main.cpp
index d2b62123ed..65800f1164 100644
--- a/base/main.cpp
+++ b/base/main.cpp
@@ -697,7 +697,7 @@ extern "C" int scummvm_main(int argc, const char * const argv[]) {
 #endif
 	Common::SearchManager::destroy();
 #ifdef USE_TRANSLATION
-	Common::TranslationManager::destroy();
+	Common::MainTranslationManager::destroy();
 #endif
 	MusicManager::destroy();
 	Graphics::CursorManager::destroy();
diff --git a/common/translation.cpp b/common/translation.cpp
index 99b1fdbc7b..3c5cc5f28e 100644
--- a/common/translation.cpp
+++ b/common/translation.cpp
@@ -39,14 +39,14 @@
 
 namespace Common {
 
-DECLARE_SINGLETON(TranslationManager);
+DECLARE_SINGLETON(MainTranslationManager);
 
 bool operator<(const TLanguage &l, const TLanguage &r) {
 	return l.name < r.name;
 }
 
-TranslationManager::TranslationManager() : _currentLang(-1) {
-	loadTranslationsInfoDat();
+TranslationManager::TranslationManager(const Common::String &fileName) : _currentLang(-1) {
+	loadTranslationsInfoDat(fileName);
 
 	// Set the default language
 	setLanguage("");
@@ -230,7 +230,7 @@ bool TranslationManager::openTranslationsFile(File &inFile) {
 
 	// Then try to open it using the SearchMan.
 	ArchiveMemberList fileList;
-	SearchMan.listMatchingMembers(fileList, "translations.dat");
+	SearchMan.listMatchingMembers(fileList, _translationsFileName);
 	for (ArchiveMemberList::iterator it = fileList.begin(); it != fileList.end(); ++it) {
 		ArchiveMember       const &m      = **it;
 		SeekableReadStream *const  stream = m.createReadStream();
@@ -251,7 +251,7 @@ bool TranslationManager::openTranslationsFile(const FSNode &node, File &inFile,
 	// Check if we can find the file in this directory
 	// Since File::open(FSNode) makes all the needed tests, it is not really
 	// necessary to make them here. But it avoid printing warnings.
-	FSNode fileNode = node.getChild("translations.dat");
+	FSNode fileNode = node.getChild(_translationsFileName);
 	if (fileNode.exists() && fileNode.isReadable() && !fileNode.isDirectory()) {
 		if (inFile.open(fileNode)) {
 			if (checkHeader(inFile))
@@ -278,10 +278,11 @@ bool TranslationManager::openTranslationsFile(const FSNode &node, File &inFile,
 	return false;
 }
 
-void TranslationManager::loadTranslationsInfoDat() {
+void TranslationManager::loadTranslationsInfoDat(const Common::String &name) {
 	File in;
+	_translationsFileName = name;
 	if (!openTranslationsFile(in)) {
-		warning("You are missing a valid 'translations.dat' file. GUI translation will not be available");
+		warning("You are missing a valid '%s' file. GUI translation will not be available", name.c_str());
 		return;
 	}
 
diff --git a/common/translation.h b/common/translation.h
index 5cd8f6b16b..5662454434 100644
--- a/common/translation.h
+++ b/common/translation.h
@@ -85,14 +85,14 @@ struct PoMessageEntry {
 /**
  * Message translation manager.
  */
-class TranslationManager : public Singleton<TranslationManager> {
+class TranslationManager : public NonCopyable {
 public:
 	/**
 	 * Constructor that sets the current language to the default language.
 	 *
 	 * The default language is the detected system language.
 	 */
-	TranslationManager();
+	TranslationManager(const Common::String &fileName);
 	~TranslationManager();
 
 	/**
@@ -221,7 +221,7 @@ private:
 	/**
 	 * Load the list of languages from the translations.dat file.
 	 */
-	void loadTranslationsInfoDat();
+	void loadTranslationsInfoDat(const Common::String &name);
 
 	/**
 	 * Load the translation for the given language from the translations.dat file.
@@ -242,13 +242,20 @@ private:
 	Array<PoMessageEntry> _currentTranslationMessages;
 	String _currentCharset;
 	int _currentLang;
+	Common::String _translationsFileName;
+};
+
+class MainTranslationManager : public TranslationManager, public Singleton<MainTranslationManager> {
+public:
+	MainTranslationManager() : TranslationManager("translations.dat") {}
+	~MainTranslationManager() {}
 };
 
 /** @} */
 
 } // End of namespace Common
 
-#define TransMan Common::TranslationManager::instance()
+#define TransMan Common::MainTranslationManager::instance()
 
 #define _(str) TransMan.getTranslation(str)
 #define _c(str, context) TransMan.getTranslation(str, context)
diff --git a/devtools/create_translations/create_translations.cpp b/devtools/create_translations/create_translations.cpp
index db6af5b3ac..713387588e 100644
--- a/devtools/create_translations/create_translations.cpp
+++ b/devtools/create_translations/create_translations.cpp
@@ -110,7 +110,7 @@ int main(int argc, char *argv[]) {
 	PoMessageList messageIds;
 	std::vector<PoMessageEntryList *> translations;
 	int numLangs = 0;
-	for (int i = 1; i < argc; ++i) {
+	for (int i = 2; i < argc; ++i) {
 		// Check file extension
 		int len = strlen(argv[i]);
 		if (scumm_stricmp(argv[i] + len - 2, "po") == 0) {
@@ -124,7 +124,7 @@ int main(int argc, char *argv[]) {
 
 	if (!numLangs) {
 		fprintf(stderr, "ERROR: No valid translation files\n");
-		fprintf(stderr, "usage: create_translations lang1.po [lang2.po ...]\n");
+		fprintf(stderr, "usage: create_translations OUTPUT lang1.po [lang2.po ...]\n");
 		return -1;
 	}
 
@@ -147,7 +147,7 @@ int main(int argc, char *argv[]) {
 	// for (i = 0; i < DATAALIGNMENT; i++)
 	//	padBuf[i] = 0;
 
-	outFile = fopen("translations.dat", "wb");
+	outFile = fopen(argv[1], "wb");
 
 	// Write header
 	fwrite("TRANSLATIONS", 12, 1, outFile);
diff --git a/po/module.mk b/po/module.mk
index e9b885be3b..87105f10a8 100644
--- a/po/module.mk
+++ b/po/module.mk
@@ -36,7 +36,7 @@ updatepot:
 	fi;
 
 translations-dat: devtools/create_translations
-	devtools/create_translations/create_translations $(POFILES)
+	devtools/create_translations/create_translations translations.dat $(POFILES)
 	mv translations.dat $(srcdir)/gui/themes/
 
 update-translations: updatepot $(POFILES) translations-dat


Commit: b8a5483047b9a46e389d887ddd5029a81173f2c4
    https://github.com/scummvm/scummvm/commit/b8a5483047b9a46e389d887ddd5029a81173f2c4
Author: Vladimir Serbinenko (phcoder at google.com)
Date: 2020-12-17T09:49:18+01:00

Commit Message:
HADESCH: Use separate file for translations

Changed paths:
    Makefile.common
    backends/platform/symbian/S60v3/scummvm-CVS-SymbianS60v3.pkg
    backends/platform/symbian/S60v3/scummvm-CVS-SymbianS60v3_split.pkg
    backends/platform/symbian/UIQ3/scummvm-CVS-SymbianUIQ3.pkg
    backends/platform/symbian/UIQ3/scummvm-CVS-SymbianUIQ3_split.pkg
    devtools/create_project/xcode.cpp
    dists/scummvm.rc
    engines/hadesch/hadesch.cpp
    engines/hadesch/hadesch.h
    engines/hadesch/module.mk
    engines/hadesch/video.cpp


diff --git a/Makefile.common b/Makefile.common
index 188c231f41..b22d0abe31 100644
--- a/Makefile.common
+++ b/Makefile.common
@@ -374,6 +374,9 @@ endif
 ifdef ENABLE_DRASCULA
 DIST_FILES_ENGINEDATA+=drascula.dat
 endif
+ifdef ENABLE_HADESCH
+DIST_FILES_ENGINEDATA+=hadesch_translations.dat
+endif
 ifdef ENABLE_HUGO
 DIST_FILES_ENGINEDATA+=hugo.dat
 endif
diff --git a/backends/platform/symbian/S60v3/scummvm-CVS-SymbianS60v3.pkg b/backends/platform/symbian/S60v3/scummvm-CVS-SymbianS60v3.pkg
index e0449fa0b0..0ba151d177 100644
--- a/backends/platform/symbian/S60v3/scummvm-CVS-SymbianS60v3.pkg
+++ b/backends/platform/symbian/S60v3/scummvm-CVS-SymbianS60v3.pkg
@@ -64,6 +64,7 @@
 "..\..\..\..\dists\engine-data\drascula.dat"-"c:\data\scummvm\drascula.dat"
 "..\..\..\..\dists\engine-data\encoding.dat"-"c:\system\apps\scummvm\encoding.dat"
 "..\..\..\..\dists\engine-data\fonts.dat"-"c:\data\scummvm\fonts.dat"
+"..\..\..\..\dists\engine-data\hadesch_translations.dat"-"c:\data\scummvm\hadesch_translations.dat"
 "..\..\..\..\dists\engine-data\hugo.dat"-"c:\data\scummvm\hugo.dat"
 "..\..\..\..\dists\engine-data\kyra.dat"-"c:\data\scummvm\kyra.dat"
 "..\..\..\..\dists\engine-data\lure.dat"-"c:\data\scummvm\lure.dat"
diff --git a/backends/platform/symbian/S60v3/scummvm-CVS-SymbianS60v3_split.pkg b/backends/platform/symbian/S60v3/scummvm-CVS-SymbianS60v3_split.pkg
index 3b7ad39671..b846f6ada4 100644
--- a/backends/platform/symbian/S60v3/scummvm-CVS-SymbianS60v3_split.pkg
+++ b/backends/platform/symbian/S60v3/scummvm-CVS-SymbianS60v3_split.pkg
@@ -69,6 +69,7 @@
 "..\..\..\..\dists\engine-data\drascula.dat"-"c:\data\scummvm\drascula.dat"
 "..\..\..\..\dists\engine-data\encoding.dat"-"c:\data\scummvm\encoding.dat"
 "..\..\..\..\dists\engine-data\fonts.dat"-"c:\data\scummvm\fonts.dat"
+"..\..\..\..\dists\engine-data\hadesch_translations.dat"-"c:\data\scummvm\hadesch_translations.dat"
 "..\..\..\..\dists\engine-data\hugo.dat"-"c:\data\scummvm\hugo.dat"
 "..\..\..\..\dists\engine-data\kyra.dat"-"c:\data\scummvm\kyra.dat"
 "..\..\..\..\dists\engine-data\lure.dat"-"c:\data\scummvm\lure.dat"
diff --git a/backends/platform/symbian/UIQ3/scummvm-CVS-SymbianUIQ3.pkg b/backends/platform/symbian/UIQ3/scummvm-CVS-SymbianUIQ3.pkg
index d976f2a062..c4e5671150 100644
--- a/backends/platform/symbian/UIQ3/scummvm-CVS-SymbianUIQ3.pkg
+++ b/backends/platform/symbian/UIQ3/scummvm-CVS-SymbianUIQ3.pkg
@@ -62,6 +62,7 @@
 "..\..\..\..\dists\engine-data\drascula.dat"-"c:\shared\scummvm\drascula.dat"
 "..\..\..\..\dists\engine-data\encoding.dat"-"c:\shared\scummvm\encoding.dat"
 "..\..\..\..\dists\engine-data\fonts.dat"-"c:\shared\scummvm\fonts.dat"
+"..\..\..\..\dists\engine-data\hadesch_translations.dat"-"c:\shared\scummvm\hadesch_translations.dat"
 "..\..\..\..\dists\engine-data\hugo.dat"-"c:\shared\scummvm\hugo.dat"
 "..\..\..\..\dists\engine-data\kyra.dat"-"c:\shared\scummvm\kyra.dat"
 "..\..\..\..\dists\engine-data\lure.dat"-"c:\shared\scummvm\lure.dat"
diff --git a/backends/platform/symbian/UIQ3/scummvm-CVS-SymbianUIQ3_split.pkg b/backends/platform/symbian/UIQ3/scummvm-CVS-SymbianUIQ3_split.pkg
index 1c7843d79e..808c60aab3 100644
--- a/backends/platform/symbian/UIQ3/scummvm-CVS-SymbianUIQ3_split.pkg
+++ b/backends/platform/symbian/UIQ3/scummvm-CVS-SymbianUIQ3_split.pkg
@@ -70,6 +70,7 @@
 "..\..\..\..\dists\engine-data\drascula.dat"-"c:\shared\scummvm\drascula.dat"
 "..\..\..\..\dists\engine-data\encoding.dat"-"c:\shared\scummvm\encoding.dat"
 "..\..\..\..\dists\engine-data\fonts.dat"-"c:\shared\scummvm\fonts.dat"
+"..\..\..\..\dists\engine-data\hadesch_translations.dat"-"c:\shared\scummvm\hadesch_translations.dat"
 "..\..\..\..\dists\engine-data\hugo.dat"-"c:\shared\scummvm\hugo.dat"
 "..\..\..\..\dists\engine-data\kyra.dat"-"c:\shared\scummvm\kyra.dat"
 "..\..\..\..\dists\engine-data\lure.dat"-"c:\shared\scummvm\lure.dat"
diff --git a/devtools/create_project/xcode.cpp b/devtools/create_project/xcode.cpp
index efb452b196..d924a82810 100644
--- a/devtools/create_project/xcode.cpp
+++ b/devtools/create_project/xcode.cpp
@@ -824,6 +824,7 @@ XcodeProvider::ValueList& XcodeProvider::getResourceFiles() const {
 		files.push_back("dists/engine-data/drascula.dat");
 		files.push_back("dists/engine-data/encoding.dat");
 		files.push_back("dists/engine-data/fonts.dat");
+		files.push_back("dists/engine-data/hadesch_translations.dat");
 		files.push_back("dists/engine-data/hugo.dat");
 		files.push_back("dists/engine-data/kyra.dat");
 		files.push_back("dists/engine-data/lure.dat");
diff --git a/dists/scummvm.rc b/dists/scummvm.rc
index 2761c250a3..d6d02d1d0f 100644
--- a/dists/scummvm.rc
+++ b/dists/scummvm.rc
@@ -58,6 +58,9 @@ cryomni3d.dat          FILE    "dists/engine-data/cryomni3d.dat"
 #if PLUGIN_ENABLED_STATIC(DRASCULA)
 drascula.dat           FILE    "dists/engine-data/drascula.dat"
 #endif
+#if PLUGIN_ENABLED_STATIC(HADESCH)
+hadesch_translations.dat          FILE    "dists/engine-data/hadesch_translations.dat"
+#endif
 #if PLUGIN_ENABLED_STATIC(HUGO)
 hugo.dat               FILE    "dists/engine-data/hugo.dat"
 #endif
diff --git a/engines/hadesch/hadesch.cpp b/engines/hadesch/hadesch.cpp
index 7f24a722c3..4d8d3501de 100644
--- a/engines/hadesch/hadesch.cpp
+++ b/engines/hadesch/hadesch.cpp
@@ -101,6 +101,10 @@ HadeschEngine::~HadeschEngine() {
 		delete _macCursors[i];
 		_macCursors[i] = nullptr;
 	}
+
+#ifdef USE_TRANSLATION
+	delete _transMan;
+#endif
 }
 
 void HadeschEngine::setVideoRoom(Common::SharedPtr<VideoRoom> room,
@@ -461,9 +465,22 @@ void HadeschEngine::exitOptions() {
 	_sceneVideoRoom->unpause();
 }
 
+Common::U32String HadeschEngine::translate(const Common::String &str) {
+#ifdef USE_TRANSLATION
+	return _transMan->getTranslation(str);
+#else
+	return str.decode();
+#endif
+}
+
 Common::Error HadeschEngine::run() {
 	debug("HadeschEngine::run");
 
+#ifdef USE_TRANSLATION
+	_transMan = new Common::TranslationManager("hadesch_translations.dat");
+	_transMan->setLanguage(TransMan.getCurrentLanguage());
+#endif
+
 	const Common::FSNode gameDataDir(ConfMan.get("path"));
 	SearchMan.addSubDirectoryMatching(gameDataDir, "WIN9x");
 
diff --git a/engines/hadesch/hadesch.h b/engines/hadesch/hadesch.h
index dec8b319d4..e4fc4d0893 100644
--- a/engines/hadesch/hadesch.h
+++ b/engines/hadesch/hadesch.h
@@ -40,6 +40,7 @@
 #include "hadesch/event.h"
 #include "hadesch/herobelt.h"
 #include "hadesch/persistent.h"
+#include "common/translation.h"
 
 struct ADGameDescription;
 
@@ -176,6 +177,7 @@ public:
 	int genSubtitleID();
 	uint32 getSubtitleDelayPerChar() const;
 	void wrapSubtitles(const Common::U32String &str, Common::Array<Common::U32String> &lines);
+	Common::U32String translate(const Common::String &str);
 
 private:
 	void addTimer(EventHandlerWrapper event, int32 start_time, int period,
@@ -225,6 +227,10 @@ private:
 	int _subtitleID;
 	int _subtitleDelayPerChar;
 
+#ifdef USE_TRANSLATION
+	Common::TranslationManager *_transMan;
+#endif
+
 	// For freeing purposes
 	Common::Array <Graphics::MacCursor *> _macCursors;
 	Common::Array <Graphics::WinCursorGroup *> _winCursors;
diff --git a/engines/hadesch/module.mk b/engines/hadesch/module.mk
index da71321b11..99f80a0da2 100644
--- a/engines/hadesch/module.mk
+++ b/engines/hadesch/module.mk
@@ -52,3 +52,55 @@ endif
 
 # Include common rules
 include $(srcdir)/rules.mk
+
+ifneq "$(HADESCH_RULES_INCLUDED)" "1"
+
+HADESCH_RULES_INCLUDED := 1
+HADESCH_POTFILE := $(srcdir)/engines/hadesch/po/hadesch.pot
+HADESCH_POFILES := $(wildcard $(srcdir)/engines/hadesch/po/*.po)
+
+hadesch-updatepot:
+	cat $(srcdir)/engines/hadesch/po/POTFILES_hadesch | \
+	xgettext -f - -D $(srcdir) -d hadesch --c++ -k_ -k_s -k_c:1,2c -k_sc:1,2c -kTranscribedSound:2 --add-comments=I18N\
+		-kDECLARE_TRANSLATION_ADDITIONAL_CONTEXT:1,2c -o $(HADESCH_POTFILE) \
+		--copyright-holder="ScummVM Team" --package-name=ScummVM \
+		--package-version=$(VERSION) --msgid-bugs-address=scummvm-devel at lists.scummvm.org -o $(HADESCH_POTFILE)_
+
+	sed -e 's/SOME DESCRIPTIVE TITLE/LANGUAGE translation for ScummVM/' \
+		-e 's/UTF-8/CHARSET/' -e 's/PACKAGE/ScummVM/' $(HADESCH_POTFILE)_ > $(HADESCH_POTFILE).new
+
+	rm $(HADESCH_POTFILE)_
+	if test -f $(HADESCH_POTFILE); then \
+		sed -f $(srcdir)/po/remove-potcdate.sed < $(HADESCH_POTFILE) > $(HADESCH_POTFILE).1 && \
+		sed -f $(srcdir)/po/remove-potcdate.sed < $(HADESCH_POTFILE).new > $(HADESCH_POTFILE).2 && \
+		if cmp $(HADESCH_POTFILE).1 $(HADESCH_POTFILE).2 >/dev/null 2>&1; then \
+			rm -f $(HADESCH_POTFILE).new; \
+		else \
+			rm -f $(HADESCH_POTFILE) && \
+			mv -f $(HADESCH_POTFILE).new $(HADESCH_POTFILE); \
+		fi; \
+		rm -f $(HADESCH_POTFILE).1 $(HADESCH_POTFILE).2; \
+	else \
+		mv -f $(HADESCH_POTFILE).new $(HADESCH_POTFILE); \
+	fi;
+
+engines/hadesch/po/%.po: $(HADESCH_POTFILE)
+	msgmerge $@ $(HADESCH_POTFILE) -o $@.new
+	if cmp $@ $@.new >/dev/null 2>&1; then \
+		rm -f $@.new; \
+	else \
+		mv -f $@.new $@; \
+	fi;
+
+hadesch-translations-dat: devtools/create_translations
+	devtools/create_translations/create_translations hadesch_translations.dat $(HADESCH_POFILES)
+	mv hadesch_translations.dat $(srcdir)/dists/engine-data/hadesch_translations.dat
+
+update-hadesch-translations: hadesch-updatepot $(HADESCH_POFILES) hadesch-translations-dat
+
+update-hadesch-translations: hadesch-updatepot $(HADESCH_POFILES)
+	@$(foreach file, $(HADESCH_POFILES), echo -n $(notdir $(basename $(file)))": ";msgfmt --statistic $(file);)
+	@rm -f messages.mo
+
+.PHONY: updatehadeschpot hadesch-translations-dat update-hadesch-translations
+endif # HADESCH_RULES_INCLUDED
diff --git a/engines/hadesch/video.cpp b/engines/hadesch/video.cpp
index ddc2b2cb1e..ed303fd03b 100644
--- a/engines/hadesch/video.cpp
+++ b/engines/hadesch/video.cpp
@@ -1097,7 +1097,7 @@ void VideoRoom::playSubtitles(const char *text, int subID) {
 	int delay = g_vm->getSubtitleDelayPerChar();
 	if (delay <= 0)
 		return;
-	Common::U32String s = _(text);
+	Common::U32String s = g_vm->translate(text);
 	Common::Array<Common::U32String> lines;
 	int32 countTime = g_vm->getCurrentTime();
 	g_vm->wrapSubtitles(s, lines);




More information about the Scummvm-git-logs mailing list