[Scummvm-cvs-logs] SF.net SVN: scummvm:[39216] scummvm/trunk

Kirben at users.sourceforge.net Kirben at users.sourceforge.net
Sun Mar 8 09:45:21 CET 2009


Revision: 39216
          http://scummvm.svn.sourceforge.net/scummvm/?rev=39216&view=rev
Author:   Kirben
Date:     2009-03-08 08:45:21 +0000 (Sun, 08 Mar 2009)

Log Message:
-----------
Add initial support for Personal Nightmare.

Thanks to dreammaster for file decompression and icon decoding code.

NOTE: setjmp/longjmp code will require conversion for portability.

Modified Paths:
--------------
    scummvm/trunk/engines/agos/agos.cpp
    scummvm/trunk/engines/agos/agos.h
    scummvm/trunk/engines/agos/charset-fontdata.cpp
    scummvm/trunk/engines/agos/charset.cpp
    scummvm/trunk/engines/agos/cursor.cpp
    scummvm/trunk/engines/agos/debug.cpp
    scummvm/trunk/engines/agos/debug.h
    scummvm/trunk/engines/agos/detection.cpp
    scummvm/trunk/engines/agos/detection_tables.h
    scummvm/trunk/engines/agos/event.cpp
    scummvm/trunk/engines/agos/gfx.cpp
    scummvm/trunk/engines/agos/icons.cpp
    scummvm/trunk/engines/agos/input.cpp
    scummvm/trunk/engines/agos/intern.h
    scummvm/trunk/engines/agos/menus.cpp
    scummvm/trunk/engines/agos/module.mk
    scummvm/trunk/engines/agos/res.cpp
    scummvm/trunk/engines/agos/res_ami.cpp
    scummvm/trunk/engines/agos/res_snd.cpp
    scummvm/trunk/engines/agos/saveload.cpp
    scummvm/trunk/engines/agos/script_e2.cpp
    scummvm/trunk/engines/agos/sound.cpp
    scummvm/trunk/engines/agos/sound.h
    scummvm/trunk/engines/agos/string.cpp
    scummvm/trunk/engines/agos/verb.cpp
    scummvm/trunk/engines/agos/vga.cpp
    scummvm/trunk/engines/agos/vga_e2.cpp
    scummvm/trunk/engines/agos/vga_ff.cpp
    scummvm/trunk/engines/agos/window.cpp
    scummvm/trunk/engines/agos/zones.cpp
    scummvm/trunk/tools/credits.pl

Added Paths:
-----------
    scummvm/trunk/engines/agos/pn.cpp
    scummvm/trunk/engines/agos/script_pn.cpp
    scummvm/trunk/engines/agos/vga_pn.cpp

Modified: scummvm/trunk/engines/agos/agos.cpp
===================================================================
--- scummvm/trunk/engines/agos/agos.cpp	2009-03-08 08:17:59 UTC (rev 39215)
+++ scummvm/trunk/engines/agos/agos.cpp	2009-03-08 08:45:21 UTC (rev 39216)
@@ -182,6 +182,7 @@
 	_lastVgaTick = 0;
 
 	_marks = 0;
+	_scanFlag = false;
 
 	_scriptVar2 = 0;
 	_runScriptReturn1 = 0;
@@ -288,11 +289,14 @@
 	_firstTimeStruct = 0;
 	_pendingDeleteTimeEvent = 0;
 
+	_initMouse = 0;
 	_leftButtonDown = 0;
+	_mouseDown = 0;
 	_rightButtonDown = 0;
 	_clickOnly = 0;
+	_oneClick = 0;
 	_leftClick = 0;
-	_oneClick = 0;
+	_rightClick = 0;
 	_noRightClick = false;
 
 	_leftButton = 0;
@@ -321,11 +325,14 @@
 	_soundFileId = 0;
 	_lastMusicPlayed = 0;
 	_nextMusicToPlay = 0;
+	_sampleEnd = 0;
+	_sampleWait = 0;
 
 	_showPreposition = 0;
 	_showMessageFlag = 0;
 
 	_newDirtyClip = false;
+	_wiped = false;
 	_copyScnFlag = 0;
 	_vgaSpriteChanged = 0;
 
@@ -341,6 +348,7 @@
 	_curVgaFile1 = 0;
 	_curVgaFile2 = 0;
 	_curSfxFile = 0;
+	_curSfxFileSize = 0;
 
 	_syncCount = 0;
 
@@ -683,6 +691,14 @@
 	 3, 3, 14, 127,
 };
 
+static const uint16 initialVideoWindows_PN[20] = {
+	 3, 0, 14, 136,
+	 0, 0,  3, 136,
+	17, 0,  3, 136,
+	 0, 0, 20, 200,
+	 3, 2, 14, 129,
+};
+
 void AGOSEngine_PuzzlePack::setupGame() {
 	gss = &puzzlepack_settings;
 	_numVideoOpcodes = 85;
@@ -836,6 +852,18 @@
 	AGOSEngine::setupGame();
 }
 
+void AGOSEngine_PN::setupGame() {
+	gss = &simon1_settings;
+	_numVideoOpcodes = 57;
+	_vgaMemSize = 1000000;
+	_frameCount = 4;
+	_vgaBaseDelay = 1;
+	_vgaPeriod = 50;
+	_numVars = 256;
+
+	AGOSEngine::setupGame();
+}
+
 void AGOSEngine::setupGame() {
 	allocItemHeap();
 	allocTablesHeap();
@@ -870,6 +898,8 @@
 	for (int i = 0; i < 20; i++) {
 		if (getGameType() == GType_SIMON1 || getGameType() == GType_SIMON2) {
 			_videoWindows[i] = initialVideoWindows_Simon[i];
+		} else if (getGameType() == GType_PN) {
+			_videoWindows[i] = initialVideoWindows_PN[i];
 		} else {
 			_videoWindows[i] = initialVideoWindows_Common[i];
 		}
@@ -965,7 +995,7 @@
 
 	while (_pause && !shouldQuit()) {
 		delay(1);
-		if (_keyPressed.keycode == Common::KEYCODE_p)
+		if (_keyPressed.keycode == Common::KEYCODE_PAUSE)
 			pauseEngine(false);
 	}
 }
@@ -1037,7 +1067,6 @@
 	return _system->getMillis() / 1000;
 }
 
-
 void AGOSEngine::syncSoundSettings() {
 	_mixer->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, ConfMan.getInt("sfx_volume"));
 	_mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, ConfMan.getInt("music_volume"));

Modified: scummvm/trunk/engines/agos/agos.h
===================================================================
--- scummvm/trunk/engines/agos/agos.h	2009-03-08 08:17:59 UTC (rev 39215)
+++ scummvm/trunk/engines/agos/agos.h	2009-03-08 08:45:21 UTC (rev 39216)
@@ -31,6 +31,7 @@
 #include "common/array.h"
 #include "common/keyboard.h"
 #include "common/rect.h"
+#include "common/stack.h"
 #include "common/util.h"
 
 #include "agos/animation.h"
@@ -38,6 +39,9 @@
 #include "agos/sound.h"
 #include "agos/vga.h"
 
+// TODO: Replace with more portable code
+#include <setjmp.h>
+
 namespace AGOS {
 
 /* Enable and set to zone number number to dump */
@@ -72,6 +76,9 @@
 	Item *itemPtr;
 	uint16 verb;
 	uint16 priority;
+
+	// Personal Nightmare specific
+	uint16 msg1, msg2;
 	HitArea() { memset(this, 0, sizeof(*this)); }
 };
 
@@ -127,6 +134,7 @@
 };
 
 enum SIMONGameType {
+	GType_PN = 0,
 	GType_ELVIRA1 = 1,
 	GType_ELVIRA2 = 2,
 	GType_WW = 3,
@@ -167,7 +175,7 @@
 
 	// Engine APIs
 	Common::Error init();
-	Common::Error go();
+	virtual Common::Error go();
 	virtual Common::Error run() {
 		Common::Error err;
 		err = init();
@@ -282,6 +290,7 @@
 	uint32 _lastVgaTick;
 
 	uint16 _marks;
+	bool _scanFlag;
 
 	bool _scriptVar2;
 	bool _runScriptReturn1;
@@ -346,7 +355,7 @@
 	int16 _scriptAdj1, _scriptAdj2;
 
 	uint16 _curWindow;
-	WindowBlock *_textWindow;
+	WindowBlock *_inputWindow, *_textWindow;
 
 	Item *_subjectItem, *_objectItem;
 	Item *_currentPlayer;
@@ -387,6 +396,7 @@
 
 	TimeEvent *_firstTimeStruct, *_pendingDeleteTimeEvent;
 
+	bool _initMouse;
 	Common::Point _mouse;
 	Common::Point _mouseOld;
 
@@ -401,8 +411,10 @@
 
 	byte _leftButtonDown;
 	byte _leftButton, _leftButtonCount, _leftButtonOld;
+	byte _mouseDown;
 	byte _rightButtonDown;
-	bool _clickOnly, _leftClick, _oneClick;
+	bool _clickOnly, _oneClick;
+	bool _leftClick, _rightClick;
 	bool _noRightClick;
 
 	Item *_dummyItem1;
@@ -429,11 +441,11 @@
 	uint16 _soundFileId;
 	int16 _lastMusicPlayed;
 	int16 _nextMusicToPlay;
-
 	bool _showPreposition;
 	bool _showMessageFlag;
 
 	bool _newDirtyClip;
+	bool _wiped;
 	uint16 _copyScnFlag, _vgaSpriteChanged;
 
 	byte *_block, *_blockEnd;
@@ -443,7 +455,6 @@
 
 	byte *_curVgaFile1;
 	byte *_curVgaFile2;
-	byte *_curSfxFile;
 
 	uint16 _syncCount;
 
@@ -503,10 +514,12 @@
 	byte _stringReturnBuffer[2][180];
 
 	HitArea _hitAreas[250];
+	HitArea *_hitAreaList;
 
 	AnimTable _screenAnim1[90];
 	VgaPointersEntry _vgaBufferPointers[450];
 	VgaSprite _vgaSprites[200];
+	VgaSleepStruct _onStopTable[60];
 	VgaSleepStruct _waitEndTable[60];
 	VgaSleepStruct _waitSyncTable[60];
 
@@ -585,6 +598,10 @@
 	AGOSEngine(OSystem *syst);
 	virtual ~AGOSEngine();
 
+	byte *_curSfxFile;
+	uint32 _curSfxFileSize;
+	uint16 _sampleEnd, _sampleWait;
+
 protected:
 	virtual uint16 to16Wrapper(uint value);
 	virtual uint16 readUint16Wrapper(const void *src);
@@ -598,17 +615,17 @@
 	void readGamePcText(Common::SeekableReadStream *in);
 	virtual void readItemChildren(Common::SeekableReadStream *in, Item *item, uint tmp);
 	void readItemFromGamePc(Common::SeekableReadStream *in, Item *item);
-	void loadGamePcFile();
+	virtual void loadGamePcFile();
 	void readGamePcFile(Common::SeekableReadStream *in);
 	void decompressData(const char *srcName, byte *dst, uint32 offset, uint32 srcSize, uint32 dstSize);
+	void decompressPN(Common::Stack<uint32> &dataList, uint8 *&dataOut, int &dataOutSize);
 	void loadOffsets(const char *filename, int number, uint32 &file, uint32 &offset, uint32 &compressedSize, uint32 &size);
-	void loadSound(uint sound);
-	void loadSound(uint sound, int pan, int vol, uint type);
+	void loadSound(uint16 sound, int16 pan, int16 vol, uint16 type);
+	void loadSound(uint16 sound, uint16 freq, uint16 flags);
 	void loadVoice(uint speechId);
 
 	void loadSoundFile(const char *filename);
 
-
 	int getUserFlag(Item *item, int a);
 	int getUserFlag1(Item *item, int a);
 	int getUserItem(Item *item, int n);
@@ -638,6 +655,7 @@
 
 	/* used in debugger */
 	void dumpAllSubroutines();
+	void dumpAllVgaFiles();
 	void dumpSubroutines();
 	void dumpSubroutine(Subroutine *sub);
 	void dumpSubroutineLine(SubroutineLine *sl, Subroutine *sub);
@@ -707,6 +725,8 @@
 	bool isBoxDead(uint hitarea);
 	void undefineBox(uint hitarea);
 	void defineBox(int id, int x, int y, int width, int height, int flags, int verb, Item *itemPtr);
+	void defineBox(uint16 id, uint16 x, uint16 y, uint16 width, uint16 height, uint16 msg1, uint16 msg2, uint16 flags);
+
 	HitArea *findEmptyHitArea();
 
 	virtual void resetVerbs();
@@ -749,6 +769,7 @@
 	virtual int weightOf(Item *x);
 	void xPlace(Item *x, Item *y);
 
+	void restoreMenu();
 	void drawMenuStrip(uint windowNum, uint menuNum);
 	void lightMenuStrip(int a);
 	void unlightMenuStrip();
@@ -826,7 +847,7 @@
 	void loadIconFile();
 	void loadMenuFile();
 
-	bool processSpecialKeys();
+	virtual bool processSpecialKeys();
 	void hitarea_stuff_helper();
 
 	void permitInput();
@@ -835,12 +856,13 @@
 	void justifyStart();
 	void justifyOutPut(byte chr);
 
-	void loadZone(uint16 zoneNum);
+	void loadZone(uint16 zoneNum, bool useError = true);
 
 	void animate(uint16 windowNum, uint16 zoneNum, uint16 vgaSpriteId, int16 x, int16 y, uint16 palette, bool vgaScript = false);
 	void setImage(uint16 vgaSpriteId, bool vgaScript = false);
-	void setWindowImage(uint16 mode, uint16 vgaSpriteId);
-	void setWindowImageEx(uint16 mode, uint16 vgaSpriteId);
+	void setWindowImage(uint16 mode, uint16 vgaSpriteId, bool specialCase = false);
+	virtual void setWindowImageEx(uint16 mode, uint16 vgaSpriteId);
+	void drawEdging();
 
 	void skipSpeech();
 
@@ -908,6 +930,17 @@
 	void vc41_scrollLeft();
 	void vc42_delayIfNotEQ();
 
+	// Video Script Opcodes, Personal Nightmare
+	void vc11_onStop();
+	void vc36_pause();
+	void vc39_volume();
+	void vc44_enableBox();
+	void vc45_disableBox();
+	void vc46_maxBox();
+	void vc48_specialEffect();
+	void vc50_setBox();
+	void vc55_scanFlag();
+
 	// Video Script Opcodes, Elvira 1
 	void vc17_waitEnd();
 	void vc22_setPaletteOld();
@@ -1121,11 +1154,12 @@
 	void clearVideoBackGround(uint16 windowNum, uint16 color);
 
 	void setPaletteSlot(uint16 srcOffs, uint8 dstOffs);
+	void checkOnStopTable();
 	void checkWaitEndTable();
 
-	bool ifObjectHere(uint16 val);
-	bool ifObjectAt(uint16 a, uint16 b);
-	bool ifObjectState(uint16 a, int16 b);
+	virtual bool ifObjectHere(uint16 val);
+	virtual bool ifObjectAt(uint16 a, uint16 b);
+	virtual bool ifObjectState(uint16 a, int16 b);
 
 	bool isVgaQueueEmpty();
 	void haltAnimation();
@@ -1152,7 +1186,7 @@
 	void colorBlock(WindowBlock *window, uint16 x, uint16 y, uint16 w, uint16 h);
 
 	void restoreWindow(WindowBlock *window);
-	void restoreBlock(uint16 h, uint16 w, uint16 y, uint16 x);
+	void restoreBlock(uint16 x, uint16 y, uint16 w, uint16 h);
 
 	byte *getBackBuf();
 	byte *getBackGround();
@@ -1162,7 +1196,7 @@
 
 	bool decrunchFile(byte *src, byte *dst, uint32 size);
 	void loadVGABeardFile(uint16 id);
-	void loadVGAVideoFile(uint16 id, uint8 type);
+	void loadVGAVideoFile(uint16 id, uint8 type, bool useError = true);
 	bool loadVGASoundFile(uint16 id, uint8 type);
 
 	void openGameFile();
@@ -1247,6 +1281,253 @@
 	virtual char *genSaveName(int slot);
 };
 
+class AGOSEngine_PN : public AGOSEngine {
+	struct stackframe {
+		struct stackframe *nextframe;
+		int16 flag[6];
+		int16 param[8];
+		int16 classnum;
+		uint8 *linpos;
+		uint8 *lbase;
+		int16 ll;
+		int16 linenum;
+		int16 process;
+		jmp_buf *savearea;
+		stackframe() { memset(this, 0, sizeof(*this)); }
+	};
+
+
+	virtual Common::Error go();
+	void demoSeq();
+	void introSeq();
+	void setupBoxes();
+public:
+	AGOSEngine_PN(OSystem *system);
+	~AGOSEngine_PN();
+
+	virtual void setupGame();
+	virtual void setupOpcodes();
+	virtual void setupVideoOpcodes(VgaOpcodeProc *op);
+
+	virtual void executeOpcode(int opcode);
+
+	int actCallD(int n);
+
+	void opn_opcode00();
+	void opn_opcode01();
+	void opn_opcode02();
+	void opn_opcode03();
+	void opn_opcode04();
+	void opn_opcode05();
+	void opn_opcode06();
+	void opn_opcode07();
+	void opn_opcode08();
+	void opn_opcode09();
+	void opn_opcode10();
+	void opn_opcode11();
+	void opn_opcode12();
+	void opn_opcode13();
+	void opn_opcode14();
+	void opn_opcode15();
+	void opn_opcode16();
+	void opn_opcode17();
+	void opn_opcode18();
+	void opn_opcode19();
+	void opn_opcode20();
+	void opn_opcode21();
+	void opn_opcode22();
+	void opn_opcode23();
+	void opn_opcode24();
+	void opn_opcode25();
+	void opn_opcode26();
+	void opn_opcode27();
+	void opn_opcode28();
+	void opn_opcode29();
+	void opn_opcode30();
+	void opn_opcode31();
+	void opn_opcode32();
+	void opn_opcode33();
+	void opn_opcode34();
+	void opn_opcode35();
+	void opn_opcode36();
+	void opn_opcode37();
+	void opn_opcode38();
+	void opn_opcode39();
+	void opn_opcode40();
+	void opn_opcode41();
+	void opn_opcode42();
+	void opn_opcode43();
+	void opn_opcode44();
+	void opn_opcode45();
+	void opn_opcode46();
+	void opn_opcode47();
+	void opn_opcode48();
+	void opn_opcode49();
+	void opn_opcode50();
+	void opn_opcode51();
+	void opn_opcode52();
+	void opn_opcode53();
+	void opn_opcode54();
+	void opn_opcode55();
+	void opn_opcode56();
+	void opn_opcode57();
+	void opn_opcode62();
+	void opn_opcode63();
+
+	// Video Script Opcodes, Personal Nightmare
+	void vc36_pause();
+
+	stackframe *_stackbase;
+
+	byte *_dataBase, *_textBase;
+	uint32 _dataBaseSize, _textBaseSize;
+
+	HitArea _invHitAreas[45];
+
+        char _buffer[80];
+	char _inputline[61];
+	char _saveFile[20];
+	char _sb[80];
+	uint8 _wordcp[7];
+
+	const char *_mouseString, *_mouseString1;
+	char _objectName1[15], _objectName2[15];
+	char _inMessage[20];
+	char _placeMessage[15];
+	uint8 _inputReady;
+	uint8 _inputting;
+	uint16 _intputCounter, _inputMax;
+	uint16 _mousePrintFG;
+	HitArea *_dragStore;
+	uint8 _hitCalled;
+
+	uint32 _quickptr[16];
+	uint16 _quickshort[12];
+
+	bool _noScanFlag;
+	char _keyboardBuffer[61];
+
+	uint16 _objects;
+	int16 _objectCountS;
+
+        int16 _bp;
+	int _xofs;
+	int16 _havinit;
+	uint16 _seed;
+
+	char *_curwrdptr;
+	char *_inpp;
+	int _fnst;
+	int _procnum;
+	int _linct;
+	int _linembr;
+	uint8 *_linebase;
+	uint8 *_workptr;
+	jmp_buf *_cjmpbuff;
+	jmp_buf _loadfail;
+
+	uint16 getptr(uint32 pos);
+	uint32 getlong(uint32 pos);
+
+	virtual void loadGamePcFile();
+
+	int bitextract(uint32 ptr, int offs);
+	int doaction();
+	int doline(int needsave);
+	int setposition(int process, int line);
+	int varval();
+
+	char *getMessage(char *msg, uint16 num);
+	void getResponse(uint16 charNum, uint16 objNum, uint16 &msgNum1, uint16 &msgNum2);
+	void getObjectName(char *v, uint16 x);
+
+	void processor();
+	void setbitf(uint32 ptr, int offs, int val);
+	void setqptrs();
+	void writeval(uint8 *ptr, int val);
+
+	void addstack(int type);
+	void dumpstack();
+	void junkstack();
+	void popstack(int type);
+	void funccpy(int *store);
+	void funcentry(int *storestore, int procn);
+
+	int findentry();
+	int findset();
+	int gvwrd(uint8 *wptr, int mask);
+	int samewrd(uint8 *w1, uint8 *w2, int ln);
+	int wrdmatch(uint8 *word1, int mask1, uint8 *word2, int mask2);
+
+	bool testContainer(uint16 a);
+	bool testObvious(uint16 a);
+	bool testSeen(uint16 a);
+
+	bool ifObjectInInv(uint16 a);
+	int inventoryOn(int val);
+	int inventoryOff();
+	void mouseHit();
+	void execMouseHit(HitArea *ha);
+	void hitBox1(HitArea *ha);
+	void hitBox2(HitArea *ha);
+	void hitBox3(HitArea *ha);
+	void hitBox4(HitArea *ha);
+	void hitBox5(HitArea *ha);
+	void hitBox6(HitArea *ha);
+	void hitBox7(HitArea *ha);
+	void hitBox8(HitArea *ha);
+	void hitBox9(HitArea *ha);
+	void hitBox11(HitArea *ha);
+
+	void drawIconHitBar();
+	void iconPage();
+	void printIcon(HitArea *ha, uint8 i, uint8 r);
+
+	bool badload(int8 errorNum);
+	int loadfl(char *name);
+	int savfl(char *name);
+	void getFilename();
+	void sysftodb();
+	void dbtosysf();
+
+	uint32 ftext(uint32 base, int n);
+	char *unctok(char *c, int n);
+	void uncomstr(char *c, uint32 x);
+	void patok(int n);
+	void pcf(uint8 ch);
+	void pcl(const char *s);
+	void pmesd(int n);
+	void plocd(int n, int m);
+	void pobjd(int n, int m);
+	void ptext(uint32 tptr);
+
+	virtual void clearVideoWindow(uint16 windowNum, uint16 color);
+	virtual void setWindowImageEx(uint16 mode, uint16 vga_res);
+
+	virtual bool ifObjectHere(uint16 val);
+	virtual bool ifObjectAt(uint16 a, uint16 b);
+	virtual bool ifObjectState(uint16 a, int16 b);
+
+	virtual void boxController(uint x, uint y, uint mode);
+	virtual void timerProc();
+
+	void addChar(uint8 chr);
+	void clearInputLine();
+	void handleKeyboard();
+	virtual void handleMouseMoved();
+	void interact(char *buffer, uint8 size);
+
+	virtual bool processSpecialKeys();
+protected:
+	typedef void (AGOSEngine_PN::*OpcodeProcPN) ();
+	struct OpcodeEntryPN {
+		OpcodeProcPN proc;
+		const char *desc;
+	};
+
+	const OpcodeEntryPN *_opcodesPN;
+};
+
 class AGOSEngine_Elvira1 : public AGOSEngine {
 public:
 	AGOSEngine_Elvira1(OSystem *system);
@@ -1322,6 +1603,10 @@
 	};
 
 	const OpcodeEntryElvira1 *_opcodesElvira1;
+
+	virtual void drawIcon(WindowBlock *window, uint icon, uint x, uint y);
+
+	virtual char *genSaveName(int slot);
 };
 
 class AGOSEngine_Elvira2 : public AGOSEngine_Elvira1 {

Modified: scummvm/trunk/engines/agos/charset-fontdata.cpp
===================================================================
--- scummvm/trunk/engines/agos/charset-fontdata.cpp	2009-03-08 08:17:59 UTC (rev 39215)
+++ scummvm/trunk/engines/agos/charset-fontdata.cpp	2009-03-08 08:45:21 UTC (rev 39216)
@@ -1767,6 +1767,107 @@
 	0x00, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0x00,
 };
 
