mirror of
https://github.com/libretro/scummvm.git
synced 2025-01-18 07:53:12 +00:00
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. svn-id: r39216
This commit is contained in:
parent
7bfab75a08
commit
2620d6836c
@ -182,6 +182,7 @@ AGOSEngine::AGOSEngine(OSystem *syst)
|
||||
_lastVgaTick = 0;
|
||||
|
||||
_marks = 0;
|
||||
_scanFlag = false;
|
||||
|
||||
_scriptVar2 = 0;
|
||||
_runScriptReturn1 = 0;
|
||||
@ -288,11 +289,14 @@ AGOSEngine::AGOSEngine(OSystem *syst)
|
||||
_firstTimeStruct = 0;
|
||||
_pendingDeleteTimeEvent = 0;
|
||||
|
||||
_initMouse = 0;
|
||||
_leftButtonDown = 0;
|
||||
_mouseDown = 0;
|
||||
_rightButtonDown = 0;
|
||||
_clickOnly = 0;
|
||||
_leftClick = 0;
|
||||
_oneClick = 0;
|
||||
_leftClick = 0;
|
||||
_rightClick = 0;
|
||||
_noRightClick = false;
|
||||
|
||||
_leftButton = 0;
|
||||
@ -321,11 +325,14 @@ AGOSEngine::AGOSEngine(OSystem *syst)
|
||||
_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 @@ AGOSEngine::AGOSEngine(OSystem *syst)
|
||||
_curVgaFile1 = 0;
|
||||
_curVgaFile2 = 0;
|
||||
_curSfxFile = 0;
|
||||
_curSfxFileSize = 0;
|
||||
|
||||
_syncCount = 0;
|
||||
|
||||
@ -683,6 +691,14 @@ static const uint16 initialVideoWindows_Common[20] = {
|
||||
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 @@ void AGOSEngine_Elvira1::setupGame() {
|
||||
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 @@ void AGOSEngine::setupGame() {
|
||||
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 @@ void AGOSEngine::pause() {
|
||||
|
||||
while (_pause && !shouldQuit()) {
|
||||
delay(1);
|
||||
if (_keyPressed.keycode == Common::KEYCODE_p)
|
||||
if (_keyPressed.keycode == Common::KEYCODE_PAUSE)
|
||||
pauseEngine(false);
|
||||
}
|
||||
}
|
||||
@ -1037,7 +1067,6 @@ uint32 AGOSEngine::getTime() const {
|
||||
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"));
|
||||
|
@ -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 @@ struct HitArea {
|
||||
Item *itemPtr;
|
||||
uint16 verb;
|
||||
uint16 priority;
|
||||
|
||||
// Personal Nightmare specific
|
||||
uint16 msg1, msg2;
|
||||
HitArea() { memset(this, 0, sizeof(*this)); }
|
||||
};
|
||||
|
||||
@ -127,6 +134,7 @@ struct AnimTable {
|
||||
};
|
||||
|
||||
enum SIMONGameType {
|
||||
GType_PN = 0,
|
||||
GType_ELVIRA1 = 1,
|
||||
GType_ELVIRA2 = 2,
|
||||
GType_WW = 3,
|
||||
@ -167,7 +175,7 @@ class AGOSEngine : public Engine {
|
||||
|
||||
// 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 @@ protected:
|
||||
uint32 _lastVgaTick;
|
||||
|
||||
uint16 _marks;
|
||||
bool _scanFlag;
|
||||
|
||||
bool _scriptVar2;
|
||||
bool _runScriptReturn1;
|
||||
@ -346,7 +355,7 @@ protected:
|
||||
int16 _scriptAdj1, _scriptAdj2;
|
||||
|
||||
uint16 _curWindow;
|
||||
WindowBlock *_textWindow;
|
||||
WindowBlock *_inputWindow, *_textWindow;
|
||||
|
||||
Item *_subjectItem, *_objectItem;
|
||||
Item *_currentPlayer;
|
||||
@ -387,6 +396,7 @@ protected:
|
||||
|
||||
TimeEvent *_firstTimeStruct, *_pendingDeleteTimeEvent;
|
||||
|
||||
bool _initMouse;
|
||||
Common::Point _mouse;
|
||||
Common::Point _mouseOld;
|
||||
|
||||
@ -401,8 +411,10 @@ protected:
|
||||
|
||||
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 @@ protected:
|
||||
uint16 _soundFileId;
|
||||
int16 _lastMusicPlayed;
|
||||
int16 _nextMusicToPlay;
|
||||
|
||||
bool _showPreposition;
|
||||
bool _showMessageFlag;
|
||||
|
||||
bool _newDirtyClip;
|
||||
bool _wiped;
|
||||
uint16 _copyScnFlag, _vgaSpriteChanged;
|
||||
|
||||
byte *_block, *_blockEnd;
|
||||
@ -443,7 +455,6 @@ protected:
|
||||
|
||||
byte *_curVgaFile1;
|
||||
byte *_curVgaFile2;
|
||||
byte *_curSfxFile;
|
||||
|
||||
uint16 _syncCount;
|
||||
|
||||
@ -503,10 +514,12 @@ protected:
|
||||
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 @@ public:
|
||||
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 @@ protected:
|
||||
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 @@ protected:
|
||||
|
||||
/* used in debugger */
|
||||
void dumpAllSubroutines();
|
||||
void dumpAllVgaFiles();
|
||||
void dumpSubroutines();
|
||||
void dumpSubroutine(Subroutine *sub);
|
||||
void dumpSubroutineLine(SubroutineLine *sl, Subroutine *sub);
|
||||
@ -707,6 +725,8 @@ protected:
|
||||
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 @@ protected:
|
||||
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 @@ protected:
|
||||
void loadIconFile();
|
||||
void loadMenuFile();
|
||||
|
||||
bool processSpecialKeys();
|
||||
virtual bool processSpecialKeys();
|
||||
void hitarea_stuff_helper();
|
||||
|
||||
void permitInput();
|
||||
@ -835,12 +856,13 @@ protected:
|
||||
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 @@ public:
|
||||
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 @@ protected:
|
||||
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 @@ protected:
|
||||
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 @@ protected:
|
||||
|
||||
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 @@ protected:
|
||||
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 @@ protected:
|
||||
};
|
||||
|
||||
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 {
|
||||
|
@ -1767,6 +1767,107 @@ static const byte english_elvira1Font[] = {
|
||||
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 @@ void AGOSEngine::windowDrawChar(WindowBlock *window, uint x, uint y, byte chr) {
|
||||
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;
|
||||
|
@ -610,13 +610,21 @@ void AGOSEngine::windowNewLine(WindowBlock *window) {
|
||||
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++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -474,6 +474,71 @@ get_out:
|
||||
_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 @@ void AGOSEngine::drawMousePointer() {
|
||||
} 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) {
|
||||
|
@ -231,8 +231,10 @@ void AGOSEngine::dumpVideoScript(const byte *src, bool singeOpcode) {
|
||||
strn = str = simon1_videoOpcodeNameTable[opcode];
|
||||
} else if (getGameType() == GType_ELVIRA2 || getGameType() == GType_WW) {
|
||||
strn = str = ww_videoOpcodeNameTable[opcode];
|
||||
} else {
|
||||
} else if (getGameType() == GType_ELVIRA1) {
|
||||
strn = str = elvira1_videoOpcodeNameTable[opcode];
|
||||
} else {
|
||||
strn = str = pn_videoOpcodeNameTable[opcode];
|
||||
}
|
||||
|
||||
if (strn == NULL) {
|
||||
@ -295,6 +297,24 @@ void AGOSEngine::dumpVgaScriptAlways(const byte *ptr, uint16 res, uint16 id) {
|
||||
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;
|
||||
|
@ -2324,6 +2324,79 @@ static const char *const puzzlepack_opcodeNameTable[256] = {
|
||||
"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",
|
||||
|
@ -65,6 +65,7 @@ static const ADObsoleteGameID obsoleteGameIDsTable[] = {
|
||||
};
|
||||
|
||||
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 AgosMetaEngine::createInstance(OSystem *syst, Engine **engine, const ADGame
|
||||
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;
|
||||
|
@ -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
|
||||
{
|
||||
{
|
||||
|
@ -185,14 +185,13 @@ void AGOSEngine::restartAnimation() {
|
||||
if (!(_lockWord & 0x10))
|
||||
return;
|
||||
|
||||
_window4Flag = 2;
|
||||
|
||||
setMoveRect(0, 0, 224, 127);
|
||||
displayScreen();
|
||||
if (getGameType() != GType_PN) {
|
||||
_window4Flag = 2;
|
||||
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 @@ void AGOSEngine::delay(uint amount) {
|
||||
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 @@ void AGOSEngine_Feeble::timerProc() {
|
||||
_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;
|
||||
|
@ -928,6 +928,12 @@ void AGOSEngine::drawImage(VC10_state *state) {
|
||||
|
||||
_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 @@ void AGOSEngine::animate(uint16 windowNum, uint16 zoneNum, uint16 vgaSpriteId, i
|
||||
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 @@ void AGOSEngine::setImage(uint16 vgaSpriteId, bool vgaScript) {
|
||||
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 @@ void AGOSEngine::setImage(uint16 vgaSpriteId, bool vgaScript) {
|
||||
_noOverWrite = 0xFFFF;
|
||||
} else {
|
||||
_curSfxFile = vpe->sfxFile;
|
||||
_curSfxFileSize = vpe->sfxFileEnd - vpe->sfxFile;
|
||||
_zoneNumber = zoneNum;
|
||||
|
||||
if (vpe->vgaFile1 != NULL)
|
||||
@ -1234,8 +1241,17 @@ void AGOSEngine::setImage(uint16 vgaSpriteId, bool vgaScript) {
|
||||
}
|
||||
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 @@ void AGOSEngine::setImage(uint16 vgaSpriteId, bool vgaScript) {
|
||||
_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::setWindowImageEx(uint16 mode, uint16 vgaSpriteId) {
|
||||
}
|
||||
}
|
||||
|
||||
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 @@ void AGOSEngine::setWindowImage(uint16 mode, uint16 vgaSpriteId) {
|
||||
|
||||
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 @@ void AGOSEngine::setWindowImage(uint16 mode, uint16 vgaSpriteId) {
|
||||
}
|
||||
}
|
||||
|
||||
setImage(vgaSpriteId);
|
||||
setImage(vgaSpriteId, specialCase);
|
||||
|
||||
if (getGameType() == GType_FF || getGameType() == GType_PP) {
|
||||
fillBackGroundFromBack();
|
||||
@ -1423,6 +1447,9 @@ void AGOSEngine::setWindowImage(uint16 mode, uint16 vgaSpriteId) {
|
||||
src = _window4BackScn;
|
||||
srcWidth = _videoWindows[18] * 16;
|
||||
}
|
||||
} else {
|
||||
src = (byte *)screen->pixels + xoffs + yoffs * _screenWidth;
|
||||
srcWidth = _screenWidth;
|
||||
}
|
||||
|
||||
_boxStarHeight = height;
|
||||
@ -1433,7 +1460,14 @@ void AGOSEngine::setWindowImage(uint16 mode, uint16 vgaSpriteId) {
|
||||
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 @@ void AGOSEngine::setWindowImage(uint16 mode, uint16 vgaSpriteId) {
|
||||
_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
|
||||
|
@ -302,7 +302,7 @@ void AGOSEngine_Elvira2::drawIcon(WindowBlock *window, uint icon, uint x, uint y
|
||||
_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 @@ void AGOSEngine::drawIcon(WindowBlock *window, uint icon, uint x, uint y) {
|
||||
_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::drawArrow(uint16 x, uint16 y, int8 dir) {
|
||||
|
||||
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 @@ void AGOSEngine::removeArrows(WindowBlock *window, uint num) {
|
||||
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 @@ void AGOSEngine::removeIconArray(uint num) {
|
||||
_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
|
||||
|
@ -606,6 +606,129 @@ bool AGOSEngine::processSpecialKeys() {
|
||||
return verbCode;
|
||||
}
|
||||
|
||||
// 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
|
||||
|
||||
|
||||
|
@ -214,6 +214,22 @@ enum BoxFlags {
|
||||
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 @@ enum GameFileTypes {
|
||||
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,
|
||||
|
@ -53,6 +53,27 @@ void AGOSEngine::loadMenuFile() {
|
||||
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];
|
||||
|
@ -20,6 +20,7 @@ MODULE_OBJS := \
|
||||
midi.o \
|
||||
midiparser_s1d.o \
|
||||
oracle.o \
|
||||
pn.o \
|
||||
res.o \
|
||||
res_ami.o \
|
||||
res_snd.o \
|
||||
@ -28,6 +29,7 @@ MODULE_OBJS := \
|
||||
script.o \
|
||||
script_e1.o \
|
||||
script_e2.o \
|
||||
script_pn.o \
|
||||
script_ww.o \
|
||||
script_s1.o \
|
||||
script_s2.o \
|
||||
@ -39,6 +41,7 @@ MODULE_OBJS := \
|
||||
verb.o \
|
||||
vga.o \
|
||||
vga_e2.o \
|
||||
vga_pn.o \
|
||||
vga_ww.o \
|
||||
vga_s1.o \
|
||||
vga_s2.o \
|
||||
|
293
engines/agos/pn.cpp
Normal file
293
engines/agos/pn.cpp
Normal file
@ -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
|
@ -27,6 +27,7 @@
|
||||
|
||||
|
||||
#include "common/file.h"
|
||||
#include "common/util.h"
|
||||
|
||||
#include "agos/agos.h"
|
||||
#include "agos/intern.h"
|
||||
@ -149,6 +150,46 @@ int AGOSEngine::allocGamePcVars(Common::SeekableReadStream *in) {
|
||||
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 @@ bool AGOSEngine::decrunchFile(byte *src, byte *dst, uint32 size) {
|
||||
#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::loadVGABeardFile(uint16 id) {
|
||||
}
|
||||
}
|
||||
|
||||
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 @@ void AGOSEngine::loadVGAVideoFile(uint16 id, uint8 type) {
|
||||
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 @@ void AGOSEngine::loadVGAVideoFile(uint16 id, uint8 type) {
|
||||
|
||||
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)
|
||||
|
@ -92,7 +92,7 @@ static void bitplaneToChunkyText(uint16 *w, uint8 colorDepth, uint8 *&dst) {
|
||||
}
|
||||
}
|
||||
|
||||
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,10 +119,19 @@ static void convertCompressedImage(const byte *src, byte *dst, uint8 colorDepth,
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -152,7 +161,7 @@ byte *AGOSEngine::convertImage(VC10_state *state, bool compressed) {
|
||||
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++) {
|
||||
|
@ -364,6 +364,8 @@ bool AGOSEngine::loadVGASoundFile(uint16 id, uint8 type) {
|
||||
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 @@ bool AGOSEngine::loadVGASoundFile(uint16 id, uint8 type) {
|
||||
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 @@ bool AGOSEngine::loadVGASoundFile(uint16 id, uint8 type) {
|
||||
}
|
||||
|
||||
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,39 +473,7 @@ void AGOSEngine::loadSoundFile(const char* filename) {
|
||||
_sound->playSfxData(dst, 0, 0, 0);
|
||||
}
|
||||
|
||||
void AGOSEngine::loadSound(uint sound) {
|
||||
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) {
|
||||
void AGOSEngine::loadSound(uint16 sound, int16 pan, int16 vol, uint16 type) {
|
||||
byte *dst;
|
||||
|
||||
if (getGameId() == GID_DIMP) {
|
||||
@ -532,12 +516,67 @@ void AGOSEngine::loadSound(uint sound, int pan, int vol, uint type) {
|
||||
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) {
|
||||
|
@ -125,12 +125,21 @@ char *AGOSEngine_Elvira2::genSaveName(int slot) {
|
||||
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 @@ bool AGOSEngine_Elvira2::saveGame(uint slot, const char *caption) {
|
||||
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
|
||||
|
@ -574,9 +574,7 @@ void AGOSEngine_Elvira2::oe2_ifExitLocked() {
|
||||
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_printMonsterDamage() {
|
||||
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 @@ void AGOSEngine_Elvira2::oe2_isAdjNoun() {
|
||||
}
|
||||
}
|
||||
|
||||
setScriptCondition(item->adjective == a && item->noun == b);
|
||||
setScriptCondition(item->adjective == a && item->noun == n);
|
||||
}
|
||||
|
||||
void AGOSEngine_Elvira2::oe2_b2Set() {
|
||||
|
1109
engines/agos/script_pn.cpp
Normal file
1109
engines/agos/script_pn.cpp
Normal file
File diff suppressed because it is too large
Load Diff
@ -389,6 +389,11 @@ Sound::Sound(AGOSEngine *vm, const GameSpecificSettings *gss, Audio::Mixer *mixe
|
||||
|
||||
_ambientPlaying = 0;
|
||||
|
||||
_soundQueuePtr = 0;
|
||||
_soundQueueNum = 0;
|
||||
_soundQueueSize = 0;
|
||||
_soundQueueFreq = 0;
|
||||
|
||||
if (_vm->getFeatures() & GF_TALKIE) {
|
||||
loadVoiceFile(gss);
|
||||
|
||||
@ -649,6 +654,10 @@ bool Sound::hasVoice() const {
|
||||
return _hasVoiceFile;
|
||||
}
|
||||
|
||||
bool Sound::isSfxActive() const {
|
||||
return _mixer->isSoundHandleActive(_effectsHandle);
|
||||
}
|
||||
|
||||
bool Sound::isVoiceActive() const {
|
||||
return _mixer->isSoundHandleActive(_voiceHandle);
|
||||
}
|
||||
@ -660,6 +669,10 @@ void Sound::stopAllSfx() {
|
||||
_ambientPlaying = 0;
|
||||
}
|
||||
|
||||
void Sound::stopSfx() {
|
||||
_mixer->stopHandle(_effectsHandle);
|
||||
}
|
||||
|
||||
void Sound::stopVoice() {
|
||||
_mixer->stopHandle(_voiceHandle);
|
||||
}
|
||||
@ -686,8 +699,33 @@ void Sound::ambientPause(bool b) {
|
||||
}
|
||||
}
|
||||
|
||||
// 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 @@ void Sound::playRawData(byte *soundData, uint sound, uint size) {
|
||||
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
|
||||
|
@ -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 @@ private:
|
||||
|
||||
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 @@ public:
|
||||
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 @@ public:
|
||||
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();
|
||||
|
@ -910,4 +910,649 @@ void AGOSEngine_Waxworks::printBox() {
|
||||
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);
|
||||
_xofs += _bp;
|
||||
_bp = 0;
|
||||
if (ch == '\n')
|
||||
_xofs = 0; /* At Newline! */
|
||||
}
|
||||
|
||||
void AGOSEngine_PN::patok(int n) {
|
||||
int x;
|
||||
uint8 *tokbase;
|
||||
tokbase = _textBase + getlong(30);
|
||||
x = n;
|
||||
while (x -= (*tokbase++ > 127));
|
||||
while (*tokbase < 128)
|
||||
pcf(*tokbase++);
|
||||
pcf((uint8)(*tokbase & 127));
|
||||
}
|
||||
|
||||
void AGOSEngine_PN::pmesd(int n) {
|
||||
ptext(ftext(getlong(24), n));
|
||||
}
|
||||
|
||||
void AGOSEngine_PN::plocd(int n, int m) {
|
||||
if (n > getptr(53))
|
||||
error("Location out of range");
|
||||
ptext(ftext(getlong(21), n * _dataBase[48] + m));
|
||||
}
|
||||
|
||||
void AGOSEngine_PN::pobjd(int n, int m) {
|
||||
if (n > getptr(51))
|
||||
error("Object out of range");
|
||||
ptext(ftext(getlong(27), n * _dataBase[47] + m));
|
||||
}
|
||||
|
||||
void AGOSEngine_PN::ptext(uint32 tptr) {
|
||||
if (tptr > _textBaseSize)
|
||||
error("ptext: attempt to print beyond end of TBASE\n");
|
||||
|
||||
while (_textBase[tptr]) {
|
||||
if (_textBase[tptr] < 244) {
|
||||
patok(_textBase[tptr++]);
|
||||
} else {
|
||||
patok((_textBase[tptr] - 244) * 254 + _textBase[tptr + 1] - 1);
|
||||
tptr += 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const uint8 characters[11][80] = {
|
||||
// PETERMASON
|
||||
{
|
||||
118, 225,
|
||||
91, 118,
|
||||
94, 124,
|
||||
236, 161,
|
||||
241, 166,
|
||||
168, 4,
|
||||
138, 46,
|
||||
139, 46,
|
||||
249, 50,
|
||||
38, 56,
|
||||
80, 59,
|
||||
149, 69,
|
||||
37, 77,
|
||||
93, 93,
|
||||
86, 95,
|
||||
0,
|
||||
0,
|
||||
58, 130,
|
||||
62, 178,
|
||||
83, 95,
|
||||
0,
|
||||
121, 58,
|
||||
122, 59,
|
||||
126, 60,
|
||||
124, 61,
|
||||
240, 62,
|
||||
123, 63,
|
||||
0
|
||||
},
|
||||
// JBLANDFORD
|
||||
{
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
},
|
||||
// SBLANDFORD
|
||||
{
|
||||
120, 223,
|
||||
94, 126,
|
||||
112, 134,
|
||||
45, 152,
|
||||
241, 166,
|
||||
168, 3,
|
||||
150, 26,
|
||||
220, 29,
|
||||
138, 42,
|
||||
139, 47,
|
||||
249, 50,
|
||||
38, 56,
|
||||
230, 64,
|
||||
37, 77,
|
||||
93, 94,
|
||||
86, 96,
|
||||
0,
|
||||
0,
|
||||
58, 129,
|
||||
59, 112,
|
||||
83, 96,
|
||||
81, 106,
|
||||
62, 169,
|
||||
0,
|
||||
121, 54,
|
||||
122, 55,
|
||||
119, 56,
|
||||
118, 57,
|
||||
0
|
||||
},
|
||||
// MRJONES
|
||||
{
|
||||
121, 218,
|
||||
91, 118,
|
||||
253, 121,
|
||||
154, 138,
|
||||
235, 173,
|
||||
236, 161,
|
||||
241, 165,
|
||||
168, 0,
|
||||
150, 21,
|
||||
36, 33,
|
||||
138, 42,
|
||||
249, 50,
|
||||
80, 60,
|
||||
4, 60,
|
||||
37, 78,
|
||||
68, 33,
|
||||
93, 92,
|
||||
101, 109,
|
||||
0,
|
||||
36, 35,
|
||||
68, 90,
|
||||
0,
|
||||
58, 128,
|
||||
59, 111,
|
||||
62, 182,
|
||||
0,
|
||||
122, 13,
|
||||
126, 14,
|
||||
124, 15,
|
||||
240, 16,
|
||||
120, 17,
|
||||
119, 18,
|
||||
118, 19,
|
||||
52, 20,
|
||||
125, 21,
|
||||
127, 22,
|
||||
123, 23,
|
||||
117, 24,
|
||||
0
|
||||
},
|
||||
// MRSJONES
|
||||
{
|
||||
122, 219,
|
||||
91, 119,
|
||||
253, 123,
|
||||
112, 136,
|
||||
154, 137,
|
||||
95, 142,
|
||||
45, 152,
|
||||
109, 155,
|
||||
235, 160,
|
||||
168, 1,
|
||||
151, 13,
|
||||
145, 15,
|
||||
150, 22,
|
||||
220, 28,
|
||||
36, 33,
|
||||
138, 43,
|
||||
13, 51,
|
||||
80, 59,
|
||||
230, 64,
|
||||
149, 69,
|
||||
86, 100,
|
||||
0,
|
||||
36, 36,
|
||||
0,
|
||||
58, 127,
|
||||
62, 179,
|
||||
83, 100,
|
||||
81, 102,
|
||||
0,
|
||||
121, 25,
|
||||
126, 26,
|
||||
124, 27,
|
||||
120, 28,
|
||||
119, 29,
|
||||
118, 30,
|
||||
52, 31,
|
||||
125, 32,
|
||||
127, 33,
|
||||
123, 34,
|
||||
117, 35,
|
||||
0
|
||||
},
|
||||
// MRROBERTS
|
||||
{
|
||||
123, 229,
|
||||
91, 117,
|
||||
253, 120,
|
||||
94, 125,
|
||||
112, 134,
|
||||
109, 156,
|
||||
235, 172,
|
||||
236, 162,
|
||||
241, 165,
|
||||
168, 3,
|
||||
36, 33,
|
||||
249, 50,
|
||||
38, 56,
|
||||
80, 58,
|
||||
37, 75,
|
||||
34, 81,
|
||||
68, 33,
|
||||
101, 109,
|
||||
0,
|
||||
36, 40,
|
||||
68, 88,
|
||||
0,
|
||||
59, 111,
|
||||
62, 181,
|
||||
0,
|
||||
0
|
||||
},
|
||||
// POSTMISTRESS
|
||||
{
|
||||
124, 221,
|
||||
91, 119,
|
||||
253, 122,
|
||||
112, 136,
|
||||
95, 142,
|
||||
130, 149,
|
||||
109, 155,
|
||||
235, 176,
|
||||
220, 29,
|
||||
36, 33,
|
||||
138, 43,
|
||||
13, 51,
|
||||
80, 57,
|
||||
149, 68,
|
||||
37, 73,
|
||||
34, 33,
|
||||
68, 33,
|
||||
86, 100,
|
||||
0,
|
||||
36, 39,
|
||||
34, 80,
|
||||
68, 86,
|
||||
0,
|
||||
58, 130,
|
||||
62, 181,
|
||||
83, 100,
|
||||
81, 103,
|
||||
0,
|
||||
121, 41,
|
||||
122, 42,
|
||||
126, 43,
|
||||
240, 44,
|
||||
120, 45,
|
||||
119, 46,
|
||||
118, 47,
|
||||
52, 48,
|
||||
123, 49,
|
||||
83, 50,
|
||||
117, 51,
|
||||
0
|
||||
},
|
||||
// MWILLIAMS
|
||||
{
|
||||
125, 227,
|
||||
94, 124,
|
||||
95, 141,
|
||||
241, 166,
|
||||
168, 4,
|
||||
150, 26,
|
||||
38, 54,
|
||||
4, 60,
|
||||
230, 65,
|
||||
149, 68,
|
||||
37, 76,
|
||||
101, 109,
|
||||
0,
|
||||
230, 63,
|
||||
0,
|
||||
59, 112,
|
||||
62, 183,
|
||||
0,
|
||||
240, 71,
|
||||
120, 72,
|
||||
118, 73,
|
||||
52, 74,
|
||||
117, 75,
|
||||
0
|
||||
},
|
||||
// TONY
|
||||
{
|
||||
126, 220,
|
||||
95, 143,
|
||||
130, 149,
|
||||
45, 153,
|
||||
109, 154,
|
||||
235, 158,
|
||||
241, 166,
|
||||
168, 2,
|
||||
145, 15,
|
||||
150, 24,
|
||||
220, 20,
|
||||
36, 20,
|
||||
4, 60,
|
||||
37, 79,
|
||||
86, 97,
|
||||
0,
|
||||
150, 23,
|
||||
220, 27,
|
||||
36, 34,
|
||||
0,
|
||||
83, 97,
|
||||
0,
|
||||
121, 36,
|
||||
122, 37,
|
||||
124, 38,
|
||||
240, 39,
|
||||
52, 40,
|
||||
0
|
||||
},
|
||||
// PIG
|
||||
{
|
||||
127, 228,
|
||||
112, 133,
|
||||
45, 153,
|
||||
235, 157,
|
||||
236, 163,
|
||||
241, 165,
|
||||
36, 33,
|
||||
80, 58,
|
||||
34, 81,
|
||||
68, 33,
|
||||
86, 98,
|
||||
0,
|
||||
36, 37,
|
||||
68, 90,
|
||||
0,
|
||||
62, 184,
|
||||
83, 98,
|
||||
0,
|
||||
121, 76,
|
||||
122, 77,
|
||||
126, 78,
|
||||
124, 79,
|
||||
240, 80,
|
||||
120, 81,
|
||||
118, 82,
|
||||
52, 83,
|
||||
125, 84,
|
||||
123, 85,
|
||||
83, 86,
|
||||
117, 87,
|
||||
0
|
||||
},
|
||||
// JUDY
|
||||
{
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
240, 52,
|
||||
117, 53,
|
||||
0
|
||||
}
|
||||
};
|
||||
|
||||
void AGOSEngine_PN::getResponse(uint16 charNum, uint16 objNum, uint16 &msgNum1, uint16 &msgNum2) {
|
||||
const uint8 *ptr;
|
||||
uint16 num;
|
||||
|
||||
msgNum1 = 0;
|
||||
msgNum2 = 0;
|
||||
|
||||
if (charNum == 83)
|
||||
charNum += 45;
|
||||
|
||||
if (charNum < 118 || charNum > 128) {
|
||||
return;
|
||||
}
|
||||
|
||||
ptr = characters[charNum - 118];
|
||||
|
||||
while ((num = *ptr++) != 0) {
|
||||
if (num == objNum) {
|
||||
msgNum1 = *ptr++;
|
||||
msgNum1 += 400;
|
||||
|
||||
while ((num = *ptr++) != 0)
|
||||
ptr++;
|
||||
break;
|
||||
}
|
||||
ptr++;
|
||||
}
|
||||
|
||||
while ((num = *ptr++) != 0) {
|
||||
if (num == objNum) {
|
||||
msgNum2 = *ptr++;
|
||||
msgNum2 += 400;
|
||||
|
||||
if (msgNum1 == 569)
|
||||
msgNum1 += 400;
|
||||
if (msgNum2 == 0)
|
||||
msgNum2 = msgNum1;
|
||||
return;
|
||||
}
|
||||
ptr++;
|
||||
}
|
||||
|
||||
if (objNum >= 200)
|
||||
msgNum1 = 0;
|
||||
|
||||
objNum -= 200;
|
||||
while ((num = *ptr++) != 0) {
|
||||
if (num == objNum) {
|
||||
msgNum1 = *ptr++;
|
||||
msgNum1 += 400;
|
||||
|
||||
if (msgNum1 == 569)
|
||||
msgNum1 += 400;
|
||||
if (msgNum2 == 0)
|
||||
msgNum2 = msgNum1;
|
||||
return;
|
||||
}
|
||||
ptr++;
|
||||
}
|
||||
|
||||
objNum += 200;
|
||||
while ((num = *ptr++) != 0) {
|
||||
if (num == objNum) {
|
||||
msgNum1 = *ptr++;
|
||||
msgNum1 += 200;
|
||||
|
||||
if (msgNum1 == 569)
|
||||
msgNum1 += 400;
|
||||
if (msgNum2 == 0)
|
||||
msgNum2 = msgNum1;
|
||||
return;
|
||||
}
|
||||
ptr++;
|
||||
}
|
||||
|
||||
if (msgNum1 == 569)
|
||||
msgNum1 += 400;
|
||||
if (msgNum2 == 0)
|
||||
msgNum2 = msgNum1;
|
||||
}
|
||||
|
||||
char *AGOSEngine_PN::getMessage(char *msg, uint16 num) {
|
||||
char *origPtr, *strPtr2, *strPtr1 = msg;
|
||||
uint8 count;
|
||||
|
||||
getObjectName(strPtr1, num);
|
||||
if (!(num & 0x8000)) {
|
||||
return msg;
|
||||
}
|
||||
|
||||
if (strPtr1[0] == 0x41 || strPtr1[0] == 0x61) {
|
||||
if (strPtr1[1] != 0x20)
|
||||
strPtr1 += 2;
|
||||
} else if (strPtr1[0] == 0x54 || strPtr1[0] == 0x74) {
|
||||
if (strPtr1[1] == 0x68 &&
|
||||
strPtr1[2] == 0x65 &&
|
||||
strPtr1[3] == 0x20)
|
||||
strPtr1 += 4;
|
||||
}
|
||||
|
||||
origPtr = strPtr1;
|
||||
while (strPtr1[0] != 13)
|
||||
strPtr1++;
|
||||
|
||||
strPtr1[0] = 32;
|
||||
strPtr1[1] = 13;
|
||||
strPtr1[2] = 0;
|
||||
|
||||
if (_lockWord & 0x10) {
|
||||
strPtr1 = origPtr;
|
||||
count = 6;
|
||||
while (strPtr1[0] != 0) {
|
||||
if (strPtr1[0] == 32) {
|
||||
count = 6;
|
||||
} else {
|
||||
count--;
|
||||
if (count == 0) {
|
||||
char *tmpPtr = strPtr1;
|
||||
strPtr2 = strPtr1;
|
||||
|
||||
while (strPtr2[0] != 0 && strPtr2[0] != 32)
|
||||
strPtr2++;
|
||||
|
||||
while (strPtr2[0] != 0) {
|
||||
strPtr1[0] = strPtr2[0];
|
||||
strPtr2++;
|
||||
strPtr1++;
|
||||
}
|
||||
|
||||
strPtr1[0] = strPtr2[0];
|
||||
strPtr2++;
|
||||
strPtr1++;
|
||||
|
||||
strPtr1 = tmpPtr;
|
||||
count = 6;
|
||||
}
|
||||
}
|
||||
strPtr1++;
|
||||
}
|
||||
}
|
||||
|
||||
return origPtr;
|
||||
}
|
||||
|
||||
} // End of namespace AGOS
|
||||
|
@ -496,6 +496,18 @@ bool AGOSEngine::isBoxDead(uint hitarea) {
|
||||
return (ha->flags & kBFBoxDead) == 0;
|
||||
}
|
||||
|
||||
void AGOSEngine::defineBox(uint16 id, uint16 x, uint16 y, uint16 height, uint16 width, uint16 msg1, uint16 msg2, uint16 flags) {
|
||||
HitArea *ha = _hitAreaList + id;
|
||||
ha->x = x;
|
||||
ha->y = y;
|
||||
ha->width = width;
|
||||
ha->height = height;
|
||||
ha->msg1 = msg1;
|
||||
ha->msg2 = msg2;
|
||||
ha->flags = flags;
|
||||
ha->id = ha->priority = id;
|
||||
}
|
||||
|
||||
void AGOSEngine::defineBox(int id, int x, int y, int width, int height, int flags, int verb, Item *itemPtr) {
|
||||
HitArea *ha;
|
||||
undefineBox(id);
|
||||
@ -985,6 +997,18 @@ void AGOSEngine::invertBox(HitArea *ha, byte a, byte b, byte c, byte d) {
|
||||
color ^= 2;
|
||||
src[i] = color;
|
||||
}
|
||||
} else if (getGameType() == GType_PN) {
|
||||
if (getPlatform() == Common::kPlatformPC) {
|
||||
if (color != 15) {
|
||||
color ^= 7;
|
||||
src[i] = color;
|
||||
}
|
||||
} else {
|
||||
if (color != 14) {
|
||||
color ^= 15;
|
||||
src[i] = color;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (a >= color && b < color) {
|
||||
if (c >= color)
|
||||
@ -1003,4 +1027,263 @@ void AGOSEngine::invertBox(HitArea *ha, byte a, byte b, byte c, byte d) {
|
||||
_lockWord &= ~0x8000;
|
||||
}
|
||||
|
||||
// Personal Nightmare specific
|
||||
void AGOSEngine_PN::boxController(uint x, uint y, uint mode) {
|
||||
HitArea *best_ha;
|
||||
HitArea *ha = _hitAreaList;
|
||||
|
||||
best_ha = NULL;
|
||||
|
||||
do {
|
||||
if (!(ha->flags & kOBFBoxDisabled)) {
|
||||
if (x >= ha->x && y >= ha->y && x - ha->x < ha->width && y - ha->y < ha->height &&
|
||||
best_ha == NULL) {
|
||||
best_ha = ha;
|
||||
} else {
|
||||
if (ha->flags & kOBFBoxSelected) {
|
||||
hitarea_leave(ha , true);
|
||||
ha->flags &= ~kOBFBoxSelected;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ha->flags &= ~kOBFBoxSelected;
|
||||
}
|
||||
} while (ha++, ha->id != 0xFFFF);
|
||||
|
||||
if (mode != 0) {
|
||||
_lastHitArea = best_ha;
|
||||
}
|
||||
|
||||
if (best_ha == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (best_ha->flags & kOBFInvertTouch && !(best_ha->flags & kOBFBoxSelected)) {
|
||||
hitarea_leave(best_ha, false);
|
||||
best_ha->flags |= kOBFBoxSelected;
|
||||
}
|
||||
}
|
||||
|
||||
void AGOSEngine_PN::mouseHit() {
|
||||
if (_hitCalled == 5) {
|
||||
execMouseHit(NULL);
|
||||
} else {
|
||||
boxController(_mouse.x, _mouse.y, 1);
|
||||
if (_hitCalled == 4 || _lastHitArea != 0) {
|
||||
execMouseHit(_lastHitArea);
|
||||
}
|
||||
}
|
||||
_hitCalled = 0;
|
||||
_oneClick = 0;
|
||||
}
|
||||
|
||||
void AGOSEngine_PN::execMouseHit(HitArea *ha) {
|
||||
if (_hitCalled == 1) {
|
||||
if (ha->flags & kOBFUseMessageList)
|
||||
hitBox11(ha);
|
||||
else if (ha->flags & kOBFMoreBox)
|
||||
hitBox9(ha);
|
||||
else if (ha->flags & kOBFExit)
|
||||
hitBox7(ha);
|
||||
else if (ha->flags & kOBFUseEmptyLine)
|
||||
hitBox2(ha);
|
||||
else
|
||||
hitBox1(ha);
|
||||
} else if (_hitCalled == 2) {
|
||||
if (ha->flags & (kOBFObject | kOBFInventoryBox | kOBFRoomBox))
|
||||
hitBox3(ha);
|
||||
else if (ha->flags & kOBFUseMessageList)
|
||||
hitBox11(ha);
|
||||
else if (ha->flags & kOBFMoreBox)
|
||||
hitBox9(ha);
|
||||
else if (ha->flags & kOBFExit)
|
||||
hitBox7(ha);
|
||||
else if (ha->flags & kOBFUseEmptyLine)
|
||||
hitBox2(ha);
|
||||
else
|
||||
hitBox1(ha);
|
||||
} else if (_hitCalled == 3) {
|
||||
if ((ha->flags & kOBFDraggable) && _dragFlag == 0) {
|
||||
_dragFlag = 1;
|
||||
_dragStore = ha;
|
||||
_needHitAreaRecalc++;
|
||||
}
|
||||
} else if (_hitCalled == 4) {
|
||||
_dragFlag = 0;
|
||||
_hitCalled = 0;
|
||||
_oneClick = 0;
|
||||
_mouseDown = 0;
|
||||
_needHitAreaRecalc++;
|
||||
if (ha != 0) {
|
||||
if (ha->flags & kOBFInventoryBox)
|
||||
hitBox5(ha);
|
||||
else if (ha->flags & kOBFRoomBox)
|
||||
hitBox6(ha);
|
||||
} else if (_lockWord & 10) {
|
||||
hitBox8(ha);
|
||||
}
|
||||
} else {
|
||||
_hitCalled = 0;
|
||||
if (_mouseString == 0) {
|
||||
_mouseString = (const char *)"\r";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AGOSEngine_PN::hitBox1(HitArea *ha) {
|
||||
if (_mouseString)
|
||||
return;
|
||||
|
||||
_mouseString = getMessage(_objectName1, ha->msg1);
|
||||
if (_intputCounter) {
|
||||
char *msgPtr = getMessage(_objectName1, ha->msg1);
|
||||
while (*msgPtr != 13)
|
||||
msgPtr++;
|
||||
*msgPtr = 0;
|
||||
} else if (!(ha->flags & kOBFNoShowName)) {
|
||||
_mousePrintFG++;
|
||||
_mouseString1 = _mouseString;
|
||||
_mouseString = (const char*)"showname \0";
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void AGOSEngine_PN::hitBox2(HitArea *ha) {
|
||||
if (!_intputCounter)
|
||||
hitBox1(ha);
|
||||
}
|
||||
|
||||
void AGOSEngine_PN::hitBox3(HitArea *ha) {
|
||||
if (!_intputCounter)
|
||||
hitBox4(ha);
|
||||
}
|
||||
|
||||
void AGOSEngine_PN::hitBox4(HitArea *ha) {
|
||||
if (_mouseString)
|
||||
return;
|
||||
|
||||
uint16 num = ha->msg1 & ~0x8000;
|
||||
if ((_lockWord & 0x10) && !(ha->flags & (kOBFInventoryBox | kOBFRoomBox)) &&
|
||||
!testContainer(num)) {
|
||||
return;
|
||||
}
|
||||
|
||||
_mouseString = getMessage(_objectName2, ha->msg2);
|
||||
_mouseString1 = getMessage(_objectName1, ha->msg1);
|
||||
_mousePrintFG++;
|
||||
}
|
||||
|
||||
void AGOSEngine_PN::hitBox5(HitArea *ha) {
|
||||
if (_intputCounter || _mouseString)
|
||||
return;
|
||||
|
||||
if (_dragStore && (_dragStore->flags & kOBFInventoryBox))
|
||||
return;
|
||||
|
||||
_mousePrintFG++;
|
||||
_mouseString = (const char *)"take \0";
|
||||
_mouseString1 = getMessage(_objectName1, _dragStore->msg1);
|
||||
|
||||
if (_dragStore->flags & kOBFRoomBox)
|
||||
_mouseString1 = (const char *)"all\r";
|
||||
}
|
||||
|
||||
void AGOSEngine_PN::hitBox6(HitArea *ha) {
|
||||
if (_intputCounter || _mouseString)
|
||||
return;
|
||||
|
||||
if (_dragStore->flags & kOBFRoomBox)
|
||||
return;
|
||||
|
||||
_mousePrintFG++;
|
||||
_mouseString = (const char *)"drop \0";
|
||||
_mouseString1 = getMessage(_objectName1, _dragStore->msg1);
|
||||
|
||||
if (_dragStore->flags & kOBFInventoryBox)
|
||||
_mouseString1 = (const char *)"all\r";
|
||||
}
|
||||
|
||||
void AGOSEngine_PN::hitBox7(HitArea *ha) {
|
||||
if (_intputCounter) {
|
||||
if (!(ha->flags & kOBFUseEmptyLine)) {
|
||||
hitBox1(ha);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (_mouseString)
|
||||
return;
|
||||
|
||||
_mousePrintFG++;
|
||||
_mouseString1 = getMessage(_objectName1, ha->msg1);
|
||||
|
||||
uint16 num = ha->msg1 & ~0x8000;
|
||||
uint16 state = getptr(_quickptr[0] + num * _quickshort[0] + 2);
|
||||
if (state == 3) {
|
||||
_mouseString = (const char *)"unlock \0";
|
||||
} else if (state == 2) {
|
||||
_mouseString = (const char *)"open \0";
|
||||
} else {
|
||||
_mouseString = (const char *)"go through \0";
|
||||
}
|
||||
}
|
||||
|
||||
void AGOSEngine_PN::hitBox8(HitArea *ha) {
|
||||
char *msgPtr;
|
||||
|
||||
if (_intputCounter || _mouseString)
|
||||
return;
|
||||
|
||||
if (ha == 0 || _dragStore == ha)
|
||||
return;
|
||||
|
||||
uint16 num = ha->msg1 & ~0x8000;
|
||||
if (!testSeen(num))
|
||||
return;
|
||||
|
||||
msgPtr = getMessage(_objectName1, ha->msg1);
|
||||
sprintf(_inMessage, " in %s", msgPtr);
|
||||
_mouseString1 = _inMessage;
|
||||
|
||||
msgPtr = getMessage(_objectName1, _dragStore->msg1);
|
||||
|
||||
char *tmpPtr = _placeMessage;
|
||||
while (*msgPtr != 0) {
|
||||
if (*msgPtr != 13)
|
||||
*tmpPtr++ = *msgPtr;
|
||||
msgPtr++;
|
||||
}
|
||||
*tmpPtr = 0;
|
||||
|
||||
sprintf(_placeMessage, " in %s", _placeMessage);
|
||||
_mouseString = _placeMessage;
|
||||
}
|
||||
|
||||
void AGOSEngine_PN::hitBox9(HitArea *ha) {
|
||||
if (_objectCountS == _objects) {
|
||||
_objectCountS = -1;
|
||||
}
|
||||
iconPage();
|
||||
}
|
||||
|
||||
static const char *messageList[9] = {
|
||||
"North\r",
|
||||
"East\r",
|
||||
"South\r",
|
||||
"West\r",
|
||||
"Up\r",
|
||||
"Down\r",
|
||||
"Push grey button\r",
|
||||
"Push red button\r",
|
||||
"Go under car\r"
|
||||
};
|
||||
|
||||
void AGOSEngine_PN::hitBox11(HitArea *ha) {
|
||||
if (_intputCounter || _mouseString)
|
||||
return;
|
||||
|
||||
_mouseString = messageList[ha->msg1];
|
||||
_mousePrintFG++;
|
||||
}
|
||||
|
||||
} // End of namespace AGOS
|
||||
|
@ -133,6 +133,7 @@ void AGOSEngine::setupVgaOpcodes() {
|
||||
memset(_vga_opcode_table, 0, sizeof(_vga_opcode_table));
|
||||
|
||||
switch (getGameType()) {
|
||||
case GType_PN:
|
||||
case GType_ELVIRA1:
|
||||
case GType_ELVIRA2:
|
||||
case GType_WW:
|
||||
@ -176,6 +177,27 @@ void AGOSEngine::runVgaScript() {
|
||||
}
|
||||
}
|
||||
|
||||
bool AGOSEngine_PN::ifObjectHere(uint16 a) {
|
||||
if (getFeatures() & GF_DEMO)
|
||||
return 0;
|
||||
else
|
||||
return _variableArray[39] == getptr(_quickptr[11] + a * _quickshort[4] + 2);
|
||||
}
|
||||
|
||||
bool AGOSEngine_PN::ifObjectAt(uint16 a, uint16 b) {
|
||||
if (getFeatures() & GF_DEMO)
|
||||
return 0;
|
||||
else
|
||||
return b == getptr(_quickptr[11] + a * _quickshort[4] + 2);
|
||||
}
|
||||
|
||||
bool AGOSEngine_PN::ifObjectState(uint16 a, int16 b) {
|
||||
if (getFeatures() & GF_DEMO)
|
||||
return 0;
|
||||
else
|
||||
return b == getptr(_quickptr[0] + a * _quickshort[0] + 2);
|
||||
}
|
||||
|
||||
bool AGOSEngine::ifObjectHere(uint16 a) {
|
||||
Item *item;
|
||||
|
||||
@ -256,7 +278,7 @@ void AGOSEngine::setBitFlag(uint bit, bool value) {
|
||||
}
|
||||
|
||||
int AGOSEngine::vcReadVarOrWord() {
|
||||
if (getGameType() == GType_ELVIRA1) {
|
||||
if (getGameType() == GType_PN || getGameType() == GType_ELVIRA1) {
|
||||
return vcReadNextWord();
|
||||
} else {
|
||||
int16 var = vcReadNextWord();
|
||||
@ -289,6 +311,17 @@ void AGOSEngine::vcWriteVar(uint var, int16 value) {
|
||||
|
||||
void AGOSEngine::vcSkipNextInstruction() {
|
||||
|
||||
static const byte opcodeParamLenPN[] = {
|
||||
0, 6, 2, 10, 6, 4, 2, 2,
|
||||
4, 4, 8, 2, 0, 2, 2, 2,
|
||||
0, 2, 2, 2, 0, 4, 2, 2,
|
||||
2, 8, 0, 10, 0, 8, 0, 2,
|
||||
2, 0, 0, 0, 0, 2, 4, 2,
|
||||
4, 4, 0, 0, 2, 2, 2, 4,
|
||||
4, 0, 18, 2, 4, 4, 4, 0,
|
||||
4
|
||||
};
|
||||
|
||||
static const byte opcodeParamLenElvira1[] = {
|
||||
0, 6, 2, 10, 6, 4, 2, 2,
|
||||
4, 4, 8, 2, 0, 2, 2, 2,
|
||||
@ -362,9 +395,12 @@ void AGOSEngine::vcSkipNextInstruction() {
|
||||
} else if (getGameType() == GType_ELVIRA2 || getGameType() == GType_WW) {
|
||||
opcode = vcReadNextWord();
|
||||
_vcPtr += opcodeParamLenWW[opcode];
|
||||
} else {
|
||||
} else if (getGameType() == GType_ELVIRA1) {
|
||||
opcode = vcReadNextWord();
|
||||
_vcPtr += opcodeParamLenElvira1[opcode];
|
||||
} else {
|
||||
opcode = vcReadNextWord();
|
||||
_vcPtr += opcodeParamLenPN[opcode];
|
||||
}
|
||||
|
||||
if (_dumpVgaOpcodes)
|
||||
@ -411,7 +447,7 @@ void AGOSEngine::vc3_loadSprite() {
|
||||
vgaSpriteId = vcReadNextWord();
|
||||
} else {
|
||||
vgaSpriteId = vcReadNextWord();
|
||||
zoneNum = vgaSpriteId / 100;
|
||||
zoneNum = (getGameType() == GType_PN) ? 0 : vgaSpriteId / 100;
|
||||
}
|
||||
|
||||
x = vcReadNextWord();
|
||||
@ -444,8 +480,9 @@ void AGOSEngine::vc5_ifEqual() {
|
||||
}
|
||||
|
||||
void AGOSEngine::vc6_ifObjectHere() {
|
||||
if (!ifObjectHere(vcReadNextWord()))
|
||||
if (!ifObjectHere(vcReadNextWord())) {
|
||||
vcSkipNextInstruction();
|
||||
}
|
||||
}
|
||||
|
||||
void AGOSEngine::vc7_ifObjectNotHere() {
|
||||
@ -610,7 +647,7 @@ void AGOSEngine::drawImage_init(int16 image, uint16 palette, int16 x, int16 y, u
|
||||
if (state.image < 0)
|
||||
state.image = vcReadVar(-state.image);
|
||||
|
||||
state.palette = palette * 16;
|
||||
state.palette = (getGameType() == GType_PN) ? 0 : palette * 16;
|
||||
state.paletteMod = 0;
|
||||
|
||||
state.x = x - _scrollX;
|
||||
@ -645,7 +682,11 @@ void AGOSEngine::drawImage_init(int16 image, uint16 palette, int16 x, int16 y, u
|
||||
state.y_skip = 0; /* rows to skip = bl */
|
||||
|
||||
if (getFeatures() & GF_PLANAR) {
|
||||
state.srcPtr = convertImage(&state, ((flags & 0x80) != 0));
|
||||
if (getGameType() == GType_PN) {
|
||||
state.srcPtr = convertImage(&state, ((state.flags & (kDFCompressed | kDFCompressedFlip)) != 0));
|
||||
}
|
||||
else
|
||||
state.srcPtr = convertImage(&state, ((flags & 0x80) != 0));
|
||||
|
||||
// converted planar clip is already uncompressed
|
||||
if (state.flags & kDFCompressedFlip) {
|
||||
@ -691,6 +732,36 @@ void AGOSEngine::drawImage_init(int16 image, uint16 palette, int16 x, int16 y, u
|
||||
drawImage(&state);
|
||||
}
|
||||
|
||||
void AGOSEngine::checkOnStopTable() {
|
||||
VgaSleepStruct *vfs = _onStopTable, *vfs_tmp;
|
||||
while (vfs->ident != 0) {
|
||||
if (vfs->ident == _vgaCurSpriteId) {
|
||||
VgaSprite *vsp = findCurSprite();
|
||||
animate(vsp->windowNum, vsp->zoneNum, vfs->id, vsp->x, vsp->y, vsp->palette, true);
|
||||
vfs_tmp = vfs;
|
||||
do {
|
||||
memcpy(vfs_tmp, vfs_tmp + 1, sizeof(VgaSleepStruct));
|
||||
vfs_tmp++;
|
||||
} while (vfs_tmp->ident != 0);
|
||||
} else {
|
||||
vfs++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AGOSEngine::vc11_onStop() {
|
||||
uint16 id = vcReadNextWord();
|
||||
|
||||
VgaSleepStruct *vfs = _onStopTable;
|
||||
while (vfs->ident)
|
||||
vfs++;
|
||||
|
||||
vfs->ident = _vgaCurSpriteId;
|
||||
vfs->codePtr = _vcPtr;
|
||||
vfs->id = id;
|
||||
vfs->zoneNum = _vgaCurZoneNum;
|
||||
}
|
||||
|
||||
void AGOSEngine::vc12_delay() {
|
||||
uint16 num;
|
||||
|
||||
@ -728,7 +799,13 @@ void AGOSEngine::vc14_addToSpriteY() {
|
||||
|
||||
void AGOSEngine::vc15_sync() {
|
||||
VgaSleepStruct *vfs = _waitSyncTable, *vfs_tmp;
|
||||
uint16 id = vcReadNextWord();
|
||||
uint16 id;
|
||||
|
||||
if (getGameType() == GType_PN)
|
||||
id = _vgaCurSpriteId;
|
||||
else
|
||||
id = vcReadNextWord();
|
||||
|
||||
while (vfs->ident != 0) {
|
||||
if (vfs->ident == id) {
|
||||
addVgaEvent(_vgaBaseDelay, ANIMATE_EVENT, vfs->codePtr, vfs->id, vfs->zoneNum);
|
||||
@ -779,12 +856,13 @@ void AGOSEngine::checkWaitEndTable() {
|
||||
|
||||
void AGOSEngine::vc17_waitEnd() {
|
||||
uint16 id = vcReadNextWord();
|
||||
uint16 zoneNum = (getGameType() == GType_PN) ? 0 : id / 100;
|
||||
|
||||
VgaSleepStruct *vfs = _waitEndTable;
|
||||
while (vfs->ident)
|
||||
vfs++;
|
||||
|
||||
if (isSpriteLoaded(id, id / 100)) {
|
||||
if (isSpriteLoaded(id, zoneNum)) {
|
||||
vfs->ident = id;
|
||||
vfs->codePtr = _vcPtr;
|
||||
vfs->id = _vgaCurSpriteId;
|
||||
@ -867,12 +945,21 @@ void AGOSEngine::vc22_setPaletteOld() {
|
||||
|
||||
b = vcReadNextWord();
|
||||
|
||||
// PC version of Personal Nightmare uses standard EGA palette
|
||||
if (getGameType() == GType_PN && getPlatform() == Common::kPlatformPC)
|
||||
return;
|
||||
|
||||
num = 16;
|
||||
|
||||
palptr = _displayPalette;
|
||||
_bottomPalette = 1;
|
||||
|
||||
if (getGameType() == GType_ELVIRA1) {
|
||||
if (getGameType() == GType_PN) {
|
||||
if (b > 128) {
|
||||
b-= 128;
|
||||
palptr = _displayPalette + 64;
|
||||
}
|
||||
} else if (getGameType() == GType_ELVIRA1) {
|
||||
if (b >= 1000) {
|
||||
b -= 1000;
|
||||
_bottomPalette = 0;
|
||||
@ -990,6 +1077,7 @@ void AGOSEngine::vc24_setSpriteXY() {
|
||||
|
||||
void AGOSEngine::vc25_halt_sprite() {
|
||||
checkWaitEndTable();
|
||||
checkOnStopTable();
|
||||
|
||||
VgaSprite *vsp = findCurSprite();
|
||||
while (vsp->id != 0) {
|
||||
@ -1046,6 +1134,12 @@ void AGOSEngine::vc27_resetSprite() {
|
||||
vfs++;
|
||||
}
|
||||
|
||||
vfs = _onStopTable;
|
||||
while (vfs->ident) {
|
||||
vfs->ident = 0;
|
||||
vfs++;
|
||||
}
|
||||
|
||||
vte = _vgaTimerList;
|
||||
while (vte->delay) {
|
||||
// Skip the animateSprites event in earlier games
|
||||
@ -1082,13 +1176,12 @@ void AGOSEngine::vc27_resetSprite() {
|
||||
|
||||
void AGOSEngine::vc28_playSFX() {
|
||||
uint16 sound = vcReadNextWord();
|
||||
uint16 channels = vcReadNextWord();
|
||||
uint16 frequency = vcReadNextWord();
|
||||
uint16 chans = vcReadNextWord();
|
||||
uint16 freq = vcReadNextWord();
|
||||
uint16 flags = vcReadNextWord();
|
||||
debug(0, "vc28_playSFX: (sound %d, channels %d, frequency %d, flags %d)", sound, chans, freq, flags);
|
||||
|
||||
loadSound(sound);
|
||||
|
||||
debug(0, "vc28_playSFX: (%d, %d, %d, %d)", sound, channels, frequency, flags);
|
||||
loadSound(sound, freq, flags);
|
||||
}
|
||||
|
||||
void AGOSEngine::vc29_stopAllSounds() {
|
||||
@ -1154,8 +1247,23 @@ void AGOSEngine::clearVideoBackGround(uint16 num, uint16 color) {
|
||||
}
|
||||
}
|
||||
|
||||
void AGOSEngine_PN::clearVideoWindow(uint16 num, uint16 color) {
|
||||
const uint16 *vlut = &_videoWindows[num * 4];
|
||||
uint16 xoffs = vlut[0] * 16;
|
||||
uint16 yoffs = vlut[1];
|
||||
|
||||
Graphics::Surface *screen = _system->lockScreen();
|
||||
byte *dst = (byte *)screen->pixels + xoffs + yoffs * screen->pitch;
|
||||
for (uint h = 0; h < vlut[3]; h++) {
|
||||
memset(dst, color, vlut[2] * 16);
|
||||
dst += screen->pitch;
|
||||
}
|
||||
_system->unlockScreen();
|
||||
}
|
||||
|
||||
void AGOSEngine_Simon2::clearVideoWindow(uint16 num, uint16 color) {
|
||||
const uint16 *vlut = &_videoWindows[num * 4];
|
||||
|
||||
uint16 xoffs = vlut[0] * 16;
|
||||
uint16 yoffs = vlut[1];
|
||||
uint16 dstWidth = _videoWindows[18] * 16;
|
||||
@ -1243,6 +1351,10 @@ void AGOSEngine::vc37_pokePalette() {
|
||||
uint16 offs = vcReadNextWord();
|
||||
uint16 color = vcReadNextWord();
|
||||
|
||||
// PC version of Personal Nightmare uses standard EGA palette
|
||||
if (getGameType() == GType_PN && getPlatform() == Common::kPlatformPC)
|
||||
return;
|
||||
|
||||
byte *palptr = _displayPalette + offs * 4;
|
||||
palptr[0] = ((color & 0xf00) >> 8) * 32;
|
||||
palptr[1] = ((color & 0x0f0) >> 4) * 32;
|
||||
|
@ -183,9 +183,9 @@ void AGOSEngine::vc52_playSound() {
|
||||
int16 vol = vcReadNextWord();
|
||||
|
||||
if (ambient)
|
||||
loadSound(sound, pan, vol, 2);
|
||||
loadSound(sound, pan, vol, Sound::TYPE_AMBIENT);
|
||||
else
|
||||
loadSound(sound, pan, vol, 1);
|
||||
loadSound(sound, pan, vol, Sound::TYPE_SFX);
|
||||
} else if (getGameType() == GType_SIMON2) {
|
||||
if (ambient)
|
||||
_sound->playAmbient(sound);
|
||||
@ -196,7 +196,7 @@ void AGOSEngine::vc52_playSound() {
|
||||
} else if (getGameId() == GID_SIMON1DOS) {
|
||||
playSting(sound);
|
||||
} else {
|
||||
loadSound(sound);
|
||||
loadSound(sound, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -205,7 +205,7 @@ void AGOSEngine::vc83_playSoundLoop() {
|
||||
int16 vol = vcReadNextWord();
|
||||
int16 pan = vcReadNextWord();
|
||||
|
||||
loadSound(sound, pan, vol, 3);
|
||||
loadSound(sound, pan, vol, Sound::TYPE_SFX5);
|
||||
}
|
||||
|
||||
void AGOSEngine::vc84_stopSoundLoop() {
|
||||
|
188
engines/agos/vga_pn.cpp
Normal file
188
engines/agos/vga_pn.cpp
Normal file
@ -0,0 +1,188 @@
|
||||
/* 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$
|
||||
*
|
||||
*/
|
||||
|
||||
// Video script opcodes for Simon1/Simon2
|
||||
|
||||
|
||||
#include "agos/agos.h"
|
||||
#include "agos/intern.h"
|
||||
#include "agos/vga.h"
|
||||
|
||||
#include "common/system.h"
|
||||
|
||||
#include "graphics/surface.h"
|
||||
|
||||
namespace AGOS {
|
||||
|
||||
void AGOSEngine_PN::setupVideoOpcodes(VgaOpcodeProc *op) {
|
||||
op[1] = &AGOSEngine::vc1_fadeOut;
|
||||
op[2] = &AGOSEngine::vc2_call;
|
||||
op[3] = &AGOSEngine::vc3_loadSprite;
|
||||
op[4] = &AGOSEngine::vc4_fadeIn;
|
||||
op[5] = &AGOSEngine::vc5_ifEqual;
|
||||
op[6] = &AGOSEngine::vc6_ifObjectHere;
|
||||
op[7] = &AGOSEngine::vc7_ifObjectNotHere;
|
||||
op[8] = &AGOSEngine::vc8_ifObjectIsAt;
|
||||
op[9] = &AGOSEngine::vc9_ifObjectStateIs;
|
||||
op[10] = &AGOSEngine::vc10_draw;
|
||||
op[11] = &AGOSEngine::vc11_onStop;
|
||||
op[13] = &AGOSEngine::vc12_delay;
|
||||
op[14] = &AGOSEngine::vc13_addToSpriteX;
|
||||
op[15] = &AGOSEngine::vc14_addToSpriteY;
|
||||
op[16] = &AGOSEngine::vc15_sync;
|
||||
op[17] = &AGOSEngine::vc16_waitSync;
|
||||
op[18] = &AGOSEngine::vc17_waitEnd;
|
||||
op[19] = &AGOSEngine::vc18_jump;
|
||||
op[20] = &AGOSEngine::vc19_loop;
|
||||
op[21] = &AGOSEngine::vc20_setRepeat;
|
||||
op[22] = &AGOSEngine::vc21_endRepeat;
|
||||
op[23] = &AGOSEngine::vc22_setPaletteOld;
|
||||
op[24] = &AGOSEngine::vc23_setPriority;
|
||||
op[25] = &AGOSEngine::vc24_setSpriteXY;
|
||||
op[26] = &AGOSEngine::vc25_halt_sprite;
|
||||
op[27] = &AGOSEngine::vc26_setSubWindow;
|
||||
op[28] = &AGOSEngine::vc27_resetSprite;
|
||||
op[29] = &AGOSEngine::vc28_playSFX;
|
||||
op[30] = &AGOSEngine::vc29_stopAllSounds;
|
||||
op[31] = &AGOSEngine::vc30_setFrameRate;
|
||||
op[32] = &AGOSEngine::vc31_setWindow;
|
||||
op[33] = &AGOSEngine::vc32_saveScreen;
|
||||
op[34] = &AGOSEngine::vc33_setMouseOn;
|
||||
op[35] = &AGOSEngine::vc34_setMouseOff;
|
||||
op[36] = &AGOSEngine::vc36_pause;
|
||||
op[38] = &AGOSEngine::vc35_clearWindow;
|
||||
op[39] = &AGOSEngine::vc39_volume;
|
||||
op[40] = &AGOSEngine::vc36_setWindowImage;
|
||||
op[41] = &AGOSEngine::vc37_pokePalette;
|
||||
op[44] = &AGOSEngine::vc44_enableBox;
|
||||
op[45] = &AGOSEngine::vc45_disableBox;
|
||||
op[46] = &AGOSEngine::vc46_maxBox;
|
||||
op[48] = &AGOSEngine::vc48_specialEffect;
|
||||
op[50] = &AGOSEngine::vc50_setBox;
|
||||
op[51] = &AGOSEngine::vc38_ifVarNotZero;
|
||||
op[52] = &AGOSEngine::vc39_setVar;
|
||||
op[53] = &AGOSEngine::vc40_scrollRight;
|
||||
op[54] = &AGOSEngine::vc41_scrollLeft;
|
||||
op[55] = &AGOSEngine::vc55_scanFlag;
|
||||
}
|
||||
|
||||
void AGOSEngine::vc36_pause() {
|
||||
const char *message1 = "Press any key to continue";
|
||||
bool oldWiped = _wiped;
|
||||
_wiped = 0;
|
||||
|
||||
_lockWord |= 8;
|
||||
|
||||
windowPutChar(_windowArray[2], 13);
|
||||
|
||||
for (; *message1; message1++)
|
||||
windowPutChar(_windowArray[2], *message1);
|
||||
|
||||
while (!shouldQuit()) {
|
||||
if (_keyPressed.ascii != 0)
|
||||
break;
|
||||
delay(1);
|
||||
}
|
||||
|
||||
_keyPressed.reset();
|
||||
|
||||
windowPutChar(_windowArray[2], 13);
|
||||
windowPutChar(_windowArray[2], 128);
|
||||
_wiped = oldWiped;
|
||||
|
||||
_lockWord &= ~8;
|
||||
}
|
||||
|
||||
void AGOSEngine::vc39_volume() {
|
||||
_vcPtr += 2;
|
||||
}
|
||||
|
||||
void AGOSEngine::vc44_enableBox() {
|
||||
HitArea *ha = _hitAreas + vcReadNextWord();
|
||||
ha->flags &= ~kOBFBoxDisabled;
|
||||
}
|
||||
|
||||
void AGOSEngine::vc45_disableBox() {
|
||||
HitArea *ha = _hitAreas + vcReadNextWord();
|
||||
ha->flags |= kOBFBoxDisabled;
|
||||
}
|
||||
|
||||
void AGOSEngine::vc46_maxBox() {
|
||||
HitArea *ha = _hitAreas + vcReadNextWord();
|
||||
ha->id = 0xFFFF;
|
||||
}
|
||||
|
||||
void AGOSEngine::vc48_specialEffect() {
|
||||
uint16 num = vcReadNextWord();
|
||||
vcReadNextWord();
|
||||
|
||||
if (getPlatform() == Common::kPlatformPC) {
|
||||
if (num == 1) {
|
||||
Graphics::Surface *screen = _system->lockScreen();
|
||||
byte *dst = (byte *)screen->pixels;
|
||||
|
||||
for (uint h = 0; h < _screenHeight; h++) {
|
||||
for (uint w = 0; w < _screenWidth; w++) {
|
||||
if (dst[w] == 15)
|
||||
dst[w] = 4;
|
||||
}
|
||||
dst += _screenWidth;
|
||||
}
|
||||
_system->unlockScreen();
|
||||
} else if (num == 2) {
|
||||
const char *str = "There are gurgling noises from the sink.";
|
||||
for (; *str; str++)
|
||||
windowPutChar(_textWindow, *str);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AGOSEngine::vc50_setBox() {
|
||||
uint16 id, x, y, w, h, msg1, msg2, flags;
|
||||
const uint16 *vlut;
|
||||
|
||||
id = vcReadNextWord();
|
||||
vlut = &_videoWindows[vcReadNextWord() * 4];
|
||||
x = vlut[0] * 16 + vcReadNextWord();
|
||||
y = vlut[1] + vcReadNextWord();
|
||||
h = vcReadNextWord();
|
||||
w = vcReadNextWord();
|
||||
msg1 = vcReadNextWord();
|
||||
msg2 = vcReadNextWord();
|
||||
flags = vcReadNextWord();
|
||||
|
||||
// Compressed string
|
||||
if (!(flags & kOBFUseMessageList)) {
|
||||
msg1 += 0x8000;
|
||||
}
|
||||
|
||||
defineBox(id, x, y, h, w, msg1, msg2, flags);
|
||||
}
|
||||
|
||||
void AGOSEngine::vc55_scanFlag() {
|
||||
_scanFlag = 1;
|
||||
}
|
||||
|
||||
} // End of namespace AGOS
|
@ -71,10 +71,12 @@ WindowBlock *AGOSEngine::openWindow(uint x, uint y, uint w, uint h, uint flags,
|
||||
// Characters are 6 pixels
|
||||
if (getGameType() == GType_ELVIRA2)
|
||||
window->textMaxLength = (window->width * 8 - 4) / 6;
|
||||
else if (getGameType() == GType_PN)
|
||||
window->textMaxLength = window->width * 8 / 6 + 1;
|
||||
else
|
||||
window->textMaxLength = window->width * 8 / 6;
|
||||
|
||||
if (getGameType() == GType_ELVIRA1 || getGameType() == GType_ELVIRA2 || getGameType() == GType_WW)
|
||||
if (getGameType() == GType_PN || getGameType() == GType_ELVIRA1 || getGameType() == GType_ELVIRA2 || getGameType() == GType_WW)
|
||||
clearWindow(window);
|
||||
|
||||
if (getGameType() == GType_SIMON1 && getPlatform() == Common::kPlatformAmiga && window->fillColor == 225)
|
||||
@ -202,9 +204,9 @@ void AGOSEngine::restoreWindow(WindowBlock *window) {
|
||||
_restoreWindow6 = 0;
|
||||
}
|
||||
|
||||
restoreBlock(window->y + window->height * 8, (window->x + window->width) * 8, window->y, window->x * 8);
|
||||
restoreBlock(window->x * 8, window->y, (window->x + window->width) * 8, window->y + window->height * 8);
|
||||
} else if (getGameType() == GType_SIMON1) {
|
||||
restoreBlock(window->y + window->height * 8 + ((window == _windowArray[2]) ? 1 : 0), (window->x + window->width) * 8, window->y, window->x * 8);
|
||||
restoreBlock(window->x * 8, window->y, (window->x + window->width) * 8, window->y + window->height * 8 + ((window == _windowArray[2]) ? 1 : 0));
|
||||
} else {
|
||||
uint16 x = window->x;
|
||||
uint16 w = window->width;
|
||||
@ -220,13 +222,13 @@ void AGOSEngine::restoreWindow(WindowBlock *window) {
|
||||
}
|
||||
}
|
||||
|
||||
restoreBlock(window->y + window->height * 8, (x + w) * 8, window->y, x * 8);
|
||||
restoreBlock(x * 8, window->y, (x + w) * 8, window->y + window->height * 8);
|
||||
}
|
||||
|
||||
_lockWord &= ~0x8000;
|
||||
}
|
||||
|
||||
void AGOSEngine::restoreBlock(uint16 h, uint16 w, uint16 y, uint16 x) {
|
||||
void AGOSEngine::restoreBlock(uint16 x, uint16 y, uint16 w, uint16 h) {
|
||||
byte *dst, *src;
|
||||
uint i;
|
||||
|
||||
@ -266,7 +268,7 @@ void AGOSEngine::setTextColor(uint color) {
|
||||
}
|
||||
|
||||
void AGOSEngine::sendWindow(uint a) {
|
||||
if (_textWindow != _windowArray[0]) {
|
||||
if (getGameType() == GType_PN || _textWindow != _windowArray[0]) {
|
||||
if (getGameType() == GType_ELVIRA1 || getGameType() == GType_ELVIRA2 || getGameType() == GType_WW) {
|
||||
if (!(_textWindow->flags & 1)) {
|
||||
haltAnimation();
|
||||
|
@ -63,29 +63,34 @@ static const uint8 zoneTable[160] = {
|
||||
2, 2, 2, 2, 2, 0, 0, 0, 0, 0,
|
||||
};
|
||||
|
||||
void AGOSEngine::loadZone(uint16 zoneNum) {
|
||||
void AGOSEngine::loadZone(uint16 zoneNum, bool useError) {
|
||||
VgaPointersEntry *vpe;
|
||||
|
||||
CHECK_BOUNDS(zoneNum, _vgaBufferPointers);
|
||||
|
||||
vpe = _vgaBufferPointers + zoneNum;
|
||||
if (vpe->vgaFile1 != NULL)
|
||||
return;
|
||||
if (getGameType() == GType_PN) {
|
||||
// Only a single zone is used in Personal Nightmare
|
||||
vpe = _vgaBufferPointers;
|
||||
vc27_resetSprite();
|
||||
} else {
|
||||
vpe = _vgaBufferPointers + zoneNum;
|
||||
if (vpe->vgaFile1 != NULL)
|
||||
return;
|
||||
}
|
||||
|
||||
// Loading order is important
|
||||
// due to resource managment
|
||||
// Loading order is important due to resource managment
|
||||
|
||||
if (getPlatform() == Common::kPlatformAmiga && getGameType() == GType_WW &&
|
||||
zoneTable[zoneNum] == 3) {
|
||||
uint8 num = (zoneNum >= 85) ? 94 : 18;
|
||||
loadVGAVideoFile(num, 2);
|
||||
loadVGAVideoFile(num, 2, useError);
|
||||
} else {
|
||||
loadVGAVideoFile(zoneNum, 2);
|
||||
loadVGAVideoFile(zoneNum, 2, useError);
|
||||
}
|
||||
vpe->vgaFile2 = _block;
|
||||
vpe->vgaFile2End = _blockEnd;
|
||||
|
||||
loadVGAVideoFile(zoneNum, 1);
|
||||
loadVGAVideoFile(zoneNum, 1, useError);
|
||||
vpe->vgaFile1 = _block;
|
||||
vpe->vgaFile1End = _blockEnd;
|
||||
|
||||
|
@ -498,6 +498,7 @@ begin_credits("Credits");
|
||||
|
||||
begin_section("AGOS");
|
||||
add_person("Torbjörn Andersson", "eriktorbjorn", "");
|
||||
add_person("Paul Gilbert", "dreammaster", "");
|
||||
add_person("Travis Howell", "Kirben", "");
|
||||
end_section();
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user