Index: scummvm-bspsx/common/util.h
===================================================================
--- scummvm-bspsx/common/util.h	(revision 38886)
+++ scummvm-bspsx/common/util.h	(working copy)
@@ -201,6 +201,7 @@
 	kPlatformApple2GS,
 	kPlatformPC98,
 	kPlatformWii,
+	kPlatformPSX,
 
 	kPlatformUnknown = -1
 };
Index: scummvm-bspsx/common/util.cpp
===================================================================
--- scummvm-bspsx/common/util.cpp	(revision 38886)
+++ scummvm-bspsx/common/util.cpp	(working copy)
@@ -271,6 +271,7 @@
 	{"nes", "nes", "nes", "NES", kPlatformNES},
 	{"segacd", "segacd", "sega", "SegaCD", kPlatformSegaCD},
 	{"windows", "win", "win", "Windows", kPlatformWindows},
+	{"playstation", "psx", "PSX", "Playstation", kPlatformPSX},
 
 
 	{0, 0, 0, "Default", kPlatformUnknown}
Index: scummvm-bspsx/engines/sword1/module.mk
===================================================================
--- scummvm-bspsx/engines/sword1/module.mk	(revision 38886)
+++ scummvm-bspsx/engines/sword1/module.mk	(working copy)
@@ -18,7 +18,8 @@
 	sound.o \
 	staticres.o \
 	sword1.o \
-	text.o
+	text.o \
+	vag.o
 
 # This module can be built as a plugin
 ifeq ($(ENABLE_SWORD1), DYNAMIC_PLUGIN)
Index: scummvm-bspsx/engines/sword1/vag.cpp
===================================================================
--- scummvm-bspsx/engines/sword1/vag.cpp	(revision 0)
+++ scummvm-bspsx/engines/sword1/vag.cpp	(revision 0)
@@ -0,0 +1,114 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+ 
+#include "sword1/vag.h"
+
+namespace Sword1 {
+
+VagStream::VagStream(Common::SeekableReadStream *stream, bool loop) : _stream(stream) {
+	_samplesRemaining = 0;
+	_predictor = 0;
+	_s1 = _s2 = 0.0;
+	_loop = loop;
+}
+
+
+VagStream::~VagStream() {
+}
+
+double f[5][2] = { { 0.0, 0.0 },
+                    {  60.0 / 64.0,  0.0 },
+                    {  115.0 / 64.0, -52.0 / 64.0 },
+                    {  98.0 / 64.0, -55.0 / 64.0 },
+                    {  122.0 / 64.0, -60.0 / 64.0 } };
+
+int VagStream::readBuffer(int16 *buffer, const int numSamples) {
+	int32 samplesDecoded = 0;
+	
+	if (_samplesRemaining) {
+		byte i = 0;
+		
+		for (i = 28 - _samplesRemaining; i < 28 && samplesDecoded < numSamples; i++) {
+			_samples[i] = _samples[i] + _s1 * f[_predictor][0] + _s2 * f[_predictor][1];
+			_s2 = _s1;
+			_s1 = _samples[i];
+			int16 d = (int) (_samples[i] + 0.5);
+			buffer[samplesDecoded] = d;
+			samplesDecoded++;
+		}
+		
+		assert(i == 28); // We're screwed if this fails :P
+		_samplesRemaining = 0;
+	}
+	
+	while (samplesDecoded < numSamples) {
+		byte i = 0;
+	
+		_predictor = _stream->readByte();
+		byte shift = _predictor & 0xf;
+		_predictor >>= 4;
+	
+		if (_stream->readByte() == 7)
+			return samplesDecoded;
+	
+		for (i = 0; i < 28; i += 2) {
+			byte d = _stream->readByte();
+			int16 s = (d & 0xf) << 12;
+			if (s & 0x8000)
+				s |= 0xffff0000;
+			_samples[i] = (double)(s >> shift);
+			s = (d & 0xf0) << 8;
+			if (s & 0x8000)
+				s |= 0xffff0000;
+			_samples[i + 1] = (double)(s >> shift);
+		}
+	
+		for (i = 0; i < 28 && samplesDecoded < numSamples; i++) {
+			_samples[i] = _samples[i] + _s1 * f[_predictor][0] + _s2 * f[_predictor][1];
+			_s2 = _s1;
+			_s1 = _samples[i];
+			int16 d = (int) (_samples[i] + 0.5);
+			buffer[samplesDecoded] = d;
+			samplesDecoded++;
+		}
+		
+		if (i != 27)
+			_samplesRemaining = 28 - i;
+	}
+
+	if(_loop && _stream->eos())
+		rewind();
+
+	return samplesDecoded;
+}
+
+void VagStream::rewind() {
+	_stream->seek(0);
+	_samplesRemaining = 0;
+	_predictor = 0;
+	_s1 = _s2 = 0.0;
+}
+
+}
Index: scummvm-bspsx/engines/sword1/detection.cpp
===================================================================
--- scummvm-bspsx/engines/sword1/detection.cpp	(revision 38886)
+++ scummvm-bspsx/engines/sword1/detection.cpp	(working copy)
@@ -45,6 +45,8 @@
 	{"sword1mac", "Broken Sword 1: The Shadow of the Templars (Mac)"};
 static const PlainGameDescriptor sword1MacDemoSettings =
 	{"sword1macdemo", "Broken Sword 1: The Shadow of the Templars (Mac demo)"};
+static const PlainGameDescriptor sword1PSXSettings =
+	{"sword1psx", "Broken Sword 1: The Shadow of the Templars (PlayStation)"};
 
 // check these subdirectories (if present)
 static const char *g_dirNames[] = {	"clusters",	"speech" };
@@ -52,20 +54,23 @@
 #define NUM_COMMON_FILES_TO_CHECK 1
 #define NUM_PC_FILES_TO_CHECK 3
 #define NUM_MAC_FILES_TO_CHECK 4
+#define NUM_PSX_FILES_TO_CHECK 2 
 #define NUM_DEMO_FILES_TO_CHECK 1
 #define NUM_MAC_DEMO_FILES_TO_CHECK 1
-#define NUM_FILES_TO_CHECK NUM_COMMON_FILES_TO_CHECK + NUM_PC_FILES_TO_CHECK + NUM_MAC_FILES_TO_CHECK + NUM_DEMO_FILES_TO_CHECK + NUM_MAC_DEMO_FILES_TO_CHECK
+#define NUM_FILES_TO_CHECK NUM_COMMON_FILES_TO_CHECK + NUM_PC_FILES_TO_CHECK + NUM_MAC_FILES_TO_CHECK + NUM_PSX_FILES_TO_CHECK + NUM_DEMO_FILES_TO_CHECK + NUM_MAC_DEMO_FILES_TO_CHECK
 static const char *g_filesToCheck[NUM_FILES_TO_CHECK] = { // these files have to be found
-	"swordres.rif", // Mac and PC version
-	"general.clu", // PC version only
-	"compacts.clu", // PC version only
-	"scripts.clu", // PC version only
+	"swordres.rif", // Mac, PC and PSX version
+	"general.clu", // PC and PSX version
+	"compacts.clu", // PC and PSX version
+	"scripts.clu", // PC and PSX version
 	"general.clm", // Mac version only
 	"compacts.clm", // Mac version only
 	"scripts.clm", // Mac version only
 	"paris2.clm", // Mac version (full game only)
 	"cows.mad",	// this one should only exist in the demo version
 	"scripts.clm", // Mac version both demo and full game
+	"speech.dat", // PSX version only
+	"tunes.dat", // PSX version only
 	// the engine needs several more files to work, but checking these should be sufficient
 };
 
@@ -123,6 +128,8 @@
 		return sword1MacFullSettings;
 	if (0 == scumm_stricmp(gameid, sword1MacDemoSettings.gameid))
 		return sword1MacDemoSettings;
+	if (0 == scumm_stricmp(gameid, sword1PSXSettings.gameid))
+		return sword1PSXSettings;
 	return GameDescriptor();
 }
 
@@ -157,6 +164,7 @@
 	bool macFilesFound = true;
 	bool demoFilesFound = true;
 	bool macDemoFilesFound = true;
+	bool psxFilesFound = true;
 	for (i = 0; i < NUM_COMMON_FILES_TO_CHECK; i++)
 		if (!filesFound[i])
 			mainFilesFound = false;
@@ -172,10 +180,15 @@
 	for (j = 0; j < NUM_DEMO_FILES_TO_CHECK; i++, j++)
 		if (!filesFound[i])
 			macDemoFilesFound = false;
+	for (j = 0; j < NUM_PSX_FILES_TO_CHECK; i++, j++)
+		if (!filesFound[i])
+			psxFilesFound = false;
 
 	if (mainFilesFound && pcFilesFound && demoFilesFound)
 		detectedGames.push_back(sword1DemoSettings);
-	else if (mainFilesFound && pcFilesFound)
+	else if (mainFilesFound && pcFilesFound && psxFilesFound)
+		detectedGames.push_back(sword1PSXSettings);
+	else if (mainFilesFound && pcFilesFound && !psxFilesFound)
 		detectedGames.push_back(sword1FullSettings);
 	else if (mainFilesFound && macFilesFound)
 		detectedGames.push_back(sword1MacFullSettings);
Index: scummvm-bspsx/engines/sword1/sword1.cpp
===================================================================
--- scummvm-bspsx/engines/sword1/sword1.cpp	(revision 38886)
+++ scummvm-bspsx/engines/sword1/sword1.cpp	(working copy)
@@ -84,14 +84,16 @@
 
 	if ( 0 == scumm_stricmp(ConfMan.get("gameid").c_str(), "sword1mac") ||
 	     0 == scumm_stricmp(ConfMan.get("gameid").c_str(), "sword1macdemo") )
-		_systemVars.isMac = true;
+		_systemVars.platform = Common::kPlatformMacintosh;
+	else if (0 == scumm_stricmp(ConfMan.get("gameid").c_str(), "sword1psx"))
+		_systemVars.platform = Common::kPlatformPSX;
 	else
-		_systemVars.isMac = false;
+		_systemVars.platform = Common::kPlatformWindows;
 
 	checkCdFiles();
 
 	debug(5, "Starting resource manager");
-	_resMan = new ResMan("swordres.rif", _systemVars.isMac);
+	_resMan = new ResMan("swordres.rif", _systemVars.platform == Common::kPlatformMacintosh);
 	debug(5, "Starting object manager");
 	_objectMan = new ObjectMan(_resMan);
 	_mouse = new Mouse(_system, _resMan, _objectMan);
@@ -308,12 +310,34 @@
 #endif
 };
 