+static const byte english_pnFont[] = {
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x10, 0x10, 0x10, 0x10, 0x00, 0x10, 0x00, 
+	0x00, 0x24, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x24, 0x7E, 0x24, 0x24, 0x7E, 0x24, 0x00, 
+	0x00, 0x08, 0x3E, 0x28, 0x3E, 0x0A, 0x3E, 0x08, 
+	0x00, 0x62, 0x64, 0x08, 0x10, 0x26, 0x46, 0x00, 
+	0x00, 0x10, 0x28, 0x10, 0x2A, 0x44, 0x3A, 0x00, 
+	0x00, 0x08, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x04, 0x08, 0x08, 0x08, 0x08, 0x04, 0x00, 
+	0x00, 0x20, 0x10, 0x10, 0x10, 0x10, 0x20, 0x00, 
+	0x00, 0x00, 0x14, 0x08, 0x3E, 0x08, 0x14, 0x00, 
+	0x00, 0x00, 0x08, 0x08, 0x3E, 0x08, 0x08, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x10, 
+	0x00, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 
+	0x00, 0x00, 0x02, 0x04, 0x08, 0x10, 0x20, 0x00, 
+	0x00, 0x3C, 0x46, 0x4A, 0x52, 0x62, 0x3C, 0x00, 
+	0x00, 0x18, 0x28, 0x08, 0x08, 0x08, 0x3E, 0x00, 
+	0x00, 0x3C, 0x42, 0x02, 0x3C, 0x40, 0x7E, 0x00, 
+	0x00, 0x3C, 0x42, 0x0C, 0x02, 0x42, 0x3C, 0x00, 
+	0x00, 0x08, 0x18, 0x28, 0x48, 0x7E, 0x08, 0x00, 
+	0x00, 0x7E, 0x40, 0x7C, 0x02, 0x42, 0x3C, 0x00, 
+	0x00, 0x3C, 0x40, 0x7C, 0x42, 0x42, 0x3C, 0x00, 
+	0x00, 0x7E, 0x02, 0x04, 0x08, 0x10, 0x10, 0x00, 
+	0x00, 0x3C, 0x42, 0x3C, 0x42, 0x42, 0x3C, 0x00, 
+	0x00, 0x3C, 0x42, 0x42, 0x3E, 0x02, 0x3C, 0x00, 
+	0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x10, 0x00, 
+	0x00, 0x00, 0x10, 0x00, 0x00, 0x10, 0x10, 0x20, 
+	0x00, 0x00, 0x04, 0x08, 0x10, 0x08, 0x04, 0x00, 
+	0x00, 0x00, 0x00, 0x3E, 0x00, 0x3E, 0x00, 0x00, 
+	0x00, 0x00, 0x10, 0x08, 0x04, 0x08, 0x10, 0x00, 
+	0x00, 0x3C, 0x42, 0x04, 0x08, 0x00, 0x08, 0x00, 
+	0x00, 0x3C, 0x4A, 0x56, 0x5E, 0x40, 0x3C, 0x00, 
+	0x00, 0x3C, 0x42, 0x42, 0x7E, 0x42, 0x42, 0x00, 
+	0x00, 0x7C, 0x42, 0x7C, 0x42, 0x42, 0x7C, 0x00, 
+	0x00, 0x3C, 0x42, 0x40, 0x40, 0x42, 0x3C, 0x00, 
+	0x00, 0x78, 0x44, 0x42, 0x42, 0x44, 0x78, 0x00, 
+	0x00, 0x7E, 0x40, 0x7C, 0x40, 0x40, 0x7E, 0x00, 
+	0x00, 0x7E, 0x40, 0x7C, 0x40, 0x40, 0x40, 0x00, 
+	0x00, 0x3C, 0x42, 0x40, 0x4E, 0x42, 0x3C, 0x00, 
+	0x00, 0x42, 0x42, 0x7E, 0x42, 0x42, 0x42, 0x00, 
+	0x00, 0x3E, 0x08, 0x08, 0x08, 0x08, 0x3E, 0x00, 
+	0x00, 0x02, 0x02, 0x02, 0x42, 0x42, 0x3C, 0x00, 
+	0x00, 0x44, 0x48, 0x70, 0x48, 0x44, 0x42, 0x00, 
+	0x00, 0x40, 0x40, 0x40, 0x40, 0x40, 0x7E, 0x00, 
+	0x00, 0x42, 0x66, 0x5A, 0x42, 0x42, 0x42, 0x00, 
+	0x00, 0x42, 0x62, 0x52, 0x4A, 0x46, 0x42, 0x00, 
+	0x00, 0x3C, 0x42, 0x42, 0x42, 0x42, 0x3C, 0x00, 
+	0x00, 0x7C, 0x42, 0x42, 0x7C, 0x40, 0x40, 0x00, 
+	0x00, 0x3C, 0x42, 0x42, 0x52, 0x4A, 0x3C, 0x00, 
+	0x00, 0x7C, 0x42, 0x42, 0x7C, 0x44, 0x42, 0x00, 
+	0x00, 0x3C, 0x40, 0x3C, 0x02, 0x42, 0x3C, 0x00, 
+	0x00, 0xFE, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 
+	0x00, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3C, 0x00, 
+	0x00, 0x42, 0x42, 0x42, 0x42, 0x24, 0x18, 0x00, 
+	0x00, 0x42, 0x42, 0x42, 0x42, 0x5A, 0x24, 0x00, 
+	0x00, 0x42, 0x24, 0x18, 0x18, 0x24, 0x42, 0x00, 
+	0x00, 0x82, 0x44, 0x28, 0x10, 0x10, 0x10, 0x00, 
+	0x00, 0x7E, 0x04, 0x08, 0x10, 0x20, 0x7E, 0x00, 
+	0x00, 0x0E, 0x08, 0x08, 0x08, 0x08, 0x0E, 0x00, 
+	0x00, 0x00, 0x40, 0x20, 0x10, 0x08, 0x04, 0x00, 
+	0x00, 0x70, 0x10, 0x10, 0x10, 0x10, 0x70, 0x00, 
+	0x00, 0x10, 0x38, 0x54, 0x10, 0x10, 0x10, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 
+	0x00, 0x1C, 0x22, 0x78, 0x20, 0x20, 0x7E, 0x00, 
+	0x00, 0x00, 0x38, 0x04, 0x3C, 0x44, 0x3C, 0x00, 
+	0x00, 0x20, 0x20, 0x3C, 0x22, 0x22, 0x3C, 0x00, 
+	0x00, 0x00, 0x1C, 0x20, 0x20, 0x20, 0x1C, 0x00, 
+	0x00, 0x04, 0x04, 0x3C, 0x44, 0x44, 0x3C, 0x00, 
+	0x00, 0x00, 0x38, 0x44, 0x78, 0x40, 0x3C, 0x00, 
+	0x00, 0x0C, 0x10, 0x18, 0x10, 0x10, 0x10, 0x00, 
+	0x00, 0x00, 0x3C, 0x44, 0x44, 0x3C, 0x04, 0x38, 
+	0x00, 0x40, 0x40, 0x78, 0x44, 0x44, 0x44, 0x00, 
+	0x00, 0x10, 0x00, 0x30, 0x10, 0x10, 0x38, 0x00, 
+	0x00, 0x04, 0x00, 0x04, 0x04, 0x04, 0x24, 0x18, 
+	0x00, 0x20, 0x28, 0x30, 0x30, 0x28, 0x24, 0x00, 
+	0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x0C, 0x00, 
+	0x00, 0x00, 0x68, 0x54, 0x54, 0x54, 0x54, 0x00, 
+	0x00, 0x00, 0x78, 0x44, 0x44, 0x44, 0x44, 0x00, 
+	0x00, 0x00, 0x38, 0x44, 0x44, 0x44, 0x38, 0x00, 
+	0x00, 0x00, 0x78, 0x44, 0x44, 0x78, 0x40, 0x40, 
+	0x00, 0x00, 0x3C, 0x44, 0x44, 0x3C, 0x04, 0x06, 
+	0x00, 0x00, 0x1C, 0x20, 0x20, 0x20, 0x20, 0x00, 
+	0x00, 0x00, 0x38, 0x40, 0x38, 0x04, 0x78, 0x00, 
+	0x00, 0x10, 0x38, 0x10, 0x10, 0x10, 0x0C, 0x00, 
+	0x00, 0x00, 0x44, 0x44, 0x44, 0x44, 0x38, 0x00, 
+	0x00, 0x00, 0x44, 0x44, 0x28, 0x28, 0x10, 0x00, 
+	0x00, 0x00, 0x44, 0x54, 0x54, 0x54, 0x28, 0x00, 
+	0x00, 0x00, 0x44, 0x28, 0x10, 0x28, 0x44, 0x00, 
+	0x00, 0x00, 0x44, 0x44, 0x44, 0x3C, 0x04, 0x38, 
+	0x00, 0x00, 0x7C, 0x08, 0x10, 0x20, 0x7C, 0x00, 
+	0x00, 0x0E, 0x08, 0x30, 0x08, 0x08, 0x0E, 0x00, 
+	0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 
+	0x00, 0x70, 0x10, 0x0C, 0x10, 0x10, 0x70, 0x00, 
+	0x00, 0x14, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x3C, 0x42, 0x99, 0xA1, 0xA1, 0x99, 0x42, 0x3C, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+};
+
 void AGOSEngine::windowDrawChar(WindowBlock *window, uint x, uint y, byte chr) {
 	const byte *src;
 	byte color, *dst;
@@ -1851,6 +1952,12 @@
 		w = 6;
 
 		src = english_elvira1Font + (chr - 32) * 8;
+	} else {
+		dst = (byte *)screen->pixels + y * _dxSurfacePitch + x + window->textColumnOffset;
+		h = 8;
+		w = 8;
+
+		src = english_pnFont + (chr - 32) * 8;
 	}
 
 	color = window->textColor;

Modified: scummvm/trunk/engines/agos/charset.cpp
===================================================================
--- scummvm/trunk/engines/agos/charset.cpp	2009-03-08 08:17:59 UTC (rev 39215)
+++ scummvm/trunk/engines/agos/charset.cpp	2009-03-08 08:45:21 UTC (rev 39216)
@@ -610,13 +610,21 @@
 	window->textColumnOffset = (getGameType() == GType_ELVIRA2) ? 4 : 0;
 	window->textLength = 0;
 
-	if (window->textRow == window->height) {
-		if (getGameType() == GType_ELVIRA1 || getGameType() == GType_ELVIRA2 ||
-			getGameType() == GType_WW) {
+	if (getGameType() == GType_PN) {
+		window->textRow++;
+		if (window->textRow == window->height) {
 			windowScroll(window);
+			window->textRow--;
 		}
 	} else {
-		window->textRow++;
+		if (window->textRow == window->height) {
+			if (getGameType() == GType_ELVIRA1 || getGameType() == GType_ELVIRA2 ||
+				getGameType() == GType_WW) {
+				windowScroll(window);
+			}
+		} else {
+			window->textRow++;
+		}
 	}
 }
 

Modified: scummvm/trunk/engines/agos/cursor.cpp
===================================================================
--- scummvm/trunk/engines/agos/cursor.cpp	2009-03-08 08:17:59 UTC (rev 39215)
+++ scummvm/trunk/engines/agos/cursor.cpp	2009-03-08 08:45:21 UTC (rev 39216)
@@ -474,6 +474,71 @@
 	_litBoxFlag = 0;
 }
 
+void AGOSEngine_PN::handleMouseMoved() {
+	if (_mouseHideCount) {
+		CursorMan.showMouse(false);
+		return;
+	}
+
+	CursorMan.showMouse(true);
+	_mouse = _eventMan->getMousePos();
+
+	if (_leftClick == true) {
+		_leftClick = false;
+		if (_dragFlag != 0) {
+			_hitCalled = 4;
+		} else if (_lockWord & 0x10) {
+			if (_oneClick != 0) {
+				_hitCalled = 2;
+				_oneClick = 0;
+			} else {
+				_oneClick++;
+			}
+		} else {
+			_hitCalled = 1;
+		}
+		_mouseDown = 0;
+	}
+
+	if (_rightClick == true) {
+		_rightClick = false;
+		if (_hitCalled == 0)
+			_hitCalled = 5;
+	}
+
+	if (_mouse != _mouseOld)
+		_needHitAreaRecalc++;
+
+	if (_leftButton != 0) {
+		if (_mouseDown <= 20) {
+			_mouseDown++;
+			if (_mouseDown > 20) {
+				if (_lockWord & 0x10) {
+					if (_oneClick == 0)
+						_hitCalled = 3;
+				} else {
+					_hitCalled = 3;
+				}
+			}
+		}
+	} else if ((_lockWord & 0x10) && _oneClick != 0) {
+		_oneClick++;
+		if (_oneClick < 10) {
+			_hitCalled = 1;
+			_oneClick = 0;
+		}
+	}
+
+	if (!_wiped)
+		boxController(_mouse.x, _mouse.y, 0);
+
+	_mouseOld = _mouse;
+	drawMousePointer();
+
+	_needHitAreaRecalc = 0;
+	_litBoxFlag = 0;
+}
+
 void AGOSEngine::handleMouseMoved() {
 	uint x;
 
@@ -721,8 +786,15 @@
 	} else {
 		const uint16 *src;
 		int i, j;
+		uint8 color;
 
-		const uint8 color = (getGameType() == GType_ELVIRA1) ? 15: 65;
+		if (getGameType() == GType_PN) {
+			color = (getPlatform() == Common::kPlatformPC) ? 15 : 14;
+		} else if (getGameType() == GType_ELVIRA1) {
+			color = 15;
+		} else {
+			color = 65;
+		}
 		memset(_mouseData, 0xFF, _maxCursorWidth * _maxCursorHeight);
 
 		if (getGameType() == GType_WW) {

Modified: scummvm/trunk/engines/agos/debug.cpp
===================================================================
--- scummvm/trunk/engines/agos/debug.cpp	2009-03-08 08:17:59 UTC (rev 39215)
+++ scummvm/trunk/engines/agos/debug.cpp	2009-03-08 08:45:21 UTC (rev 39216)
@@ -231,8 +231,10 @@
 			strn = str = simon1_videoOpcodeNameTable[opcode];
 		} else if (getGameType() == GType_ELVIRA2 || getGameType() == GType_WW) {
 			strn = str = ww_videoOpcodeNameTable[opcode];
+		} else if (getGameType() == GType_ELVIRA1) {
+			strn = str = elvira1_videoOpcodeNameTable[opcode];
 		} else {
-			strn = str = elvira1_videoOpcodeNameTable[opcode];
+			strn = str = pn_videoOpcodeNameTable[opcode];
 		}
 
 		if (strn == NULL) {
@@ -295,6 +297,24 @@
 	printf("; end\n");
 }
 
+void AGOSEngine::dumpAllVgaFiles() {
+	uint8 start = (getGameType() == GType_PN) ? 0 : 2;
+	uint8 end = (getGameType() == GType_PN) ? 26 : 450;
+
+	for (int f = start; f < end; f++) {
+		uint16 zoneNum = (getGameType() == GType_PN) ? 0 : f;
+		loadZone(f, false);
+
+		VgaPointersEntry *vpe = &_vgaBufferPointers[zoneNum];
+		if (vpe->vgaFile1 != NULL) {
+			_curVgaFile1 = vpe->vgaFile1;
+			dumpVgaFile(_curVgaFile1);
+		}
+	}
+
+	error("Complete");
+}
+
 void AGOSEngine_Feeble::dumpVgaFile(const byte *vga) {
 	const byte *pp;
 	const byte *p;

Modified: scummvm/trunk/engines/agos/debug.h
===================================================================
--- scummvm/trunk/engines/agos/debug.h	2009-03-08 08:17:59 UTC (rev 39215)
+++ scummvm/trunk/engines/agos/debug.h	2009-03-08 08:45:21 UTC (rev 39216)
@@ -2324,6 +2324,79 @@
 	"BBBB|SET_COLOR",
 };
 
+const char *const pn_videoOpcodeNameTable[] = {
+	/* 0 */
+	"x|RET",
+	"ddd|FADEOUT",
+	"d|CALL",
+	"ddddd|NEW_SPRITE",
+	/* 4 */
+	"ddd|FADEIN",
+	"vdj|IF_EQUAL",
+	"dj|IF_OBJECT_HERE",
+	"dj|IF_OBJECT_NOT_HERE",
+	/* 8 */
+	"ddj|IF_OBJECT_IS_AT",
+	"ddj|IF_OBJECT_STATE_IS",
+	"dddd|DRAW",
+	"d|ON_STOP",
+	/* 12 */
+	"|TEST_STOP",
+	"d|DELAY",
+	"d|SET_SPRITE_OFFSET_X",
+	"d|SET_SPRITE_OFFSET_Y",
+	/* 16 */
+	"|SYNC",
+	"d|WAIT_SYNC",
+	"d|WAIT_END",
+	"i|JUMP_REL",
+	/* 20 */
+	"|CHAIN_TO",
+	"dd|SET_REPEAT",
+	"i|END_REPEAT",
+	"d|SET_PALETTE",
+	/* 24 */
+	"d|SET_PRIORITY",
+	"diid|SET_SPRITE_XY",
+	"x|HALT_SPRITE",
+	"ddddd|SET_WINDOW",
+	/* 28 */
+	"|RESET",
+	"dddd|PLAY_SOUND",
+	"|STOP_ALL_SOUNDS",
+	"d|SET_FRAME_RATE",
+	/* 32 */
+	"d|SET_WINDOW",
+	"|SAVE_SCREEN",
+	"|MOUSE_ON",
+	"|MOUSE_OFF",
+	/* 36 */
+	"|PAUSE",
+	"d|VC_37",
+	"dd|CLEAR_WINDOW",
+	"d|SET_VOLUME",
+	/* 40 */
+	"dd|SET_WINDOW_IMAGE",
+	"dd|POKE_PALETTE",
+	"|VC_42",
+	"|VC_43",
+	/* 44 */
+	"d|ENABLE_BOX",
+	"d|DISABLE_BOX",
+	"d|MAX_BOX",
+	"dd|VC_47",
+	/* 48 */
+	"dd|SPEC_EFFECT",
+	"|VC_49",
+	"ddddddddd|SET_BOX",
+	"v|IF_VAR_NOT_ZERO",
+	/* 52 */
+	"vd|SET_VAR",
+	"vd|ADD_VAR",
+	"vd|SUB_VAR",
+	"|SCAN_FLAGS",
+};
+
 const char *const elvira1_videoOpcodeNameTable[] = {
 	/* 0 */
 	"x|RET",

Modified: scummvm/trunk/engines/agos/detection.cpp
===================================================================
--- scummvm/trunk/engines/agos/detection.cpp	2009-03-08 08:17:59 UTC (rev 39215)
+++ scummvm/trunk/engines/agos/detection.cpp	2009-03-08 08:45:21 UTC (rev 39216)
@@ -65,6 +65,7 @@
 };
 
 static const PlainGameDescriptor simonGames[] = {
+	{"pn", "Personal Nightmare"},
 	{"elvira1", "Elvira - Mistress of the Dark"},
 	{"elvira2", "Elvira II - The Jaws of Cerberus"},
 	{"waxworks", "Waxworks"},
@@ -132,6 +133,9 @@
 	bool res = true;
 
 	switch (gd->gameType) {
+	case AGOS::GType_PN:
+		*engine = new AGOS::AGOSEngine_PN(syst);
+		break;
 	case AGOS::GType_ELVIRA1:
 		*engine = new AGOS::AGOSEngine_Elvira1(syst);
 		break;

Modified: scummvm/trunk/engines/agos/detection_tables.h
===================================================================
--- scummvm/trunk/engines/agos/detection_tables.h	2009-03-08 08:17:59 UTC (rev 39215)
+++ scummvm/trunk/engines/agos/detection_tables.h	2009-03-08 08:45:21 UTC (rev 39216)
@@ -26,6 +26,93 @@
 namespace AGOS {
 
 static const AGOSGameDescription gameDescriptions[] = {
+	// Personal Nightmare 1.1 - English Amiga
+	{
+		{
+			"pn",
+			"Floppy",
+
+			{
+	{ "icon.tmp",		GAME_ICONFILE,	"cd94091218ac2c46918fd3c0cbd81d5e", -1},
+	{ "night.dbm",		GAME_BASEFILE,	"712c445d8e938956403a759978eab01b", -1},
+	{ "night.txt",		GAME_TEXTFILE,	"52630ad100f473a2cdc7c699536d6730", -1},
+	{ NULL, 0, NULL, 0}
+			},
+			Common::EN_ANY,
+			Common::kPlatformAmiga,
+			ADGF_NO_FLAGS
+		},
+
+		GType_PN,
+		GID_PN,
+		GF_OLD_BUNDLE | GF_CRUNCHED | GF_PLANAR
+	},
+
+	// Personal Nightmare - English Atari ST Floppy Demo
+	{
+		{
+			"pn",
+			"Demo",
+
+			{
+	{ "01.IN",		0,	"23a4c8c4c9ac460fee7281080b5274e3", 756},
+	{ "02.IN",		0,	"31be87808826538f0c0caebd5fedd48f", 73100},
+	{ "03.IN",		0,	"0e125f3df4e4b800936ebdcc8dc96060", 101664},
+	{ NULL, 0, NULL, 0}
+			},
+			Common::EN_ANY,
+			Common::kPlatformAtariST,
+			ADGF_DEMO
+		},
+
+		GType_PN,
+		GID_PN,
+		GF_OLD_BUNDLE | GF_CRUNCHED | GF_PLANAR | GF_DEMO
+	},
+
+	// Personal Nightmare 1.1 - English AtariST Floppy
+	{
+		{
+			"pn",
+			"Floppy",
+
+			{
+	{ "night.dbm",		GAME_BASEFILE,	"712c445d8e938956403a759978eab01b", -1},
+	{ "night.txt",		GAME_TEXTFILE,	"52630ad100f473a2cdc7c699536d6730", -1},
+	{ NULL, 0, NULL, 0}
+			},
+			Common::EN_ANY,
+			Common::kPlatformAtariST,
+			ADGF_NO_FLAGS
+		},
+
+		GType_PN,
+		GID_PN,
+		GF_OLD_BUNDLE | GF_CRUNCHED | GF_PLANAR
+	},
+
+	// Personal Nightmare 1.1c - English DOS Floppy
+	{
+		{
+			"pn",
+			"Floppy",
+
+			{
+	{ "icon.out",		GAME_ICONFILE,	"40d8347c3154bfa8b642d6860a4b9481", -1},
+	{ "night.dbm",		GAME_BASEFILE,	"177311ae059243f6a2740e950585d786", -1},
+	{ "night.txt",		GAME_TEXTFILE,	"861fc1fa0864eef585f5865dee52e325", -1},
+	{ NULL, 0, NULL, 0}
+			},
+			Common::EN_ANY,
+			Common::kPlatformPC,
+			ADGF_NO_FLAGS
+		},
+
+		GType_PN,
+		GID_PN,
+		GF_OLD_BUNDLE | GF_CRUNCHED | GF_PLANAR
+	},
+
 	// Elvira 1 - English Amiga Floppy Demo
 	{
 		{

Modified: scummvm/trunk/engines/agos/event.cpp
===================================================================
--- scummvm/trunk/engines/agos/event.cpp	2009-03-08 08:17:59 UTC (rev 39215)
+++ scummvm/trunk/engines/agos/event.cpp	2009-03-08 08:45:21 UTC (rev 39216)
@@ -185,14 +185,13 @@
 	if (!(_lockWord & 0x10))
 		return;
 
-	_window4Flag = 2;
+	if (getGameType() != GType_PN) {
+		_window4Flag = 2;
+		setMoveRect(0, 0, 224, 127);
+		displayScreen();
+	}
 
-	setMoveRect(0, 0, 224, 127);
-	displayScreen();
-
 	_lockWord &= ~0x10;
-
-	// Check picture queue
 }
 
 void AGOSEngine::addVgaEvent(uint16 num, uint8 type, const byte *codePtr, uint16 curSprite, uint16 curZoneNum) {
@@ -520,6 +519,9 @@
 					setBitFlag(92, false);
 				_rightButtonDown++;
 				break;
+			case Common::EVENT_RBUTTONUP:
+				_rightClick = true;
+				break;
 			case Common::EVENT_RTL:
 			case Common::EVENT_QUIT:
 				return;
@@ -611,6 +613,45 @@
 	_lockWord &= ~2;
 }
 
+void AGOSEngine_PN::timerProc() {
+	if (_lockWord & 0x80E9 || _lockWord & 2)
+		return;
+
+	_syncCount++;
+
+	_lockWord |= 2;
+
+	_sound->handleSound();
+	handleMouseMoved();
+	handleKeyboard();
+
+	if (!(_lockWord & 0x10)) {
+		if (_sampleWait) {
+			_vgaCurSpriteId = 0xFFFF;
+			vc15_sync();
+			_sampleWait = false;
+		}
+		if (_sampleEnd) {
+			_vgaCurSpriteId = 0xFFFE;
+			vc15_sync();
+			_sampleEnd = false;
+		}
+
+		processVgaEvents();
+		processVgaEvents();
+		_cepeFlag ^= 1;
+		if (!_cepeFlag)
+			processVgaEvents();
+	}
+
+	if (_displayScreen) {
+		displayScreen();
+		_displayScreen = false;
+	}
+
+	_lockWord &= ~2;
+}
+
 void AGOSEngine::timerProc() {
 	if (_lockWord & 0x80E9 || _lockWord & 2)
 		return;

Modified: scummvm/trunk/engines/agos/gfx.cpp
===================================================================
--- scummvm/trunk/engines/agos/gfx.cpp	2009-03-08 08:17:59 UTC (rev 39215)
+++ scummvm/trunk/engines/agos/gfx.cpp	2009-03-08 08:45:21 UTC (rev 39216)
@@ -928,6 +928,12 @@
 
 			_window4Flag = 1;
 		}
+	} else {
+		state->surf_addr = (byte *)screen->pixels;
+		state->surf_pitch = _screenWidth;
+
+		xoffs = (vlut[0] * 2 + state->x) * 8;
+		yoffs = vlut[1] + state->y;
 	}
 
 	state->surf_addr += xoffs + yoffs * state->surf_pitch;
@@ -1057,7 +1063,7 @@
 	vsp->y = y;
 	vsp->x = x;
 	vsp->image = 0;
-	if (getGameType() == GType_ELVIRA1 || getGameType() == GType_ELVIRA2 || getGameType() == GType_WW)
+	if (getGameType() == GType_PN || getGameType() == GType_ELVIRA1 || getGameType() == GType_ELVIRA2 || getGameType() == GType_WW)
 		vsp->palette = 0;
 	else
 		vsp->palette = palette;
@@ -1168,7 +1174,7 @@
 	uint16 count;
 	const byte *vc_ptr_org;
 
-	zoneNum = vgaSpriteId / 100;
+	zoneNum = (getGameType() == GType_PN) ? 0 : vgaSpriteId / 100;
 
 	for (;;) {
 		vpe = &_vgaBufferPointers[zoneNum];
@@ -1185,6 +1191,7 @@
 			_noOverWrite = 0xFFFF;
 		} else {
 			_curSfxFile = vpe->sfxFile;
+			_curSfxFileSize = vpe->sfxFileEnd - vpe->sfxFile;
 			_zoneNumber = zoneNum;
 
 			if (vpe->vgaFile1 != NULL)
@@ -1234,8 +1241,17 @@
 		}
 		assert(READ_BE_UINT16(&((ImageHeader_WW *) b)->id) == vgaSpriteId);
 
-		if (!vgaScript)
-			clearVideoWindow(_windowNum, READ_BE_UINT16(&((ImageHeader_WW *) b)->color));
+		if (!vgaScript) {
+			uint16 color = READ_BE_UINT16(&((ImageHeader_WW *) b)->color);
+			if (getGameType() == GType_PN) {
+				if (color & 0x80)
+					_wiped = true;
+				else if (_wiped == true)
+					restoreMenu();
+				color &= 0xFF7F;
+			}
+			clearVideoWindow(_windowNum, color);
+		}
 	}
 
 	if (_dumpVgaScripts) {
@@ -1262,6 +1278,14 @@
 	_vcPtr = vc_ptr_org;
 }
 
+void AGOSEngine_PN::setWindowImageEx(uint16 mode, uint16 vga_res) {
+	if (!_initMouse) {
+		_initMouse = 1;
+		vc33_setMouseOn();
+	}
+	setWindowImage(mode, vga_res);
+}
+
 void AGOSEngine::setWindowImageEx(uint16 mode, uint16 vgaSpriteId) {
 	_window3Flag = 0;
 
@@ -1299,7 +1323,7 @@
 	}
 }
 
-void AGOSEngine::setWindowImage(uint16 mode, uint16 vgaSpriteId) {
+void AGOSEngine::setWindowImage(uint16 mode, uint16 vgaSpriteId, bool specialCase) {
 	uint16 updateWindow;
 
 	_windowNum = updateWindow = mode;
@@ -1307,7 +1331,7 @@
 
 	if (getGameType() == GType_FF || getGameType() == GType_PP) {
 		vc27_resetSprite();
-	} else {
+	} else if (!specialCase) {
 		VgaTimerEntry *vte = _vgaTimerList;
 		while (vte->type != ANIMATE_INT)
 			vte++;
@@ -1331,7 +1355,7 @@
 		}
 	}
 
-	setImage(vgaSpriteId);
+	setImage(vgaSpriteId, specialCase);
 
 	if (getGameType() == GType_FF || getGameType() == GType_PP) {
 		fillBackGroundFromBack();
@@ -1423,6 +1447,9 @@
 				src = _window4BackScn;
 				srcWidth = _videoWindows[18] * 16;
 			}
+		} else {
+			src = (byte *)screen->pixels + xoffs + yoffs * _screenWidth;
+			srcWidth = _screenWidth;
 		}
 
 		_boxStarHeight = height;
@@ -1433,7 +1460,14 @@
 			src += srcWidth;
 		}
 
-		if (getGameType() == GType_ELVIRA1 && updateWindow == 3 && _bottomPalette) {
+		if (getGameType() == GType_PN && !_wiped && !specialCase) {
+			uint8 color = (getPlatform() == Common::kPlatformPC) ? 7 : 15;
+			dst = (byte *)screen->pixels + 48;
+			memset(dst, color, 224);
+
+			dst = (byte *)screen->pixels + 132 * _screenWidth + 48;
+			memset(dst, color, 224);
+		} else if (getGameType() == GType_ELVIRA1 && updateWindow == 3 && _bottomPalette) {
 			dst = (byte *)screen->pixels + 133 * _screenWidth;
 			int size = 67 * _screenWidth;
 
@@ -1449,4 +1483,26 @@
 	_lockWord &= ~0x20;
 }
 
+// Personal Nightmare specific
+void AGOSEngine::drawEdging() {
+	byte *dst;
+	uint8 color = (getPlatform() == Common::kPlatformPC) ? 7 : 15;
+
+	Graphics::Surface *screen = _system->lockScreen();
+
+	dst = (byte *)screen->pixels + 136 * _screenWidth;
+	uint8 len = 52;
+
+	while (len--) {
+		dst[0] = color;
+		dst[319] = color;
+		dst += _screenWidth;
+	}
+
+	dst = (byte *)screen->pixels + 187 * _screenWidth;
+	memset(dst, color, _screenWidth);
+
+	_system->unlockScreen();
+}
+
 } // End of namespace AGOS

Modified: scummvm/trunk/engines/agos/icons.cpp
===================================================================
--- scummvm/trunk/engines/agos/icons.cpp	2009-03-08 08:17:59 UTC (rev 39215)
+++ scummvm/trunk/engines/agos/icons.cpp	2009-03-08 08:45:21 UTC (rev 39216)
@@ -302,7 +302,7 @@
 	_lockWord &= ~0x8000;
 }
 
-void AGOSEngine::drawIcon(WindowBlock *window, uint icon, uint x, uint y) {
+void AGOSEngine_Elvira1::drawIcon(WindowBlock *window, uint icon, uint x, uint y) {
 	byte *dst;
 	byte *src;
 
@@ -329,6 +329,43 @@
 	_lockWord &= ~0x8000;
 }
 
+void AGOSEngine::drawIcon(WindowBlock *window, uint icon, uint x, uint y) {
+	byte *dst;
+	byte *src;
+
+	_lockWord |= 0x8000;
+
+	Graphics::Surface *screen = _system->lockScreen();
+	dst = (byte *)screen->pixels + y * _dxSurfacePitch + x * 8;
+	src = _iconFilePtr + icon * 146;
+
+	if (icon == 0xFF) {
+		// Draw Blank Icon
+		for (int yp = 0; yp < 24; yp++) {
+			memset(dst, 0, 24);
+			dst += _dxSurfacePitch;
+		}
+	} else {
+		uint8 palette[4];	
+		palette[0] = *src >> 4;	
+		palette[1] = *src++ & 0xf;	
+		palette[2] = *src >> 4;	
+		palette[3] = *src++ & 0xf;	
+		for (int yp = 0; yp < 24; ++yp, src += 6) {
+			// Get bit-set representing the 24 pixels for the line
+			uint32 v1 = (READ_BE_UINT16(src) << 8) | *(src + 4);
+			uint32 v2 = (READ_BE_UINT16(src + 2) << 8) | *(src + 5);
+			for (int xp = 0; xp < 24; ++xp, v1 >>= 1, v2 >>= 1) {
+				dst[yp * _screenWidth + (23 - xp)] = palette[((v1 & 1) << 1) | (v2 & 1)];
+			}
+		}
+	}
+
+	_system->unlockScreen();
+
+	_lockWord &= ~0x8000;
+}
+
 void AGOSEngine_Feeble::drawIconArray(uint num, Item *itemRef, int line, int classMask) {
 	Item *item_ptr_org = itemRef;
 	WindowBlock *window;
@@ -923,7 +960,7 @@
 
 void AGOSEngine_Simon1::removeArrows(WindowBlock *window, uint num) {
 	if (getGameType() == GType_SIMON1) {
-		restoreBlock(200, 320, 146, 304);
+		restoreBlock(304, 146, 320, 200);
 	}
 }
 
@@ -941,7 +978,7 @@
 	if (num != 2) {
 		uint y = window->height * 4 + window->y - 19;
 		uint x = window->width + window->x;
-		restoreBlock(y + 38, x + 16, y, x);
+		restoreBlock(x, y, x + 16, y + 38);
 	} else {
 		colorBlock(window, 240, 151, 16, 38);
 	}
@@ -984,4 +1021,94 @@
 	_fcsData2[num] = 0;
 }
 
+static const byte hitBarData[12 * 7] = {
+	0x3C, 0x00, 0x80, 0x00, 0x88, 0x00, 0x00, 0x03, 0x80, 0x00, 0x00, 0x00,
+	0x20, 0x00, 0x04, 0x00, 0xD8, 0x00, 0x00, 0x04, 0x48, 0x00, 0x00, 0x00,
+	0x20, 0x89, 0x8E, 0x00, 0xA8, 0x86, 0x10, 0x04, 0x08, 0x21, 0x88, 0x00,
+	0x38, 0x50, 0x84, 0x00, 0x89, 0x49, 0x28, 0x04, 0x08, 0x52, 0x14, 0x00,
+	0x20, 0x20, 0x84, 0x00, 0x89, 0x48, 0x38, 0x04, 0x08, 0x53, 0x9C, 0x00,
+	0x20, 0x50, 0x84, 0x00, 0x89, 0x48, 0x20, 0x04, 0x48, 0x50, 0x90, 0x00,
+	0x3C, 0x89, 0xC3, 0x00, 0x88, 0x88, 0x18, 0x03, 0x86, 0x23, 0x0C, 0x00
+};
+
+// Personal Nightmare specific
+void AGOSEngine_PN::drawIconHitBar() {
+	Graphics::Surface *screen = _system->lockScreen();
+	byte *dst = (byte *)screen->pixels + 3 * _dxSurfacePitch + 6 * 8;
+	const byte *src = hitBarData;
+	uint8 color = (getPlatform() == Common::kPlatformPC) ? 7 : 15;
+
+	for (int h = 0; h < 7; h++) {
+		for (int w = 0; w < 12; w++) {
+			int8 b = *src++;
+			for (int i = 0; i < 8; i++) {
+				if (b < 0) {
+					dst[w * 8 + i] = color;
+				}
+
+				b <<= 1;
+			}
+		}
+		dst += _dxSurfacePitch;
+	}
+
+	_system->unlockScreen();
+}
+
+void AGOSEngine_PN::iconPage() {
+	_objectCountS = -1;
+
+	mouseOff();
+
+	uint8 objRoom = getptr(_quickptr[12] + _variableArray[210] * _quickshort[5] + 20);
+	uint8 iconNum = getptr(_quickptr[0] + objRoom * _quickshort[0] + 4);
+
+	drawIcon(NULL, iconNum, 6, 12);
+
+	HitArea *ha = _invHitAreas + 5;
+	for (uint8 r = 0; r < 5; r++) {
+		for (uint8 i = 0; i < 7; i++) {
+			printIcon(ha, i, r);
+			ha++;
+		}
+	}
+
+	mouseOn();
+}
+
+bool AGOSEngine_PN::ifObjectInInv(uint16 a) {
+	return _variableArray[210] == getptr(_quickptr[11] + a * _quickshort[4] + 2);
+}
+
+bool AGOSEngine_PN::testContainer(uint16 a) {
+	return 	bitextract(_quickptr[1] + a * _quickshort[1], 0) != 0;
+}
+
+bool AGOSEngine_PN::testObvious(uint16 a) {
+	return 	bitextract(_quickptr[1] + a * _quickshort[1], 4) != 0;
+}
+
+bool AGOSEngine_PN::testSeen(uint16 a) {
+	return 	bitextract(_quickptr[1] + a * _quickshort[1], 3) != 0;
+}
+
+void AGOSEngine_PN::printIcon(HitArea *ha, uint8 i, uint8 r) {
+	 if (_objects == _objectCountS) {
+		ha->flags |= kOBFBoxDisabled;
+		drawIcon(NULL, 0xFF, 12 + i * 3, 12 + 24 * r);
+	} else {
+		_objectCountS++;
+		if (!ifObjectInInv(_objectCountS) || !testObvious(_objectCountS)) {
+			printIcon(ha, i, r);
+		} else {
+
+			uint8 iconNum = getptr(_quickptr[0] + _objectCountS * _quickshort[0] + 4);
+			drawIcon(NULL, iconNum, 12 + i * 3, 12 + 24 * r);
+
+			ha->msg1 = _objectCountS | 0x8000;
+			ha->flags &= ~kOBFBoxDisabled;
+		}
+	}
+}
+
 } // End of namespace AGOS

Modified: scummvm/trunk/engines/agos/input.cpp
===================================================================
--- scummvm/trunk/engines/agos/input.cpp	2009-03-08 08:17:59 UTC (rev 39215)
+++ scummvm/trunk/engines/agos/input.cpp	2009-03-08 08:45:21 UTC (rev 39216)
@@ -606,6 +606,129 @@
 	return verbCode;
 }
 