+const CdFile SwordEngine::_psxCdFileList[] = { // PSX edition has only one cd
+	{ "paris2.clu", FLAG_CD1 },
+	{ "ireland.clu", FLAG_CD1 },
+	{ "paris3.clu", FLAG_CD1 },
+	{ "paris4.clu", FLAG_CD1 },
+	{ "scotland.clu", FLAG_CD1 },
+	{ "spain.clu", FLAG_CD1 },
+	{ "syria.clu", FLAG_CD1 },
+	{ "train.clu", FLAG_CD1 },
+	{ "train.plx", FLAG_CD1 },
+	{ "compacts.clu", FLAG_CD1 | FLAG_IMMED },
+	{ "general.clu", FLAG_CD1 | FLAG_IMMED },
+	{ "maps.clu", FLAG_CD1 },
+	{ "paris1.clu", FLAG_CD1 },
+	{ "scripts.clu", FLAG_CD1 | FLAG_IMMED },
+	{ "swordres.rif", FLAG_CD1 | FLAG_IMMED },
+	{ "text.clu", FLAG_CD1 },
+	{ "speech.dat", FLAG_SPEECH1 },
+	{ "speech.tab", FLAG_SPEECH1 },
+	{ "speech.inf", FLAG_SPEECH1 },
+	{ "speech.lis", FLAG_SPEECH1 }
+};
 
 void SwordEngine::showFileErrorMsg(uint8 type, bool *fileExists) {
 	char msg[1024];
 	int missCnt = 0, missNum = 0;
 
-	if (_systemVars.isMac) {
+	if (SwordEngine::isMac()) {
 		for (int i = 0; i < ARRAYSIZE(_macCdFileList); i++)
 			if (!fileExists[i]) {
 				missCnt++;
@@ -335,6 +359,27 @@
 					pos += sprintf(pos, "\"%s\" (CD %d)\n", _macCdFileList[i].name, (_macCdFileList[i].flags & FLAG_CD2) ? 2 : 1);
 				}
 		}
+	} else if (SwordEngine::isPsx()) {
+		for (int i = 0; i < ARRAYSIZE(_psxCdFileList); i++)
+			if (!fileExists[i]) {
+				missCnt++;
+				missNum = i;
+			}
+		assert(missCnt > 0); // this function shouldn't get called if there's nothing missing.
+		warning("%d files missing", missCnt);
+		int msgId = (type == TYPE_IMMED) ? 0 : 2;
+		if (missCnt == 1) {
+			sprintf(msg, errorMsgs[msgId], _psxCdFileList[missNum].name, 1);
+			warning("%s", msg);
+		} else {
+			char *pos = msg + sprintf(msg, errorMsgs[msgId + 1], missCnt);
+			warning("%s", msg);
+			for (int i = 0; i < ARRAYSIZE(_psxCdFileList); i++)
+				if (!fileExists[i]) {
+					warning("\"%s\"", _macCdFileList[i].name);
+					pos += sprintf(pos, "\"%s\"\n", _macCdFileList[i].name);
+				}
+		} 
 	} else {
 		for (int i = 0; i < ARRAYSIZE(_pcCdFileList); i++)
 			if (!fileExists[i]) {
@@ -374,7 +419,7 @@
 	_systemVars.playSpeech = true;
 
 	// check all files and look out if we can find a file that wouldn't exist if this was the demo version
-	if (_systemVars.isMac) {
+	if (SwordEngine::isMac()) {
 		for (int fcnt = 0; fcnt < ARRAYSIZE(_macCdFileList); fcnt++) {
 			if (Common::File::exists(_macCdFileList[fcnt].name)) {
 				fileExists[fcnt] = true;
@@ -388,6 +433,18 @@
 				fileExists[fcnt] = false;
 			}
 		}
+	} else if (SwordEngine::isPsx()) {
+		for (int fcnt = 0; fcnt < ARRAYSIZE(_psxCdFileList); fcnt++) {
+			if (Common::File::exists(_psxCdFileList[fcnt].name)) {
+				fileExists[fcnt] = true;
+				flagsToBool(foundTypes, _psxCdFileList[fcnt].flags);
+				isFullVersion = true;
+				cd2FilesFound = true;
+			} else {
+				flagsToBool(missingTypes, _psxCdFileList[fcnt].flags);
+				fileExists[fcnt] = false;
+			}
+		}
 	} else {
 		for (int fcnt = 0; fcnt < ARRAYSIZE(_pcCdFileList); fcnt++) {
 			if (Common::File::exists(_pcCdFileList[fcnt].name)) {
@@ -422,7 +479,7 @@
 		somethingMissing |= missingTypes[i];
 	if (somethingMissing) { // okay, there *are* files missing
 		// first, update the fileExists[] array depending on our changed missingTypes
-		if (_systemVars.isMac) {
+		if (SwordEngine::isMac()) {
 			for (int fileCnt = 0; fileCnt < ARRAYSIZE(_macCdFileList); fileCnt++)
 				if (!fileExists[fileCnt]) {
 					fileExists[fileCnt] = true;
@@ -430,6 +487,14 @@
 						if (missingTypes[flagCnt] && ((_macCdFileList[fileCnt].flags & (1 << flagCnt)) != 0))
 							fileExists[fileCnt] = false; // this is one of the files we were looking for
 				}
+		} else if (SwordEngine::isPsx()) {
+			for (int fileCnt = 0; fileCnt < ARRAYSIZE(_psxCdFileList); fileCnt++)
+				if (!fileExists[fileCnt]) {
+					fileExists[fileCnt] = true;
+					for (int flagCnt = 0; flagCnt < 8; flagCnt++)
+						if (missingTypes[flagCnt] && ((_psxCdFileList[fileCnt].flags & (1 << flagCnt)) != 0))
+							fileExists[fileCnt] = false; // this is one of the files we were looking for
+				}
 		} else {
 			for (int fileCnt = 0; fileCnt < ARRAYSIZE(_pcCdFileList); fileCnt++)
 				if (!fileExists[fileCnt]) {
Index: scummvm-bspsx/engines/sword1/music.cpp
===================================================================
--- scummvm-bspsx/engines/sword1/music.cpp	(revision 38886)
+++ scummvm-bspsx/engines/sword1/music.cpp	(working copy)
@@ -29,7 +29,10 @@
 #include "common/util.h"
 #include "common/system.h"
 
+#include "sword1/sword1.h"
 #include "sword1/music.h"
+#include "sword1/vag.h"
+
 #include "sound/aiff.h"
 #include "sound/flac.h"
 #include "sound/mixer.h"
@@ -252,6 +255,35 @@
 	return true;
 }
 
+bool MusicHandle::playPSX(uint16 id, bool loop) {
+	stop();
+
+	if (!_file.isOpen())
+		if (!_file.open("tunes.dat"))
+			return false;
+		
+	Common::File tableFile;
+	if (!tableFile.open("tunes.tab"))
+		return false;
+
+	tableFile.seek((id - 1) * 8, SEEK_SET);
+	uint32 offset = tableFile.readUint32LE() * 0x800;
+	uint32 size = tableFile.readUint32LE();
+
+	tableFile.close();
+
+	if (size != 0xffffffff) {
+		_file.seek(offset, SEEK_SET);
+		_audioSource = new VagStream(_file.readStream(size), loop);
+		fadeUp();
+	} else {
+		_audioSource = NULL;
+		return false;
+	}
+	
+	return true;
+}
+
 void MusicHandle::fadeDown() {
 	if (streaming()) {
 		if (_fading < 0)
@@ -276,8 +308,7 @@
 	return !streaming();
 }
 
-// is we don't have an audiosource, return some dummy values.
-// shouldn't happen anyways.
+// if we don't have an audiosource, return some dummy values.
 bool MusicHandle::streaming(void) const {
 	return (_audioSource) ? (!_audioSource->endOfStream()) : false;
 }
@@ -411,7 +442,13 @@
 		/* The handle will load the music file now. It can take a while, so unlock
 		   the mutex before, to have the soundthread playing normally.
 		   As the corresponding _converter is NULL, the handle will be ignored by the playing thread */
-		if (_handles[newStream].play(_tuneList[tuneId], loopFlag != 0)) {
+		if (SwordEngine::isPsx()) { ;
+			if (_handles[newStream].playPSX(tuneId, loopFlag != 0)) {
+				_mutex.lock();
+				_converter[newStream] = Audio::makeRateConverter(_handles[newStream].getRate(), _mixer->getOutputRate(), _handles[newStream].isStereo(), false);
+				_mutex.unlock();
+			}
+		} else if (_handles[newStream].play(_tuneList[tuneId], loopFlag != 0)) {
 			_mutex.lock();
 			_converter[newStream] = Audio::makeRateConverter(_handles[newStream].getRate(), _mixer->getOutputRate(), _handles[newStream].isStereo(), false);
 			_mutex.unlock();
Index: scummvm-bspsx/engines/sword1/screen.h
===================================================================
--- scummvm-bspsx/engines/sword1/screen.h	(revision 38886)
+++ scummvm-bspsx/engines/sword1/screen.h	(working copy)
@@ -96,6 +96,8 @@
 	void fnFlash(uint8 color);
 	void fnBorder(uint8 color);
 
+	static void decompressHIF(uint8 *src, uint8 *dest);
+
 #ifdef BACKEND_8BIT
 	void plotYUV(byte *lut, int width, int height, byte *const *dat);
 #endif
@@ -116,6 +118,11 @@
 	void processImage(uint32 id);
 	void spriteClipAndSet(uint16 *pSprX, uint16 *pSprY, uint16 *sprWidth, uint16 *sprHeight, uint16 *incr);
 	void drawSprite(uint8 *sprData, uint16 sprX, uint16 sprY, uint16 sprWidth, uint16 sprHeight, uint16 sprPitch);
+	void drawPsxHalfShrinkedSprite(uint8 *sprData, uint16 sprX, uint16 sprY, uint16 sprWidth, uint16 sprHeight, uint16 sprPitch);
+	void drawPsxFullShrinkedSprite(uint8 *sprData, uint16 sprX, uint16 sprY, uint16 sprWidth, uint16 sprHeight, uint16 sprPitch);
+	uint8* psxBackgroundToIndexed(uint8* psxBackground, uint32 bakXres, uint32 bakYres);
+	uint8* psxShrinkedBackgroundToIndexed(uint8* psxBackground, uint32 bakXres, uint32 bakYres);
+	uint8* psxParallaxToIndexed(uint8* psxParallax);
 	void decompressRLE7(uint8 *src, uint32 compSize, uint8 *dest);
 	void decompressRLE0(uint8 *src, uint32 compSize, uint8 *dest);
 	void decompressTony(uint8 *src, uint32 compSize, uint8 *dest);
@@ -160,3 +167,5 @@
 
 #endif //BSSCREEN_H
 
+
+
Index: scummvm-bspsx/engines/sword1/mouse.cpp
===================================================================
--- scummvm-bspsx/engines/sword1/mouse.cpp	(revision 38886)
+++ scummvm-bspsx/engines/sword1/mouse.cpp	(working copy)
@@ -37,6 +37,7 @@
 #include "sword1/sworddefs.h"
 #include "sword1/swordres.h"
 #include "sword1/menu.h"
+#include "sword1/sword1.h"
 
 namespace Sword1 {
 
@@ -201,13 +202,30 @@
 	if (ptrId) {
 		MousePtr *lugg = NULL;
 		MousePtr *ptr = (MousePtr*)_resMan->openFetchRes(ptrId);
-		uint16 resSizeX = _resMan->getLEUint16(ptr->sizeX);
-		uint16 resSizeY = _resMan->getLEUint16(ptr->sizeY);
 		uint16 noFrames = _resMan->getLEUint16(ptr->numFrames);
+		uint16 ptrSizeX = _resMan->getLEUint16(ptr->sizeX);
+		uint16 ptrSizeY = _resMan->getLEUint16(ptr->sizeY);
+		uint16 luggSizeX;
+		uint16 luggSizeY;
+		uint16 resSizeX;
+		uint16 resSizeY;
+
+		if (SwordEngine::isPsx()) //PSX pointers are half height	
+			ptrSizeY *= 2;
+
 		if (luggageId) {
 			lugg = (MousePtr*)_resMan->openFetchRes(luggageId);
-			resSizeX = MAX(resSizeX, (uint16)((resSizeX / 2) + _resMan->getLEUint16(lugg->sizeX)));
-			resSizeY = MAX(resSizeY, (uint16)((resSizeY / 2) + _resMan->getLEUint16(lugg->sizeY)));
+			luggSizeX = _resMan->getLEUint16(lugg->sizeX);
+			luggSizeY = _resMan->getLEUint16(lugg->sizeY);
+
+			if (SwordEngine::isPsx())
+				luggSizeY *= 2;
+
+			resSizeX = MAX(ptrSizeX, (uint16)((ptrSizeX / 2) + luggSizeX));
+			resSizeY = MAX(ptrSizeY, (uint16)((ptrSizeY / 2) + luggSizeY));
+		} else {
+			resSizeX = ptrSizeX;
+			resSizeY = ptrSizeY;
 		}
 		_currentPtr = (MousePtr*)malloc(sizeof(MousePtr) + resSizeX * resSizeY * noFrames);
 		_currentPtr->hotSpotX = _resMan->getLEUint16(ptr->hotSpotX);
@@ -218,31 +236,48 @@
 		uint8 *ptrData = (uint8*)_currentPtr + sizeof(MousePtr);
 		memset(ptrData, 255, resSizeX * resSizeY * noFrames);
 		if (luggageId) {
-			uint8 *dstData = ptrData + resSizeX - _resMan->getLEUint16(lugg->sizeX);
+			uint8 *dstData = ptrData + resSizeX - luggSizeX;
 			for (uint32 frameCnt = 0; frameCnt < noFrames; frameCnt++) {
 				uint8 *luggSrc = (uint8*)lugg + sizeof(MousePtr);
-				dstData += (resSizeY - _resMan->getLEUint16(lugg->sizeY)) * resSizeX;
-				for (uint32 cnty = 0; cnty < _resMan->getLEUint16(lugg->sizeY); cnty++) {
-					for (uint32 cntx = 0; cntx < _resMan->getLEUint16(lugg->sizeX); cntx++)
+				dstData += (resSizeY - luggSizeY) * resSizeX;
+				for (uint32 cnty = 0; cnty < (SwordEngine::isPsx() ? luggSizeY / 2 : luggSizeY); cnty++) {
+					for (uint32 cntx = 0; cntx < luggSizeX; cntx++)
 						if (luggSrc[cntx])
 							dstData[cntx] = luggSrc[cntx];
+					
+					if(SwordEngine::isPsx()) {
+						dstData += resSizeX;
+						for (uint32 cntx = 0; cntx < luggSizeX; cntx++)
+							if (luggSrc[cntx])
+								dstData[cntx] = luggSrc[cntx];
+					}
+
 					dstData += resSizeX;
-					luggSrc += _resMan->getLEUint16(lugg->sizeX);
+					luggSrc += luggSizeX;
 				}
 			}
 			_resMan->resClose(luggageId);
 		}
+		
 		uint8 *dstData = ptrData;
 		uint8 *srcData = (uint8*)ptr + sizeof(MousePtr);
 		for (uint32 frameCnt = 0; frameCnt < noFrames; frameCnt++) {
-			for (uint32 cnty = 0; cnty < _resMan->getLEUint16(ptr->sizeY); cnty++) {
-				for (uint32 cntx = 0; cntx < _resMan->getLEUint16(ptr->sizeX); cntx++)
+			for (uint32 cnty = 0; cnty < (SwordEngine::isPsx() ? ptrSizeY / 2 : ptrSizeY); cnty++) {
+				for (uint32 cntx = 0; cntx < ptrSizeX; cntx++)
 					if (srcData[cntx])
 						dstData[cntx] = srcData[cntx];
-				srcData += _resMan->getLEUint16(ptr->sizeX);
+
+				if(SwordEngine::isPsx()) {		
+					dstData +=resSizeX;
+					for (uint32 cntx = 0; cntx < ptrSizeX; cntx++)
+						if (srcData[cntx])
+							dstData[cntx] = srcData[cntx];
+				}
+
+				srcData += ptrSizeX;
 				dstData += resSizeX;
 			}
-			dstData += (resSizeY - _resMan->getLEUint16(ptr->sizeY)) * resSizeX;
+			dstData += (resSizeY - ptrSizeY) * resSizeX;
 		}
 		_resMan->resClose(ptrId);
 	}
Index: scummvm-bspsx/engines/sword1/text.h
===================================================================
--- scummvm-bspsx/engines/sword1/text.h	(revision 38886)
+++ scummvm-bspsx/engines/sword1/text.h	(working copy)
@@ -34,6 +34,7 @@
 #define MAX_TEXT_OBS 3
 
 #define BORDER_COL	200
+#define BORDER_COL_PSX 199
 #define LETTER_COL	193
 #define NO_COL		0	// sprite background - 0 for transparency
 
Index: scummvm-bspsx/engines/sword1/sound.h
===================================================================
--- scummvm-bspsx/engines/sword1/sound.h	(revision 38886)
+++ scummvm-bspsx/engines/sword1/sound.h	(working copy)
@@ -69,7 +69,8 @@
 	CowFlac,
 	CowVorbis,
 	CowMp3,
-	CowDemo
+	CowDemo,
+	CowPSX
 };
 
 class Sound {
Index: scummvm-bspsx/engines/sword1/screen.cpp
===================================================================
--- scummvm-bspsx/engines/sword1/screen.cpp	(revision 38886)
+++ scummvm-bspsx/engines/sword1/screen.cpp	(working copy)
@@ -34,6 +34,7 @@
 #include "sword1/resman.h"
 #include "sword1/objectman.h"
 #include "sword1/menu.h"
+#include "sword1/swordres.h"
 #include "sword1/sword1.h"
 
 #ifdef BACKEND_8BIT
@@ -137,7 +138,7 @@
 	if (start == 0) // force color 0 to black
 		palData[0] = palData[1] = palData[2] = 0;
 
-	if (SwordEngine::_systemVars.isMac) {  // see bug #1701058
+	if (SwordEngine::isMac()) {  // see bug #1701058
 		if (start != 0 && start + length == 256) // and force color 255 to black as well
 			palData[(length-1)*3+0] = palData[(length-1)*3+1] = palData[(length-1)*3+2] = 0;
 	}
@@ -358,24 +359,45 @@
 
 void Screen::draw(void) {
 	uint8 cnt;
+	
+	debug(8, "Screen::draw() -> _currentScreen %u", _currentScreen);
+	
 	if (_currentScreen == 54) {
 		// rm54 has a BACKGROUND parallax layer in parallax[0]
-		if (_parallax[0])
+		if (_parallax[0] && !SwordEngine::isPsx() ) //Avoid drawing this parallax on PSX edition, it gets occluded by background
 			renderParallax(_parallax[0]);
 		uint8 *src = _layerBlocks[0];
 		uint8 *dest = _screenBuf;
+		uint8 *indxScreen = NULL;
 
+		if(SwordEngine::isPsx()) {
+			indxScreen = psxShrinkedBackgroundToIndexed(_layerBlocks[0], _scrnSizeX, _scrnSizeY);
+			src = indxScreen;
+		}
+
 		for (uint16 cnty = 0; cnty < _scrnSizeY; cnty++)
 			for (uint16 cntx = 0; cntx < _scrnSizeX; cntx++) {
 				if (*src)
-					if (!SwordEngine::_systemVars.isMac || *src != 255) // see bug #1701058
+					if (!(SwordEngine::isMac()) || *src != 255) // see bug #1701058
 						*dest = *src;
 				dest++;
 				src++;
 			}
 
-	} else
+		free(indxScreen);
+
+	} else if (!(SwordEngine::isPsx())) {
 		memcpy(_screenBuf, _layerBlocks[0], _scrnSizeX * _scrnSizeY);
+	} else { //We are using PSX version
+		uint8 *indxScreen; 		
+		if(_currentScreen == 45 || _currentScreen == 55 ||
+		   _currentScreen == 57 || _currentScreen == 63 || _currentScreen == 71) // Width shrinked backgrounds
+			indxScreen = psxShrinkedBackgroundToIndexed(_layerBlocks[0], _scrnSizeX, _scrnSizeY);
+		else
+			indxScreen = psxBackgroundToIndexed(_layerBlocks[0], _scrnSizeX, _scrnSizeY);
+		memcpy(_screenBuf, indxScreen, _scrnSizeX * _scrnSizeY);
+		free(indxScreen);
+	}
 
 	for (cnt = 0; cnt < _backLength; cnt++)
 		processImage(_backList[cnt]);
@@ -393,6 +415,18 @@
 	if (_parallax[1])
 		renderParallax(_parallax[1]);
 
+	// PSX version has parallax layer for this room in an external file (TRAIN.PLX) 
+	if(SwordEngine::isPsx() && _currentScreen == 63) {
+		Common::File parallax; 
+		uint8 *trainPLX = NULL; 
+		parallax.open("TRAIN.PLX");
+		trainPLX = (uint8*) malloc(parallax.size());
+		parallax.read(trainPLX, parallax.size());
+		parallax.close();
+		renderParallax(trainPLX);
+		free(trainPLX);
+	}
+
 	for (cnt = 0; cnt < _foreLength; cnt++)
 		processImage(_foreList[cnt]);
 
@@ -403,8 +437,9 @@
 	Object *compact;
 	FrameHeader *frameHead;
 	int scale;
-
+	
 	compact = _objMan->fetchObject(id);
+	
 	if (compact->o_type == TYPE_TEXT)
 		frameHead = _textMan->giveSpriteData((uint8)compact->o_target);
 	else
@@ -414,6 +449,7 @@
 
 	uint16 spriteX = compact->o_anim_x;
 	uint16 spriteY = compact->o_anim_y;
+	
 	if (compact->o_status & STAT_SHRINK) {
 		scale = (compact->o_scale_a * compact->o_ycoord + compact->o_scale_b) / 256;
 		spriteX += ((int16)_resMan->readUint16(&frameHead->offsetX) * scale) / 256;
@@ -425,7 +461,13 @@
 	}
 
 	uint8 *tonyBuf = NULL;
-	if (frameHead->runTimeComp[3] == '7') { // RLE7 encoded?
+	uint8 *hifBuf = NULL;
+	if (SwordEngine::isPsx() && compact->o_type != TYPE_TEXT) { // PSX sprites are compressed with HIF
+		hifBuf = (uint8*)malloc(_resMan->readUint16(&frameHead->width) * _resMan->readUint16(&frameHead->height)/2);
+		memset(hifBuf, 0x00, (_resMan->readUint16(&frameHead->width) * _resMan->readUint16(&frameHead->height)/2));
+		decompressHIF(sprData, hifBuf);
+		sprData = hifBuf;
+	} else if (frameHead->runTimeComp[3] == '7') { // RLE7 encoded?
 		decompressRLE7(sprData, _resMan->readUint32(&frameHead->compSize), _rleBuffer);
 		sprData = _rleBuffer;
 	} else if (frameHead->runTimeComp[3] == '0') { // RLE0 encoded?
@@ -439,14 +481,29 @@
 
 	uint16 sprSizeX, sprSizeY;
 	if (compact->o_status & STAT_SHRINK) {
-		sprSizeX = (scale * _resMan->readUint16(&frameHead->width)) / 256;
-		sprSizeY = (scale * _resMan->readUint16(&frameHead->height)) / 256;
-		fastShrink(sprData, _resMan->readUint16(&frameHead->width), _resMan->readUint16(&frameHead->height), scale, _shrinkBuffer);
+		memset(_shrinkBuffer, 0, SHRINK_BUFFER_SIZE); //Clean shrink buffer to avoid corruption
+		if( SwordEngine::isPsx() && (compact->o_resource != GEORGE_MEGA)) { //PSX Height shrinked sprites
+			sprSizeX = (scale * _resMan->readUint16(&frameHead->width)) / 256;
+			sprSizeY = (scale * (_resMan->readUint16(&frameHead->height))) / 256 / 2;
+			fastShrink(sprData, _resMan->readUint16(&frameHead->width), (_resMan->readUint16(&frameHead->height)) / 2, scale, _shrinkBuffer);
+		} else if (SwordEngine::isPsx()) { //PSX width/height shrinked sprites
+			sprSizeX = (scale * _resMan->readUint16(&frameHead->width)) / 256 / 2;
+			sprSizeY = (scale * _resMan->readUint16(&frameHead->height)) / 256 / 2;
+			fastShrink(sprData, _resMan->readUint16(&frameHead->width) / 2, _resMan->readUint16(&frameHead->height) / 2, scale, _shrinkBuffer);
+		} else {
+			sprSizeX = (scale * _resMan->readUint16(&frameHead->width)) / 256;
+			sprSizeY = (scale * _resMan->readUint16(&frameHead->height)) / 256;
+			fastShrink(sprData, _resMan->readUint16(&frameHead->width), _resMan->readUint16(&frameHead->height), scale, _shrinkBuffer);
+		}
 		sprData = _shrinkBuffer;
 	} else {
 		sprSizeX = _resMan->readUint16(&frameHead->width);
-		sprSizeY = _resMan->readUint16(&frameHead->height);
+		if(SwordEngine::isPsx()) { //PSX sprites are half height
+			sprSizeY = _resMan->readUint16(&frameHead->height) / 2;
+		} else
+			sprSizeY = (_resMan->readUint16(&frameHead->height));
 	}
+	
 	if (!(compact->o_status & STAT_OVERRIDE)) {
 		//mouse size linked to exact size & coordinates of sprite box - shrink friendly
 		if (_resMan->readUint16(&frameHead->offsetX) || _resMan->readUint16(&frameHead->offsetY)) {
@@ -463,24 +520,45 @@
 			compact->o_mouse_y2 = spriteY + sprSizeY;
 		}
 	}
+
 	uint16 sprPitch = sprSizeX;
 	uint16 incr;
 	spriteClipAndSet(&spriteX, &spriteY, &sprSizeX, &sprSizeY, &incr);
+
 	if ((sprSizeX > 0) && (sprSizeY > 0)) {
-		drawSprite(sprData + incr, spriteX, spriteY, sprSizeX, sprSizeY, sprPitch);
-		if (!(compact->o_status&STAT_FORE))
+		if( (!(SwordEngine::isPsx()) || (compact->o_type == TYPE_TEXT) 
+		|| (compact->o_resource == LVSFLY) || !(compact->o_resource == GEORGE_MEGA) && (sprSizeX < 260))) 
+			drawSprite(sprData + incr, spriteX, spriteY, sprSizeX, sprSizeY, sprPitch);
+		else if (((sprSizeX >= 260) && (sprSizeX < 450)) || ((compact->o_resource == GMWRITH) && (sprSizeX < 515))  // a psx shrinked sprite (1/2 width)
+				|| ((compact->o_resource == GMPOWER) && (sprSizeX < 515)) )                                         // some needs to be hardcoded, headers don't give useful infos
+			drawPsxHalfShrinkedSprite(sprData + incr, spriteX, spriteY, sprSizeX / 2, sprSizeY, sprPitch / 2);
+		else if (sprSizeX >= 450) // A PSX double shrinked sprite (1/3 width)
+			drawPsxFullShrinkedSprite(sprData + incr, spriteX, spriteY, sprSizeX / 3, sprSizeY, sprPitch / 3);
+		else // This is for psx half shrinked, walking george and remaining sprites
+			drawPsxHalfShrinkedSprite(sprData + incr, spriteX, spriteY, sprSizeX, sprSizeY, sprPitch);
+		if (!(compact->o_status&STAT_FORE) && !(SwordEngine::isPsx() && (compact->o_resource == MOUBUSY))) // Check fixes moue sprite being masked by layer, happens only on psx
 			verticalMask(spriteX, spriteY, sprSizeX, sprSizeY);
 	}
+	
 	if (compact->o_type != TYPE_TEXT)
 		_resMan->resClose(compact->o_resource);
+	
 	if (tonyBuf)
 		free(tonyBuf);
+		
+	if (hifBuf)
+		free(hifBuf);
 }
 
 void Screen::verticalMask(uint16 x, uint16 y, uint16 bWidth, uint16 bHeight) {
 	if (_roomDefTable[_currentScreen].totalLayers <= 1)
 		return;
 
+	if (SwordEngine::isPsx()) { // PSX sprites are vertical shrinked, and some width shrinked
+		bHeight *= 2;
+		bWidth *= 2;
+	}
+		
 	bWidth = (bWidth + (x & (SCRNGRID_X - 1)) + (SCRNGRID_X - 1)) / SCRNGRID_X;
 	bHeight = (bHeight + (y & (SCRNGRID_Y - 1)) + (SCRNGRID_Y - 1)) / SCRNGRID_Y;
 
@@ -504,7 +582,11 @@
 				uint16 *grid = _layerGrid[level] + gridX + blkx + gridY * lGridSizeX;
 				for (int16 blky = bHeight - 1; blky >= 0; blky--) {
 					if (*grid) {
-						uint8 *blkData = _layerBlocks[level + 1] + (_resMan->readUint16(grid) - 1) * 128;
+						uint8 *blkData;
+						if (SwordEngine::isPsx())
+							blkData = _layerBlocks[level + 1] + (_resMan->readUint16(grid) - 1) * 64; //PSX layers are half height too...
+						else
+							blkData = _layerBlocks[level + 1] + (_resMan->readUint16(grid) - 1) * 128;
 						blitBlockClear(x + blkx, y + blky, blkData);
 					} else
 						break;
@@ -517,100 +599,192 @@
 
 void Screen::blitBlockClear(uint16 x, uint16 y, uint8 *data) {
 	uint8 *dest = _screenBuf + (y * SCRNGRID_Y) * _scrnSizeX + (x * SCRNGRID_X);
-	for (uint8 cnty = 0; cnty < SCRNGRID_Y; cnty++) {
+
+	for (uint8 cnty = 0; cnty < (SwordEngine::isPsx() ? SCRNGRID_Y / 2 : SCRNGRID_Y); cnty++) {
 		for (uint8 cntx = 0; cntx < SCRNGRID_X; cntx++)
 			if (data[cntx])
 				dest[cntx] = data[cntx];
+				
+		if (SwordEngine::isPsx()) {
+			dest += _scrnSizeX;
+			for (uint8 cntx = 0; cntx < SCRNGRID_X; cntx++)
+				if (data[cntx])
+					dest[cntx] = data[cntx];
+		}	
+			
 		data += SCRNGRID_X;
 		dest += _scrnSizeX;
 	}
 }
 
 void Screen::renderParallax(uint8 *data) {
-	ParallaxHeader *header = (ParallaxHeader*)data;
-	uint32 *lineIndexes = (uint32*)(data + sizeof(ParallaxHeader));
-	assert((_resMan->getUint16(header->sizeX) >= SCREEN_WIDTH) && (_resMan->getUint16(header->sizeY) >= SCREEN_DEPTH));
-
 	uint16 paraScrlX, paraScrlY;
 	uint16 scrnScrlX, scrnScrlY;
 	uint16 scrnWidth, scrnHeight;
+	uint16 paraSizeX, paraSizeY;
+	uint8 *psxPlx = NULL;
+	ParallaxHeader *header = NULL;
+	uint32 *lineIndexes = NULL;
 
+	if (SwordEngine::isPsx()) { //Parallax headers are different in PSX version
+		psxPlx = psxParallaxToIndexed(data);
+		paraSizeX = READ_LE_UINT16(psxPlx);
+		paraSizeY = READ_LE_UINT16(psxPlx+2);
+	} else {
+		header = (ParallaxHeader*)data;
+		lineIndexes = (uint32*)(data + sizeof(ParallaxHeader));
+		paraSizeX = _resMan->getUint16(header->sizeX);
+		paraSizeY = _resMan->getUint16(header->sizeY);
+	}
+
+	assert((paraSizeX >= SCREEN_WIDTH) && (paraSizeY >= SCREEN_DEPTH));
+
 	// we have to render more than the visible screen part for displaying scroll frames
 	scrnScrlX = MIN((uint32)_oldScrollX, Logic::_scriptVars[SCROLL_OFFSET_X]);
 	scrnWidth = SCREEN_WIDTH + ABS((int32)_oldScrollX - (int32)Logic::_scriptVars[SCROLL_OFFSET_X]);
 	scrnScrlY = MIN((uint32)_oldScrollY, Logic::_scriptVars[SCROLL_OFFSET_Y]);
 	scrnHeight = SCREEN_DEPTH + ABS((int32)_oldScrollY - (int32)Logic::_scriptVars[SCROLL_OFFSET_Y]);
 
+
 	if (_scrnSizeX != SCREEN_WIDTH) {
-		double scrlfx = (_resMan->getUint16(header->sizeX) - SCREEN_WIDTH) / ((double)(_scrnSizeX - SCREEN_WIDTH));
+		double scrlfx = (paraSizeX - SCREEN_WIDTH) / ((double)(_scrnSizeX - SCREEN_WIDTH));
 		paraScrlX = (uint16)(scrnScrlX * scrlfx);
 	} else
 		paraScrlX = 0;
 
 	if (_scrnSizeY != SCREEN_DEPTH) {
-		double scrlfy = (_resMan->getUint16(header->sizeY) - SCREEN_DEPTH) / ((double)(_scrnSizeY - SCREEN_DEPTH));
+		double scrlfy = (paraSizeY - SCREEN_DEPTH) / ((double)(_scrnSizeY - SCREEN_DEPTH));
 		paraScrlY = (uint16)(scrnScrlY * scrlfy);
 	} else
 		paraScrlY = 0;
 
-	for (uint16 cnty = 0; cnty < scrnHeight; cnty++) {
-		uint8 *src = data + _resMan->readUint32(lineIndexes + cnty + paraScrlY);
-		uint8 *dest = _screenBuf + scrnScrlX + (cnty + scrnScrlY) * _scrnSizeX;
-		uint16 remain = paraScrlX;
-		uint16 xPos = 0;
-		while (remain) { // skip past the first part of the parallax to get to the right scrolling position
-			uint8 doSkip = *src++;
-			if (doSkip <= remain)
-				remain -= doSkip;
-			else {
-				xPos = doSkip - remain;
-				dest += xPos;
-				remain = 0;
-			}
-			uint8 doCopy = *src++;
-			if (doCopy <= remain) {
-				remain -= doCopy;
-				src += doCopy;
-			} else {
-				uint16 remCopy = doCopy - remain;
-				memcpy(dest, src + remain, remCopy);
-				dest += remCopy;
-				src += doCopy;
-				xPos = remCopy;
-				remain = 0;
-			}
+	if(SwordEngine::isPsx())
+		for (uint16 cnty = 0; (cnty < SCREEN_DEPTH) && (cnty < paraSizeY); cnty++) {
+			uint8 *src = psxPlx + 4 + paraScrlY * paraSizeX + cnty * paraSizeX + paraScrlX;
+			uint8 *dest = _screenBuf + scrnScrlX + (cnty + scrnScrlY) * _scrnSizeX/* * 2*/;
+			uint8 pix;
+			for (uint16 idx = 0; (idx < SCREEN_WIDTH) && (idx < paraSizeX); idx++) // make sure we don't write outside screen
+				if (pix = *(src + idx)) //If data is 0x00, don't write (transparency)
+					*(dest + idx) = pix;
 		}
-		while (xPos < scrnWidth) {
-			if (uint8 skip = *src++) {
-				dest += skip;
-				xPos += skip;
-			}
-			if (xPos < scrnWidth) {
-				if (uint8 doCopy = *src++) {
-					if (xPos + doCopy > scrnWidth)
-						doCopy = scrnWidth - xPos;
-					memcpy(dest, src, doCopy);
-					dest += doCopy;
-					xPos += doCopy;
+	else
+		for (uint16 cnty = 0; cnty < scrnHeight; cnty++) {
+			uint8 *src = data + _resMan->readUint32(lineIndexes + cnty + paraScrlY);
+			uint8 *dest = _screenBuf + scrnScrlX + (cnty + scrnScrlY) * _scrnSizeX;
+			uint16 remain = paraScrlX;
+			uint16 xPos = 0;
+			while (remain) { // skip past the first part of the parallax to get to the right scrolling position
+				uint8 doSkip = *src++;
+				if (doSkip <= remain)
+					remain -= doSkip;
+				else {
+					xPos = doSkip - remain;
+					dest += xPos;
+					remain = 0;
+				}
+				uint8 doCopy = *src++;
+				if (doCopy <= remain) {
+					remain -= doCopy;
 					src += doCopy;
+				} else {
+					uint16 remCopy = doCopy - remain;
+					memcpy(dest, src + remain, remCopy);
+					dest += remCopy;
+					src += doCopy;
+					xPos = remCopy;
+					remain = 0;
 				}
 			}
+			while (xPos < scrnWidth) {
+				if (uint8 skip = *src++) {
+					dest += skip;
+					xPos += skip;
+				}
+				if (xPos < scrnWidth) {
+					if (uint8 doCopy = *src++) {
+						if (xPos + doCopy > scrnWidth)
+							doCopy = scrnWidth - xPos;
+						memcpy(dest, src, doCopy);
+						dest += doCopy;
+						xPos += doCopy;
+						src += doCopy;
+					}
+				}
+			}
 		}
-	}
+
+	if (psxPlx)
+		free(psxPlx);
 }
 
 void Screen::drawSprite(uint8 *sprData, uint16 sprX, uint16 sprY, uint16 sprWidth, uint16 sprHeight, uint16 sprPitch) {
 	uint8 *dest = _screenBuf + (sprY * _scrnSizeX) + sprX;
-
+	
 	for (uint16 cnty = 0; cnty < sprHeight; cnty++) {
 		for (uint16 cntx = 0; cntx < sprWidth; cntx++)
 			if (sprData[cntx])
 				dest[cntx] = sprData[cntx];
+				
+		if (SwordEngine::isPsx()) { //On PSX version we need to double horizontal lines
+			dest += _scrnSizeX; 
+			for (uint16 cntx = 0; cntx < sprWidth; cntx++)
+				if (sprData[cntx])
+					dest[cntx] = sprData[cntx];
+		}
+			
 		sprData += sprPitch;
 		dest += _scrnSizeX;
 	}
 }
 
+// Used to draw psx sprites which are 1/2 of original width
+void Screen::drawPsxHalfShrinkedSprite(uint8 *sprData, uint16 sprX, uint16 sprY, uint16 sprWidth, uint16 sprHeight, uint16 sprPitch) {
+	uint8 *dest = _screenBuf + (sprY * _scrnSizeX) + sprX;
+	
+	for (uint16 cnty = 0; cnty < sprHeight; cnty++) {
+		for (uint16 cntx = 0; cntx < sprWidth; cntx++)
+			if (sprData[cntx]) {
+				dest[cntx * 2] = sprData[cntx]; //In these sprites we need to double vetical lines too...
+				dest[cntx * 2 + 1] = sprData[cntx];
+			}
+				
+		dest += _scrnSizeX;
+		for (uint16 cntx = 0; cntx < sprWidth; cntx++)
+			if (sprData[cntx]) {
+				dest[cntx * 2] = sprData[cntx];
+				dest[cntx * 2 + 1] = sprData[cntx];
+			}
+
+		sprData += sprPitch;
+		dest += _scrnSizeX; 
+	}
+}
+
+// Used to draw psx sprites which are 1/3 of original width
+void Screen::drawPsxFullShrinkedSprite(uint8 *sprData, uint16 sprX, uint16 sprY, uint16 sprWidth, uint16 sprHeight, uint16 sprPitch) {
+	uint8 *dest = _screenBuf + (sprY * _scrnSizeX) + sprX;
+
+	for (uint16 cnty = 0; cnty < sprHeight; cnty++) {
+		for (uint16 cntx = 0; cntx < sprWidth ; cntx++)
+			if (sprData[cntx]) {
+				dest[cntx * 3] = sprData[cntx]; //In these sprites we need to double vertical lines too...
+				dest[cntx * 3 + 1] = sprData[cntx];
+				dest[cntx * 3 + 2] = sprData[cntx];
+			}
+				
+		dest += _scrnSizeX;
+		for (uint16 cntx = 0; cntx < sprWidth; cntx++)
+			if (sprData[cntx]) {
+				dest[cntx * 3] = sprData[cntx];
+				dest[cntx * 3 + 1] = sprData[cntx];
+				dest[cntx * 3 + 2] = sprData[cntx];
+			}
+		
+		sprData += sprPitch;
+		dest += _scrnSizeX;
+	}
+}
+
 // nearest neighbor filter:
 void Screen::fastShrink(uint8 *src, uint32 width, uint32 height, uint32 scale, uint8 *dest) {
 	uint32 resHeight = (height * scale) >> 8;
@@ -618,6 +792,7 @@
 	uint32 step = 0x10000 / scale;
 	uint8 columnTab[160];
 	uint32 res = step >> 1;
+	
 	for (uint16 cnt = 0; cnt < resWidth; cnt++) {
 		columnTab[cnt] = (uint8)(res >> 8);
 		res += step;
@@ -675,6 +850,188 @@
 	}
 }
 
+uint8* Screen::psxBackgroundToIndexed(uint8* psxBackground, uint32 bakXres, uint32 bakYres) {
+	uint32 xresInTiles = bakXres / 16;
+	uint32 yresInTiles = ((bakYres / 2) % 16) ? (bakYres / 32) + 1 : (bakYres / 32);
+	uint32 totTiles = xresInTiles * yresInTiles;
+	uint32 tileYpos = 0; //tile position in a virtual xresInTiles * yresInTiles grid
+	uint32 tileXpos = 0;
+	uint32 tag = READ_LE_UINT32(psxBackground);
+
+	uint8 *decomp_tile = (uint8 *)malloc(16 * 16); //Tiles are always 16 * 16
+	uint8 *halfres_buffer = (uint8 *)malloc(totTiles * 16 * 16); //This buffer will contain the half vertical res image
+
+	bool isCompressed = (tag == 0x434F4D50);
+
+	psxBackground += 4; //We skip the id tag
+
+	for (uint32 currentTile = 0; currentTile < totTiles; currentTile++) {
+		uint32 tileOffset = READ_LE_UINT32(psxBackground + 4 * currentTile); 
+		
+		if(isCompressed)
+			decompressHIF(psxBackground + tileOffset - 4, decomp_tile); //Decompress the tile into decomp_tile
+		else
+			memcpy(decomp_tile, psxBackground + tileOffset - 4, 16*16);
+
+		if (currentTile > 0 && !(currentTile % xresInTiles)) { //Finished a line of tiles, going down
+			tileYpos++;
+			tileXpos = 0;
+		} 
+		
+		for (byte tileLine=0; tileLine<16; tileLine++)
+			memcpy(halfres_buffer + tileLine * bakXres + tileXpos * 16 + tileYpos * bakXres * 16, decomp_tile + tileLine * 16, 16); //Copy data to destination buffer
+		
+		tileXpos++;
+	}
+
+	free(decomp_tile);
+
+	uint8 *fullres_buffer = (uint8 *)malloc(bakXres * yresInTiles * 32);
+	memset(fullres_buffer, 0x00, bakXres * yresInTiles * 32);
+
+	//Let's linedouble the image (to keep correct aspect ratio)
+	for (uint32 currentLine = 0; currentLine < (bakYres/2); currentLine++) {
+		memcpy(fullres_buffer + currentLine * bakXres * 2, halfres_buffer + currentLine * bakXres, bakXres);        // destination_line is 2*original_line
+		memcpy(fullres_buffer + currentLine * bakXres * 2 + bakXres, halfres_buffer + currentLine * bakXres, bakXres); // destination_line+1
+	}
+	
+	free(halfres_buffer);
+
+	return fullres_buffer;
+}
+
+// needed because some psx backgrounds are half width and half height
+uint8* Screen::psxShrinkedBackgroundToIndexed(uint8* psxBackground, uint32 bakXres, uint32 bakYres) {
+	uint32 xresInTiles = (bakXres / 2) % 16 ? (bakXres / 32) + 1 : (bakXres / 32);
+	uint32 yresInTiles =  (bakYres / 2) % 16 ? (bakYres / 32) + 1 : (bakYres / 32);
+	uint32 totTiles = xresInTiles * yresInTiles;
+	uint32 tileYpos = 0; //tile position in a virtual xresInTiles * yresInTiles grid
+	uint32 tileXpos = 0;
+	uint32 dataBegin = READ_LE_UINT32(psxBackground + 4);
+	uint32 realWidth = xresInTiles * 16;
+
+	uint8 *decomp_tile = (uint8 *)malloc(16 * 16); //Tiles are always 16 * 16
+	uint8 *halfres_buffer = (uint8*) malloc(totTiles * 16 * 16); //This buffer will contain the half vertical res image
+	memset(halfres_buffer, 0, totTiles * 16 * 16);
+
+	bool isCompressed = (READ_LE_UINT32(psxBackground) == MKID_BE('COMP'));
+
+	totTiles -= xresInTiles;
+	psxBackground += 4; //We skip the id tag
+
+	uint32 currentTile;
+	for (currentTile = 0; currentTile < totTiles; currentTile++) {
+		uint32 tileOffset = READ_LE_UINT32(psxBackground + 4 * currentTile); 
+		
+		if(isCompressed)
+			decompressHIF(psxBackground + tileOffset - 4, decomp_tile); //Decompress the tile into decomp_tile
+		else
+			memcpy(decomp_tile, psxBackground + tileOffset - 4, 16 * 16);
+
+		if (currentTile > 0 && !(currentTile % xresInTiles)) { //Finished a line of tiles, going down
+			tileYpos++;
+			tileXpos = 0;
+		} 
+	
+		for (byte tileLine = 0; tileLine < 16; tileLine++)
+			memcpy(halfres_buffer + (tileLine * realWidth) + (tileXpos * 16) + (tileYpos * realWidth * 16), decomp_tile + (tileLine * 16), 16); //Copy data to destination buffer
+
+		tileXpos++;
+	}
+
+	uint8 *fullres_buffer = (uint8 *)malloc(bakXres * (yresInTiles + 1) * 32);
+	memset(fullres_buffer, 0x00, bakXres * (yresInTiles + 1) * 32);
+
+	for (uint32 currentLine = 0; currentLine < ((yresInTiles - 1) * 16); currentLine++) {
+		for (uint32 cntx = 0; cntx < realWidth; cntx++) {
+			fullres_buffer[currentLine * 2 * bakXres + cntx * 2] = halfres_buffer[currentLine * realWidth + cntx];
+			fullres_buffer[currentLine * 2 * bakXres + cntx * 2 + 1] = halfres_buffer[currentLine * realWidth + cntx];
+		}
+		for (uint32 cntx = 0; cntx < realWidth; cntx++) {
+			fullres_buffer[(currentLine * 2 + 1) * bakXres + cntx * 2] = halfres_buffer[currentLine * realWidth + cntx];
+			fullres_buffer[(currentLine * 2 + 1) * bakXres + cntx * 2 + 1] = halfres_buffer[currentLine * realWidth + cntx];
+		}
+	}
+	free(halfres_buffer);
+
+	//Calculate number of remaining tiles
+	uint32 remainingTiles = (dataBegin - (currentTile * 4 + 4)) / 4;
+
+	// Last line of tiles is FULL WIDTH!
+	uint32 tileHeight = (remainingTiles == xresInTiles * 2) ? 16 : 8;
+
+	halfres_buffer = (uint8*) malloc(bakXres * 16 * 2);
+	memset(halfres_buffer, 0, bakXres * 16 * 2);
+
+	tileXpos = 0;
+	for (; currentTile < totTiles + remainingTiles; currentTile++) {
+		uint32 tileOffset = READ_LE_UINT32(psxBackground + 4 * currentTile); 
+
+		if(isCompressed)
+			decompressHIF(psxBackground + tileOffset - 4, decomp_tile); //Decompress the tile into decomp_tile
+		else
+			memcpy(decomp_tile, psxBackground + tileOffset - 4, 256);
+
+		for (byte tileLine = 0; tileLine < tileHeight; tileLine++)
+			memcpy(halfres_buffer + tileLine * bakXres * 2 + tileXpos * 16, decomp_tile + tileLine * 16, 16);
+
+		tileXpos++;
+	}
+
+	free(decomp_tile);
+
+	for (uint32 currentLine = 0; currentLine < tileHeight; currentLine++) { 
+		memcpy(fullres_buffer + (currentLine + (yresInTiles - 1) * 16) * bakXres * 2, halfres_buffer + currentLine * bakXres * 2, bakXres * 2);
+		memcpy(fullres_buffer + (currentLine + (yresInTiles - 1) * 16) * bakXres * 2 + bakXres, halfres_buffer + currentLine * bakXres * 2, bakXres * 2);
+	}
+
+	free(halfres_buffer);
+	
+	return fullres_buffer;
+}
+
+uint8* Screen::psxParallaxToIndexed(uint8* psxParallax) {
+	uint16 xresInTiles = READ_LE_UINT16(psxParallax + 10);
+	uint16 yresInTiles = READ_LE_UINT16(psxParallax + 12);
+	uint16 totTiles = READ_LE_UINT16(psxParallax + 14);
+	uint32 plxXres = xresInTiles * 16;
+	uint32 plxYres = yresInTiles * 16;
+
+	uint8 *plxPos = psxParallax + 16;
+	uint8 *plxOff = psxParallax + 16 + totTiles * 2;
+	uint8 *plxData = psxParallax + 16 + totTiles * 2 + totTiles * 4;
+
+	uint8 *decomp_tile = (uint8 *)malloc(16 * 16); // Tiles are always 16 * 16
+	uint8 *halfres_buffer = (uint8 *)malloc(4 + yresInTiles * xresInTiles * 16 * 16); //This buffer will contain the half vertical res image
+	memset(halfres_buffer, 0, 4 + yresInTiles * xresInTiles * 16 * 16); //Clean the buffer
+
+	for (uint16 currentTile = 0; currentTile < totTiles - 1; currentTile++) {
+		uint32 tileOffset = READ_LE_UINT32(plxOff + 4 * currentTile);
+		uint8 tileXpos = *(plxPos + 2 * currentTile); //Fetch tile position in grid
+		uint8 tileYpos = *(plxPos + 2 * currentTile + 1);
+		decompressHIF(plxData + tileOffset, decomp_tile); //Decompress the tile into decomp_tile
+
+		for (byte tileLine = 0; tileLine < 16; tileLine++)
+			memcpy(halfres_buffer + tileLine * plxXres + tileXpos * 16 + tileYpos * plxXres * 16, decomp_tile + tileLine * 16, 16); //Copy data to destination buffer
+	}
+	
+	free(decomp_tile);
+
+	uint8 *dest_buffer = (uint8*) malloc (plxXres * plxYres * 2 + 4);
+	WRITE_LE_UINT16(dest_buffer, plxXres);      //Insert resolution information
+	WRITE_LE_UINT16(dest_buffer + 2, plxYres*2);
+
+	//Let's linedouble the image (to keep correct aspect ratio)
+	for (uint32 currentLine = 0; currentLine < plxYres; currentLine++) {
+		memcpy(dest_buffer + 4 + currentLine * plxXres * 2, halfres_buffer + currentLine * plxXres, plxXres); // destination_line is 2*original_line
+		memcpy(dest_buffer + 4 + currentLine * plxXres * 2 + plxXres, halfres_buffer + currentLine * plxXres, plxXres); // destination_line+1
+	}
+	
+	free(halfres_buffer);
+
+	return dest_buffer;
+}
+
 void Screen::decompressTony(uint8 *src, uint32 compSize, uint8 *dest) {
 	uint8 *endOfData = src + compSize;
 	while (src < endOfData) {
@@ -721,6 +1078,30 @@
 	}
 }
 
+void Screen::decompressHIF(uint8 *src, uint8 *dest) {
+	for (;;) { //Main loop
+		byte control_byte = *src++;
+		uint32 byte_count = 0;
+		while (byte_count < 8) {
+			if (control_byte & 0x80) {
+				uint16 info_word = READ_BE_UINT16(src); //Read the info word
+				src += 2;
+				if (info_word == 0xFFFF) return; //Got 0xFFFF code, finished.
+
+				int32 repeat_count = (info_word >> 12) + 2; //How many time data needs to be refetched 
+				while(repeat_count >= 0) {
+					uint8 *old_data_src = dest - ((info_word & 0xFFF) + 1); 
+					*dest++ = *old_data_src;
+					repeat_count--;
+				}
+			} else
+				*dest++ = *src++;
+			byte_count++;
+			control_byte <<= 1; //Shifting left the control code one bit
+		}
+	}
+}
+
 void Screen::fadePalette(void) {
 	if (_fadingStep == 16)
 		memcpy(_currentPalette, _targetPalette, 256 * 4);
@@ -773,6 +1154,7 @@
 		*pSprWidth = 0;
 	else
 		*pSprWidth = (uint16)sprW;
+	
 	*pSprX = (uint16)sprX;
 	*pSprY = (uint16)sprY;
 
@@ -780,6 +1162,19 @@
 		// sprite will be drawn, so mark it in the grid buffer
 		uint16 gridH = (*pSprHeight + (sprY & (SCRNGRID_Y - 1)) + (SCRNGRID_Y - 1)) / SCRNGRID_Y;
 		uint16 gridW = (*pSprWidth +  (sprX & (SCRNGRID_X - 1)) + (SCRNGRID_X - 1)) / SCRNGRID_X;
+		
+		if(SwordEngine::isPsx()) { 
+			gridH *= 2; // This will correct the PSX sprite being cut at half height
+			gridW *= 2; // and masking problems when sprites are stretched in width
+			
+			uint16 bottomSprPos = (*pSprY + (*pSprHeight) * 2); //Position of bottom line of sprite
+			if ( bottomSprPos > _scrnSizeY ) { //Check that resized psx sprite isn't drawn outside of screen boundaries
+				uint16 outScreen = bottomSprPos - _scrnSizeY;
+				*pSprHeight -= (outScreen % 2) ? (outScreen + 1) / 2 : outScreen / 2;
+			}
+
+		}		
+
 		uint16 gridX = sprX / SCRNGRID_X;
 		uint16 gridY = sprY / SCRNGRID_Y;
 		uint8 *gridBuf = _screenGrid + gridX + gridY * _gridSizeX;
@@ -806,16 +1201,32 @@
 	uint8 frame[40 * 40];
 	int i, j;
 
-	memset(frame, 199, sizeof(frame));	// Dark gray background
+	if(SwordEngine::isPsx())
+		memset(frame, 0, sizeof(frame)); // PSX top menu is black	
+	else
+		memset(frame, 199, sizeof(frame)); // Dark gray background
 
 	if (resId != 0xffffffff) {
 		FrameHeader *frameHead = _resMan->fetchFrame(_resMan->openFetchRes(resId), frameNo);
 		uint8 *frameData = ((uint8*)frameHead) + sizeof(FrameHeader);
 
-		for (i = 0; i < _resMan->getUint16(frameHead->height); i++) {
-			for (j = 0; j < _resMan->getUint16(frameHead->height); j++) {
-				frame[(i + 4) * 40 + j + 2] = frameData[i * _resMan->getUint16(frameHead->width) + j];
+		if (SwordEngine::isPsx()) { //We need to decompress PSX frames
+			uint8 *frameBufferPSX = (uint8 *)malloc(_resMan->getUint16(frameHead->width) *  _resMan->getUint16(frameHead->height)/2);
+			decompressHIF(frameData, frameBufferPSX);
+
+			for (i = 0; i < _resMan->getUint16(frameHead->height) / 2; i++) {
+				for (j = 0; j < _resMan->getUint16(frameHead->width); j++) {
+					uint8 data = frameBufferPSX[i * _resMan->getUint16(frameHead->width) + j];
+					frame[(i * 2 + 4) * 40 + j + 2] = data;
+					frame[(i * 2 + 1 + 4) * 40 + j + 2] = data; //Linedoubling the sprite
+				}
 			}
+			
+			free(frameBufferPSX);
+		} else {
+			for (i = 0; i < _resMan->getUint16(frameHead->height); i++) 
+				for (j = 0; j < _resMan->getUint16(frameHead->height); j++) 
+					frame[(i + 4) * 40 + j + 2] = frameData[i * _resMan->getUint16(frameHead->width) + j];
 		}
 
 		_resMan->resClose(resId);
Index: scummvm-bspsx/engines/sword1/control.cpp
===================================================================
--- scummvm-bspsx/engines/sword1/control.cpp	(revision 38886)
+++ scummvm-bspsx/engines/sword1/control.cpp	(working copy)
@@ -45,6 +45,7 @@
 #include "sword1/sword1.h"
 #include "sword1/sworddefs.h"
 #include "sword1/swordres.h"
+#include "sword1/screen.h"
 
 namespace Sword1 {
 
@@ -120,10 +121,11 @@
 	_resMan->resOpen(_resId);
 	FrameHeader *tmp = _resMan->fetchFrame(_resMan->fetchRes(_resId), 0);
 	_width = _resMan->getUint16(tmp->width);
+	_width = (_width > SCREEN_WIDTH) ? SCREEN_WIDTH : _width;
 	_height = _resMan->getUint16(tmp->height);
 	if ((x == 0) && (y == 0)) { // center the frame (used for panels);
-		_x = (640 - _width) / 2;
-		_y = (480 - _height) / 2;
+		_x = (((640 - _width) / 2) < 0)? 0 : ((640 - _width) / 2) ;
+		_y = (((480 - _height) / 2) < 0)? 0 : ((480 - _height) / 2);
 	}
 	_dstBuf = screenBuf + _y * SCREEN_WIDTH + _x;
 	_system = system;
@@ -141,13 +143,78 @@
 	FrameHeader *fHead = _resMan->fetchFrame(_resMan->fetchRes(_resId), _frameIdx);
 	uint8 *src = (uint8*)fHead + sizeof(FrameHeader);
 	uint8 *dst = _dstBuf;
-	for (uint16 cnt = 0; cnt < _resMan->readUint16(&fHead->height); cnt++) {
-		for (uint16 cntx = 0; cntx < _resMan->readUint16(&fHead->width); cntx++)
-			if (src[cntx])
-				dst[cntx] = src[cntx];
-		dst += SCREEN_WIDTH;
-		src += _resMan->readUint16(&fHead->width);
-	}
+
+	if (SwordEngine::isPsx() && _resId) {
+		uint8 *HIFbuf = (uint8*)malloc(_resMan->readUint16(&fHead->height) * _resMan->readUint16(&fHead->width));
+		memset(HIFbuf, 0, _resMan->readUint16(&fHead->height) * _resMan->readUint16(&fHead->width));
+		Screen::decompressHIF(src, HIFbuf);
+		src = HIFbuf;
+	
+		if (_resMan->readUint16(&fHead->width) < 300)
+			for (uint16 cnt = 0; cnt < _resMan->readUint16(&fHead->height); cnt++) {
+				for (uint16 cntx = 0; cntx < _resMan->readUint16(&fHead->width); cntx++)
+					if (src[cntx])
+						dst[cntx] = src[cntx];
+				
+				dst += SCREEN_WIDTH; 
+				for (uint16 cntx = 0; cntx < _resMan->readUint16(&fHead->width); cntx++)
+					if (src[cntx])
+						dst[cntx] = src[cntx];
+
+				dst += SCREEN_WIDTH;
+				src += _resMan->readUint16(&fHead->width);
+			}
+		else if (_resId == SR_DEATHPANEL) { //Hardcoded goodness for death panel psx version
+			for (uint16 cnt = 0; cnt < _resMan->readUint16(&fHead->height)/2; cnt++) {
+				//Stretched panel is bigger than 640px, check we don't draw outside screen
+				for (uint16 cntx = 0; (cntx < (_resMan->readUint16(&fHead->width))/3) && (cntx < (SCREEN_WIDTH-3) ); cntx++)
+					if (src[cntx]) {
+						dst[cntx * 3] = src[cntx];
+						dst[cntx * 3 + 1] = src[cntx];
+						dst[cntx * 3 + 2] = src[cntx];
+					}
+				dst+= SCREEN_WIDTH;
+
+				for (uint16 cntx = 0; cntx < (_resMan->readUint16(&fHead->width))/3; cntx++)
+					if (src[cntx]) {
+						dst[cntx * 3] = src[cntx];
+						dst[cntx * 3 + 1] = src[cntx];
+						dst[cntx * 3 + 2] = src[cntx];
+					}
+				dst += SCREEN_WIDTH;
+				src += _resMan->readUint16(&fHead->width)/3;
+			}
+		} else { //NASTY HACK, save slots needs to be multiplied my 4 in height... need a better way to identify these images
+			for (uint16 cnt = 0; cnt < _resMan->readUint16(&fHead->height); cnt++) {
+				for (uint16 cntx = 0; cntx < _resMan->readUint16(&fHead->width) / 2; cntx++)
+					if (src[cntx]) {
+						dst[cntx * 2] = src[cntx];
+						dst[cntx * 2 + 1] = src[cntx];
+					}
+				
+				dst += SCREEN_WIDTH; 
+				for (uint16 cntx = 0; cntx < _resMan->readUint16(&fHead->width) / 2; cntx++)
+					if (src[cntx]) {
+						dst[cntx * 2] = src[cntx];
+						dst[cntx * 2 + 1] = src[cntx];
+					}
+			
+				dst += SCREEN_WIDTH;
+				src += _resMan->readUint16(&fHead->width)/2;
+			}
+		}
+
+		free(HIFbuf);
+	} else
+		for (uint16 cnt = 0; cnt < _resMan->readUint16(&fHead->height); cnt++) {
+			for (uint16 cntx = 0; cntx < _resMan->readUint16(&fHead->width); cntx++)
+				if (src[cntx])
+					dst[cntx] = src[cntx];
+
+			dst += SCREEN_WIDTH;
+			src += _resMan->readUint16(&fHead->width);
+		}
+	
 	_system->copyRectToScreen(_dstBuf, SCREEN_WIDTH, _x, _y, _width, _height);
 }
 
@@ -940,17 +1007,37 @@
 
 		FrameHeader *chSpr = _resMan->fetchFrame(font, *str - 32);
 		uint8 *sprData = (uint8*)chSpr + sizeof(FrameHeader);
+		uint8 *HIFbuf = NULL;
+
+		if (SwordEngine::isPsx()) { //Text fonts are compressed in psx version
+			HIFbuf = (uint8 *)malloc(_resMan->getUint16(chSpr->height) * _resMan->getUint16(chSpr->width));
+			memset(HIFbuf, 0, _resMan->getUint16(chSpr->height) * _resMan->getUint16(chSpr->width));
+			Screen::decompressHIF(sprData, HIFbuf);
+			sprData = HIFbuf;
+		}
+		
 		for (uint16 cnty = 0; cnty < _resMan->getUint16(chSpr->height); cnty++) {
 			for (uint16 cntx = 0; cntx < _resMan->getUint16(chSpr->width); cntx++) {
 				if (sprData[cntx])
 					dst[cntx] = sprData[cntx];
 			}
+			
+			if(SwordEngine::isPsx()) { //On PSX version we need to double horizontal lines
+				dst += SCREEN_WIDTH; 
+				for (uint16 cntx = 0; cntx < _resMan->getUint16(chSpr->width); cntx++)
+					if (sprData[cntx])
+						dst[cntx] = sprData[cntx];
+			}
+
 			sprData += _resMan->getUint16(chSpr->width);
 			dst += SCREEN_WIDTH;
 		}
 		destX += _resMan->getUint16(chSpr->width) - 3;
 		str++;
+		
+		free(HIFbuf);
 	}
+	
 	_system->copyRectToScreen(_screenBuf + y * SCREEN_WIDTH + x, SCREEN_WIDTH, x, y, (destX - x) + 3, 28);
 }
 
@@ -963,14 +1050,34 @@
 		FrameHeader *frHead = _resMan->fetchFrame(_resMan->openFetchRes(SR_VLIGHT), (vol + 15) >> 4);
 		uint8 *destMem = _screenBuf + destY * SCREEN_WIDTH + destX;
 		uint8 *srcMem = (uint8*)frHead + sizeof(FrameHeader);
-		for (uint16 cnty = 0; cnty < _resMan->getUint16(frHead->height); cnty++) {
+		uint16 barHeight = _resMan->getUint16(frHead->height);
+		uint8 *psxVolBuf = NULL;
+
+		if (SwordEngine::isPsx()) {
+			psxVolBuf = (uint8 *)malloc(_resMan->getUint16(frHead->height) / 2 * _resMan->getUint16(frHead->width));
+			memset(psxVolBuf, 0, _resMan->getUint16(frHead->height) / 2 * _resMan->getUint16(frHead->width));
+			Screen::decompressHIF(srcMem, psxVolBuf);
+			srcMem = psxVolBuf;
+			barHeight /= 2;
+		}
+
+		for (uint16 cnty = 0; cnty < barHeight; cnty++) {
 			memcpy(destMem, srcMem, _resMan->getUint16(frHead->width));
+			
+			if(SwordEngine::isPsx()) { //linedoubling
+				destMem += SCREEN_WIDTH;
+				memcpy(destMem, srcMem, _resMan->getUint16(frHead->width));
+			}
+
 			srcMem += _resMan->getUint16(frHead->width);
 			destMem += SCREEN_WIDTH;
 		}
+		
 		_system->copyRectToScreen(_screenBuf + destY * SCREEN_WIDTH + destX, SCREEN_WIDTH, destX, destY, _resMan->getUint16(frHead->width), _resMan->getUint16(frHead->height));
 		_resMan->resClose(SR_VLIGHT);
 		destX += 32;
+
+		free(psxVolBuf);
 	}
 }
 
Index: scummvm-bspsx/engines/sword1/vag.h
===================================================================
--- scummvm-bspsx/engines/sword1/vag.h	(revision 0)
+++ scummvm-bspsx/engines/sword1/vag.h	(revision 0)
@@ -0,0 +1,58 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+ 
+#ifndef SWORD1_VAG_H
+#define SWORD1_VAG_H
+
+#include "sound/audiostream.h"
+#include "common/stream.h"
+ 
+namespace Sword1 {
+
+class VagStream : public Audio::AudioStream {
+public:
+	VagStream(Common::SeekableReadStream *stream, bool loop = false);
+	~VagStream();
+	
+	bool isStereo() const { return false; }
+	bool endOfData() const { return _stream->pos() == _stream->size(); }
+	int getRate() const { return 11025; }
+	int readBuffer(int16 *buffer, const int numSamples);
+
+	void rewind();	
+
+private:
+	Common::SeekableReadStream *_stream;
+
+	bool _loop;
+	byte _predictor;
+	double _samples[28];
+	byte _samplesRemaining;
+	double _s1, _s2;
+};
+
+} // End of namespace Sword1
+
+#endif
Index: scummvm-bspsx/engines/sword1/sword1.h
===================================================================
--- scummvm-bspsx/engines/sword1/sword1.h	(revision 38886)
+++ scummvm-bspsx/engines/sword1/sword1.h	(working copy)
@@ -66,7 +66,7 @@
 	uint8	showText;
 	uint8	language;
 	bool    isDemo;
-	bool    isMac;
+	Common::Platform platform;
 };
 
 class SwordEngine : public Engine {
@@ -79,6 +79,9 @@
 	uint32 _features;
 
 	bool mouseIsActive();
+	
+	static bool isMac() { return _systemVars.platform == Common::kPlatformMacintosh; }
+	static bool isPsx() { return _systemVars.platform == Common::kPlatformPSX; }
 
 protected:
 	// Engine APIs
@@ -119,6 +122,7 @@
 	static const uint8  _cdList[TOTAL_SECTIONS];
 	static const CdFile	_pcCdFileList[];
 	static const CdFile	_macCdFileList[];
+	static const CdFile _psxCdFileList[];
 };
 
 } // End of namespace Sword1
Index: scummvm-bspsx/engines/sword1/text.cpp
===================================================================
--- scummvm-bspsx/engines/sword1/text.cpp	(revision 38886)
+++ scummvm-bspsx/engines/sword1/text.cpp	(working copy)
@@ -32,6 +32,8 @@
 #include "sword1/objectman.h"
 #include "sword1/swordres.h"
 #include "sword1/sworddefs.h"
+#include "sword1/screen.h"
+#include "sword1/sword1.h"
 
 namespace Sword1 {
 
@@ -78,12 +80,13 @@
 void Text::makeTextSprite(uint8 slot, uint8 *text, uint16 maxWidth, uint8 pen) {
 	LineInfo lines[MAX_LINES];
 	uint16 numLines = analyzeSentence(text, maxWidth, lines);
-
+	
 	uint16 sprWidth = 0;
 	uint16 lineCnt;
 	for (lineCnt = 0; lineCnt < numLines; lineCnt++)
 		if (lines[lineCnt].width > sprWidth)
 			sprWidth = lines[lineCnt].width;
+
 	uint16 sprHeight = _charHeight * numLines;
 	uint32 sprSize = sprWidth * sprHeight;
 	assert(!_textBlocks[slot]); // if this triggers, the speechDriver failed to call Text::releaseText.
@@ -100,10 +103,13 @@
 	memset(linePtr, NO_COL, sprSize);
 	for (lineCnt = 0; lineCnt < numLines; lineCnt++) {
 		uint8 *sprPtr = linePtr + (sprWidth - lines[lineCnt].width) / 2; // center the text
-		for (uint16 pos = 0; pos < lines[lineCnt].length; pos++)
+		for (uint16 pos = 0; pos < lines[lineCnt].length; pos++) 
 			sprPtr += copyChar(*text++, sprPtr, sprWidth, pen) - OVERLAP;
 		text++; // skip space at the end of the line
-		linePtr += _charHeight * sprWidth;
+		if(SwordEngine::isPsx()) //Chars are half height in psx version
+			linePtr += (_charHeight / 2) * sprWidth;
+		else
+			linePtr += _charHeight * sprWidth;
 	}
 }
 
@@ -157,16 +163,34 @@
 	FrameHeader *chFrame = _resMan->fetchFrame(_font, ch - SPACE);
 	uint8 *chData = ((uint8*)chFrame) + sizeof(FrameHeader);
 	uint8 *dest = sprPtr;
-	for (uint16 cnty = 0; cnty < _resMan->getUint16(chFrame->height); cnty++) {
+	uint8 *decBuf = NULL;
+	uint8 *decChr;
+	uint16 frameHeight = 0;
+	
+	if(SwordEngine::isPsx()) {
+		frameHeight =  _resMan->getUint16(chFrame->height)/2;
+		if(_fontId == CZECH_GAME_FONT) { //Czech game fonts are compressed
+			decBuf = (uint8*) malloc((_resMan->getUint16(chFrame->width))*(_resMan->getUint16(chFrame->height)/2));
+			Screen::decompressHIF(chData, decBuf);
+			decChr = decBuf;
+		} else //Normal game fonts are not compressed
+			decChr = chData;
+	} else {
+		frameHeight =  _resMan->getUint16(chFrame->height);
+		decChr = chData;
+	}
+	
+	for (uint16 cnty = 0; cnty < frameHeight; cnty++) {
 		for (uint16 cntx = 0; cntx < _resMan->getUint16(chFrame->width); cntx++) {
-			if (*chData == LETTER_COL)
+			if (*decChr == LETTER_COL)
 				dest[cntx] = pen;
-			else if ((*chData == BORDER_COL) && (!dest[cntx])) // don't do a border if there's already a color underneath (chars can overlap)
+			else if (((*decChr == BORDER_COL) || (*decChr == BORDER_COL_PSX)) && (!dest[cntx])) // don't do a border if there's already a color underneath (chars can overlap)
 				dest[cntx] = BORDER_COL;
-			chData++;
+			decChr++;
 		}
 		dest += sprWidth;
 	}
+	free(decBuf);
 	return _resMan->getUint16(chFrame->width);
 }
 
Index: scummvm-bspsx/engines/sword1/music.h
===================================================================
--- scummvm-bspsx/engines/sword1/music.h	(revision 38886)
+++ scummvm-bspsx/engines/sword1/music.h	(working copy)
@@ -47,6 +47,7 @@
 	MusicHandle() : _fading(0), _audioSource(NULL) {}
 	virtual int readBuffer(int16 *buffer, const int numSamples);
 	bool play(const char *filename, bool loop);
+	bool playPSX(uint16 id, bool loop);
 	void stop();
 	void fadeUp();
 	void fadeDown();
Index: scummvm-bspsx/engines/sword1/sound.cpp
===================================================================
--- scummvm-bspsx/engines/sword1/sound.cpp	(revision 38886)
+++ scummvm-bspsx/engines/sword1/sound.cpp	(working copy)
@@ -34,6 +34,7 @@
 #include "sword1/resman.h"
 #include "sword1/logic.h"
 #include "sword1/sword1.h"
+#include "sword1/vag.h"
 
 #include "sound/flac.h"
 #include "sound/mp3.h"
@@ -160,22 +161,29 @@
 		if (_fxList[elem->id].roomVolList[cnt].roomNo) {
 			if ((_fxList[elem->id].roomVolList[cnt].roomNo == (int)Logic::_scriptVars[SCREEN]) ||
 				(_fxList[elem->id].roomVolList[cnt].roomNo == -1)) {
-
+						
 					uint8 volL = (_fxList[elem->id].roomVolList[cnt].leftVol * 10 * _sfxVolL) / 255;
 					uint8 volR = (_fxList[elem->id].roomVolList[cnt].rightVol * 10 * _sfxVolR) / 255;
 					int8 pan = (volR - volL) / 2;
 					uint8 volume = (volR + volL) / 2;
-					uint32 size = READ_LE_UINT32(sampleData + 0x28);
-					uint8 flags;
-					if (READ_LE_UINT16(sampleData + 0x22) == 16)
-						flags = Audio::Mixer::FLAG_16BITS | Audio::Mixer::FLAG_LITTLE_ENDIAN;
-					else
-						flags = Audio::Mixer::FLAG_UNSIGNED;
-					if (READ_LE_UINT16(sampleData + 0x16) == 2)
-						flags |= Audio::Mixer::FLAG_STEREO;
-					if (_fxList[elem->id].type == FX_LOOP)
-						flags |= Audio::Mixer::FLAG_LOOP;
-					_mixer->playRaw(Audio::Mixer::kSFXSoundType, &elem->handle, sampleData + 0x2C, size, 11025, flags, elem->id, volume, pan);
+						
+					if (SwordEngine::isPsx()) { ;
+						uint32 size = READ_LE_UINT32(sampleData);
+						Audio::AudioStream *audStream = new VagStream(new Common::MemoryReadStream(sampleData + 4, size-4), _fxList[elem->id].type == FX_LOOP);
+						_mixer->playInputStream(Audio::Mixer::kSFXSoundType, &elem->handle, audStream, elem->id, volume, pan, false, false, false);
+					} else {
+						uint32 size = READ_LE_UINT32(sampleData + 0x28);
+						uint8 flags;
+						if (READ_LE_UINT16(sampleData + 0x22) == 16)
+							flags = Audio::Mixer::FLAG_16BITS | Audio::Mixer::FLAG_LITTLE_ENDIAN;
+						else
+							flags = Audio::Mixer::FLAG_UNSIGNED;
+						if (READ_LE_UINT16(sampleData + 0x16) == 2)
+							flags |= Audio::Mixer::FLAG_STEREO;
+						if (_fxList[elem->id].type == FX_LOOP)
+							flags |= Audio::Mixer::FLAG_LOOP;
+						_mixer->playRaw(Audio::Mixer::kSFXSoundType, &elem->handle, sampleData + 0x2C, size, 11025, flags, elem->id, volume, pan);
+					}
 			}
 		} else
 			break;
@@ -187,11 +195,69 @@
 		warning("Sound::startSpeech: COW file isn't open");
 		return false;
 	}
+	
+	uint32 locIndex = 0xFFFFFFFF;
+	uint32 sampleSize = 0;
+	uint32 index = 0;
 
-	uint32 locIndex = _cowHeader[roomNo] >> 2;
-	uint32 sampleSize = _cowHeader[locIndex + (localNo * 2)];
-	uint32 index = _cowHeader[locIndex + (localNo * 2) - 1];
+	if (_cowMode == CowPSX) {
+		Common::File file;
+		uint16 i;
+		
+		if (!file.open("speech.lis")) {
+			warning ("Could not open speech.lis");
+			return false;
+		}
+
+		for (i = 0; !file.eos() && !file.err(); i++) 
+			if (file.readUint16LE() == roomNo) {
+				locIndex = i;
+				break;
+			}
+		file.close();
+		
+		if (locIndex == 0xFFFFFFFF) {
+			warning ("Could not find room %d in speech.lis", roomNo);
+			return false;
+		}
+		
+		if (!file.open("speech.inf")) {
+			warning ("Could not open speech.inf");
+			return false;
+		}
+	
+		file.seek(locIndex * 4 + 2); // 4 bytes per room, skip first 2 bytes
+		
+		uint16 numLines = file.readUint16LE();
+		uint16 roomOffset = file.readUint16LE(); 
+
+		file.seek(0x112 + roomOffset * 2); // The offset is in terms of uint16's, so multiply by 2. Skip the 0x112 byte header too.
+		
+		locIndex = 0xFFFFFFFF;
+		
+		for (i = 0; i < numLines; i++)
+			if (file.readUint16LE() == localNo) {
+				locIndex = i;
+				break;
+			}
+				
+		if (locIndex == 0xFFFFFFFF) {
+			warning ("Could not find local number %d in room %d in speech.inf", roomNo, localNo);
+			return false;
+		}
+		
+		file.close();
+
+		index = _cowHeader[(roomOffset + locIndex) * 2];
+		sampleSize = _cowHeader[(roomOffset + locIndex) * 2 + 1];
+	} else {
+		locIndex = _cowHeader[roomNo] >> 2;
+		sampleSize = _cowHeader[locIndex + (localNo * 2)];
+		index = _cowHeader[locIndex + (localNo * 2) - 1];
+	}
+	
 	debug(6, "startSpeech(%d, %d): locIndex %d, sampleSize %d, index %d", roomNo, localNo, locIndex, sampleSize, index);
+	
 	if (sampleSize) {
 		uint8 speechVol = (_speechVolR + _speechVolL) / 2;
 		int8 speechPan = (_speechVolR - _speechVolL) / 2;
@@ -200,6 +266,14 @@
 			int16 *data = uncompressSpeech(index + _cowHeaderSize, sampleSize, &size);
 			if (data)
 				_mixer->playRaw(Audio::Mixer::kSpeechSoundType, &_speechHandle, data, size, 11025, SPEECH_FLAGS, SOUND_SPEECH_ID, speechVol, speechPan);
+		} else if (_cowMode == CowPSX && sampleSize != 0xffffffff) {
+			_cowFile.seek(index * 2048);
+			_mixer->playInputStream(Audio::Mixer::kSpeechSoundType, &_speechHandle, new VagStream(_cowFile.readStream(sampleSize)), SOUND_SPEECH_ID, speechVol, speechPan);
+			// with compressed audio, we can't calculate the wave volume.
+			// so default to talking.
+			for (int cnt = 0; cnt < 480; cnt++)
+				_waveVolume[cnt] = true;
+			_waveVolPos = 0;
 		}
 #ifdef USE_FLAC
 		else if (_cowMode == CowFlac) {
@@ -419,21 +493,47 @@
 		debug(1, "Using uncompressed Speech Cluster");
 		_cowMode = CowWave;
 	}
+	
+	if (SwordEngine::isPsx()) {
+		// There's only one file on the PSX, so set it to the current disc.
+		_currentCowFile = SwordEngine::_systemVars.currentCD;
+		if (!_cowFile.isOpen()) {
+			if (!_cowFile.open("speech.dat"))
+				error ("Could not open speech.dat");
+			_cowMode = CowPSX;
+		}
+	}
+	
 	if (!_cowFile.isOpen())
 		_cowFile.open("speech.clu");
+		
 	if (!_cowFile.isOpen()) {
 		_cowFile.open("cows.mad");
 		if (_cowFile.isOpen())
 			_cowMode = CowDemo;
 	}
+	
 	if (_cowFile.isOpen()) {
-		_cowHeaderSize = _cowFile.readUint32LE();
-		_cowHeader = (uint32*)malloc(_cowHeaderSize);
-		if (_cowHeaderSize & 3)
-			error("Unexpected cow header size %d", _cowHeaderSize);
-		for (uint32 cnt = 0; cnt < (_cowHeaderSize / 4) - 1; cnt++)
-			_cowHeader[cnt] = _cowFile.readUint32LE();
-		_currentCowFile = SwordEngine::_systemVars.currentCD;
+		if (SwordEngine::isPsx()) {
+			// Get data from the external table file
+			Common::File tableFile;
+			if (!tableFile.open("speech.tab"))
+				error ("Could not open speech.tab");
+			_cowHeaderSize = tableFile.size();
+			_cowHeader = (uint32 *)malloc(_cowHeaderSize);
+			if (_cowHeaderSize & 3)
+				error("Unexpected cow header size %d", _cowHeaderSize);
+			for (uint32 cnt = 0; cnt < _cowHeaderSize / 4; cnt++)
+				_cowHeader[cnt] = tableFile.readUint32LE();
+		} else {
+			_cowHeaderSize = _cowFile.readUint32LE();
+			_cowHeader = (uint32*)malloc(_cowHeaderSize);
+			if (_cowHeaderSize & 3)
+				error("Unexpected cow header size %d", _cowHeaderSize);
+			for (uint32 cnt = 0; cnt < (_cowHeaderSize / 4) - 1; cnt++)
+				_cowHeader[cnt] = _cowFile.readUint32LE();
+			_currentCowFile = SwordEngine::_systemVars.currentCD;
+		}
 	} else
 		warning("Sound::initCowSystem: Can't open SPEECH%d.CLU", SwordEngine::_systemVars.currentCD);
 }
Index: scummvm-bspsx/engines/sword1/logic.cpp
===================================================================
--- scummvm-bspsx/engines/sword1/logic.cpp	(revision 38886)
+++ scummvm-bspsx/engines/sword1/logic.cpp	(working copy)
@@ -112,6 +112,10 @@
 			fnFullSetFrame(cpt, SAND_25, IMPPLSCDT, IMPPLS, 0, 0, 0, 0); // impression filled with plaster
 	}
 
+	// work around, at screen 69 in psx version TOP menu gets stuck at disabled, fix it at next screen (71)
+	if( (screen == 71) && (SwordEngine::isPsx()))
+		_scriptVars[TOP_MENU_DISABLED] = 0;
+
 	if (SwordEngine::_systemVars.justRestoredGame) { // if we've just restored a game - we want George to be exactly as saved
 		fnAddHuman(NULL, 0, 0, 0, 0, 0, 0, 0);
 		if (_scriptVars[GEORGE_WALKING]) { // except that if George was walking when we saveed the game