-} // End of namespace AGOS
+// Personal Nightmare specific
+void AGOSEngine_PN::clearInputLine() {
+	_inputting = 0;
+	_inputReady = 0;
+	clearWindow(_windowArray[2]);
+}
 
+void AGOSEngine_PN::handleKeyboard() {
+	if (!_inputReady)
+		return;
 
+	if (_hitCalled != 0) {
+		mouseHit();
+	}
+
+	int16 chr = -1;
+	if (_mouseString) {
+		const char *strPtr = _mouseString;
+		while (*strPtr != 0 && *strPtr != 13)
+			addChar(*strPtr++);
+		_mouseString = 0;
+
+		chr = *strPtr;
+		if (chr == 13) {
+			addChar(13);
+		}
+	}
+	if (_mouseString1 && chr != 13) {
+		const char *strPtr = _mouseString1;
+		while (*strPtr != 13)
+			addChar(*strPtr++);
+		_mouseString1 = 0;
+
+		chr = *strPtr;
+		if (chr == 13) {
+			addChar(13);
+		}
+	}
+	if (chr == -1) {
+		chr = _keyPressed.ascii;
+		if (chr == 8 || chr == 13) {
+			addChar(chr);
+		} else if (!(_lockWord & 0x10)) {
+			if (chr >= 32)
+				addChar(chr);
+		}
+	}
+
+	if (chr == 13) {
+		_mouseString = 0;
+		_mouseString1 = 0;
+		_mousePrintFG = 0;
+		_inputReady = 0;	
+	}
+
+	_keyPressed.reset();
+}
+
+void AGOSEngine_PN::interact(char *buffer, uint8 size) {
+	if (!_inputting) {
+		memset(_keyboardBuffer, 0, sizeof(_keyboardBuffer));
+		_intputCounter = 0;
+		_inputMax = size;
+		_inputWindow = _windowArray[_curWindow];
+		windowPutChar(_inputWindow, 128);
+		_inputting = 1;
+		_inputReady = 1;
+	}
+	
+	while (!shouldQuit() && _inputReady) {
+		if (!_noScanFlag && _scanFlag) {
+			buffer[0] = 1;
+			buffer[1] = 0;
+			_scanFlag = 0;
+			break;
+		}
+		delay(1);
+	}
+
+	if (!_inputReady) {
+		memcpy(buffer, _keyboardBuffer, size);
+		_inputting = 0;
+	}
+}
+
+void AGOSEngine_PN::addChar(uint8 chr) {
+	if (chr == 13) {
+		_keyboardBuffer[_intputCounter++] = chr;
+		userGameBackSpace(_inputWindow, 8);
+		windowPutChar(_inputWindow, 13);
+	} else if (chr == 8 && _intputCounter) {
+		userGameBackSpace(_inputWindow, 8);
+		userGameBackSpace(_inputWindow, 8);
+		windowPutChar(_inputWindow, 128);
+
+		_keyboardBuffer[--_intputCounter] = 0;
+	} else if (chr >= 32 && _intputCounter < _inputMax) {
+		_keyboardBuffer[_intputCounter++] = chr;
+
+		userGameBackSpace(_inputWindow, 8);
+		windowPutChar(_inputWindow, chr);
+		windowPutChar(_inputWindow, 128);
+	}
+}
+
+bool AGOSEngine_PN::processSpecialKeys() {
+	if (shouldQuit())
+		_exitCutscene = true;		
+
+	switch (_keyPressed.keycode) {
+	case Common::KEYCODE_ESCAPE:
+		_exitCutscene = true;
+		break;
+	case Common::KEYCODE_PAUSE:
+		pause();
+		break;
+	default:
+		break;
+	}
+
+	_keyPressed.reset();
+	return false;
+}
+
+
+} // End of namespace AGOS

Modified: scummvm/trunk/engines/agos/intern.h
===================================================================
--- scummvm/trunk/engines/agos/intern.h	2009-03-08 08:17:59 UTC (rev 39215)
+++ scummvm/trunk/engines/agos/intern.h	2009-03-08 08:45:21 UTC (rev 39216)
@@ -214,6 +214,22 @@
 	kBFBoxItem        = 0x80
 };
 
+enum OldBoxFlags_PN {
+	kOBFObject         = 0x1,
+	kOBFExit           = 0x2,
+	kOBFDraggable      = 0x4,
+	kOBFUseEmptyLine   = 0x8,
+	kOBFBoxDisabled    = 0x10,
+	kOBFInventoryBox   = 0x20,
+	kOBFRoomBox        = 0x40,
+	kOBFMoreBox        = 0x80,
+	kOBFNoShowName     = 0x100,
+	kOBFUseMessageList = 0x400,
+	// ScummVM specific
+	kOBFBoxSelected    = 0x800,
+	kOBFInvertTouch    = 0x1000
+};
+
 enum SubObjectFlags {
 	kOFText           = 0x1,
 	kOFSize           = 0x2,
@@ -251,11 +267,13 @@
 	GAME_TBLFILE  = 1 << 7,
 	GAME_XTBLFILE = 1 << 8,
 	GAME_RESTFILE = 1 << 9,
+	GAME_TEXTFILE = 1 << 10,
 
-	GAME_GFXIDXFILE = 1 << 10
+	GAME_GFXIDXFILE = 1 << 11
 };
 
 enum GameIds {
+	GID_PN,
 	GID_ELVIRA1,
 	GID_ELVIRA2,
 	GID_WAXWORKS,

Modified: scummvm/trunk/engines/agos/menus.cpp
===================================================================
--- scummvm/trunk/engines/agos/menus.cpp	2009-03-08 08:17:59 UTC (rev 39215)
+++ scummvm/trunk/engines/agos/menus.cpp	2009-03-08 08:45:21 UTC (rev 39216)
@@ -53,6 +53,27 @@
 	in.close();
 }
 
+// Personal Nightmare specific
+void AGOSEngine::restoreMenu() {
+	_wiped = 0;
+
+	_lockWord |= 0x80;
+
+	clearVideoWindow(3, 0);
+
+	uint16 oldWindowNum = _windowNum;
+
+	setWindowImage(1, 1);
+	setWindowImage(2, 2);
+
+	drawEdging();
+
+	_windowNum = oldWindowNum;
+
+	_lockWord |= 0x20;
+	_lockWord &= ~0x80;
+}
+
 // Elvira 1 specific
 void AGOSEngine::drawMenuStrip(uint windowNum, uint menuNum) {
 	WindowBlock *window = _windowArray[windowNum % 8];

Modified: scummvm/trunk/engines/agos/module.mk
===================================================================
--- scummvm/trunk/engines/agos/module.mk	2009-03-08 08:17:59 UTC (rev 39215)
+++ scummvm/trunk/engines/agos/module.mk	2009-03-08 08:45:21 UTC (rev 39216)
@@ -20,6 +20,7 @@
 	midi.o \
 	midiparser_s1d.o \
 	oracle.o \
+	pn.o \
 	res.o \
 	res_ami.o \
 	res_snd.o \
@@ -28,6 +29,7 @@
 	script.o \
 	script_e1.o \
 	script_e2.o \
+	script_pn.o \
 	script_ww.o \
 	script_s1.o \
 	script_s2.o \
@@ -39,6 +41,7 @@
 	verb.o \
 	vga.o \
 	vga_e2.o \
+	vga_pn.o \
 	vga_ww.o \
 	vga_s1.o \
 	vga_s2.o \

Added: scummvm/trunk/engines/agos/pn.cpp
===================================================================
--- scummvm/trunk/engines/agos/pn.cpp	                        (rev 0)
+++ scummvm/trunk/engines/agos/pn.cpp	2009-03-08 08:45:21 UTC (rev 39216)
@@ -0,0 +1,293 @@
+/* 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 "common/config-manager.h"
+
+#include "agos/intern.h"
+#include "agos/agos.h"
+
+namespace AGOS {
+
+AGOSEngine_PN::AGOSEngine_PN(OSystem *system)
+	: AGOSEngine(system) {
+
+	_dataBase = 0;
+	_dataBaseSize = 0;
+	_textBase = 0;
+	_textBaseSize = 0;
+
+	memset(_buffer, 0, sizeof(_buffer));
+	memset(_inputline, 0, sizeof(_inputline));
+	memset(_saveFile, 0, sizeof(_saveFile));
+	memset(_sb, 0, sizeof(_sb));
+	memset(_wordcp, 0, sizeof(_wordcp));
+
+	memset(_objectName1, 0, sizeof(_objectName1));
+	memset(_objectName2, 0, sizeof(_objectName2));
+
+	_dragStore = 0;
+	_hitCalled = 0;
+	_inputReady = 0;
+	_inputting = 0;
+	_intputCounter = 0;
+	_inputMax = 0;
+	_mousePrintFG = 0;
+	_mouseString = 0;
+	_mouseString1 = 0;
+	memset(_inMessage, 0, sizeof(_inMessage));
+	memset(_placeMessage, 0, sizeof(_placeMessage));
+
+	memset(_quickptr, 0, sizeof(_quickptr));
+	memset(_quickshort, 0, sizeof(_quickshort));
+
+	_noScanFlag = false;
+	memset(_keyboardBuffer, 0, sizeof(_keyboardBuffer));
+
+	_objects = 0;
+	_objectCountS = 0;
+
+        _bp = 0;
+	_xofs = 0;
+	_havinit = 0;
+	_seed = 0;
+
+	_curwrdptr = 0;
+	_inpp = 0;
+	_fnst = 0;
+	_linembr = 0;
+	_linct = 0;
+	_procnum = 0;
+
+	_linebase = 0;
+	_workptr = 0;
+
+	_cjmpbuff = NULL;
+}
+
+AGOSEngine_PN::~AGOSEngine_PN() {
+	free(_dataBase);
+	free(_textBase);
+
+	free(_cjmpbuff);
+	free(_stackbase);
+}
+
+const byte egaPalette[48] = {
+	  0,   0,   0,
+	  0,   0, 170,
+	  0, 170,   0,
+	  0, 170, 170,
+	170,   0,   0,
+	170,   0, 170,
+	170,  85,   0,
+	170, 170, 170,
+	 85,  85,  85,
+	 85,  85, 255,
+	 85, 255,  85,
+	 85, 255, 255,
+	255,  85,  85,
+	255,  85, 255,
+	255, 255,  85,
+	255, 255, 255
+};
+
+Common::Error AGOSEngine_PN::go() {
+	loadGamePcFile();
+
+	if (getFileName(GAME_ICONFILE) != NULL) {
+		loadIconFile();
+	}
+
+	setupBoxes();
+
+	vc34_setMouseOff();
+
+	addVgaEvent(_frameCount, ANIMATE_INT, NULL, 0, 0);
+
+	if (getPlatform() == Common::kPlatformPC) {
+		// Set EGA Palette
+		for (int i = 0; i < 16; i++) {
+			_displayPalette[i * 4 + 0] = egaPalette[i * 3 + 0];
+			_displayPalette[i * 4 + 1] = egaPalette[i * 3 + 1];
+			_displayPalette[i * 4 + 2] = egaPalette[i * 3 + 2];
+			_displayPalette[i * 4 + 3] = 0;
+		}
+		_paletteFlag = 1;
+	}
+
+	_inputWindow = _windowArray[2] = openWindow(0, 192, 40, 1, 1, 0, 15);
+	_textWindow = _windowArray[0] = openWindow(1, 136, 38, 6, 1, 0, 15);
+
+	if (getFeatures() & GF_DEMO) {
+		demoSeq();
+	} else {
+		introSeq();
+		processor();
+	}
+
+	return Common::kNoError;
+}
+
+void AGOSEngine_PN::demoSeq() {
+	while (!shouldQuit()) {
+		loadZone(0);
+		setWindowImage(3, 0);
+		while (!shouldQuit() && _variableArray[228] != 1)
+			delay(1);
+
+		loadZone(1);
+		setWindowImage(0, 0);
+		while (!shouldQuit() && _variableArray[228] != 2)
+			delay(1);
+
+		loadZone(2);
+		setWindowImage(0, 0);
+		while (!shouldQuit() && _variableArray[228] != 3)
+			delay(1);
+	}
+}
+
+void AGOSEngine_PN::introSeq() {
+	loadZone(25); // Zone 'I'
+	setWindowImage(3, 0);
+
+	_exitCutscene = false;
+	while (!shouldQuit() && !_exitCutscene && _variableArray[228] != 1) {
+		processSpecialKeys();
+		delay(1);
+	}
+
+	setWindowImage(3, 3);
+	delay(100);
+
+	loadZone(27); // Zone 'K'
+	setWindowImage(3, 0);
+
+	_exitCutscene = false;
+	while (!shouldQuit() && !_exitCutscene && _variableArray[228] != 2) {
+		processSpecialKeys();
+		delay(1);
+	}
+}
+
+void AGOSEngine_PN::setupBoxes() {
+	_hitAreaList = _invHitAreas;
+	// Inventory box
+	defineBox( 0,  11,  68, 16,  26, 25, 0, kOBFDraggable | kOBFUseEmptyLine | kOBFInventoryBox | kOBFNoShowName);
+	// Room Box
+	defineBox( 1,  11, 103, 16,  26, 26, 0, kOBFDraggable | kOBFUseEmptyLine | kOBFRoomBox | kOBFNoShowName);
+	// Exit box
+	defineBox( 2,  48,   2,  8,  28, 27, 0, kOBFUseEmptyLine | kOBFNoShowName);
+	// More box
+	defineBox( 3,  80,   2,  8,  26, 28, 0, kOBFUseEmptyLine | kOBFMoreBox | kOBFNoShowName);
+	// Close box
+	defineBox( 4, 110,   2,  8,  28, 29, 0, kOBFUseEmptyLine | kOBFNoShowName);
+
+	// Icon boxes
+	uint8 num = 5;
+	for (uint8 r = 0; r < 5; r++) {
+		for (uint8 i = 0; i < 7; i++) {
+			defineBox(num,  96 + i * 24,  12 + r * 24, 24,  24, 0, 3, kOBFObject | kOBFDraggable);
+			num++;
+		}
+	}
+
+	// Mark the end of inventory boxes
+	HitArea *ha = _hitAreaList + num;
+	ha->id = 0xFFFF;
+
+	_hitAreaList = _hitAreas;
+	defineBox( 0,  0,    0, 200, 320, 0, 0, kOBFBoxDisabled | kOBFNoShowName);
+	defineBox( 1, 273,   4,   5,  45, 1, 0, kOBFUseEmptyLine | kOBFNoShowName | kOBFInvertTouch);
+	defineBox( 2, 273,  12,   5,  45, 2, 0, kOBFUseEmptyLine | kOBFNoShowName | kOBFInvertTouch);
+	defineBox( 3, 273,  20,   5,  45, 3, 0, kOBFUseEmptyLine | kOBFNoShowName | kOBFInvertTouch);
+	defineBox( 4, 273,  28,   5,  45, 4, 0, kOBFUseEmptyLine | kOBFNoShowName | kOBFInvertTouch);
+	defineBox( 5, 273,  36,   5,  45, 5, 0, kOBFUseEmptyLine | kOBFNoShowName | kOBFInvertTouch);
+	defineBox( 6, 273,  44,   5,  45, 6, 0, kOBFUseEmptyLine | kOBFNoShowName | kOBFInvertTouch);
+	defineBox( 7, 273,  52,   5,  45, 7, 0, kOBFUseEmptyLine | kOBFNoShowName | kOBFInvertTouch);
+	defineBox( 8, 273,  60,   5,  45, 8, 0, kOBFUseEmptyLine | kOBFNoShowName | kOBFInvertTouch);
+	defineBox( 9, 273,  68,   5,  45, 9, 0, kOBFUseEmptyLine | kOBFNoShowName | kOBFInvertTouch);
+	defineBox(10, 273,  76,   5,  45, 10, 0, kOBFUseEmptyLine | kOBFNoShowName | kOBFInvertTouch);
+	defineBox(11, 273,  84,   5,  45, 11, 0, kOBFUseEmptyLine | kOBFNoShowName | kOBFInvertTouch);
+	defineBox(12, 273,  92,   5,  45, 12, 0, kOBFUseEmptyLine | kOBFNoShowName | kOBFInvertTouch);
+	defineBox(13, 273, 100,   5,  45, 13, 0, kOBFUseEmptyLine | kOBFBoxDisabled | kOBFNoShowName);
+	defineBox(14, 273, 107,   5,  45, 14, 0, kOBFUseEmptyLine | kOBFNoShowName | kOBFInvertTouch);
+	defineBox(15, 273, 115,   5,  45, 15, 0, kOBFUseEmptyLine | kOBFNoShowName | kOBFInvertTouch);
+	defineBox(16, 273, 123,   5,  45, 16, 0, kOBFUseEmptyLine | kOBFBoxDisabled | kOBFNoShowName);
+	defineBox(17,  20,   5,   7,   7, 17, 0, kOBFUseEmptyLine | kOBFNoShowName);
+	defineBox(18,  28,  11,   7,  13, 18, 0, kOBFUseEmptyLine | kOBFNoShowName);
+	defineBox(19,  36,  21,   7,   7, 19, 0, kOBFUseEmptyLine | kOBFNoShowName);
+	defineBox(20,  27,  31,   7,  13, 20, 0, kOBFUseEmptyLine | kOBFNoShowName);
+	defineBox(21,  20,  37,   7,   7, 21, 0, kOBFUseEmptyLine | kOBFNoShowName);
+	defineBox(22,   5,  31,   7,  13, 22, 0, kOBFUseEmptyLine | kOBFNoShowName);
+	defineBox(23,   4,  21,   7,   7, 23, 0, kOBFUseEmptyLine | kOBFNoShowName);
+	defineBox(24,   5,  11,   7,  13, 24, 0, kOBFUseEmptyLine | kOBFNoShowName);
+	defineBox(25,  11,  68,  16,  26, 25, 0, kOBFDraggable | kOBFUseEmptyLine | kOBFInventoryBox | kOBFNoShowName);
+	defineBox(26,  11, 103,  16,  26, 26, 0, kOBFDraggable | kOBFUseEmptyLine | kOBFRoomBox | kOBFNoShowName);
+}
+
+void AGOSEngine_PN::processor() {
+	int q;
+
+	setqptrs();
+	q = setjmp(_loadfail);
+
+	_variableArray[6] = 0;
+
+	if (getPlatform() == Common::kPlatformAtariST) {
+		_variableArray[21] = 2;
+	} else if (getPlatform() == Common::kPlatformAmiga) {
+		_variableArray[21] = 0;
+	} else {
+		_variableArray[21] = 1;
+	}
+
+	_variableArray[16] = _quickshort[6];
+	_variableArray[17] = _quickshort[7];
+	_variableArray[19] = getptr(55L);
+	setposition(q, 0);
+	doline(0);
+}
+
+void AGOSEngine_PN::setqptrs() {
+	int a = 0;
+
+	while (a < 11) {
+		_quickptr[a] = getlong(3L * a);
+		a++;
+	}
+	_quickptr[11] = getlong(58L);
+	_quickptr[12] = getlong(61L);
+	_quickshort[0] = getptr(35L);
+	_quickshort[1] = getptr(37L);
+	_quickshort[2] = getptr(39L);
+	_quickshort[3] = getptr(41L);
+	_quickshort[4] = getptr(43L);
+	_quickshort[5] = getptr(45L);
+	_quickshort[6] = getptr(51L);
+	_quickshort[7] = getptr(53L);
+}
+
+} // End of namespace AGOS


Property changes on: scummvm/trunk/engines/agos/pn.cpp
___________________________________________________________________
Added: svn:mime-type
   + text/plain
Added: svn:keywords
   + Date Rev Author URL Id
Added: svn:eol-style
   + native

Modified: scummvm/trunk/engines/agos/res.cpp
===================================================================
--- scummvm/trunk/engines/agos/res.cpp	2009-03-08 08:17:59 UTC (rev 39215)
+++ scummvm/trunk/engines/agos/res.cpp	2009-03-08 08:45:21 UTC (rev 39216)
@@ -27,6 +27,7 @@
 
 
 #include "common/file.h"
+#include "common/util.h"
 
 #include "agos/agos.h"
 #include "agos/intern.h"
@@ -149,6 +150,46 @@
 	return itemArrayInited;
 }
 
+void AGOSEngine_PN::loadGamePcFile() {
+	Common::File in;
+
+	if (getFileName(GAME_BASEFILE) != NULL) {
+		// Read dataBase
+		in.open(getFileName(GAME_BASEFILE));
+		if (in.isOpen() == false) {
+			error("loadGamePcFile: Can't load database file '%s'", getFileName(GAME_BASEFILE));
+		}
+
+		_dataBaseSize = in.size();
+		_dataBase = (byte *)malloc(_dataBaseSize);
+		if (_dataBase == NULL)
+			error("loadGamePcFile: Out of memory for dataBase");
+		in.read(_dataBase, _dataBaseSize);
+		in.close();
+
+		if (_dataBase[31] != 0)
+			error("Later version of system requested");
+	}
+
+	if (getFileName(GAME_TEXTFILE) != NULL) {
+		// Read textBase
+		in.open(getFileName(GAME_TEXTFILE));
+		if (in.isOpen() == false) {
+			error("loadGamePcFile: Can't load textbase file '%s'", getFileName(GAME_TEXTFILE));
+		}
+
+		_textBaseSize = in.size();
+		_textBase = (byte *)malloc(_textBaseSize);
+		if (_textBase == NULL)
+			error("loadGamePcFile: Out of memory for textBase");
+		in.read(_textBase, _textBaseSize);
+		in.close();
+
+		if (_textBase[getlong(30L)] != 128)
+			error("Unknown compression format");
+	}
+}
+
 void AGOSEngine::loadGamePcFile() {
 	Common::File in;
 	int fileSize;
@@ -646,6 +687,96 @@
 #undef SD_TYPE_LITERAL
 #undef SD_TYPE_MATCH
 
+static bool getBit(Common::Stack<uint32> &dataList, uint32 &srcVal) {
+	bool result = srcVal & 1;
+	srcVal >>= 1;
+	if (srcVal == 0) {
+		srcVal = dataList.pop();
+
+		result = srcVal & 1;
+		srcVal = (srcVal >> 1) | 0x80000000L;
+	}
+
+	return result;
+}
+
+static uint32 copyBits(Common::Stack<uint32> &dataList, uint32 &srcVal, int numBits) {
+	uint32 destVal = 0;
+	
+	for (int i = 0; i < numBits; ++i) {
+		bool f = getBit(dataList, srcVal);
+		destVal = (destVal << 1) | (f ? 1 : 0);
+	}
+
+	return destVal;
+}
+
+static void transferLoop(uint8 *dataOut, int &outIndex, uint32 destVal, int max) {
+	assert(outIndex > max - 1);
+	byte *pDest = dataOut + outIndex;
+
+	 for (int i = 0; (i <= max) && (outIndex > 0) ; ++i) {
+		pDest = dataOut + --outIndex;
+		*pDest = pDest[destVal];
+	 }
+}
+
+void AGOSEngine::decompressPN(Common::Stack<uint32> &dataList, uint8 *&dataOut, int &dataOutSize) {
+	// Set up the output data area
+	dataOutSize = dataList.pop();
+	dataOut = new uint8[dataOutSize];
+	int outIndex = dataOutSize;
+
+	// Decompression routine
+	uint32 srcVal = dataList.pop();
+	uint32 destVal;
+
+	while (outIndex > 0) {
+		uint32 numBits = 0;
+		int count = 0;
+
+		if (getBit(dataList, srcVal)) {
+			destVal = copyBits(dataList, srcVal, 2);
+
+			if (destVal < 2) {
+				count = destVal + 2;
+				destVal = copyBits(dataList, srcVal, destVal + 9);
+				transferLoop(dataOut, outIndex, destVal, count);
+				continue;
+			} else if (destVal != 3) {
+				count = copyBits(dataList, srcVal, 8);
+				destVal = copyBits(dataList, srcVal, 8);
+				transferLoop(dataOut, outIndex, destVal, count);
+				continue;
+			} else {
+				numBits = 8;
+				count = 8;
+			}
+		} else if (getBit(dataList, srcVal)) {
+			destVal = copyBits(dataList, srcVal, 8);
+			transferLoop(dataOut, outIndex, destVal, 1);
+			continue;
+		} else {
+			numBits = 3;
+			count = 0;
+		}
+
+		destVal = copyBits(dataList, srcVal, numBits);
+		count += destVal;
+
+		// Loop through extracting specified number of bytes
+		for (int i = 0; i <= count; ++i) {
+			// Shift 8 bits from the source to the destination
+			for (int bitCtr = 0; bitCtr < 8; ++bitCtr) {
+				bool flag = getBit(dataList, srcVal);
+				destVal = (destVal << 1) | (flag ? 1 : 0);
+			}
+
+			dataOut[--outIndex] = destVal & 0xff;
+		}
+	}
+}
+
 void AGOSEngine::loadVGABeardFile(uint16 id) {
 	uint32 offs, size;
 
@@ -690,7 +821,7 @@
 	}
 }
 
-void AGOSEngine::loadVGAVideoFile(uint16 id, uint8 type) {
+void AGOSEngine::loadVGAVideoFile(uint16 id, uint8 type, bool useError) {
 	File in;
 	char filename[15];
 	byte *dst;
@@ -729,12 +860,16 @@
 					sprintf(filename, "%c%d.out", 48 + id, type);
 			} else if (getGameType() == GType_ELVIRA1 || getGameType() == GType_ELVIRA2) {
 				sprintf(filename, "%.2d%d.pkd", id, type);
+			} else if (getGameType() == GType_PN) {
+				sprintf(filename, "%c%d.in", id + 48, type);
 			} else {
 				sprintf(filename, "%.3d%d.pkd", id, type);
 			}
 		} else {
 			if (getGameType() == GType_ELVIRA1 || getGameType() == GType_ELVIRA2 || getGameType() == GType_WW) {
 				sprintf(filename, "%.2d%d.VGA", id, type);
+			} else if (getGameType() == GType_PN) {
+				sprintf(filename, "%c%d.out", id + 48, type);
 			} else {
 				sprintf(filename, "%.3d%d.VGA", id, type);
 			}
@@ -742,19 +877,42 @@
 
 		in.open(filename);
 		if (in.isOpen() == false) {
-			error("loadVGAVideoFile: Can't load %s", filename);
+			if (useError)
+				error("loadVGAVideoFile: Can't load %s", filename);
+
+			_block = _blockEnd = NULL;
+			return;
 		}
 
 		dstSize = srcSize = in.size();
-		if (getFeatures() & GF_CRUNCHED) {
-			byte *srcBuffer = (byte *)malloc(srcSize);
-			if (in.read(srcBuffer, srcSize) != srcSize)
+		if (getGameType() == GType_PN && getPlatform() == Common::kPlatformPC && id == 17 && type == 2) {
+			// The A2.out file isn't compressed in PC version of Personal Nightmare
+			dst = allocBlock(dstSize + extraBuffer);
+			if (in.read(dst, dstSize) != dstSize)
 				error("loadVGAVideoFile: Read failed");
+		} else if (getFeatures() & GF_CRUNCHED) {
+			if (getGameType() == GType_PN) {
+				Common::Stack<uint32> data;
+				byte *dataOut = 0;
+				int dataOutSize = 0;
 
-			dstSize = READ_BE_UINT32(srcBuffer + srcSize - 4);
-			dst = allocBlock (dstSize + extraBuffer);
-			decrunchFile(srcBuffer, dst, srcSize);
-			free(srcBuffer);
+				for (uint i = 0; i < srcSize / 4; ++i)
+					data.push(in.readUint32BE());
+
+				decompressPN(data, dataOut, dataOutSize);
+				dst = allocBlock (dataOutSize + extraBuffer);
+				memcpy(dst, dataOut, dataOutSize);
+				delete[] dataOut;
+			} else {
+				byte *srcBuffer = (byte *)malloc(srcSize);
+				if (in.read(srcBuffer, srcSize) != srcSize)
+					error("loadVGAVideoFile: Read failed");
+
+				dstSize = READ_BE_UINT32(srcBuffer + srcSize - 4);
+				dst = allocBlock (dstSize + extraBuffer);
+				decrunchFile(srcBuffer, dst, srcSize);
+				free(srcBuffer);
+			}
 		} else {
 			dst = allocBlock(dstSize + extraBuffer);
 			if (in.read(dst, dstSize) != dstSize)

Modified: scummvm/trunk/engines/agos/res_ami.cpp
===================================================================
--- scummvm/trunk/engines/agos/res_ami.cpp	2009-03-08 08:17:59 UTC (rev 39215)
+++ scummvm/trunk/engines/agos/res_ami.cpp	2009-03-08 08:45:21 UTC (rev 39216)
@@ -92,7 +92,7 @@
 	}
 }
 
-static void convertCompressedImage(const byte *src, byte *dst, uint8 colorDepth, int height, int width) {
+static void convertCompressedImage(const byte *src, byte *dst, uint8 colorDepth, int height, int width, bool horizontal = true) {
 	const byte *plane[kMaxColorDepth];
 	byte *uncptr[kMaxColorDepth];
 	int length, i, j;
@@ -119,11 +119,20 @@
 
 	uncbfroutptr = uncbfrout;
 	const int chunkSize = colorDepth > 4 ? 16 : 8;
-	for (i = 0; i < width / 16; ++i) {
+	if (horizontal)  {
 		for (j = 0; j < height; ++j) {
-			memcpy(dst + width * chunkSize / 16 * j + chunkSize * i, uncbfroutptr, chunkSize);
-			uncbfroutptr += chunkSize;
+			for (i = 0; i < width / 16; ++i) {
+				memcpy(dst + width * chunkSize / 16 * j + chunkSize * i, uncbfroutptr, chunkSize);
+				uncbfroutptr += chunkSize;
+			}
 		}
+	} else {
+		for (i = 0; i < width / 16; ++i) {
+			for (j = 0; j < height; ++j) {
+				memcpy(dst + width * chunkSize / 16 * j + chunkSize * i, uncbfroutptr, chunkSize);
+				uncbfroutptr += chunkSize;
+			}
+		}
 	}
 
 	free(uncbfrout);
@@ -152,7 +161,7 @@
 	byte *dst = _planarBuf;
 
 	if (compressed) {
-		convertCompressedImage(src, dst, colorDepth, height, width);
+		convertCompressedImage(src, dst, colorDepth, height, width, (getGameType() == GType_PN));
 	} else {
 		length = (width + 15) / 16 * height;
 		for (i = 0; i < length; i++) {

Modified: scummvm/trunk/engines/agos/res_snd.cpp
===================================================================
--- scummvm/trunk/engines/agos/res_snd.cpp	2009-03-08 08:17:59 UTC (rev 39215)
+++ scummvm/trunk/engines/agos/res_snd.cpp	2009-03-08 08:45:21 UTC (rev 39216)
@@ -364,6 +364,8 @@
 			sprintf(filename, "%c%d.out", 48 + id, type);
 		} else if (getGameType() == GType_ELVIRA1 || getGameType() == GType_ELVIRA2) {
 			sprintf(filename, "%.2d%d.out", id, type);
+		} else if (getGameType() == GType_PN) {
+			sprintf(filename, "%c%d.in", id + 48, type);
 		} else {
 			sprintf(filename, "%.3d%d.out", id, type);
 		}
@@ -375,6 +377,8 @@
 			sprintf(filename, "%.2d.SND", elvira1_soundTable[id]);
 		} else if (getGameType() == GType_ELVIRA2 || getGameType() == GType_WW) {
 			sprintf(filename, "%.2d%d.VGA", id, type);
+		} else if (getGameType() == GType_PN) {
+			sprintf(filename, "%c%d.out", id + 48, type);
 		} else {
 			sprintf(filename, "%.3d%d.VGA", id, type);
 		}
@@ -386,7 +390,19 @@
 	}
 
 	dstSize = srcSize = in.size();
-	if (getGameType() == GType_ELVIRA1 && getFeatures() & GF_DEMO) {
+	if (getGameType() == GType_PN) {
+		Common::Stack<uint32> data;
+		byte *dataOut = 0;
+		int dataOutSize = 0;
+
+		for (uint i = 0; i < srcSize / 4; ++i)
+			data.push(in.readUint32BE());
+
+		decompressPN(data, dataOut, dataOutSize);
+		dst = allocBlock (dataOutSize);
+		memcpy(dst, dataOut, dataOutSize);
+		delete[] dataOut;
+	} else if (getGameType() == GType_ELVIRA1 && getFeatures() & GF_DEMO) {
 		byte *srcBuffer = (byte *)malloc(srcSize);
 		if (in.read(srcBuffer, srcSize) != srcSize)
 			error("loadVGASoundFile: Read failed");
@@ -457,41 +473,9 @@
 	_sound->playSfxData(dst, 0, 0, 0);
 }
 
-void AGOSEngine::loadSound(uint sound) {
+void AGOSEngine::loadSound(uint16 sound, int16 pan, int16 vol, uint16 type) {
 	byte *dst;
-	uint32 offs, size;
 
-	if (_curSfxFile == NULL)
-		return;
-
-	dst = _curSfxFile;
-	if (getGameType() == GType_WW) {
-		uint tmp = sound;
-		while (tmp--)
-			dst += READ_LE_UINT16(dst) + 4;
-
-		size = READ_LE_UINT16(dst);
-		offs = 4;
-	} else if (getGameType() == GType_ELVIRA2) {
-		while (READ_BE_UINT32(dst + 4) != sound)
-			dst += 12;
-
-		size = READ_BE_UINT32(dst);
-		offs = READ_BE_UINT32(dst + 8);
-	} else {
-		while (READ_BE_UINT16(dst + 6) != sound)
-			dst += 12;
-
-		size = READ_BE_UINT16(dst + 2);
-		offs = READ_BE_UINT32(dst + 8);
-	}
-
-	_sound->playRawData(dst + offs, sound, size);
-}
-
-void AGOSEngine::loadSound(uint sound, int pan, int vol, uint type) {
-	byte *dst;
-
 	if (getGameId() == GID_DIMP) {
 		File in;
 		char filename[15];
@@ -532,14 +516,69 @@
 		dst = _curSfxFile + READ_LE_UINT32(_curSfxFile + sound * 4);
 	}
 
-	if (type == 3)
-		_sound->playSfx5Data(dst, sound, pan, vol);
-	else if (type == 2)
+	if (type == Sound::TYPE_AMBIENT)
 		_sound->playAmbientData(dst, sound, pan, vol);
-	else
+	else if (type == Sound::TYPE_SFX)
 		_sound->playSfxData(dst, sound, pan, vol);
+	else if (type == Sound::TYPE_SFX5)
+		_sound->playSfx5Data(dst, sound, pan, vol);
 }
 
+void AGOSEngine::loadSound(uint16 sound, uint16 freq, uint16 flags) {
+	byte *dst;
+	uint32 offs, size = 0;
+
+	if (_curSfxFile == NULL)
+		return;
+
+	dst = _curSfxFile;
+	if (getGameType() == GType_WW) {
+		uint tmp = sound;
+		while (tmp--) {
+			dst += READ_LE_UINT16(dst) + 4;
+			size += READ_LE_UINT16(dst) + 4;
+
+			if (size > _curSfxFileSize)
+				error("loadSound: Reading beyond EOF");
+		}
+
+		size = READ_LE_UINT16(dst);
+		offs = 4;
+	} else if (getGameType() == GType_ELVIRA2) {
+		while (READ_BE_UINT32(dst + 4) != sound) {
+			dst += 12;
+			size += 12;
+
+			if (size > _curSfxFileSize)
+				error("loadSound: Reading beyond EOF");
+		}
+
+		size = READ_BE_UINT32(dst);
+		offs = READ_BE_UINT32(dst + 8);
+	} else {
+		while (READ_BE_UINT16(dst + 6) != sound) {
+			dst += 12;
+			size += 12;
+
+			if (size > _curSfxFileSize)
+				error("loadSound: Reading beyond EOF");
+
+		}
+
+		size = READ_BE_UINT16(dst + 2);
+		offs = READ_BE_UINT32(dst + 8);
+	}
+
+	// TODO: Handle other sound flags and frequency
+	if (flags == 2 && _sound->isSfxActive()) {
+		_sound->queueSound(dst + offs, sound, size, 8000);
+	} else {
+		if (flags == 0)
+			_sound->stopSfx();
+		_sound->playRawData(dst + offs, sound, size, 8000);
+	}
+}
+
 void AGOSEngine::loadVoice(uint speechId) {
 	if (getGameType() == GType_PP && speechId == 99) {
 		_sound->stopVoice();

Modified: scummvm/trunk/engines/agos/saveload.cpp
===================================================================
--- scummvm/trunk/engines/agos/saveload.cpp	2009-03-08 08:17:59 UTC (rev 39215)
+++ scummvm/trunk/engines/agos/saveload.cpp	2009-03-08 08:45:21 UTC (rev 39216)
@@ -125,12 +125,21 @@
 	return buf;
 }
 
-char *AGOSEngine::genSaveName(int slot) {
+char *AGOSEngine_Elvira1::genSaveName(int slot) {
 	static char buf[20];
 	sprintf(buf, "elvira1.%.3d", slot);
 	return buf;
 }
 
+char *AGOSEngine::genSaveName(int slot) {
+	static char buf[20];
+	if (getPlatform() == Common::kPlatformPC)
+		sprintf(buf, "pn-pc.%.3d", slot);
+	else
+		sprintf(buf, "pn.%.3d", slot);
+	return buf;
+}
+
 void AGOSEngine::quickLoadOrSave() {
 	// Quick load & save is only supported complete version of Simon the Sorcerer 1/2
 	if (getGameType() == GType_PP || getGameType() == GType_FF ||
@@ -1544,4 +1553,125 @@
 	return result;
 }
 
+// Personal Nightmare specific
+bool AGOSEngine_PN::badload(int8 errorNum) {
+	if (errorNum == -2)
+		return 0;
+	/* Load error recovery routine */
+	while (_stackbase != NULL) {
+		/* Clear any stack */
+		dumpstack();
+	}
+	/* Restart from process 1 */
+	longjmp(_loadfail, 1);
+	return 1;
+}
+
+void AGOSEngine_PN::getFilename() {
+	_noScanFlag = 1;
+	clearInputLine();
+
+	memset(_saveFile, 0, sizeof(_saveFile));
+	while (!shouldQuit() && !strlen(_saveFile)) {
+		const char *msg = "File name : ";
+	        pcf((unsigned char)'\n');
+		while (*msg)
+			pcf((unsigned char)*msg++);
+
+		interact(_saveFile, 8);
+		pcf((unsigned char)'\n');
+		_noScanFlag = 0;
+	}
+}
+
+int AGOSEngine_PN::loadfl(char *name) {
+	Common::InSaveFile *f;
+	haltAnimation();
+
+	f = _saveFileMan->openForLoading(name);
+	if (f == NULL) {
+		restartAnimation();
+		return -2;
+	}
+	f->read(_saveFile, 8);
+
+	if (f->readByte() != 41) {
+		restartAnimation();
+		delete f;
+		return -2;
+	}
+	if (f->readByte() != 33) {
+		restartAnimation();
+		delete f;
+		return -2;
+	}
+	// TODO: Make endian safe
+	if (!f->read(_dataBase + _quickptr[2], (int)(_quickptr[6] - _quickptr[2]))) {
+		restartAnimation();
+		delete f;
+		return -1;
+	}
+		delete f;
+	restartAnimation();
+	dbtosysf();
+	return 0;
+}
+
+int AGOSEngine_PN::savfl(char *name) {
+	Common::OutSaveFile *f;
+	sysftodb();
+	haltAnimation();
+
+	f = _saveFileMan->openForSaving(name);
+	if (f == NULL) {
+		restartAnimation();
+
+		const char *msg = "Couldn't save. ";
+	        pcf((unsigned char)'\n');
+		while (*msg)
+			pcf((unsigned char)*msg++);
+
+		return 0;
+	}
+	f->write(_saveFile, 8);
+
+	f->writeByte(41);
+	f->writeByte(33);
+	// TODO: Make endian safe
+	if (!f->write(_dataBase + _quickptr[2], (int)(_quickptr[6] - _quickptr[2]))) {
+		delete f;
+		restartAnimation();
+		error("Couldn't save ");
+		return 0;
+	}
+	f->finalize();
+	delete f;
+
+	restartAnimation();
+	return 1;
+}
+
+void AGOSEngine_PN::sysftodb() {
+	uint32 pos = _quickptr[2];
+	int ct = 0;
+
+	while (ct < (getptr(49L) / 2)) {
+		_dataBase[pos] = (uint8)(_variableArray[ct] % 256);
+		_dataBase[pos + 1] = (uint8)(_variableArray[ct] / 256);
+		pos+=2;
+		ct++;
+	}
+}
+
+void AGOSEngine_PN::dbtosysf() {
+	uint32 pos = _quickptr[2];
+	int ct = 0;
+
+	while (ct < (getptr(49L) / 2)) {
+		_variableArray[ct] = _dataBase[pos] + 256 * _dataBase[pos + 1];
+		pos += 2;
+		ct++;
+	}
+}
+
 } // End of namespace AGOS

Modified: scummvm/trunk/engines/agos/script_e2.cpp
===================================================================
--- scummvm/trunk/engines/agos/script_e2.cpp	2009-03-08 08:17:59 UTC (rev 39215)
+++ scummvm/trunk/engines/agos/script_e2.cpp	2009-03-08 08:45:21 UTC (rev 39216)
@@ -574,9 +574,7 @@
 void AGOSEngine_Elvira2::oe2_playEffect() {
 	// 174: play sound
 	uint soundId = getVarOrWord();
-	loadSound(soundId);
-
-	debug(0, "oe2_playEffect: stub (%d)", soundId);
+	loadSound(soundId, 0, 0);
 }
 
 void AGOSEngine_Elvira2::oe2_getDollar2() {
@@ -636,7 +634,7 @@
 void AGOSEngine_Elvira2::oe2_isAdjNoun() {
 	// 179: item unk1 unk2 is
 	Item *item = getNextItemPtr();
-	int16 a = getNextWord(), b = getNextWord();
+	int16 a = getNextWord(), n = getNextWord();
 
 	if (getGameType() == GType_ELVIRA2) {
 		// WORKAROUND bug #1745996: A NULL item can occur when
@@ -647,7 +645,7 @@
 		}
 	}
 
-	setScriptCondition(item->adjective == a && item->noun == b);
+	setScriptCondition(item->adjective == a && item->noun == n);
 }
 
 void AGOSEngine_Elvira2::oe2_b2Set() {

Added: scummvm/trunk/engines/agos/script_pn.cpp
===================================================================
--- scummvm/trunk/engines/agos/script_pn.cpp	                        (rev 0)
+++ scummvm/trunk/engines/agos/script_pn.cpp	2009-03-08 08:45:21 UTC (rev 39216)
@@ -0,0 +1,1109 @@
+/* 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 "agos/agos.h"
+#include "agos/vga.h"
+
+namespace AGOS {
+
+#define OPCODE(x)	_OPCODE(AGOSEngine_PN, x)
+
+void AGOSEngine_PN::setupOpcodes() {
+	static const OpcodeEntryPN opcodes[] = {
+		/* 00 */
+		OPCODE(opn_opcode00),
+		OPCODE(opn_opcode01),
+		OPCODE(opn_opcode02),
+		OPCODE(opn_opcode03),
+		/* 04 */
+		OPCODE(opn_opcode04),
+		OPCODE(opn_opcode05),
+		OPCODE(opn_opcode06),
+		OPCODE(opn_opcode07),
+		/* 08 */
+		OPCODE(opn_opcode08),
+		OPCODE(opn_opcode09),
+		OPCODE(opn_opcode10),
+		OPCODE(opn_opcode11),
+		/* 12 */
+		OPCODE(opn_opcode12),
+		OPCODE(opn_opcode13),
+		OPCODE(opn_opcode14),
+		OPCODE(opn_opcode15),
+		/* 16 */
+		OPCODE(opn_opcode16),
+		OPCODE(opn_opcode17),
+		OPCODE(opn_opcode18),
+		OPCODE(opn_opcode19),
+		/* 20 */
+		OPCODE(opn_opcode20),
+		OPCODE(opn_opcode21),
+		OPCODE(opn_opcode22),
+		OPCODE(opn_opcode23),
+		/* 24 */
+		OPCODE(opn_opcode24),
+		OPCODE(opn_opcode25),
+		OPCODE(opn_opcode26),
+		OPCODE(opn_opcode27),
+		/* 28 */
+		OPCODE(opn_opcode28),
+		OPCODE(opn_opcode29),
+		OPCODE(opn_opcode30),
+		OPCODE(opn_opcode31),
+		/* 32 */
+		OPCODE(opn_opcode32),
+		OPCODE(opn_opcode33),
+		OPCODE(opn_opcode34),
+		OPCODE(opn_opcode35),
+		/* 36 */
+		OPCODE(opn_opcode36),
+		OPCODE(opn_opcode37),
+		OPCODE(opn_opcode38),
+		OPCODE(opn_opcode39),
+		/* 40 */
+		OPCODE(opn_opcode40),
+		OPCODE(opn_opcode41),
+		OPCODE(opn_opcode42),
+		OPCODE(opn_opcode43),
+		/* 44 */
+		OPCODE(opn_opcode44),
+		OPCODE(opn_opcode45),
+		OPCODE(opn_opcode46),
+		OPCODE(opn_opcode47),
+		/* 48 */
+		OPCODE(opn_opcode48),
+		OPCODE(opn_opcode49),
+		OPCODE(opn_opcode50),
+		OPCODE(opn_opcode51),
+		/* 52 */
+		OPCODE(opn_opcode52),
+		OPCODE(opn_opcode53),
+		OPCODE(opn_opcode54),
+		OPCODE(opn_opcode55),
+		/* 56 */
+		OPCODE(opn_opcode56),
+		OPCODE(opn_opcode57),
+		OPCODE(o_invalid),
+		OPCODE(o_invalid),
+		/* 60 */
+		OPCODE(o_invalid),
+		OPCODE(o_invalid),
+		OPCODE(opn_opcode62),
+		OPCODE(opn_opcode63),
+	};
+
+	_opcodesPN = opcodes;
+	_numOpcodes = 64;
+}
+
+void AGOSEngine_PN::executeOpcode(int opcode) {
+	OpcodeProcPN op = _opcodesPN[opcode].proc;
+	(this->*op) ();
+}
+
+#define readfromline() (_linct-- ? (int)*_workptr++ : readoverr())
+
+int readoverr() {
+	error("Internal Error - Line Over-run");
+}
+
+// -----------------------------------------------------------------------
+// Personal Nightmare Opcodes
+// -----------------------------------------------------------------------
+
+void AGOSEngine_PN::opn_opcode00() {
+	uint8 *str = _workptr;
+	varval();
+	writeval(str, varval());
+	setScriptReturn(true);
+}
+
+void AGOSEngine_PN::opn_opcode01() {
+	uint8 *str = _workptr;
+	int32 sp = varval() + varval();
+	_variableArray[12] = sp % 65536;
+	_variableArray[13] = sp / 65536;
+	if (sp > 65535) 
+		sp=65535;
+	writeval(str, (int)sp);
+	setScriptReturn(true);
+}
+
+void AGOSEngine_PN::opn_opcode02() {
+	uint8 *str = _workptr;
+	int32 sp = varval();
+	sp -= varval();
+	_variableArray[12] = sp % 65536;
+	_variableArray[13] = sp / 65536;
+	if(sp < 0)
+		sp = 0;
+	writeval(str, (int)sp);
+	setScriptReturn(true);
+}
+
+void AGOSEngine_PN::opn_opcode03() {
+	uint8 *str = _workptr;
+	int32 sp = varval() * varval();
+	_variableArray[12] = sp % 65536;
+	_variableArray[13] = sp / 65536;
+	if (sp > 65535)
+		sp = 65535;
+	writeval(str, (int)sp);
+	setScriptReturn(true);
+}
+
+void AGOSEngine_PN::opn_opcode04() {
+	uint8 *str = _workptr;
+	int32 sp = varval();
+	int32 sp2 = varval();
+	if (sp2 == 0)
+		error("Division by 0");
+	sp = sp / sp2;
+	_variableArray[12] = sp % 65536;
+	_variableArray[13] = sp / 65536;
+	writeval(str, (int)sp);
+	setScriptReturn(true);
+}
+
+void AGOSEngine_PN::opn_opcode05() {
+	pcf((uint8)'\n');
+	setScriptReturn(true);
+}
+
+void AGOSEngine_PN::opn_opcode06() {
+	pmesd(varval());
+	setScriptReturn(true);
+}
+
+void AGOSEngine_PN::opn_opcode07() {
+	int32 sp = varval();
+	plocd((int)sp, varval());
+	setScriptReturn(true);
+}
+
+void AGOSEngine_PN::opn_opcode08() {
+	int32 sp = varval();
+	pobjd((int)sp, varval());
+	setScriptReturn(true);
+}
+
+void AGOSEngine_PN::opn_opcode09() {
+	pmesd(varval());
+	pcf((uint8)'\n');
+	setScriptReturn(true);
+}
+
+void AGOSEngine_PN::opn_opcode10() {
+	int32 sp = varval();
+	plocd((int)sp, varval());
+	pcf((uint8)'\n');
+	setScriptReturn(true);
+}
+
+void AGOSEngine_PN::opn_opcode11() {
+	int32 sp = varval();
+	pobjd((int)sp, varval());
+	setScriptReturn(true);
+}
+
+void AGOSEngine_PN::opn_opcode12() {
+	char bf[8];
+	int a = 0;
+	sprintf(bf,"%d", varval());
+	while(bf[a])
+		pcf(bf[a++]);
+	setScriptReturn(true);
+}
+
+void AGOSEngine_PN::opn_opcode13() {
+	char bf[8];
+	int a = 0;
+	sprintf(bf,"%d", varval());
+	while(bf[a])
+		pcf(bf[a++]);
+	pcf((uint8)'\n');
+	setScriptReturn(true);
+}
+
+void AGOSEngine_PN::opn_opcode14() {
+	clearWindow(_windowArray[_curWindow]);
+	pcf((uint8)255);
+	setScriptReturn(true);
+}
+
+void AGOSEngine_PN::opn_opcode15() {
+	int32 x = varval();;
+	if ((x < 0) || (x > 4))
+		x = 0;
+
+	pcf((unsigned char)254);
+	_curWindow = x;
+	_xofs = (8 * _windowArray[_curWindow]->textLength) / 6 + 1;
+	setScriptReturn(true);
+}
+
+void AGOSEngine_PN::opn_opcode16() {
+	int32 sp = varval();
+	setScriptReturn((sp >= 0 && sp <= 4));
+}
+
+void AGOSEngine_PN::opn_opcode17() {
+	int16 v1 = varval();
+	int16 v2 = varval();
+	setScriptReturn(v1 < v2);
+}
+
+void AGOSEngine_PN::opn_opcode18() {
+	int16 v1 = varval();
+	int16 v2 = varval();
+	setScriptReturn(v1 > v2);
+}
+
+void AGOSEngine_PN::opn_opcode19() {
+	int16 v1 = varval();
+	int16 v2 = varval();
+	setScriptReturn(v1 == v2);
+}
+
+void AGOSEngine_PN::opn_opcode20() {
+	int16 v1 = varval();
+	int16 v2 = varval();
+	setScriptReturn(v1 != v2);
+}
+
+void AGOSEngine_PN::opn_opcode21() {
+	setposition(_procnum, varval());
+	setScriptReturn(true);
+}
+
+void AGOSEngine_PN::opn_opcode22() {
+	int pf[8];
+	int a;
+	a = varval();
+	funcentry(pf, a);
+	funccpy(pf);
+	setposition(a, 0);
+	setScriptReturn(true);
+}
+
+void AGOSEngine_PN::opn_opcode23() {
+	setScriptReturn(actCallD(varval()));
+}
+
+void AGOSEngine_PN::opn_opcode24() {
+	popstack(-1);
+	longjmp(*(_stackbase->savearea), 2);
+	setScriptReturn(false);
+}
+
+void AGOSEngine_PN::opn_opcode25() {
+	popstack(-1);
+	longjmp(*(_stackbase->savearea), 1);
+	setScriptReturn(false);
+}
+
+void AGOSEngine_PN::opn_opcode26() {
+	while ((_stackbase->classnum != -1) && (_stackbase != NULL))
+		junkstack();
+	dumpstack(); 
+	setScriptReturn(true);
+}
+
+void AGOSEngine_PN::opn_opcode27() {
+	quitGame();
+	// Make sure the quit event is processed immediately.
+	delay(0);
+}
+
+void AGOSEngine_PN::opn_opcode28() {
+	addstack(varval());
+	_stackbase->savearea = _cjmpbuff;
+	setScriptReturn(false);
+}
+
+void AGOSEngine_PN::opn_opcode29() {
+	popstack(varval());
+	longjmp(*(_stackbase->savearea), -1);
+	setScriptReturn(false);
+}
+
+void AGOSEngine_PN::opn_opcode30() {
+	_variableArray[1] = varval();
+	setScriptReturn(true);
+}
+
+void AGOSEngine_PN::opn_opcode31() {
+	int a, slot = 0;
+	char bf[60];
+
+	if ((a = varval()) > 2) {
+		setScriptReturn(false);
+		return;
+	}
+
+	switch (a) {
+		case 0:
+			getFilename();
+			slot = matchSaveGame(_saveFile, countSaveGames());
+			strcpy(bf, genSaveName(slot));
+			break;
+		case 1: 
+			strcpy(bf, "test.sav");
+			break;
+		case 2: 
+			// NOTE: Is this case ever used?
+			error("opn_opcode31: case 2");
+			break;
+	}
+
+	a = loadfl(bf);
+	if (a)
+		setScriptReturn(badload(a));
+	else
+		setScriptReturn(true);
+}
+
+void AGOSEngine_PN::opn_opcode32() {
+	char bf[60];
+	int a;
+
+	if ((a = varval()) > 2) {
+		setScriptReturn(true);
+		return;
+	}
+
+	switch (a) {
+		case 0:
+			getFilename();
+			strcpy(bf, genSaveName(countSaveGames()));
+			break;
+		case 1:
+			strcpy(bf, "test.sav");
+			break;
+		case 2:
+			// NOTE: Is this case ever used?
+			error("opn_opcode32: case 2");
+			break;
+	}
+
+	a = savfl(bf);
+	setScriptReturn(a);
+}
+
+void AGOSEngine_PN::opn_opcode33() {
+	setScriptReturn((varval() < 3) ? 1 : 0);
+}
+
+void AGOSEngine_PN::opn_opcode34() {
+	uint16 msgNum1, msgNum2;
+	varval();
+	getResponse((int)_variableArray[166], (int)_variableArray[167], msgNum1, msgNum2);
+	_variableArray[168]= msgNum1;
+	_variableArray[169]= msgNum2;
+	setScriptReturn(true);
+}
+
+void AGOSEngine_PN::opn_opcode35() {
+	int a;
+	uint8 *sav = _workptr;
+	varval();
+	a = varval();
+	if ((a = gvwrd((uint8 *)_wordcp, a)) == -1) {
+		setScriptReturn(false);
+		return;
+	}
+
+	writeval(sav, a);
+	setScriptReturn(true);
+}
+
+void AGOSEngine_PN::opn_opcode36() {
+	int ct = 0;
+	while (ct < _dataBase[57] + 1)
+		_wordcp[ct++] = 0;
+	ct = 1;
+	if (isspace(*_inpp))
+		while ((*_inpp) && (isspace(*_inpp)))
+			_inpp++;
+	if (*_inpp == 0) {
+		setScriptReturn(false);
+		return;
+	}
+	_curwrdptr = _inpp;
+	_wordcp[0] = *_inpp++;
+	if ((_wordcp[0] == '.') || (_wordcp[0] == ',') || (_wordcp[0] == '"')) {
+		setScriptReturn(true);
+		return;
+	}
+	while ((*_inpp != '.') && (*_inpp != ',') && (!isspace(*_inpp)) && (*_inpp != '\0') &&
+		(*_inpp!='"')) {
+		if (ct < _dataBase[57])
+			_wordcp[ct++] = *_inpp;
+		_inpp++;
+	}
+	setScriptReturn(true);
+}
+
+void AGOSEngine_PN::opn_opcode37() {
+	_curwrdptr = NULL;
+
+	_inputReady = 1;
+	interact(_inputline, 49);
+
+	if ((_inpp = strchr(_inputline,'\n')) != NULL)
+		*_inpp = '\0';
+	_inpp = _inputline;
+	setScriptReturn(true);
+}
+
+void AGOSEngine_PN::opn_opcode38() {
+	_noScanFlag = 1;
+	clearInputLine();
+	writeval(_workptr, _keyPressed.ascii);
+	_keyPressed.reset();
+	_noScanFlag = 0;
+	varval();
+	setScriptReturn(true);
+}
+
+void AGOSEngine_PN::opn_opcode39() {
+	pcf((uint8)varval());
+	setScriptReturn(true);
+}
+
+void AGOSEngine_PN::opn_opcode40() {
+	setScriptReturn(doaction() | doaction());
+}
+
+void AGOSEngine_PN::opn_opcode41() {
+	setScriptReturn(doaction() & doaction());
+}
+
+void AGOSEngine_PN::opn_opcode42() {
+	setScriptReturn(doaction() ^ doaction());
+}
+
+void AGOSEngine_PN::opn_opcode43() {
+	setScriptReturn(!(doaction()));
+}
+
+void AGOSEngine_PN::opn_opcode44() {
+	pcf((uint8)254);
+	setScriptReturn(true);
+}
+
+void AGOSEngine_PN::opn_opcode45() {
+	uint8 *myptr;
+	int x;
+
+	if (_havinit == 0) {
+		_seed = (int16)getTime();
+		_havinit = 1;
+	}
+	_seed = 1 + (75 * (_seed + 1) - 1) % 65537;
+	myptr = _workptr;
+	varval();
+	x = varval();
+	if (x == 0)
+		error("Illegal range specified for RANDOM");
+	writeval(myptr, (_seed % x));
+	setScriptReturn(true);
+}
+
+void AGOSEngine_PN::opn_opcode46() {
+	char *x = _curwrdptr;
+	if (x == NULL) {
+		setScriptReturn(true);
+		return;
+	}
+	pcf(*x);
+	if ((*x == '.') || (*x == '"') || (*x == ',')) {
+		setScriptReturn(true);
+		return;
+	}
+	x++;
+	while ((*x != '.') && (*x != ',') && (*x != '"') && (!isspace(*x)) && (*x != '\0'))
+		pcf(*x++);
+	setScriptReturn(true);
+}
+
+void AGOSEngine_PN::opn_opcode47() {
+	pmesd(varval() * 256 + varval());
+	setScriptReturn(true);
+}
+
+void AGOSEngine_PN::opn_opcode48() {
+	pmesd(varval() * 256 + varval());
+	pcf((uint8)'\n');
+	setScriptReturn(true);
+}
+
+void AGOSEngine_PN::opn_opcode49() {
+	setScriptReturn(findentry());
+}
+
+void AGOSEngine_PN::opn_opcode50() {
+	_fnst = 0;
+	setScriptReturn(findset());
+}
+
+void AGOSEngine_PN::opn_opcode51() {
+	_fnst = varval();
+	setScriptReturn(findset());
+}
+
+void AGOSEngine_PN::opn_opcode52() {
+	int32 mode = varval();
+	if (mode == 1) {
+		setWindowImage(mode, varval(), true);
+	} else {
+		setWindowImageEx(mode, varval());
+	}
+
+	setScriptReturn(true);
+}
+
+void AGOSEngine_PN::opn_opcode53() {
+	vc27_resetSprite();
+	setScriptReturn(true);
+}
+
+void AGOSEngine_PN::opn_opcode54() {
+	stopAnimate(varval());
+	setScriptReturn(true);
+}
+
+void AGOSEngine_PN::opn_opcode55() {
+	varval();
+	varval();
+	varval();
+	setScriptReturn(true);
+}
+
+void AGOSEngine_PN::opn_opcode56() {
+	varval();
+	varval();
+	varval();
+	setScriptReturn(true);
+}
+
+void AGOSEngine_PN::opn_opcode57() {
+	uint16 windowNum = varval();
+	uint16 vgaSpriteId = varval();
+	int16 x = varval();
+	int16 y = varval();
+	uint16 palette = varval();
+
+	_lockWord |= 0x40;
+	animate(windowNum, 0, vgaSpriteId, x, y, palette);
+	_lockWord &= ~0x40;
+
+	setScriptReturn(true);
+}
+
+void AGOSEngine_PN::opn_opcode62() {
+	int32 zoneNum = varval();
+
+	_lockWord |= 0x80;
+
+	vc29_stopAllSounds();
+
+	_hitCalled = 0;
+	_oneClick = 0;
+
+	loadZone(zoneNum);
+
+	setWindowImage(2, 2);
+
+	_copyScnFlag = 0;
+	_vgaSpriteChanged = 0;
+
+	_lockWord &= ~0x80;
+
+	setScriptReturn(true);
+}
+
+void AGOSEngine_PN::opn_opcode63() {
+	int a = readfromline();
+	switch (a) {
+		case 65:
+			setScriptReturn(inventoryOn(varval()));
+			break;
+		case 64:
+			setScriptReturn((_lockWord & 0x10) != 0);
+			break;
+		case 63:
+			setScriptReturn(inventoryOff());
+			break;
+		default:
+			error("opn_opcode63: unknown code %d", a);
+	}
+}
+
+int AGOSEngine_PN::inventoryOn(int val) {
+	writeVariable(210, val);
+	if (_lockWord & 0x10) {
+		iconPage();
+	} else {
+		_lockWord |= 0x10;
+		_hitAreaList = _invHitAreas;
+
+		_windowArray[2]->textColor = 0;
+		windowPutChar(_windowArray[2], 13);
+
+		clearVideoWindow(4, 0);
+		drawIconHitBar();
+
+		_objects = _variableArray[211];
+		_objectCountS = -1;
+		iconPage();
+	}
+	return 1;
+}
+
+int AGOSEngine_PN::inventoryOff() {
+	if (_lockWord & 0x10) {
+		_windowArray[2]->textColor = 15;
+
+		restoreBlock(48, 2, 272, 130);
+
+		_hitAreaList = _hitAreas;
+		_lockWord &= ~0x10;
+		_vgaSpriteChanged++;
+	}
+	return 1;
+}
+
+// -----------------------------------------------------------------------
+// Personal Nightmare Script Code
+// -----------------------------------------------------------------------
+
+
+static int bitvalue[8] = {128, 64, 32, 16, 8, 4, 2, 1};
+
+int AGOSEngine_PN::bitextract(uint32 ptr, int offs) {
+	return ((bitvalue[offs % 8] & _dataBase[ptr + offs / 8]) != 0);
+}
+
+uint16 AGOSEngine_PN::getptr(uint32 pos) {
+	if (pos > _dataBaseSize)
+		error("getptr: Read beyond EOF (%d)", pos);
+	return (int)READ_LE_UINT16(_dataBase + pos);
+}
+
+uint32 AGOSEngine_PN::getlong(uint32 pos) {
+	if (pos > _dataBaseSize)
+		error("getlong: Read beyond EOF (%d)", pos);
+	return (uint32)READ_LE_UINT24(_dataBase + pos);
+}
+
+int AGOSEngine_PN::varval() {
+	int a;
+	int b;
+
+	if ((a = readfromline()) < 247) {
+		return a;
+	}
+
+	switch (a) {
+		case 249:
+			b = readfromline();
+			return((int)(b + 256 * readfromline()));
+			break;
+		case 250:
+			return(readfromline());
+		case 251:
+			return((int)_variableArray[varval()]);
+		case 252:
+			b = varval();
+			return((int)_dataBase[_quickptr[0] + b * _quickshort[0] + varval()]);
+		case 254:
+			b = varval();
+			return((int)_dataBase[_quickptr[3] + b * _quickshort[2] + varval()]);
+		case 247:
+			b = varval();
+			return((int)getptr(_quickptr[11] + (b * _quickshort[4]) + (2 * varval())));
+		case 248:
+			b = varval();
+			return((int)getptr(_quickptr[12] + (b * _quickshort[5]) + (2 * varval())));
+		case 253:
+			b = varval();
+			return(bitextract((int32)_quickptr[1] + b * _quickshort[1], varval()));
+		case 255:
+			b = varval();
+			return(bitextract((int32)_quickptr[4] + b * _quickshort[3], varval()));
+		default:
+			error("VARVAL : Illegal code encountered");
+	}
+}
+
+void AGOSEngine_PN::writeval(uint8 *ptr, int val) {
+	uint8 *savpt = _workptr;
+	int lsav = _linct, a, b, x;
+	_workptr = ptr;
+	_linct = 255;
+
+	if ((a = readfromline()) < 247) 
+		error("Write to constant");
+
+	switch (a) {
+		case 249:
+			error("Write to constant");
+			break;
+		case 250:
+			error("Write to constant");
+			break;
+		case 251:
+			_variableArray[varval()] = val;
+			break;
+		case 252:
+			b = varval();
+			_dataBase[_quickptr[0] + b * _quickshort[0] + varval()] = val;
+			break;
+		case 254:
+			b = varval();
+			_dataBase[_quickptr[3] + b * _quickshort[2] + varval()] = val;
+			break;
+		case 247:
+			b = varval();
+			x = _quickptr[11] + b * _quickshort[4] + varval() * 2;
+			WRITE_LE_UINT16(_dataBase + x, val);
+			break;
+		case 248:
+			b = varval();
+			x = _quickptr[12] + b * _quickshort[5] + varval() * 2;
+			WRITE_LE_UINT16(_dataBase + x, val);
+			break;
+		case 253:
+			b = varval();
+			setbitf((uint32)_quickptr[1] + b * _quickshort[1], varval(), val);
+			break;
+		case 255:
+			b = varval();
+			setbitf((uint32)_quickptr[4] + b * _quickshort[3], varval(), val);
+			break;
+		default:
+			error("WRITEVAL : undefined evaluation");
+	}
+	_linct = lsav;
+	_workptr = savpt;
+}
+
+void AGOSEngine_PN::setbitf(uint32 ptr, int offs, int val) {
+	ptr += offs / 8;
+	_dataBase[ptr] &= (255 - bitvalue[offs % 8]);
+	if (val != 0)
+		_dataBase[ptr] |= bitvalue[offs % 8];
+}
+
+int AGOSEngine_PN::actCallD(int n) {
+	int pf[8];
+	funcentry(pf, n);
+	addstack(-1);
+	funccpy(pf);
+	setposition(n, 0); 
+	return(doline(1));
+}
+
+int AGOSEngine_PN::doaction() {
+	if (_linct == 0)
+		return 0;
+
+	_opcode = readfromline();
+
+	if (_opcode > 63) {
+		return (actCallD(_opcode - 64));
+	}
+
+	setScriptReturn(0);
+	executeOpcode(_opcode);
+	delay(0);
+
+	return getScriptReturn();
+}
+
+int AGOSEngine_PN::doline(int needsave) {
+	int x;
+	jmp_buf *ljmpbuff = NULL;
+	jmp_buf *mybuf;
+
+	mybuf = (jmp_buf *)malloc(sizeof(jmp_buf));
+	if (mybuf == NULL)
+		error("Out of memory - stack overflow");
+
+	if ((x = setjmp(*mybuf)) > 0) {
+		dumpstack();
+		_cjmpbuff = ljmpbuff;
+		free((char *)mybuf);
+		return (x - 1);
+	}
+
+	if (x == -1) {
+		_cjmpbuff = mybuf;
+		goto carryon;
+	}
+	ljmpbuff = _cjmpbuff;
+	_cjmpbuff = mybuf;
+	if (needsave)
+		_stackbase->savearea = mybuf;
+
+nln:	_linct = ((*_linebase) & 127) - 1;
+	_workptr = _linebase + 1;
+	if (*_linebase > 127) {
+		x = varval();
+		if (x != (int)_variableArray[1])
+			goto skipln;
+	}
+
+carryon:
+	while((x = doaction()) && !shouldQuit());
+
+skipln:	_linebase += 127 & *_linebase;
+	_linembr++;
+
+	if (!shouldQuit())
+		goto nln;
+
+	return 0;
+}
+
+int AGOSEngine_PN::findentry() {
+	int stepmt;
+	int curObj = 0;
+	uint32 ofs = _quickptr[11];
+	int c1, c2;
+
+	c1 = varval();
+	c2 = varval();
+	stepmt = _quickshort[4];
+
+	while (curObj < _quickshort[6]) {
+		if (((c1 == 255) || (c1 == getptr(ofs))) &&
+			(c2 == getptr(ofs + 2))) {
+				_variableArray[23] = curObj;
+				return 1;
+		}
+		curObj++;
+		ofs += stepmt;
+	}
+	return 0;
+}
+
+int AGOSEngine_PN::findset() {
+	int curObj = _fnst;
+	int c1, c2, c3, c4;
+	int stepmt = _quickshort[4];
+	uint32 ofs = _quickptr[11] + stepmt * curObj;
+	c1 = varval();
+	c2 = varval();
+	c3 = varval();
+	c4 = varval();
+	while (curObj < _quickshort[6]) {
+		if (((c1 ==255) || (c1 == getptr(ofs))) &&
+			((c2 == 255) || (c2 == getptr(ofs + 2))) &&
+			((c3 == 255) || (c3 == getptr(ofs + 4))) &&
+			((c4 == 255) || (c4 == getptr(ofs + 6)))) {
+				_variableArray[23] = curObj;
+				_fnst = curObj + 1;
+				return 1;
+		}
+		curObj++;
+		ofs += stepmt;
+	}
+	return 0;
+}
+
+void AGOSEngine_PN::funccpy(int *store) {
+	int a = 0;
+	int b = 24;
+
+	while (a < 8) {
+		_variableArray[b++] = *store++;
+		a++;
+	}
+}
+
+void AGOSEngine_PN::funcentry(int *store, int procn) {
+	int ct = 0;
+	int nprm;
+
+	nprm = _dataBase[getlong(_quickptr[6] + 3L * procn)];
+	while (ct < nprm) {
+		*store++ = varval();
+		ct++;
+	}
+}
+
+int AGOSEngine_PN::gvwrd(uint8 *wptr, int mask) {
+	int val, code, q = _dataBase[57];
+	uint8 *vocbase = _dataBase + getlong(15);
+	while (*vocbase != 255) {
+		if (*vocbase < 128) {
+			val = vocbase[q] + 256 * vocbase[q + 1];
+			code = vocbase[q + 2];
+		}
+		if (wrdmatch(vocbase, mask, wptr, code))
+			return val;
+		vocbase += (*vocbase > 127) ? q : q + 3;
+	}
+	return -1;
+}
+
+int AGOSEngine_PN::samewrd(uint8 *w1, uint8 *w2, int ln) {
+	int ct = 0;
+
+	while (ct < ln) {
+		if (toupper(*w1) > toupper(*w2))
+			return 1;
+		if (toupper(*w1) < toupper(*w2))
+			return -1;
+		ct++;
+		w1++;
+		w2++;
+	}
+	return 0;
+}
+
+int AGOSEngine_PN::setposition(int process, int line) {
+	uint8 *ourptr;
+	int np;
+	int ct = 0;
+	ourptr = _dataBase + getlong(_quickptr[6] + 3L * process);
+	np = *ourptr++;
+	while (ct < line) {
+		ourptr += (127 & *ourptr);
+		ct++;
+	}
+x1:	_linebase = ourptr;
+	_linct = (127 & (*ourptr)) - 1;
+	if (*ourptr++ > 127) {
+		ct = varval();
+		if (ct != (int)_variableArray[1]) {
+			ourptr += _linct - 1;
+			line++;
+			goto x1;
+		}
+	}
+	_linembr = line;
+	_procnum = process;
+	_variableArray[0] = process;
+	_workptr = ourptr;
+	return np;
+}
+
+int AGOSEngine_PN::wrdmatch(uint8 *word1, int mask1, uint8 *word2, int mask2) {
+	uint8 sv;
+
+	if ((mask1 & mask2) == 0)
+		return 0;
+
+	sv = *word1;
+	*word1 &= 127;
+	if (samewrd(word1, word2, _dataBase[57])) {
+		*word1 = sv;
+		return 0;
+	}
+	*word1 = sv;
+	return 1;
+}
+
+// -----------------------------------------------------------------------
+// Personal Nightmare Stack Code
+// -----------------------------------------------------------------------
+
+void AGOSEngine_PN::addstack(int type) {
+	struct stackframe *a;
+	int pt, ct = 0;
+
+	a = (struct stackframe *)malloc(sizeof(struct stackframe));
+	if (a == NULL)
+		error("Out of memory - stack overflow");
+
+	a->nextframe = _stackbase;
+	_stackbase = a;
+	pt = 0;
+	while (ct < 6)
+		a->flag[ct++] = _variableArray[pt++];
+	ct = 0;
+	pt = 24;
+	while (ct < 8)
+		a->param[ct++] = _variableArray[pt++];
+	a->classnum = type;
+	a->ll = _linct;
+	a->linenum = _linembr;
+	a->linpos = _workptr;
+	a->lbase = _linebase;
+	a->process = _procnum;
+}
+
+void AGOSEngine_PN::dumpstack() {
+	struct stackframe *a;
+
+	if (_stackbase == NULL)
+		error("Stack underflow or unknown longjmp");
+
+	a = _stackbase->nextframe; 
+	free((char *)_stackbase);
+	_stackbase = a;
+}
+
+void AGOSEngine_PN::junkstack() {
+	struct stackframe *a;
+
+	if (_stackbase == NULL)
+		error("Stack underflow or unknown longjmp");
+
+	a = _stackbase->nextframe; 
+	if (_stackbase->classnum == -1)
+		free((char *)_stackbase->savearea);
+	free((char *)_stackbase);
+	_stackbase = a;
+}
+
+void AGOSEngine_PN::popstack(int type) {
+	int a = 0, b;
+
+	while ((_stackbase != NULL) && (_stackbase->classnum != type))
+		junkstack();
+
+	if (_stackbase == NULL)
+		error("Stack underflow or unknown longjmp");
+
+	_linct = _stackbase->ll;
+	_linebase = _stackbase->lbase;
+	_workptr = _stackbase->linpos;
+	_procnum = _stackbase->process;
+	_linembr = _stackbase->linenum;
+	b = 0;
+	while (a < 6)
+		_variableArray[b++] = _stackbase->flag[a++];
+	b = 24; 
+	a = 0;
+	while (a < 8)
+		_variableArray[b++] = _stackbase->param[a++];
+}
+
+} // End of namespace AGOS


Property changes on: scummvm/trunk/engines/agos/script_pn.cpp
___________________________________________________________________
Added: svn:mime-type
   + text/plain
Added: svn:keywords
   + Date Rev Author URL Id
Added: svn:eol-style
   + native

Modified: scummvm/trunk/engines/agos/sound.cpp
===================================================================
--- scummvm/trunk/engines/agos/sound.cpp	2009-03-08 08:17:59 UTC (rev 39215)
+++ scummvm/trunk/engines/agos/sound.cpp	2009-03-08 08:45:21 UTC (rev 39216)
@@ -389,6 +389,11 @@
 
 	_ambientPlaying = 0;
 
+	_soundQueuePtr = 0;
+	_soundQueueNum = 0;
+	_soundQueueSize = 0;
+	_soundQueueFreq = 0;
+
 	if (_vm->getFeatures() & GF_TALKIE) {
 		loadVoiceFile(gss);
 
@@ -649,6 +654,10 @@
 	return _hasVoiceFile;
 }
 
+bool Sound::isSfxActive() const {
+	return _mixer->isSoundHandleActive(_effectsHandle);
+}
+
 bool Sound::isVoiceActive() const {
 	return _mixer->isSoundHandleActive(_voiceHandle);
 }
@@ -660,6 +669,10 @@
 	_ambientPlaying = 0;
 }
 
+void Sound::stopSfx() {
+	_mixer->stopHandle(_effectsHandle);
+}
+
 void Sound::stopVoice() {
 	_mixer->stopHandle(_voiceHandle);
 }
@@ -686,8 +699,33 @@
 	}
 }
 
+// Personal Nightmare specific
+void Sound::handleSound() {
+	if (_soundQueuePtr && !isSfxActive()) {
+		playRawData(_soundQueuePtr, _soundQueueNum, _soundQueueSize, _soundQueueFreq);
+
+		_vm->_sampleWait = 1;
+		_vm->_sampleEnd = 1;
+		_soundQueuePtr = 0;
+		_soundQueueNum = 0;
+		_soundQueueSize = 0;
+		_soundQueueFreq = 0;
+	}
+}
+
+void Sound::queueSound(byte *ptr, uint16 sound, uint32 size, uint16 freq) {
+	if (_effectsPaused)
+		return;
+
+	// Only a single sound can be queued
+	_soundQueuePtr = ptr;
+	_soundQueueNum = sound;
+	_soundQueueSize = size;
+	_soundQueueFreq = freq;
+}
+
 // Elvira 1/2 and Waxworks specific
-void Sound::playRawData(byte *soundData, uint sound, uint size) {
+void Sound::playRawData(byte *soundData, uint sound, uint size, uint freq) {
 	if (_effectsPaused)
 		return;
 
@@ -695,9 +733,9 @@
 	memcpy(buffer, soundData, size);
 
 	if (_vm->getPlatform() == Common::kPlatformPC)
-		_mixer->playRaw(Audio::Mixer::kSFXSoundType, &_effectsHandle, buffer, size, 8000, Audio::Mixer::FLAG_UNSIGNED | Audio::Mixer::FLAG_AUTOFREE);
+		_mixer->playRaw(Audio::Mixer::kSFXSoundType, &_effectsHandle, buffer, size, freq, Audio::Mixer::FLAG_UNSIGNED | Audio::Mixer::FLAG_AUTOFREE);
 	else
-		_mixer->playRaw(Audio::Mixer::kSFXSoundType, &_effectsHandle, buffer, size, 8000, Audio::Mixer::FLAG_AUTOFREE);
+		_mixer->playRaw(Audio::Mixer::kSFXSoundType, &_effectsHandle, buffer, size, freq, Audio::Mixer::FLAG_AUTOFREE);
 }
 
 // Feeble Files specific

Modified: scummvm/trunk/engines/agos/sound.h
===================================================================
--- scummvm/trunk/engines/agos/sound.h	2009-03-08 08:17:59 UTC (rev 39215)
+++ scummvm/trunk/engines/agos/sound.h	2009-03-08 08:45:21 UTC (rev 39216)
@@ -26,6 +26,7 @@
 #ifndef AGOS_SOUND_H
 #define AGOS_SOUND_H
 
+#include "sound/audiostream.h"
 #include "sound/mixer.h"
 #include "agos/intern.h"
 #include "common/str.h"
@@ -60,12 +61,23 @@
 
 	bool _hasEffectsFile;
 	bool _hasVoiceFile;
-	uint _ambientPlaying;
+	uint16 _ambientPlaying;
 
+	// Personal Nightmare specfic
+	byte *_soundQueuePtr;
+	uint16 _soundQueueNum;
+	uint32 _soundQueueSize;
+	uint16 _soundQueueFreq;
 public:
 	Sound(AGOSEngine *vm, const GameSpecificSettings *gss, Audio::Mixer *mixer);
 	~Sound();
 
+	enum TypeFlags {
+		TYPE_AMBIENT = 1 << 0,
+		TYPE_SFX     = 1 << 1,
+		TYPE_SFX5    = 1 << 2
+	};
+
 	void loadVoiceFile(const GameSpecificSettings *gss);
 	void loadSfxFile(const GameSpecificSettings *gss);
 
@@ -77,8 +89,12 @@
 	void playEffects(uint sound);
 	void playAmbient(uint sound);
 
+	// Personal Nightmare specfic
+	void handleSound();
+	void queueSound(byte *ptr, uint16 sound, uint32 size, uint16 freq);
+
 	// Elvira 1/2 and Waxworks specific
-	void playRawData(byte *soundData, uint sound, uint size);
+	void playRawData(byte *soundData, uint sound, uint size, uint freq);
 
 	// Feeble Files specific
 	void playAmbientData(byte *soundData, uint sound, uint pan, uint vol);
@@ -89,8 +105,10 @@
 	void switchVoiceFile(const GameSpecificSettings *gss, uint disc);
 
 	bool hasVoice() const;
+	bool isSfxActive() const;
 	bool isVoiceActive() const;
 	void stopAllSfx();
+	void stopSfx();
 	void stopSfx5();
 	void stopVoice();
 	void stopAll();

Modified: scummvm/trunk/engines/agos/string.cpp
===================================================================
--- scummvm/trunk/engines/agos/string.cpp	2009-03-08 08:17:59 UTC (rev 39215)
+++ scummvm/trunk/engines/agos/string.cpp	2009-03-08 08:45:21 UTC (rev 39216)
@@ -910,4 +910,649 @@
 	changeWindow(0);
 }
 
+// Personal Nightmare specific
+
+uint32 AGOSEngine_PN::ftext(uint32 base, int n) {
+	uint32 b = base;
+	int ct = n;
+	while (ct) {
+		while(_textBase[b++]);
+		ct--;
+	}
+	return b;
+}
+
+char *AGOSEngine_PN::unctok(char *c, int n) {
+	int x;
+	uint8 *tokbase;
+	tokbase = _textBase + getlong(30);
+	x = n;
+	while (x-=(*tokbase++ > 127)); 
+	while (*tokbase < 128)
+		*c++=*tokbase++;
+	*c++ = *tokbase & 127;
+	*c = 0;
+	return c;
+}
+	
+void AGOSEngine_PN::uncomstr(char *c, uint32 x) {
+	if (x > _textBaseSize)
+		error("UNCOMSTR: TBASE over-run\n");
+	while (_textBase[x]) {
+		if (_textBase[x] < 244) {
+			c = unctok(c, _textBase[x]);
+		} else {
+			c = unctok(c, (_textBase[x] - 244) * 254 + _textBase[x + 1] - 1);
+			x++;
+		}
+		x++;
+	}
+	*c++ = 13;
+	*c = 0;
+}
+
+static const char *objectNames[30] = {
+	"\0",
+	"Take \0",
+	"Inventory\r",
+	"Open \0",
+	"Close \0",
+	"Lock \0",
+	"Unlock \0",
+	"Examine \0",
+	"Look in \0",
+	"Exits \r",
+	"Look\r",
+	"Wait\r",
+	"Pause\r",
+	"\0",
+	"Save\r",
+	"Restore\r",
+	"\0",
+	"N\r",
+	"NE\r",
+	"E\r",
+	"SE\r",
+	"S\r",
+	"SW\r",
+	"W\r",
+	"NW\r",
+	"INVENTORY\r",
+	"ROOM DESCRIPTION\r",
+	"x\r",
+	"MORE\r",
+	"CLOSE\r"
+};
+
+void AGOSEngine_PN::getObjectName(char *v, uint16 x) {
+	if (x & 0x8000) {
+		x &= ~0x8000;
+		if (x > getptr(51))
+			error("getObjectName: Object %d out of range", x);
+		uncomstr(v, ftext(getlong(27), x * _dataBase[47]));
+	} else {
+		assert(x < 30);
+		strcpy(v, objectNames[x]);
+	}
+}
+
+void AGOSEngine_PN::pcl(const char *s) {
+	strcat(_sb, s);
+	if (strchr(s, '\n') == 0) {
+		for (char *str = _sb; *str; str++)
+			windowPutChar(_windowArray[_curWindow], *str);
+		strcpy(_sb, "");
+	}
+}
+
+void AGOSEngine_PN::pcf(uint8 ch) {
+	int ct = 0;
+	if (ch == '[')
+		ch = '\n';
+	if (ch == 0)
+		return;	/* Trap any C EOS chrs */
+	if (ch == 255) {
+		_bp = 0;
+		_xofs = 0;
+		return;		/* pcf(255) initialises the routine */
+	}			/* pcf(254) flushes its working _buffer */
+	if (ch != 254) {
+		if ((ch != 32) || (_bp + _xofs != 50))
+			_buffer[_bp++] = ch;
+	}
+	if ((ch != 254) && (!isspace(ch)) && (_bp < 60))
+		return;
+	/* We know have a case of needing to print the text */
+	if (_bp + _xofs > 50) {
+		pcl("\n");
+		if (_buffer[0] == ' ')
+			ct = 1;	/* Skip initial space */
+		/* Note '  ' will give a single start of line space */
+		_xofs = 0;
+	}
+	_buffer[_bp] = 0;
+	pcl(_buffer + ct);

@@ Diff output truncated at 100000 characters. @@

This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.




More information about the Scummvm-git-logs mailing list