[Scummvm-cvs-logs] CVS: scummvm/awe awe.cpp,NONE,1.1 awe.h,NONE,1.1 bank.cpp,NONE,1.1 bank.h,NONE,1.1 engine.cpp,NONE,1.1 engine.h,NONE,1.1 file.cpp,NONE,1.1 file.h,NONE,1.1 intern.h,NONE,1.1 logic.cpp,NONE,1.1 logic.h,NONE,1.1 module.mk,NONE,1.1 resource.cpp,NONE,1.1 resource.h,NONE,1.1 sdlstub.cpp,NONE,1.1 serializer.cpp,NONE,1.1 serializer.h,NONE,1.1 staticres.cpp,NONE,1.1 systemstub.h,NONE,1.1 util.cpp,NONE,1.1 util.h,NONE,1.1 video.cpp,NONE,1.1 video.h,NONE,1.1

Pawel Kolodziejski aquadran at users.sourceforge.net
Wed May 5 00:26:09 CEST 2004


Update of /cvsroot/scummvm/scummvm/awe
In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv2783/awe

Added Files:
	awe.cpp awe.h bank.cpp bank.h engine.cpp engine.h file.cpp 
	file.h intern.h logic.cpp logic.h module.mk resource.cpp 
	resource.h sdlstub.cpp serializer.cpp serializer.h 
	staticres.cpp systemstub.h util.cpp util.h video.cpp video.h 
Log Message:
adding initial code for Another World engine

--- NEW FILE: awe.cpp ---
/* AWE - Another World Engine
 * Copyright (C) 2004 Gregory Montoir
 * Copyright (C) 2004 The ScummVM project
 *
 * 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */

#include "common/stdafx.h"

#include "base/gameDetector.h"
#include "base/plugins.h"
#include "backends/fs/fs.h"

#include "sound/mixer.h"
#include "common/file.h"
#include "common/config-manager.h"

#include "awe/awe.h"
#include "awe/engine.h"
#include "awe/systemstub.h"
#include "awe/util.h"


struct AWEGameSettings {
	const char *name;
	const char *description;
	byte id;
	uint32 features;
	const char *detectname;
	GameSettings toGameSettings() const {
		GameSettings dummy = { name, description, features };
		return dummy;
	}
};

static const AWEGameSettings awe_settings[] = {
	/* Another World - Out of this World - Europe DOS version */
	{ "worlde", "Another World - Out of this World - (Europe, DOS)", Awe::GID_WORLDE, MDT_ADLIB, "bank01" },
	{ NULL, NULL, 0, 0, NULL }
};

GameList Engine_AWE_gameList() {
	const AWEGameSettings *g = awe_settings;
	GameList games;
	while (g->name) {
		games.push_back(g->toGameSettings());
		g++;
	}
	return games;
}

DetectedGameList Engine_AWE_detectGames(const FSList &fslist) {
	DetectedGameList detectedGames;
	const AWEGameSettings *g;

	for (g = awe_settings; g->name; ++g) {
		// Iterate over all files in the given directory
		for (FSList::const_iterator file = fslist.begin(); file != fslist.end(); ++file) {
			const char *gameName = file->displayName().c_str();

			if (0 == scumm_stricmp(g->detectname, gameName)) {
				// Match found, add to list of candidates, then abort inner loop.
				detectedGames.push_back(g->toGameSettings());
				break;
			}
		}
	}
	return detectedGames;
}

Engine *Engine_AWE_create(GameDetector *detector, OSystem *syst) {
	return new Awe::AweEngine(detector, syst);
}

REGISTER_PLUGIN("AWE Engine", Engine_AWE_gameList, Engine_AWE_create, Engine_AWE_detectGames)

namespace Awe {

AweEngine::AweEngine(GameDetector *detector, OSystem *syst)
	: Engine(syst) {

	// Setup mixer
	if (!_mixer->isReady()) {
		::warning("Sound initialization failed.");
	}

	_mixer->setVolume(ConfMan.getInt("sfx_volume") * ConfMan.getInt("master_volume") / 255);

	_dataPath = getGameDataPath();
	_savePath = getSavePath();

	// Initialize backend
	syst->initSize(320, 200);
}

AweEngine::~AweEngine() {

}

void AweEngine::errorString(const char *buf1, char *buf2) {
	strcpy(buf2, buf1);
}

void AweEngine::go() {
	g_debugMask = DBG_INFO;
	SystemStub *stub = SystemStub_SDL_create();
	debug(0, "%s %s", _dataPath, _savePath);
	Awe::Engine *e = new Awe::Engine(stub, _dataPath, _savePath);
	e->run();
	delete e;
	delete stub;
}

void AweEngine::shutdown() {
	_system->quit();
}

}

--- NEW FILE: awe.h ---
/* AWE - Another World Engine
 * Copyright (C) 2004 Gregory Montoir
 * Copyright (C) 2004 The ScummVM project
 *
 * 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */

#ifndef AWE_H
#define AWE_H

#include "common/stdafx.h"
#include "common/scummsys.h"
#include "base/engine.h"
#include "base/gameDetector.h"
#include "common/util.h"

namespace Awe {

#define BYPASS_PROTECTION

enum AWEGameId {
	GID_WORLDE
};

class AweEngine : public ::Engine {

	void errorString( const char *buf_input, char *buf_output);

protected:
	void go();
	void shutdown();

	const char *_dataPath;
	const char *_savePath;

public:

	AweEngine(GameDetector *detector, OSystem *syst);
	virtual ~AweEngine();

};

}

#endif

--- NEW FILE: bank.cpp ---
/* AWE - Another World Engine
 * Copyright (C) 2004 Gregory Montoir
 * Copyright (C) 2004 The ScummVM project
 *
 * 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */

#include "common/stdafx.h"

#include "awe/awe.h"
#include "awe/bank.h"
#include "awe/file.h"
#include "awe/resource.h"

namespace Awe {

Bank::Bank(const char *dataDir)
	: _dataDir(dataDir) {
}

bool Bank::read(const MemEntry *me, uint8 *buf) {
	bool ret = false;
	char bankName[10];
	sprintf(bankName, "bank%02x", me->bankNum);
	File f;
	if (f.open(bankName, _dataDir)) {
		f.seek(me->bankPos);
		if (me->packedSize == me->unpackedSize) {
			f.read(buf, me->packedSize);
			ret = true;
		} else {
			f.read(buf, me->packedSize);
			_startBuf = buf;
			_iBuf = buf + me->packedSize - 4;
			ret = unpack();
		}
	} else {
		::error("Bank::read() unable to open '%s'", bankName);
	}
	return ret;
}

void Bank::decUnk1(uint8 numChunks, uint8 addCount) {
	uint16 count = getCode(numChunks) + addCount + 1;
	debug(DBG_BANK, "Bank::decUnk1(%d, %d) count=%d", numChunks, addCount, count);
	_unpCtx.datasize -= count;
	while (count--) {
		assert(_oBuf >= _iBuf && _oBuf >= _startBuf);
		*_oBuf = (uint8)getCode(8);
		--_oBuf;
	}
}

void Bank::decUnk2(uint8 numChunks) {
	uint16 i = getCode(numChunks);
	uint16 count = _unpCtx.size + 1;
	debug(DBG_BANK, "Bank::decUnk2(%d) i=%d count=%d", numChunks, i, count);
	_unpCtx.datasize -= count;
	while (count--) {
		assert(_oBuf >= _iBuf && _oBuf >= _startBuf);
		*_oBuf = *(_oBuf + i);
		--_oBuf;
	}
}

bool Bank::unpack() {
	_unpCtx.size = 0;
	_unpCtx.datasize = READ_BE_UINT32(_iBuf); _iBuf -= 4;
	_oBuf = _startBuf + _unpCtx.datasize - 1;
	_unpCtx.crc = READ_BE_UINT32(_iBuf); _iBuf -= 4;
	_unpCtx.chk = READ_BE_UINT32(_iBuf); _iBuf -= 4;
	_unpCtx.crc ^= _unpCtx.chk;
	do {
		if (!nextChunk()) {
			_unpCtx.size = 1;
			if (!nextChunk()) {
				decUnk1(3, 0);
			} else {
				decUnk2(8);
			}
		} else {
			uint16 c = getCode(2);
			if (c == 3) {
				decUnk1(8, 8);
			} else {
				if (c < 2) {
					_unpCtx.size = c + 2;
					decUnk2(c + 9);
				} else {
					_unpCtx.size = getCode(8);
					decUnk2(12);
				}
			}
		}
	} while (_unpCtx.datasize > 0);
	return (_unpCtx.crc == 0);
}

uint16 Bank::getCode(uint8 numChunks) {
	uint16 c = 0;
	while (numChunks--) {
		c <<= 1;
		if (nextChunk()) {
			c |= 1;
		}			
	}
	return c;
}

bool Bank::nextChunk() {
	bool CF = rcr(false);
	if (_unpCtx.chk == 0) {
		assert(_iBuf >= _startBuf);
		_unpCtx.chk = READ_BE_UINT32(_iBuf); _iBuf -= 4;
		_unpCtx.crc ^= _unpCtx.chk;
		CF = rcr(true);
	}
	return CF;
}

bool Bank::rcr(bool CF) {
	bool rCF = (_unpCtx.chk & 1);
	_unpCtx.chk >>= 1;
	if (CF) _unpCtx.chk |= 0x80000000;
	return rCF;
}

}

--- NEW FILE: bank.h ---
/* AWE - Another World Engine
 * Copyright (C) 2004 Gregory Montoir
 * Copyright (C) 2004 The ScummVM project
 *
 * 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */

#ifndef __BANK_H__
#define __BANK_H__

#include "stdafx.h"

#include "intern.h"

namespace Awe {

struct MemEntry;

struct UnpackContext {
	uint16 size;
	uint32 crc;
	uint32 chk;
	int32 datasize;
};

struct Bank {
	UnpackContext _unpCtx;
	const char *_dataDir;
	uint8 *_iBuf, *_oBuf, *_startBuf;

	Bank(const char *dataDir);

	bool read(const MemEntry *me, uint8 *buf);
	void decUnk1(uint8 numChunks, uint8 addCount);
	void decUnk2(uint8 numChunks);
	bool unpack();
	uint16 getCode(uint8 numChunks);
	bool nextChunk();
	bool rcr(bool CF);
};

}

#endif

--- NEW FILE: engine.cpp ---
/* AWE - Another World Engine
 * Copyright (C) 2004 Gregory Montoir
 * Copyright (C) 2004 The ScummVM project
 *
 * 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */

#include "stdafx.h"

#include "awe.h"
#include "engine.h"
#include "file.h"
#include "serializer.h"
#include "systemstub.h"

namespace Awe {

Engine::Engine(SystemStub *stub, const char *dataDir, const char *saveDir)
	: _stub(stub), _log(&_res, &_vid, stub), _res(&_vid, dataDir), _vid(&_res, stub), 
	_dataDir(dataDir), _saveDir(saveDir), _stateSlot(0) {
}

void Engine::run() {
	_stub->init("Out Of This World");
	setup();
	// XXX
	_log.restartAt(0x3E80); // demo starts at 0x3E81
	while (!_stub->_pi.quit) {
		_log.setupScripts();
		_log.inp_updatePlayer();
		processInput();
		_log.runScripts();
	}
	finish();
	_stub->destroy();
}

void Engine::setup() {
	_vid.init();
	_res.allocMemBlock();
	_res.readEntries();
	_log.init();
}

void Engine::finish() {
	 // XXX
	 _res.freeMemBlock();
}

void Engine::processInput() {
	if (_stub->_pi.load) {
		loadGameState(_stateSlot);
		_stub->_pi.load = false;
	}
	if (_stub->_pi.save) {
		saveGameState(_stateSlot, "quicksave");
		_stub->_pi.save = false;
	}
	if (_stub->_pi.fastMode) {
		_log._fastMode = !_log._fastMode;
		_stub->_pi.fastMode = false;
	}
	if (_stub->_pi.stateSlot != 0) {
		int8 slot = _stateSlot + _stub->_pi.stateSlot;
		if (slot >= 0 && slot < MAX_SAVE_SLOTS) {
			_stateSlot = slot;
			debug(DBG_INFO, "Current game state slot is %d", _stateSlot);
		}
		_stub->_pi.stateSlot = 0;
	}
}

void Engine::makeGameStateName(uint8 slot, char *buf) {
	sprintf(buf, "raw.s%02d", slot);
}

void Engine::saveGameState(uint8 slot, const char *desc) {
	char stateFile[20];
	makeGameStateName(slot, stateFile);
	File f(true);
	if (!f.open(stateFile, _saveDir, "wb")) {
		::warning("Unable to save state file '%s'", stateFile);
	} else {
		// header
		f.writeUint32BE('AWSV');
		f.writeUint16BE(Serializer::CUR_VER);
		f.writeUint16BE(0);
		char hdrdesc[32];
		strncpy(hdrdesc, desc, sizeof(hdrdesc) - 1);
		f.write(hdrdesc, sizeof(hdrdesc));
		// contents
		Serializer s(&f, Serializer::SM_SAVE, _res._memPtrStart);
		_log.saveOrLoad(s);
		_res.saveOrLoad(s);
		_vid.saveOrLoad(s);
		if (f.ioErr()) {
			::warning("I/O error when saving game state");
		} else {
			debug(DBG_INFO, "Saved state to slot %d", _stateSlot);
		}
	}
}

void Engine::loadGameState(uint8 slot) {
	char stateFile[20];
	makeGameStateName(slot, stateFile);
	File f(true);
	if (!f.open(stateFile, _saveDir, "rb")) {
		::warning("Unable to open state file '%s'", stateFile);
	} else {
		uint32 id = f.readUint32BE();
		if (id != 'AWSV') {
			::warning("Bad savegame format");
		} else {
			uint16 ver = f.readUint16BE();
			f.readUint16BE();
			char hdrdesc[32];
			f.read(hdrdesc, sizeof(hdrdesc));
			// contents
			Serializer s(&f, Serializer::SM_LOAD, _res._memPtrStart, ver);
			_log.saveOrLoad(s);
			_res.saveOrLoad(s);
			_vid.saveOrLoad(s);
		}
		if (f.ioErr()) {
			::warning("I/O error when loading game state");
		} else {
			debug(DBG_INFO, "Loaded state from slot %d", _stateSlot);
		}
	}
}

}

--- NEW FILE: engine.h ---
/* AWE - Another World Engine
 * Copyright (C) 2004 Gregory Montoir
 * Copyright (C) 2004 The ScummVM project
 *
 * 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */

#ifndef __ENGINE_H__
#define __ENGINE_H__

#include "stdafx.h"

#include "intern.h"
#include "logic.h"
#include "resource.h"
#include "video.h"

namespace Awe {

struct SystemStub;

struct Engine {
	enum {
		MAX_SAVE_SLOTS = 100
	};

	SystemStub *_stub;
	Logic _log;
	Resource _res;
	Video _vid;
	const char *_dataDir, *_saveDir;
	uint8 _stateSlot;

	Engine(SystemStub *stub, const char *dataDir, const char *saveDir);

	void run();
	void setup();
	void finish();
	void processInput();
	
	void makeGameStateName(uint8 slot, char *buf);
	void saveGameState(uint8 slot, const char *desc);
	void loadGameState(uint8 slot);
};

}

#endif

--- NEW FILE: file.cpp ---
/* AWE - Another World Engine
 * Copyright (C) 2004 Gregory Montoir
 * Copyright (C) 2004 The ScummVM project
 *
 * 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */

#include "stdafx.h"

#include "zlib.h"
#include "file.h"

namespace Awe {

struct File_impl {
	bool _ioErr;
	File_impl() : _ioErr(false) {}
	virtual bool open(const char *path, const char *mode) = 0;
	virtual void close() = 0;
	virtual void seek(int32 off) = 0;
	virtual void read(void *ptr, uint32 size) = 0;
	virtual void write(void *ptr, uint32 size) = 0;
};

struct stdFile : File_impl {
	FILE *_fp;
	stdFile() : _fp(0) {}
	bool open(const char *path, const char *mode) {
		_ioErr = false;
		_fp = fopen(path, mode);
		return (_fp != NULL);
	}
	void close() {
		if (_fp) {
			fclose(_fp);
			_fp = 0;
		}
	}
	void seek(int32 off) {
		if (_fp) {
			fseek(_fp, off, SEEK_SET);
		}
	}
	void read(void *ptr, uint32 size) {
		if (_fp) {
			uint32 r = fread(ptr, 1, size, _fp);
			if (r != size) {
				_ioErr = true;
			}
		}
	}
	void write(void *ptr, uint32 size) {
		if (_fp) {
			uint32 r = fwrite(ptr, 1, size, _fp);
			if (r != size) {
				_ioErr = true;
			}
		}
	}
};

struct zlibFile : File_impl {
	gzFile _fp;
	zlibFile() : _fp(0) {}
	bool open(const char *path, const char *mode) {
		_ioErr = false;
		_fp = gzopen(path, mode);
		return (_fp != NULL);
	}
	void close() {
		if (_fp) {
			gzclose(_fp);
			_fp = 0;
		}
	}
	void seek(int32 off) {
		if (_fp) {
			gzseek(_fp, off, SEEK_SET);
		}
	}
	void read(void *ptr, uint32 size) {
		if (_fp) {
			uint32 r = gzread(_fp, ptr, size);
			if (r != size) {
				_ioErr = true;
			}
		}
	}
	void write(void *ptr, uint32 size) {
		if (_fp) {
			uint32 r = gzwrite(_fp, ptr, size);
			if (r != size) {
				_ioErr = true;
			}
		}
	}
};

File::File(bool gzipped) {
	if (gzipped) {
		_impl = new zlibFile;
	} else {
		_impl = new stdFile;
	}
}

File::~File() {
	_impl->close();
	delete _impl;
}

bool File::open(const char *filename, const char *directory, const char *mode) {	
	_impl->close();
	char buf[512];
	sprintf(buf, "%s/%s", directory, filename);
	char *p = buf + strlen(directory) + 1;
	string_lower(p);
	bool opened = _impl->open(buf, mode);
	if (!opened) { // let's try uppercase
		string_upper(p);
		opened = _impl->open(buf, mode);
	}
	return opened;
}

void File::close() {
	_impl->close();
}

bool File::ioErr() const {
	return _impl->_ioErr;
}

void File::seek(int32 off) {
	_impl->seek(off);
}

void File::read(void *ptr, uint32 size) {
	_impl->read(ptr, size);
}

uint8 File::readByte() {
	uint8 b;
	read(&b, 1);
	return b;
}

uint16 File::readUint16BE() {
	uint8 hi = readByte();
	uint8 lo = readByte();
	return (hi << 8) | lo;
}

uint32 File::readUint32BE() {
	uint16 hi = readUint16BE();
	uint16 lo = readUint16BE();
	return (hi << 16) | lo;
}

void File::write(void *ptr, uint32 size) {
	_impl->write(ptr, size);
}

void File::writeByte(uint8 b) {
	write(&b, 1);
}

void File::writeUint16BE(uint16 n) {
	writeByte(n >> 8);
	writeByte(n & 0xFF);
}

void File::writeUint32BE(uint32 n) {
	writeUint16BE(n >> 16);
	writeUint16BE(n & 0xFFFF);
}

}

--- NEW FILE: file.h ---
/* AWE - Another World Engine
 * Copyright (C) 2004 Gregory Montoir
 * Copyright (C) 2004 The ScummVM project
 *
 * 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */

#ifndef __FILE_H__
#define __FILE_H__

#include "stdafx.h"

#include "intern.h"

namespace Awe {

struct File_impl;

struct File {
	File_impl *_impl;

	File(bool gzipped = false);
	~File();

	bool open(const char *filename, const char *directory, const char *mode="rb");
	void close();
	bool ioErr() const;
	void seek(int32 off);
	void read(void *ptr, uint32 size);
	uint8 readByte();
	uint16 readUint16BE();
	uint32 readUint32BE();
	void write(void *ptr, uint32 size);
	void writeByte(uint8 b);
	void writeUint16BE(uint16 n);
	void writeUint32BE(uint32 n);
};

}

#endif

--- NEW FILE: intern.h ---
/* AWE - Another World Engine
 * Copyright (C) 2004 Gregory Montoir
 * Copyright (C) 2004 The ScummVM project
 *
 * 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */

#ifndef __INTERN_H__
#define __INTERN_H__

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cassert>

#include "stdafx.h"

#include "common/scummsys.h"

#include "util.h"

namespace Awe {

template<typename T>
inline void SWAP(T &a, T &b) {
	T tmp = a; 
	a = b;
	b = tmp;
}

struct Ptr {
	uint8 *pc;
	
	uint8 fetchByte() {
		return *pc++;
	}
	
	uint16 fetchWord() {
		uint16 i = READ_BE_UINT16(pc);
		pc += 2;
		return i;
	}
};

struct Point {
	int16 x, y;

	Point() : x(0), y(0) {}
	Point(int16 xx, int16 yy) : x(xx), y(yy) {}
	Point(const Point &p) : x(p.x), y(p.y) {}
};

}

#endif

--- NEW FILE: logic.cpp ---
/* AWE - Another World Engine
 * Copyright (C) 2004 Gregory Montoir
 * Copyright (C) 2004 The ScummVM project
 *
 * 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */

#include <ctime>

#include "stdafx.h"

#include "awe.h"
#include "logic.h"
#include "resource.h"
#include "video.h"
#include "serializer.h"
#include "systemstub.h"

namespace Awe {

Logic::Logic(Resource *res, Video *vid, SystemStub *stub)
	: _res(res), _vid(vid), _stub(stub) {
}

void Logic::init() {
	memset(_scriptVars, 0, sizeof(_scriptVars));
	_scriptVars[0x54] = 0x81;
	_scriptVars[VAR_RANDOM_SEED] = time(0);
	_fastMode = false;
}

void Logic::op_movConst() {
	uint8 i = _scriptPtr.fetchByte();
	int16 n = _scriptPtr.fetchWord();
	debug(DBG_LOGIC, "Logic::op_movConst(0x%02X, %d)", i, n);
	_scriptVars[i] = n;
}

void Logic::op_mov() {
	uint8 i = _scriptPtr.fetchByte();
	uint8 j = _scriptPtr.fetchByte();	
	debug(DBG_LOGIC, "Logic::op_mov(0x%02X, 0x%02X)", i, j);
	_scriptVars[i] = _scriptVars[j];
}

void Logic::op_add() {
	uint8 i = _scriptPtr.fetchByte();
	uint8 j = _scriptPtr.fetchByte();
	debug(DBG_LOGIC, "Logic::op_add(0x%02X, 0x%02X)", i, j);
	_scriptVars[i] += _scriptVars[j];
}

void Logic::op_addConst() {
	uint8 i = _scriptPtr.fetchByte();
	int16 n = _scriptPtr.fetchWord();
	debug(DBG_LOGIC, "Logic::op_addConst(0x%02X, %d)", i, n);
	_scriptVars[i] += n;
}

void Logic::op_call() {
	uint16 off = _scriptPtr.fetchWord();
	uint8 sp = _stackPtr;
	debug(DBG_LOGIC, "Logic::op_call(0x%X)", off);
	_scriptStackCalls[sp] = _scriptPtr.pc - _res->_segCode;
	++_stackPtr;
	_scriptPtr.pc = _res->_segCode + off;
}

void Logic::op_ret() {
	debug(DBG_LOGIC, "Logic::op_ret()");
	--_stackPtr;
	uint8 sp = _stackPtr;
	_scriptPtr.pc = _res->_segCode + _scriptStackCalls[sp];
}

void Logic::op_break() {
	debug(DBG_LOGIC, "Logic::op_break()");
	_scriptHalted = true;
}

void Logic::op_jmp() {
	uint16 off = _scriptPtr.fetchWord();
	debug(DBG_LOGIC, "Logic::op_jmp(0x%02X)", off);
	_scriptPtr.pc = _res->_segCode + off;	
}

void Logic::op_setScriptPos() {
	uint8 i = _scriptPtr.fetchByte();
	uint16 n = _scriptPtr.fetchWord();
	debug(DBG_LOGIC, "Logic::op_setScriptPos(0x%X, 0x%X)", i, n);
	_scriptPos[1][i] = n;
}

void Logic::op_jnz() {
	uint8 i = _scriptPtr.fetchByte();
	debug(DBG_LOGIC, "Logic::op_jnz(0x%02X)", i);
	--_scriptVars[i];
	if (_scriptVars[i] != 0) {
		op_jmp();
	} else {
		_scriptPtr.fetchWord();
	}
}

void Logic::op_condJmp() {
#ifdef BYPASS_PROTECTION
	if (_res->_curPtrsId == 0x3E80 && _scriptPtr.pc == _res->_segCode + 0xCB9) {
		// (0x0CB8) condJmp(0x80, VAR(41), VAR(30), 0xCD3)
		*(_scriptPtr.pc + 0x00) = 0x81;
		*(_scriptPtr.pc + 0x03) = 0x0D;
		*(_scriptPtr.pc + 0x04) = 0x24;
		// (0x0D4E) condJmp(0x4, VAR(50), 6, 0xDBC)		
		*(_scriptPtr.pc + 0x99) = 0x0D;
		*(_scriptPtr.pc + 0x9A) = 0x5A;
		::warning("Logic::op_condJmp() bypassing protection");	
	}
#endif
	uint8 op = _scriptPtr.fetchByte();
	int16 b = _scriptVars[_scriptPtr.fetchByte()];
	int16 a = _scriptPtr.fetchByte();	
	if (op & 0x80) {
		a = _scriptVars[a];
	} else {
		if (op & 0x40) {
			a = (a << 8) | _scriptPtr.fetchByte();
		}
	}
	debug(DBG_LOGIC, "Logic::op_condJmp(%d, 0x%02X, 0x%02X)", op, b, a);
	bool expr = false;
	switch (op & 7) {
	case 0:	// jz
		expr = (b == a);
		break;
	case 1: // jnz
		expr = (b != a);
		break;
	case 2: // jg
		expr = (b > a);
		break;
	case 3: // jge
		expr = (b >= a);
		break;
	case 4: // jl
		expr = (b < a);
		break;
	case 5: // jle
		expr = (b <= a);
		break;
	default:
		::warning("Logic::op_condJmp() invalid condition %d", (op & 7));
		break;
	}
	if (expr) {
		op_jmp();
	} else {
		_scriptPtr.fetchWord();
	}
}

void Logic::op_setPalette() {
	uint16 i = _scriptPtr.fetchWord();
	debug(DBG_LOGIC, "Logic::op_changePalette(%d)", i);
	_vid->_newPal = i >> 8;
}

void Logic::op_resetScript() {
	uint8 j = _scriptPtr.fetchByte();
	uint8 i = _scriptPtr.fetchByte();
	int8 n = (i & 0x3F) - j;
	if (n < 0) {
		::warning("Logic::op_resetScript() ec=0x%X (n < 0)", 0x880);
		return;
	}
	++n;
	uint8 _al = _scriptPtr.fetchByte();

	debug(DBG_LOGIC, "Logic::op_resetScript(%d, %d, %d)", j, i, _al);

	if (_al == 2) {
		uint16 *_si = &_scriptPos[1][j];
		while (n--) {
			*_si = 0xFFFE;
			++_si;
		}
	} else if (_al < 2) {
		uint8 *_si = &_scriptPaused[1][j];
		while (n--) {
			*_si = _al;
			++_si;
		}
	}
}

void Logic::op_selectPage() {
	uint8 i = _scriptPtr.fetchByte();
	debug(DBG_LOGIC, "Logic::op_selectPage(%d)", i);
	_vid->changePagePtr1(i);
}

void Logic::op_fillPage() {
	uint8 screen = _scriptPtr.fetchByte();
	uint8 color = _scriptPtr.fetchByte();
	debug(DBG_LOGIC, "Logic::op_fillPage(%d, %d)", screen, color);
	_vid->fillPage(screen, color);
}

void Logic::op_copyPage() {
	uint8 i = _scriptPtr.fetchByte();
	uint8 j = _scriptPtr.fetchByte();
	debug(DBG_LOGIC, "Logic::op_copyPage(%d, %d)", i, j);
	_vid->copyPage(i, j, _scriptVars[VAR_SCROLL_Y]);
}

void Logic::op_updateDisplay() {
	uint8 page = _scriptPtr.fetchByte();
	debug(DBG_LOGIC, "Logic::op_updateDisplay(%d)", page);
	inp_handleSpecialKeys();
	if (_res->_curPtrsId == 0x3E80 && _scriptVars[0x67] == 1) {
		_scriptVar_0xBF = _scriptVars[0xBF];
		_scriptVars[0xDC] = 0x21;
	}

	static uint32 tstamp = 0;
	if (!_fastMode) {
		// XXX experimental
		int32 delay = _stub->getTimeStamp() - tstamp;
		int32 pause = _scriptVars[VAR_PAUSE_SLICES] * 20 - delay;
		if (pause > 0) {
			_stub->sleep(pause);
		}
	}
	_scriptVars[0xF7] = 0;

	_vid->updateDisplay(page);
	tstamp = _stub->getTimeStamp();
}

void Logic::op_halt() {
	debug(DBG_LOGIC, "Logic::op_halt()");
	_scriptPtr.pc = _res->_segCode + 0xFFFF;
	_scriptHalted = true;
}

void Logic::op_drawString() {
	uint16 strId = _scriptPtr.fetchWord();
	uint16 x = _scriptPtr.fetchByte();
	uint16 y = _scriptPtr.fetchByte();
	uint16 col = _scriptPtr.fetchByte();
	debug(DBG_LOGIC, "Logic::op_drawString(0x%03X, %d, %d, %d)", strId, x, y, col);
	_vid->drawString(col, x, y, strId);
}

void Logic::op_sub() {
	uint8 i = _scriptPtr.fetchByte();
	uint8 j = _scriptPtr.fetchByte();
	debug(DBG_LOGIC, "Logic::op_sub(0x%02X, 0x%02X)", i, j);
	_scriptVars[i] -= _scriptVars[j];
}

void Logic::op_and() {
	uint8 i = _scriptPtr.fetchByte();
	uint16 n = _scriptPtr.fetchWord();
	debug(DBG_LOGIC, "Logic::op_and(0x%02X, %d)", i, n);
	_scriptVars[i] = (uint16)_scriptVars[i] & n;
}

void Logic::op_or() {
	uint8 i = _scriptPtr.fetchByte();
	uint16 n = _scriptPtr.fetchWord();
	debug(DBG_LOGIC, "Logic::op_or(0x%02X, %d)", i, n);
	_scriptVars[i] = (uint16)_scriptVars[i] | n;
}

void Logic::op_shl() {
	uint8 i = _scriptPtr.fetchByte();
	uint16 n = _scriptPtr.fetchWord();
	debug(DBG_LOGIC, "Logic::op_shl(0x%02X, %d)", i, n);
	_scriptVars[i] = (uint16)_scriptVars[i] << n;
}

void Logic::op_shr() {
	uint8 i = _scriptPtr.fetchByte();
	uint16 n = _scriptPtr.fetchWord();
	debug(DBG_LOGIC, "Logic::op_shr(0x%02X, %d)", i, n);
	_scriptVars[i] = (uint16)_scriptVars[i] >> n;
}

void Logic::op_soundUnk1() {
	uint16 b = _scriptPtr.fetchWord();
	uint16 c = _scriptPtr.fetchWord();
	uint8 a = _scriptPtr.fetchByte();
	debug(DBG_LOGIC, "Logic::op_soundUnk1(0x%X, 0x%X, %d)", b, c, a);
	// XXX
}

void Logic::op_updateMemList() {
	uint16 num = _scriptPtr.fetchWord();
	debug(DBG_LOGIC, "Logic::op_updateMemList(%d)", num);
	_res->update(num);
}

void Logic::op_soundUnk2() {
	uint16 b = _scriptPtr.fetchWord();
	uint16 c = _scriptPtr.fetchWord();
	uint8 a = _scriptPtr.fetchByte();
	debug(DBG_LOGIC, "Logic::op_soundUnk2(0x%X, 0x%X, %d)", b, c, a);
	// XXX
}

void Logic::restartAt(uint16 ptrId) {
	// XXX
	_scriptVars[0xE4] = 0x14;
	_res->setupPtrs(ptrId);
	memset((uint8 *)_scriptPos, 0xFF, sizeof(_scriptPos));
	memset((uint8 *)_scriptPaused, 0, sizeof(_scriptPaused));
	_scriptPos[0][0] = 0;	
}

void Logic::setupScripts() {
	if (_res->_newPtrsId != 0) {
		restartAt(_res->_newPtrsId);
		_res->_newPtrsId = 0;
	}
	for (int i = 0; i < 0x40; ++i) {
		_scriptPaused[0][i] = _scriptPaused[1][i];
		uint16 n = _scriptPos[1][i];
		if (n != 0xFFFF) {
			_scriptPos[0][i] = (n == 0xFFFE) ? 0xFFFF : n;
			_scriptPos[1][i] = 0xFFFF;
		}
	}
}

void Logic::runScripts() {
	for (int i = 0; i < 0x40; ++i) {
		if (_scriptPaused[0][i] == 0) {
			uint16 n = _scriptPos[0][i];
			if (n != 0xFFFF) {
				_scriptPtr.pc = _res->_segCode + n;
				_stackPtr = 0;
				_scriptHalted = false;
				debug(DBG_LOGIC, "Logic::runScripts() i=0x%02X n=0x%02X *p=0x%02X", i, n, *_scriptPtr.pc);
				executeScript();
				_scriptPos[0][i] = _scriptPtr.pc - _res->_segCode;
				debug(DBG_LOGIC, "Logic::runScripts() i=0x%02X pos=0x%X", i, _scriptPos[0][i]);
				if (_stub->_pi.quit) {
					break;
				}
			}
		}
	}
}

void Logic::executeScript() {
	while (!_scriptHalted) {
		uint8 opcode = _scriptPtr.fetchByte();
		if (opcode & 0x80) {
			uint16 off = ((opcode << 8) | _scriptPtr.fetchByte()) * 2;
			_res->_useSegVideo2 = false;
			int16 x = _scriptPtr.fetchByte();
			int16 y = _scriptPtr.fetchByte();
			int16 h = y - 199;
			if (h > 0) {
				y = 199;
				x += h;
			}
			debug(DBG_VIDEO, "vid_opcd_0x80 : opcode=0x%X off=0x%X x=%d y=%d", opcode, off, x, y);
			_vid->setDataBuffer(_res->_segVideo1, off);
			_vid->drawShape(0xFF, 0x40, Point(x,y));
		} else if (opcode & 0x40) {
			int16 x, y;
			uint16 off = _scriptPtr.fetchWord() * 2;
			x = _scriptPtr.fetchByte();
			_res->_useSegVideo2 = false;
			if (!(opcode & 0x20)) {
				if (!(opcode & 0x10)) {
					x = (x << 8) | _scriptPtr.fetchByte();
				} else {
					x = _scriptVars[x];
				}
			} else {
				if (opcode & 0x10) {
					x += 0x100;
				}
			}
			y = _scriptPtr.fetchByte();
			if (!(opcode & 8)) {
				if (!(opcode & 4)) {
					y = (y << 8) | _scriptPtr.fetchByte();
				} else {
					y = _scriptVars[y];
				}
			}
			uint16 zoom = _scriptPtr.fetchByte();
			if (!(opcode & 2)) {
				if (!(opcode & 1)) {
					--_scriptPtr.pc;
					zoom = 0x40;
				} else {
					zoom = _scriptVars[zoom];
				}
			} else {
				if (opcode & 1) {
					_res->_useSegVideo2 = true;
					--_scriptPtr.pc;
					zoom = 0x40;
				}
			}
			debug(DBG_VIDEO, "vid_opcd_0x40 : off=0x%X x=%d y=%d", off, x, y);
			_vid->setDataBuffer(_res->_useSegVideo2 ? _res->_segVideo2 : _res->_segVideo1, off);
			_vid->drawShape(0xFF, zoom, Point(x, y));
		} else {
			if (opcode > 0x1A) {
				::error("Logic::executeScript() ec=0x%X invalid opcode=0x%X", 0xFFF, opcode);
			} else {
				(this->*_opTable[opcode])();
			}
		}
	}
}

void Logic::inp_updatePlayer() {
	_stub->processEvents();
	if (_res->_curPtrsId == 0x3E89) {
		char c = _stub->_pi.lastChar;
		if (c == 8 || /*c == 0xD ||*/ c == 0 || (c >= 'a' && c <= 'z')) {
			_scriptVars[VAR_LAST_KEYCHAR] = c & ~0x20;
			_stub->_pi.lastChar = 0;
		}
	}
	int16 lr = 0;
	int16 m = 0;
	int16 ud = 0;
	if (_stub->_pi.dirMask & PlayerInput::DIR_RIGHT) {
		lr = 1;
		m |= 1;
	}
	if (_stub->_pi.dirMask & PlayerInput::DIR_LEFT) {
		lr = -1;
		m |= 2;
	}
	if (_stub->_pi.dirMask & PlayerInput::DIR_DOWN) {
		ud = 1;
		m |= 4;
	}
	_scriptVars[VAR_HERO_POS_UP_DOWN] = ud;
	if (_stub->_pi.dirMask & PlayerInput::DIR_UP) {
		_scriptVars[VAR_HERO_POS_UP_DOWN] = -1;
	}
	if (_stub->_pi.dirMask & PlayerInput::DIR_UP) { // inpJump
		ud = -1;
		m |= 8;
	}
	_scriptVars[VAR_HERO_POS_JUMP_DOWN] = ud;
	_scriptVars[VAR_HERO_POS_LEFT_RIGHT] = lr;
	_scriptVars[VAR_HERO_POS_MASK] = m;
	int16 button = 0;
	if (_stub->_pi.button) { // inpButton
		button = 1;
		m |= 0x80;
	}
	_scriptVars[VAR_HERO_ACTION] = button;
	_scriptVars[VAR_HERO_ACTION_POS_MASK] = m;
}

void Logic::inp_handleSpecialKeys() {
	if (_stub->_pi.pause) {
		if (_res->_curPtrsId != 0x3E80 && _res->_curPtrsId != 0x3E81) {
			_stub->_pi.pause = false;
			while (!_stub->_pi.pause) {
				_stub->processEvents();
				_stub->sleep(200);
			}
		}
		_stub->_pi.pause = false;
	}
	if (_stub->_pi.code) {
		_stub->_pi.code = false;
		if (_res->_curPtrsId != 0x3E89 && _res->_curPtrsId != 0x3E80) {
			_res->_newPtrsId = 0x3E89;
		}
	}
	// XXX
	if (_scriptVars[0xC9] == 1) {
		::warning("Logic::inp_handleSpecialKeys() unhandled case (_scriptVars[0xC9] == 1)");
	}
}

void Logic::saveOrLoad(Serializer &ser) {
	Serializer::Entry entries[] = {
		SE_ARRAY(_scriptVars, 0x100, Serializer::SES_INT16, VER(1)),
		SE_ARRAY(_scriptStackCalls, 0x100, Serializer::SES_INT16, VER(1)),
		SE_ARRAY(_scriptPos, 0x40 * 2, Serializer::SES_INT16, VER(1)),
		SE_ARRAY(_scriptPaused, 0x40 * 2, Serializer::SES_INT8, VER(1)),
		SE_END()
	};
	ser.saveOrLoadEntries(entries);
}

}

--- NEW FILE: logic.h ---
/* AWE - Another World Engine
 * Copyright (C) 2004 Gregory Montoir
 * Copyright (C) 2004 The ScummVM project
 *
 * 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */

#ifndef __LOGIC_H__
#define __LOGIC_H__

#include "stdafx.h"

#include "intern.h"

namespace Awe {

struct Resource;
struct Serializer;
struct SystemStub;
struct Video;

struct Logic {
	typedef void (Logic::*OpcodeStub)();

	enum ScriptVars {
		VAR_RANDOM_SEED          = 0x3C,
		
		VAR_LAST_KEYCHAR         = 0xDA,

		VAR_HERO_POS_UP_DOWN     = 0xE5,

		VAR_SCROLL_Y             = 0xF9,
		VAR_HERO_ACTION          = 0xFA,
		VAR_HERO_POS_JUMP_DOWN   = 0xFB,
		VAR_HERO_POS_LEFT_RIGHT  = 0xFC,
		VAR_HERO_POS_MASK        = 0xFD,
		VAR_HERO_ACTION_POS_MASK = 0xFE,
		VAR_PAUSE_SLICES         = 0xFF
	};
	
	static const OpcodeStub _opTable[];

	Resource *_res;
	Video *_vid;
	SystemStub *_stub;

	int16 _scriptVar_0xBF;
	int16 _scriptVars[0x100];
	uint16 _scriptStackCalls[0x40];
	uint16 _scriptPos[2][0x40];
	uint8 _scriptPaused[2][0x40];
	Ptr _scriptPtr;
	uint8 _stackPtr;
	bool _scriptHalted;
	bool _fastMode;

	Logic(Resource *res, Video *vid, SystemStub *stub);
	void init();
	
	void op_movConst();
	void op_mov();
	void op_add();
	void op_addConst();
	void op_call();
	void op_ret();
	void op_break();
	void op_jmp();
	void op_setScriptPos();
	void op_jnz();
	void op_condJmp();
	void op_setPalette();
	void op_resetScript();
	void op_selectPage();
	void op_fillPage();
	void op_copyPage();
	void op_updateDisplay();
	void op_halt();	
	void op_drawString();
	void op_sub();
	void op_and();
	void op_or();
	void op_shl();
	void op_shr();
	void op_soundUnk1();
	void op_updateMemList();
	void op_soundUnk2();

	void restartAt(uint16 ptrId);
	void setupPtrs(uint16 ptrId);
	void setupScripts();
	void runScripts();
	void executeScript();

	void inp_updatePlayer();
	void inp_handleSpecialKeys();
	
	void saveOrLoad(Serializer &ser);
};

}

#endif

--- NEW FILE: module.mk ---
MODULE := awe

MODULE_OBJS = \
	awe/awe.o \
	awe/bank.o \
	awe/engine.o \
	awe/file.o \
	awe/logic.o \
	awe/resource.o \
	awe/sdlstub.o \
	awe/serializer.o \
	awe/staticres.o \
	awe/util.o \
	awe/video.o

MODULE_DIRS += \
	awe

# This module can be built as a plugin
ifdef BUILD_PLUGINS
PLUGIN := 1
endif

# Include common rules 
include $(srcdir)/common.rules

--- NEW FILE: resource.cpp ---
/* AWE - Another World Engine
 * Copyright (C) 2004 Gregory Montoir
 * Copyright (C) 2004 The ScummVM project
 *
 * 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */

#include "stdafx.h"

#include "awe.h"
#include "resource.h"
#include "bank.h"
#include "file.h"
#include "serializer.h"
#include "video.h"

namespace Awe {

Resource::Resource(Video *vid, const char *dataDir) 
	: _vid(vid), _dataDir(dataDir) {
}

void Resource::readBank(const MemEntry *me, uint8 *dstBuf) {
	uint16 n = me - _memList;
	debug(DBG_BANK, "Resource::readBank(%d)", n);
#ifdef USE_UNPACKED
	char bankEntryName[64];
	sprintf(bankEntryName, "ootw-%02X-%d.dump", n, me->type);
	File f;
	if (!f.open(bankEntryName, _dataDir)) {
		::error("Resource::readBank() unable to open '%s' file\n", bankEntryName);
	}
	f.read(dstBuf, me->unpackedSize);
#else
	Bank bk(_dataDir);
	if (!bk.read(me, dstBuf)) {
		::error("Resource::readBank() unable to unpack entry %d\n", n);
	}
#endif
}

void Resource::readEntries() {	
	File f;
	if (!f.open("memlist.bin", _dataDir)) {
		::error("Resource::readEntries() unable to open 'memlist.bin' file\n");
	}
	_numMemList = 0;
	MemEntry *me = _memList;
	while (1) {
		assert(_numMemList < ARRAYSIZE(_memList));
		me->valid = f.readByte();
		me->type = f.readByte();
		me->bufPtr = 0; f.readUint16BE();
		me->unk4 = f.readUint16BE();
		me->rankNum = f.readByte();
		me->bankNum = f.readByte();
		me->bankPos = f.readUint32BE();
		me->unkC = f.readUint16BE();
		me->packedSize = f.readUint16BE();
		me->unk10 = f.readUint16BE();
		me->unpackedSize = f.readUint16BE();
		if (me->valid == 0xFF) {
			break;
		}
		++_numMemList;
		++me;
	}
}

void Resource::load() {
	while (1) {
		MemEntry *it = _memList;
		MemEntry *me = 0;

		// get resource with max rankNum
		uint8 maxNum = 0;
		uint16 i = _numMemList;
		while (i--) {
			if (it->valid == 2 && maxNum <= it->rankNum) {
				maxNum = it->rankNum;
				me = it;
			}
			++it;
		}
		if (me == 0) {
			break; // no entry found
		}

		uint8 *memPtr = 0;
		// XXX if (_audio_no_sound != 0 && _audio_use_roland != 0 && me->type < 2) {
		// XXX		me->valid = 0;
		// XXX		continue;
		// XXX }
		if (me->type == 2) {
			memPtr = _vidCurPtr;
		} else {
			memPtr = _scriptCurPtr;
			if (me->unpackedSize > _vidBakPtr - _scriptCurPtr) {
				::warning("Resource::load() not enough memory");
				me->valid = 0;
				continue;
			}
		}
		if (me->bankNum == 0) {
			::warning("Resource::load() ec=0x%X (me->bankNum == 0)", 0xF00);
			me->valid = 0;
		} else {
			debug(DBG_BANK, "Resource::load() bufPos=%X size=%X type=%X pos=%X bankNum=%X", memPtr - _memPtrStart, me->packedSize, me->type, me->bankPos, me->bankNum);
			readBank(me, memPtr);
			if(me->type == 2) {
				_vid->copyPagePtr(_vidCurPtr);
				me->valid = 0;
			} else {
				me->bufPtr = memPtr;
				me->valid = 1;
				_scriptCurPtr += me->unpackedSize;
			}
		}
	}
}

void Resource::invalidateRes() {
	// XXX call ds:sound_stub_1_ptr
	MemEntry *me = _memList;
	uint16 i = _numMemList;
	while (i--) {
		if (me->type <= 2 || me->type > 6) {
			me->valid = 0;
		}
		++me;
	}
	_scriptCurPtr = _scriptBakPtr;
}

void Resource::invalidateAll() {
	MemEntry *me = _memList;
	uint16 i = _numMemList;
	while (i--) {
		me->valid = 0;
		++me;
	}
	_scriptCurPtr = _memPtrStart;
}

void Resource::update(uint16 num) {
	if (num == 0) {
		invalidateRes();
	} else {
		if (num > _numMemList) {
			_newPtrsId = num;
		} else {
			if (false) { // XXX (_audio_use_pro_or_adlib == 1 || _audio_use_spk == 1) {
				for (const uint16 *ml = _memListAudio; *ml != 0xFFFF; ++ml) {
					if (*ml == num)
						return;
				}
			}
			MemEntry *me = &_memList[num];
			if (me->valid == 0) {
				me->valid = 2;
				load();
			}
		}
	}
}

void Resource::setupPtrs(uint16 ptrId) {
	if (ptrId != _curPtrsId) {
		uint8 ipal = 0;
		uint8 icod = 0;
		uint8 ivd1 = 0;
		uint8 ivd2 = 0;
		if (ptrId >= 0x3E80 && ptrId <= 0x3E89) {
			uint16 part = ptrId - 0x3E80;
			ipal = _memListParts[part][0];
			icod = _memListParts[part][1];
			ivd1 = _memListParts[part][2];
			ivd2 = _memListParts[part][3];
		} else {
			::error("Resource::setupPtrs() ec=0x%X invalid ptrId", 0xF07);
		}
		invalidateAll();
		_memList[ipal].valid = 2;
		_memList[icod].valid = 2;
		_memList[ivd1].valid = 2;
		if (ivd2 != 0) {
			_memList[ivd2].valid = 2;
		}
		load();
		_segVideoPal = _memList[ipal].bufPtr;
		_segCode = _memList[icod].bufPtr;
		_segVideo1 = _memList[ivd1].bufPtr;
		if (ivd2 != 0) {
			_segVideo2 = _memList[ivd2].bufPtr;
		}
		_curPtrsId = ptrId;
	}
	_scriptBakPtr = _scriptCurPtr;	
}

void Resource::allocMemBlock() {
	_memPtrStart = (uint8 *)malloc(MEM_BLOCK_SIZE);
	_scriptBakPtr = _scriptCurPtr = _memPtrStart;
	_vidBakPtr = _vidCurPtr = _memPtrStart + MEM_BLOCK_SIZE - 0x800 * 16;
	_useSegVideo2 = false;
}

void Resource::freeMemBlock() {
	free(_memPtrStart);
}

void Resource::saveOrLoad(Serializer &ser) {
	uint8 loadedList[64];
	if (ser._mode == Serializer::SM_SAVE) {
		memset(loadedList, 0, sizeof(loadedList));
		uint8 *p = loadedList;
		uint8 *q = _memPtrStart;
		while (1) {
			MemEntry *it = _memList;
			MemEntry *me = 0;
			uint16 num = _numMemList;
			while (num--) {
				if (it->valid == 1 && it->bufPtr == q) {
					me = it;
				}
				++it;
			}
			if (me == 0) {
				break;
			} else {
				assert(p < loadedList + 64);
				*p++ = me - _memList;
				q += me->unpackedSize;
			}
		}
	}
	Serializer::Entry entries[] = {
		SE_ARRAY(loadedList, 64, Serializer::SES_INT8, VER(1)),
		SE_INT(&_curPtrsId, Serializer::SES_INT16, VER(1)),
		SE_PTR(&_scriptBakPtr, VER(1)),
		SE_PTR(&_scriptCurPtr, VER(1)),
		SE_PTR(&_vidBakPtr, VER(1)),
		SE_PTR(&_vidCurPtr, VER(1)),
		SE_INT(&_useSegVideo2, Serializer::SES_INT8, VER(1)),
		SE_PTR(&_segVideoPal, VER(1)),
		SE_PTR(&_segCode, VER(1)),
		SE_PTR(&_segVideo1, VER(1)),
		SE_PTR(&_segVideo2, VER(1)),
		SE_END()		
	};
	ser.saveOrLoadEntries(entries);
	if (ser._mode == Serializer::SM_LOAD) {
		uint8 *p = loadedList;
		uint8 *q = _memPtrStart;
		while (*p) {
			MemEntry *me = &_memList[*p++];
			readBank(me, q);
			me->bufPtr = q;
			me->valid = 1;
			q += me->unpackedSize;
		}
	}	
}

}

--- NEW FILE: resource.h ---
/* AWE - Another World Engine
 * Copyright (C) 2004 Gregory Montoir
 * Copyright (C) 2004 The ScummVM project
 *
 * 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */

#ifndef __RESOURCE_H__
#define __RESOURCE_H__

#include "stdafx.h"

#include "intern.h"

namespace Awe {

struct MemEntry {
	uint8 valid;         // 0x0
	uint8 type;          // 0x1, Resource::ResType
	uint8 *bufPtr;       // 0x2
	uint16 unk4;         // 0x4, unused ?
	uint8 rankNum;       // 0x6
	uint8 bankNum;       // 0x7
	uint32 bankPos;      // 0x8 0xA
	uint16 unkC;         // 0xC, unused ?
	uint16 packedSize;   // 0xE
	uint16 unk10;        // 0x10, unused ?
	uint16 unpackedSize; // 0x12
};

struct Serializer;
struct Video;

struct Resource {
	enum ResType {
		RT_SOUND  = 0,
		RT_MUSIC  = 1,
		RT_VIDBUF = 2, // full screen video buffer, size=0x7D00
		RT_PAL    = 3, // palette (1024=vga + 1024=ega), size=2048
		RT_SCRIPT = 4,
		RT_VBMP   = 5
	};
	
	enum {
		MEM_BLOCK_SIZE = 600 * 1024
	};
	
	static const uint16 _memListAudio[];
	static const uint16 _memListParts[][4];
	
	Video *_vid;
	const char *_dataDir;
	MemEntry _memList[150];
	uint16 _numMemList;
	uint16 _curPtrsId, _newPtrsId;
	uint8 *_memPtrStart, *_scriptBakPtr, *_scriptCurPtr, *_vidBakPtr, *_vidCurPtr;
	bool _useSegVideo2;
	uint8 *_segVideoPal;
	uint8 *_segCode;
	uint8 *_segVideo1;
	uint8 *_segVideo2;

	Resource(Video *vid, const char *dataDir);
	
	void readBank(const MemEntry *me, uint8 *dstBuf);
	void readEntries();
	void load();
	void invalidateAll();
	void invalidateRes();	
	void update(uint16 num);
	void setupPtrs(uint16 ptrId);
	void allocMemBlock();
	void freeMemBlock();
	
	void saveOrLoad(Serializer &ser);
};

}

#endif

--- NEW FILE: sdlstub.cpp ---
/* AWE - Another World Engine
 * Copyright (C) 2004 Gregory Montoir
 * Copyright (C) 2004 The ScummVM project
 *
 * 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */

#include "stdafx.h"
#include "common/util.h"

#include <SDL.h>

#include "awe.h"
#include "systemstub.h"
#include "util.h"

namespace Awe {

struct SDLStub : SystemStub {
	typedef void (SDLStub::*ScaleProc)(uint16 *dst, uint16 dstPitch, const uint16 *src, uint16 srcPitch, uint16 w, uint16 h);

	enum {
		SCREEN_W = 320,
		SCREEN_H = 200
	};

	struct Scaler {
		const char *name;
		ScaleProc proc;
		uint8 factor;
	};
	
	static const Scaler _scalers[];

	uint8 *_offscreen;
	SDL_Surface *_screen;
	SDL_Surface *_sclscreen;
	bool _fullscreen;
	uint8 _scaler;
	uint16 _pal[16];

	virtual ~SDLStub() {}
	virtual void init(const char *title);
	virtual void destroy();
	virtual void setPalette(uint8 s, uint8 n, const uint8 *buf);
	virtual void copyRect(uint16 x, uint16 y, uint16 w, uint16 h, const uint8 *buf, uint32 pitch);
	virtual void processEvents();
	virtual void sleep(uint32 duration);
	virtual uint32 getTimeStamp();

	void prepareGfxMode();
	void cleanupGfxMode();
	void switchGfxMode(bool fullscreen, uint8 scaler);

	void point1x(uint16 *dst, uint16 dstPitch, const uint16 *src, uint16 srcPitch, uint16 w, uint16 h);
	void point2x(uint16 *dst, uint16 dstPitch, const uint16 *src, uint16 srcPitch, uint16 w, uint16 h);
	void point3x(uint16 *dst, uint16 dstPitch, const uint16 *src, uint16 srcPitch, uint16 w, uint16 h);
};

const SDLStub::Scaler SDLStub::_scalers[] = {
	{ "Point1x", &SDLStub::point1x, 1 },
	{ "Point2x", &SDLStub::point2x, 2 },
	{ "Point3x", &SDLStub::point3x, 3 }
};

SystemStub *SystemStub_SDL_create() {
	return new SDLStub();
}

void SDLStub::init(const char *title) {
	SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER);
	SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
	SDL_ShowCursor(SDL_DISABLE);
	SDL_WM_SetCaption(title, NULL);
	memset(&_pi, 0, sizeof(_pi));
	_offscreen = (uint8 *)malloc(SCREEN_W * SCREEN_H * 2);
	if (!_offscreen) {
		::error("Unable to allocate offscreen buffer");
	}
	_fullscreen = false;
	_scaler = 1;
	prepareGfxMode();
}

void SDLStub::destroy() {
	cleanupGfxMode();
}

void SDLStub::setPalette(uint8 s, uint8 n, const uint8 *buf) {
	assert(s + n <= 16);
	for (int i = s; i < s + n; ++i) {
		uint8 c[3];
		for (int j = 0; j < 3; ++j) {
			uint8 col = buf[i * 3 + j];
			c[j] =  (col << 2) | (col & 3);
		}
		_pal[i] = SDL_MapRGB(_screen->format, c[0], c[1], c[2]);
	}	
}

void SDLStub::copyRect(uint16 x, uint16 y, uint16 w, uint16 h, const uint8 *buf, uint32 pitch) {
	buf += y * pitch + x;
	uint16 *p = (uint16 *)_offscreen;
	while (h--) {
		for (int i = 0; i < w / 2; ++i) {
			uint8 p1 = *(buf + i) >> 4;
			uint8 p2 = *(buf + i) & 0xF;
			*(p + i * 2 + 0) = _pal[p1];
			*(p + i * 2 + 1) = _pal[p2];
		}
		p += SCREEN_W;
		buf += pitch;
	}
	SDL_LockSurface(_sclscreen);
	(this->*_scalers[_scaler].proc)((uint16 *)_sclscreen->pixels, _sclscreen->pitch, (uint16 *)_offscreen, SCREEN_W, SCREEN_W, SCREEN_H);
	SDL_UnlockSurface(_sclscreen);
	SDL_BlitSurface(_sclscreen, NULL, _screen, NULL);
	SDL_UpdateRect(_screen, 0, 0, 0, 0);
}

void SDLStub::processEvents() {
	SDL_Event ev;
	while(SDL_PollEvent(&ev)) {
		switch (ev.type) {
		case SDL_QUIT:
			exit(0);
			break;
		case SDL_KEYUP:
			switch(ev.key.keysym.sym) {
			case SDLK_LEFT:
				_pi.dirMask &= ~PlayerInput::DIR_LEFT;
				break;
			case SDLK_RIGHT:
				_pi.dirMask &= ~PlayerInput::DIR_RIGHT;
				break;
			case SDLK_UP:
				_pi.dirMask &= ~PlayerInput::DIR_UP;
				break;
			case SDLK_DOWN:
				_pi.dirMask &= ~PlayerInput::DIR_DOWN;
				break;
			case SDLK_SPACE:
			case SDLK_RETURN:
				_pi.button = false;
				break;
			default:
				break;
			}
			break;
		case SDL_KEYDOWN:
			if (ev.key.keysym.mod & KMOD_ALT) {
				if (ev.key.keysym.sym == SDLK_RETURN) {
					switchGfxMode(!_fullscreen, _scaler);
				} else if (ev.key.keysym.sym == SDLK_KP_PLUS) {
					uint8 s = _scaler + 1;
					if (s < ARRAYSIZE(_scalers)) {
						switchGfxMode(_fullscreen, s);
					}
				} else if (ev.key.keysym.sym == SDLK_KP_MINUS) {
					int8 s = _scaler - 1;
					if (_scaler > 0) {
						switchGfxMode(_fullscreen, s);
					}
				} else if (ev.key.keysym.sym == SDLK_x) {
					_pi.quit = true;
				}
				break;
			} else if (ev.key.keysym.mod & KMOD_CTRL) {
				if (ev.key.keysym.sym == SDLK_s) {
					_pi.save = true;
				} else if (ev.key.keysym.sym == SDLK_l) {
					_pi.load = true;
				} else if (ev.key.keysym.sym == SDLK_f) {
					_pi.fastMode = true;
				} else if (ev.key.keysym.sym == SDLK_KP_PLUS) {
					_pi.stateSlot = 1;
				} else if (ev.key.keysym.sym == SDLK_KP_MINUS) {
					_pi.stateSlot = -1;
				}
				break;
			}
			_pi.lastChar = ev.key.keysym.sym;
			switch(ev.key.keysym.sym) {
			case SDLK_LEFT:
				_pi.dirMask |= PlayerInput::DIR_LEFT;
				break;
			case SDLK_RIGHT:
				_pi.dirMask |= PlayerInput::DIR_RIGHT;
				break;
			case SDLK_UP:
				_pi.dirMask |= PlayerInput::DIR_UP;
				break;
			case SDLK_DOWN:
				_pi.dirMask |= PlayerInput::DIR_DOWN;
				break;
			case SDLK_SPACE:
			case SDLK_RETURN:
				_pi.button = true;
				break;
			case SDLK_c:
				_pi.code = true;
				break;
			case SDLK_p:
				_pi.pause = true;
				break;
			default:
				break;
			}
			break;
		default:
			break;
		}
	}
}

void SDLStub::sleep(uint32 duration) {
	SDL_Delay(duration);
}

uint32 SDLStub::getTimeStamp() {
	return SDL_GetTicks();	
}

void SDLStub::prepareGfxMode() {
	int w = SCREEN_W * _scalers[_scaler].factor;
	int h = SCREEN_H * _scalers[_scaler].factor;
	_screen = SDL_SetVideoMode(w, h, 16, _fullscreen ? (SDL_FULLSCREEN | SDL_HWSURFACE) : SDL_HWSURFACE);
	if (!_screen) {
		::error("SDLStub::prepareGfxMode() unable to allocate _screen buffer");
	}
	_sclscreen = SDL_CreateRGBSurface(SDL_SWSURFACE, w, h, 16,
						_screen->format->Rmask,
						_screen->format->Gmask,
						_screen->format->Bmask,
						_screen->format->Amask);
	if (!_sclscreen) {
		::error("SDLStub::prepareGfxMode() unable to allocate _sclscreen buffer");
	}
}

void SDLStub::cleanupGfxMode() {
	if (_offscreen) {
		free(_offscreen);
		_offscreen = 0;
	}
	if (_sclscreen) {
		SDL_FreeSurface(_sclscreen);
		_sclscreen = 0;
	}
	if (_screen) {
		SDL_FreeSurface(_screen);
		_screen = 0;
	}
}

void SDLStub::switchGfxMode(bool fullscreen, uint8 scaler) {
	SDL_Surface *prev_sclscreen = _sclscreen;
	SDL_FreeSurface(_screen); 	
	_fullscreen = fullscreen;
	_scaler = scaler;
	prepareGfxMode();
	SDL_BlitSurface(prev_sclscreen, NULL, _sclscreen, NULL);
	SDL_FreeSurface(prev_sclscreen);
}

void SDLStub::point1x(uint16 *dst, uint16 dstPitch, const uint16 *src, uint16 srcPitch, uint16 w, uint16 h) {
	dstPitch >>= 1;
	while (h--) {
		memcpy(dst, src, w * 2);
		dst += dstPitch;
		src += dstPitch;
	}
}

void SDLStub::point2x(uint16 *dst, uint16 dstPitch, const uint16 *src, uint16 srcPitch, uint16 w, uint16 h) {
	dstPitch >>= 1;
	while (h--) {
		uint16 *p = dst;
		for (int i = 0; i < w; ++i, p += 2) {
			uint16 c = *(src + i);
			*(p + 0) = c;
			*(p + 1) = c;
			*(p + 0 + dstPitch) = c;
			*(p + 1 + dstPitch) = c;
		}
		dst += dstPitch * 2;
		src += srcPitch;
	}
}

void SDLStub::point3x(uint16 *dst, uint16 dstPitch, const uint16 *src, uint16 srcPitch, uint16 w, uint16 h) {
	dstPitch >>= 1;
	while (h--) {
		uint16 *p = dst;
		for (int i = 0; i < w; ++i, p += 3) {
			uint16 c = *(src + i);
			*(p + 0) = c;
			*(p + 1) = c;
			*(p + 2) = c;
			*(p + 0 + dstPitch) = c;
			*(p + 1 + dstPitch) = c;
			*(p + 2 + dstPitch) = c;
			*(p + 0 + dstPitch * 2) = c;
			*(p + 1 + dstPitch * 2) = c;
			*(p + 2 + dstPitch * 2) = c;
		}
		dst += dstPitch * 3;
		src += srcPitch;
	}
}

}

--- NEW FILE: serializer.cpp ---
/* AWE - Another World Engine
 * Copyright (C) 2004 Gregory Montoir
 * Copyright (C) 2004 The ScummVM project
 *
 * 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */

#include "stdafx.h"

#include "serializer.h"
#include "file.h"
#include "util.h"

namespace Awe {

Serializer::Serializer(File *stream, Mode mode, uint8 *ptrBlock, uint16 saveVer)
	: _stream(stream), _mode(mode), _ptrBlock(ptrBlock), _saveVer(saveVer) {
}

void Serializer::saveOrLoadEntries(Entry *entry) {
	switch (_mode) {
	case SM_SAVE:
		saveEntries(entry);
		break;
	case SM_LOAD:
		loadEntries(entry);
		break;	
	}
}

void Serializer::saveEntries(Entry *entry) {
	for (; entry->type != SET_END; ++entry) {
		if (entry->maxVer == CUR_VER) {
			switch (entry->type) {
			case SET_INT:
				saveInt(entry->size, entry->data);
				break;
			case SET_ARRAY:
				if (entry->size == Serializer::SES_INT8) {
					_stream->write(entry->data, entry->n);
				} else {
					uint8 *p = (uint8 *)entry->data;
					for (int i = 0; i < entry->n; ++i) {
						saveInt(entry->size, p);
						p += entry->size;
					}
				}
				break;
			case SET_PTR:
				_stream->writeUint32BE(*(uint8 **)(entry->data) - _ptrBlock);
				break;
			case SET_END:
				break;
			}
		}
	}
}

void Serializer::loadEntries(Entry *entry) {
	for (; entry->type != SET_END; ++entry) {
		if (_saveVer >= entry->minVer && _saveVer <= entry->maxVer) {
			switch (entry->type) {
			case SET_INT:
				loadInt(entry->size, entry->data);
				break;
			case SET_ARRAY:
				if (entry->size == Serializer::SES_INT8) {
					_stream->read(entry->data, entry->n);
				} else {
					uint8 *p = (uint8 *)entry->data;
					for (int i = 0; i < entry->n; ++i) {
						loadInt(entry->size, p);
						p += entry->size;
					}
				}
				break;
			case SET_PTR:
				*(uint8 **)(entry->data) = _ptrBlock + _stream->readUint32BE();
				break;
			case SET_END:
				break;				
			}
		}
	}
}

void Serializer::saveInt(uint8 es, void *p) {
	switch (es) {
	case SES_INT8:
		_stream->writeByte(*(uint8 *)p);
		break;
	case SES_INT16:
		_stream->writeUint16BE(*(uint16 *)p);
		break;
	case SES_INT32:
		_stream->writeUint32BE(*(uint32 *)p);
		break;
	}
}

void Serializer::loadInt(uint8 es, void *p) {
	switch (es) {
	case SES_INT8:
		*(uint8 *)p = _stream->readByte();
		break;
	case SES_INT16:
		*(uint16 *)p = _stream->readUint16BE();
		break;
	case SES_INT32:
		*(uint32 *)p = _stream->readUint32BE();
		break;
	}
}

}

--- NEW FILE: serializer.h ---
/* AWE - Another World Engine
 * Copyright (C) 2004 Gregory Montoir
 * Copyright (C) 2004 The ScummVM project
 *
 * 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */

#ifndef __SERIALIZER_H__
#define __SERIALIZER_H__

#include "stdafx.h"

#include "intern.h"

namespace Awe {

#define VER(x) x

#define SE_INT(i,sz,ver)     { Serializer::SET_INT, sz, 1, i, ver, Serializer::CUR_VER }
#define SE_ARRAY(a,n,sz,ver) { Serializer::SET_ARRAY, sz, n, a, ver, Serializer::CUR_VER }
#define SE_PTR(p,ver)        { Serializer::SET_PTR, 0, 0, p, ver, Serializer::CUR_VER }
#define SE_END()             { Serializer::SET_END, 0, 0, 0, 0, 0 }

struct File;

struct Serializer {
	enum {
		CUR_VER = 1
	};

	enum EntryType {
		SET_INT,
		SET_ARRAY,
		SET_PTR,
		SET_END
	};

	enum {
		SES_INT8  = 1,
		SES_INT16 = 2,
		SES_INT32 = 4
	};

	enum Mode {
		SM_SAVE,
		SM_LOAD
	};

	struct Entry {
		EntryType type;
		uint8 size;
		uint16 n;
		void *data;
		uint16 minVer;
		uint16 maxVer;
	};

	File *_stream;
	Mode _mode;
	uint8 *_ptrBlock;
	uint16 _saveVer;
	
	Serializer(File *stream, Mode mode, uint8 *ptrBlock, uint16 saveVer = CUR_VER);

	void saveOrLoadEntries(Entry *entry);

	void saveEntries(Entry *entry);
	void loadEntries(Entry *entry);

	void saveInt(uint8 es, void *p);
	void loadInt(uint8 es, void *p);
};

}

#endif

--- NEW FILE: staticres.cpp ---
/* AWE - Another World Engine
 * Copyright (C) 2004 Gregory Montoir
 * Copyright (C) 2004 The ScummVM project
 *
 * 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */

#include "stdafx.h"

#include "logic.h"
#include "resource.h"
#include "video.h"

namespace Awe {

const Logic::OpcodeStub Logic::_opTable[] = {
	/* 0x00 */
	&Logic::op_movConst,
	&Logic::op_mov,
	&Logic::op_add,
	&Logic::op_addConst,
	/* 0x04 */
	&Logic::op_call,
	&Logic::op_ret,
	&Logic::op_break,
	&Logic::op_jmp,
	/* 0x08 */
	&Logic::op_setScriptPos,
	&Logic::op_jnz,
	&Logic::op_condJmp,
	&Logic::op_setPalette,
	/* 0x0C */
	&Logic::op_resetScript,
	&Logic::op_selectPage,
	&Logic::op_fillPage,
	&Logic::op_copyPage,
	/* 0x10 */
	&Logic::op_updateDisplay,
	&Logic::op_halt,
	&Logic::op_drawString,
	&Logic::op_sub,
	/* 0x14 */
	&Logic::op_and,
	&Logic::op_or,
	&Logic::op_shl,
	&Logic::op_shr,
	/* 0x18 */
	&Logic::op_soundUnk1,
	&Logic::op_updateMemList,
	&Logic::op_soundUnk2
};

const uint16 Resource::_memListAudio[] = { 
	8, 0x10, 0x61, 0x66, 0xFFFF
};

const uint16 Resource::_memListParts[][4] = {
	{ 0x14, 0x15, 0x16, 0x00 }, // protection screens
	{ 0x17, 0x18, 0x19, 0x00 }, // introduction
	{ 0x1A, 0x1B, 0x1C, 0x11 },
	{ 0x1D, 0x1E, 0x1F, 0x11 },
	{ 0x20, 0x21, 0x22, 0x11 },
	{ 0x23, 0x24, 0x25, 0x00 },
	{ 0x26, 0x27, 0x28, 0x11 },
	{ 0x29, 0x2A, 0x2B, 0x11 },
	{ 0x7D, 0x7E, 0x7F, 0x00 },
	{ 0x7D, 0x7E, 0x7F, 0x00 }  // password screen
};

const uint8 Video::_font[] = {
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x10, 0x00,
	0x28, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x7E, 0x24, 0x24, 0x7E, 0x24, 0x00,
	0x08, 0x3E, 0x48, 0x3C, 0x12, 0x7C, 0x10, 0x00, 0x42, 0xA4, 0x48, 0x10, 0x24, 0x4A, 0x84, 0x00,
	0x60, 0x90, 0x90, 0x70, 0x8A, 0x84, 0x7A, 0x00, 0x08, 0x08, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x06, 0x08, 0x10, 0x10, 0x10, 0x08, 0x06, 0x00, 0xC0, 0x20, 0x10, 0x10, 0x10, 0x20, 0xC0, 0x00,
	0x00, 0x44, 0x28, 0x10, 0x28, 0x44, 0x00, 0x00, 0x00, 0x10, 0x10, 0x7C, 0x10, 0x10, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x20, 0x00, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x10, 0x28, 0x10, 0x00, 0x00, 0x04, 0x08, 0x10, 0x20, 0x40, 0x00, 0x00,
	0x78, 0x84, 0x8C, 0x94, 0xA4, 0xC4, 0x78, 0x00, 0x10, 0x30, 0x50, 0x10, 0x10, 0x10, 0x7C, 0x00,
	0x78, 0x84, 0x04, 0x08, 0x30, 0x40, 0xFC, 0x00, 0x78, 0x84, 0x04, 0x38, 0x04, 0x84, 0x78, 0x00,
	0x08, 0x18, 0x28, 0x48, 0xFC, 0x08, 0x08, 0x00, 0xFC, 0x80, 0xF8, 0x04, 0x04, 0x84, 0x78, 0x00,
	0x38, 0x40, 0x80, 0xF8, 0x84, 0x84, 0x78, 0x00, 0xFC, 0x04, 0x04, 0x08, 0x10, 0x20, 0x40, 0x00,
	0x78, 0x84, 0x84, 0x78, 0x84, 0x84, 0x78, 0x00, 0x78, 0x84, 0x84, 0x7C, 0x04, 0x08, 0x70, 0x00,
	0x00, 0x18, 0x18, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x10, 0x10, 0x60,
	0x04, 0x08, 0x10, 0x20, 0x10, 0x08, 0x04, 0x00, 0x00, 0x00, 0xFE, 0x00, 0x00, 0xFE, 0x00, 0x00,
	0x20, 0x10, 0x08, 0x04, 0x08, 0x10, 0x20, 0x00, 0x7C, 0x82, 0x02, 0x0C, 0x10, 0x00, 0x10, 0x00,
	0x30, 0x18, 0x0C, 0x0C, 0x0C, 0x18, 0x30, 0x00, 0x78, 0x84, 0x84, 0xFC, 0x84, 0x84, 0x84, 0x00,
	0xF8, 0x84, 0x84, 0xF8, 0x84, 0x84, 0xF8, 0x00, 0x78, 0x84, 0x80, 0x80, 0x80, 0x84, 0x78, 0x00,
	0xF8, 0x84, 0x84, 0x84, 0x84, 0x84, 0xF8, 0x00, 0x7C, 0x40, 0x40, 0x78, 0x40, 0x40, 0x7C, 0x00,
	0xFC, 0x80, 0x80, 0xF0, 0x80, 0x80, 0x80, 0x00, 0x7C, 0x80, 0x80, 0x8C, 0x84, 0x84, 0x7C, 0x00,
	0x84, 0x84, 0x84, 0xFC, 0x84, 0x84, 0x84, 0x00, 0x7C, 0x10, 0x10, 0x10, 0x10, 0x10, 0x7C, 0x00,
	0x04, 0x04, 0x04, 0x04, 0x84, 0x84, 0x78, 0x00, 0x8C, 0x90, 0xA0, 0xE0, 0x90, 0x88, 0x84, 0x00,
	0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xFC, 0x00, 0x82, 0xC6, 0xAA, 0x92, 0x82, 0x82, 0x82, 0x00,
	0x84, 0xC4, 0xA4, 0x94, 0x8C, 0x84, 0x84, 0x00, 0x78, 0x84, 0x84, 0x84, 0x84, 0x84, 0x78, 0x00,
	0xF8, 0x84, 0x84, 0xF8, 0x80, 0x80, 0x80, 0x00, 0x78, 0x84, 0x84, 0x84, 0x84, 0x8C, 0x7C, 0x03,
	0xF8, 0x84, 0x84, 0xF8, 0x90, 0x88, 0x84, 0x00, 0x78, 0x84, 0x80, 0x78, 0x04, 0x84, 0x78, 0x00,
	0x7C, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x78, 0x00,
	0x84, 0x84, 0x84, 0x84, 0x84, 0x48, 0x30, 0x00, 0x82, 0x82, 0x82, 0x82, 0x92, 0xAA, 0xC6, 0x00,
	0x82, 0x44, 0x28, 0x10, 0x28, 0x44, 0x82, 0x00, 0x82, 0x44, 0x28, 0x10, 0x10, 0x10, 0x10, 0x00,
	0xFC, 0x04, 0x08, 0x10, 0x20, 0x40, 0xFC, 0x00, 0x3C, 0x30, 0x30, 0x30, 0x30, 0x30, 0x3C, 0x00,
	0x3C, 0x30, 0x30, 0x30, 0x30, 0x30, 0x3C, 0x00, 0x3C, 0x30, 0x30, 0x30, 0x30, 0x30, 0x3C, 0x00,
	0x3C, 0x30, 0x30, 0x30, 0x30, 0x30, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE,
	0x3C, 0x30, 0x30, 0x30, 0x30, 0x30, 0x3C, 0x00, 0x00, 0x00, 0x38, 0x04, 0x3C, 0x44, 0x3C, 0x00,
	0x40, 0x40, 0x78, 0x44, 0x44, 0x44, 0x78, 0x00, 0x00, 0x00, 0x3C, 0x40, 0x40, 0x40, 0x3C, 0x00,
	0x04, 0x04, 0x3C, 0x44, 0x44, 0x44, 0x3C, 0x00, 0x00, 0x00, 0x38, 0x44, 0x7C, 0x40, 0x3C, 0x00,
	0x38, 0x44, 0x40, 0x60, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x3C, 0x44, 0x44, 0x3C, 0x04, 0x78,
	0x40, 0x40, 0x58, 0x64, 0x44, 0x44, 0x44, 0x00, 0x10, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00,
	0x02, 0x00, 0x02, 0x02, 0x02, 0x02, 0x42, 0x3C, 0x40, 0x40, 0x46, 0x48, 0x70, 0x48, 0x46, 0x00,
	0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0xEC, 0x92, 0x92, 0x92, 0x92, 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, 0x04,
	0x00, 0x00, 0x4C, 0x70, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x3C, 0x40, 0x38, 0x04, 0x78, 0x00,
	0x10, 0x10, 0x3C, 0x10, 0x10, 0x10, 0x0C, 0x00, 0x00, 0x00, 0x44, 0x44, 0x44, 0x44, 0x78, 0x00,
	0x00, 0x00, 0x44, 0x44, 0x44, 0x28, 0x10, 0x00, 0x00, 0x00, 0x82, 0x82, 0x92, 0xAA, 0xC6, 0x00,
	0x00, 0x00, 0x44, 0x28, 0x10, 0x28, 0x44, 0x00, 0x00, 0x00, 0x42, 0x22, 0x24, 0x18, 0x08, 0x30,
	0x00, 0x00, 0x7C, 0x08, 0x10, 0x20, 0x7C, 0x00, 0x60, 0x90, 0x20, 0x40, 0xF0, 0x00, 0x00, 0x00,
	0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0x00, 0x38, 0x44, 0xBA, 0xA2, 0xBA, 0x44, 0x38, 0x00,
	0x38, 0x44, 0x82, 0x82, 0x44, 0x28, 0xEE, 0x00, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA
};

const StrEntry Video::_stringsTableEng[] = {
	{ 0x001, "P E A N U T  3000" },
	{ 0x002, "Copyright  } 1990 Peanut Computer, Inc.\nAll rights reserved.\n\nCDOS Version 5.01" },
	{ 0x003, "2" },
	{ 0x004, "3" },
	{ 0x005, "." },
	{ 0x006, "A" },
	{ 0x007, "@" },
	{ 0x008, "PEANUT 3000" },
	{ 0x00A, "R" },
	{ 0x00B, "U" },
	{ 0x00C, "N" },
	{ 0x00D, "P" },
	{ 0x00E, "R" },
	{ 0x00F, "O" },
	{ 0x010, "J" },
	{ 0x011, "E" },
	{ 0x012, "C" },
	{ 0x013, "T" },
	{ 0x014, "Shield 9A.5f Ok" },
	{ 0x015, "Flux % 5.0177 Ok" },
	{ 0x016, "CDI Vector ok" },
	{ 0x017, " %%%ddd ok" },
	{ 0x018, "Race-Track ok" },
	{ 0x019, "SYNCHROTRON" },
	{ 0x01A, "E: 23%\ng: .005\n\nRK: 77.2L\n\nopt: g+\n\n Shield:\n1: OFF\n2: ON\n3: ON\n\nP~: 1\n" },
	{ 0x01B, "ON" },
	{ 0x01C, "-" },
	{ 0x021, "|" },
	{ 0x022, "--- Theoretical study ---" },
	{ 0x023, " THE EXPERIMENT WILL BEGIN IN    SECONDS" },
	{ 0x024, "  20" },
	{ 0x025, "  19" },
	{ 0x026, "  18" },
	{ 0x027, "  4" },
	{ 0x028, "  3" },
	{ 0x029, "  2" },
	{ 0x02A, "  1" },
	{ 0x02B, "  0" },
	{ 0x02C, "L E T ' S   G O" },
	{ 0x031, "- Phase 0:\nINJECTION of particles\ninto synchrotron" },
	{ 0x032, "- Phase 1:\nParticle ACCELERATION." },
	{ 0x033, "- Phase 2:\nEJECTION of particles\non the shield." },
	{ 0x034, "A  N  A  L  Y  S  I  S" },
	{ 0x035, "- RESULT:\nProbability of creating:\n ANTIMATTER: 91.V %\n NEUTRINO 27:  0.04 %\n NEUTRINO 424: 18 %\n" },
	{ 0x036, "   Practical verification Y/N ?" },
	{ 0x037, "SURE ?" },
	{ 0x038, "MODIFICATION OF PARAMETERS\nRELATING TO PARTICLE\nACCELERATOR (SYNCHROTRON)." },
	{ 0x039, "       RUN EXPERIMENT ?" },
	{ 0x03C, "t---t" },
	{ 0x03D, "000 ~" },
	{ 0x03E, ".20x14dd" },
	{ 0x03F, "gj5r5r" },
	{ 0x040, "tilgor 25%" },
	{ 0x041, "12% 33% checked" },
	{ 0x042, "D=4.2158005584" },
	{ 0x043, "d=10.00001" },
	{ 0x044, "+" },
	{ 0x045, "*" },
	{ 0x046, "% 304" },
	{ 0x047, "gurgle 21" },
	{ 0x048, "{{{{" },
	{ 0x049, "Delphine Software" },
	{ 0x04A, "By Eric Chahi" },
	{ 0x04B, "  5" },
	{ 0x04C, "  17" },
	{ 0x12C, "0" },
	{ 0x12D, "1" },
	{ 0x12E, "2" },
	{ 0x12F, "3" },
	{ 0x130, "4" },
	{ 0x131, "5" },
	{ 0x132, "6" },
	{ 0x133, "7" },
	{ 0x134, "8" },
	{ 0x135, "9" },
	{ 0x136, "A" },
	{ 0x137, "B" },
	{ 0x138, "C" },
	{ 0x139, "D" },
	{ 0x13A, "E" },
	{ 0x13B, "F" },
	{ 0x13C, "        ACCESS CODE:" },
	{ 0x13D, "PRESS BUTTON OR RETURN TO CONTINUE" },
	{ 0x13E, "   ENTER ACCESS CODE" },
	{ 0x13F, "   INVALID PASSWORD !" },
	{ 0x140, "ANNULER" },
	{ 0x141, "      INSERT DISK ?\n\n\n\n\n\n\n\n\nPRESS ANY KEY TO CONTINUE" },
	{ 0x142, " SELECT SYMBOLS CORRESPONDING TO\n THE POSITION\n ON THE CODE WHEEL" },
	{ 0x143, "    LOADING..." },
	{ 0x144, "              ERROR" },
	{ 0x15E, "LDKD" },
	{ 0x15F, "HTDC" },
	{ 0x160, "CLLD" },
	{ 0x161, "FXLC" },
	{ 0x162, "KRFK" },
	{ 0x163, "XDDJ" },
	{ 0x164, "LBKG" },
	{ 0x165, "KLFB" },
	{ 0x166, "TTCT" },
	{ 0x167, "DDRX" },
	{ 0x168, "TBHK" },
	{ 0x169, "BRTD" },
	{ 0x16A, "CKJL" },
	{ 0x16B, "LFCK" },
	{ 0x16C, "BFLX" },
	{ 0x16D, "XJRT" },
	{ 0x16E, "HRTB" },
	{ 0x16F, "HBHK" },
	{ 0x170, "JCGB" },
	{ 0x171, "HHFL" },
	{ 0x172, "TFBB" },
	{ 0x173, "TXHF" },
	{ 0x174, "JHJL" },
	{ 0x181, " BY" },
	{ 0x182, "ERIC CHAHI" },
	{ 0x183, "         MUSIC AND SOUND EFFECTS" },
	{ 0x184, " " },
	{ 0x185, "JEAN-FRANCOIS FREITAS" },
	{ 0x186, "IBM PC VERSION" },
	{ 0x187, "      BY" },
	{ 0x188, " DANIEL MORAIS" },
	{ 0x18B, "       THEN PRESS FIRE" },
	{ 0x18C, " PUT THE PADDLE ON THE UPPER LEFT CORNER" },
	{ 0x18D, "PUT THE PADDLE IN CENTRAL POSITION" },
	{ 0x18E, "PUT THE PADDLE ON THE LOWER RIGHT CORNER" },
	{ 0x258, "      Designed by ..... Eric Chahi" },
	{ 0x259, "    Programmed by...... Eric Chahi" },
	{ 0x25A, "      Artwork ......... Eric Chahi" },
	{ 0x25B, "Music by ........ Jean-francois Freitas" },
	{ 0x25C, "            Sound effects" },
	{ 0x25D, "        Jean-Francois Freitas\n             Eric Chahi" },
	{ 0x263, "              Thanks To" },
	{ 0x264, "           Jesus Martinez\n\n          Daniel Morais\n\n        Frederic Savoir\n\n      Cecile Chahi\n\n    Philippe Delamarre\n\n  Philippe Ulrich\n\nSebastien Berthet\n\nPierre Gousseau" },
	{ 0x265, "Now Go Out Of This World" },
	{ 0x190, "Good evening professor." },
	{ 0x191, "I see you have driven here in your\nFerrari." },
	{ 0x192, "IDENTIFICATION" },
	{ 0x193, "Monsieur est en parfaite sante." },
	{ 0x194, "Y\n" },
	{ 0x193, "AU BOULOT !!!\n" },
	{ 0xFFFF, "" }
};

const StrEntry Video::_stringsTableDemo[] = {
	{ 0x001, "P E A N U T  3000" },
	{ 0x002, "Copyright  } 1990 Peanut Computer, Inc.\nAll rights reserved.\n\nCDOS Version 5.01" },
	{ 0x003, "2" },
	{ 0x004, "3" },
	{ 0x005, "." },
	{ 0x006, "A" },
	{ 0x007, "@" },
	{ 0x008, "PEANUT 3000" },
	{ 0x00A, "R" },
	{ 0x00B, "U" },
	{ 0x00C, "N" },
	{ 0x00D, "P" },
	{ 0x00E, "R" },
	{ 0x00F, "O" },
	{ 0x010, "J" },
	{ 0x011, "E" },
	{ 0x012, "C" },
	{ 0x013, "T" },
	{ 0x014, "Shield 9A.5f Ok" },
	{ 0x015, "Flux % 5.0177 Ok" },
	{ 0x016, "CDI Vector ok" },
	{ 0x017, " %%%ddd ok" },
	{ 0x018, "Race-Track ok" },
	{ 0x019, "SYNCHROTRON" },
	{ 0x01A, "E: 23%\ng: .005\n\nRK: 77.2L\n\nopt: g+\n\n Shield:\n1: OFF\n2: ON\n3: ON\n\nP~: 1\n" },
	{ 0x01B, "ON" },
	{ 0x01C, "-" },
	{ 0x021, "|" },
	{ 0x022, "--- Theoretical study ---" },
	{ 0x023, " THE EXPERIMENT WILL BEGIN IN    SECONDS" },
	{ 0x024, "  20" },
	{ 0x025, "  19" },
	{ 0x026, "  18" },
	{ 0x027, "  4" },
	{ 0x028, "  3" },
	{ 0x029, "  2" },
	{ 0x02A, "  1" },
	{ 0x02B, "  0" },
	{ 0x02C, "L E T ' S   G O" },
	{ 0x031, "- Phase 0:\nINJECTION of particles\ninto synchrotron" },
	{ 0x032, "- Phase 1:\nParticle ACCELERATION." },
	{ 0x033, "- Phase 2:\nEJECTION of particles\non the shield." },
	{ 0x034, "A  N  A  L  Y  S  I  S" },
	{ 0x035, "- RESULT:\nProbability of creating:\n ANTIMATTER: 91.V %\n NEUTRINO 27:  0.04 %\n NEUTRINO 424: 18 %\n" },
	{ 0x036, "   Practical verification Y/N ?" },
	{ 0x037, "SURE ?" },
	{ 0x038, "MODIFICATION OF PARAMETERS\nRELATING TO PARTICLE\nACCELERATOR (SYNCHROTRON)." },
	{ 0x039, "       RUN EXPERIMENT ?" },
	{ 0x03C, "t---t" },
	{ 0x03D, "000 ~" },
	{ 0x03E, ".20x14dd" },
	{ 0x03F, "gj5r5r" },
	{ 0x040, "tilgor 25%" },
	{ 0x041, "12% 33% checked" },
	{ 0x042, "D=4.2158005584" },
	{ 0x043, "d=10.00001" },
	{ 0x044, "+" },
	{ 0x045, "*" },
	{ 0x046, "% 304" },
	{ 0x047, "gurgle 21" },
	{ 0x048, "{{{{" },
	{ 0x049, "Delphine Software" },
	{ 0x04A, "By Eric Chahi" },
	{ 0x04B, "  5" },
	{ 0x04C, "  17" },
	{ 0x12C, "0" },
	{ 0x12D, "1" },
	{ 0x12E, "2" },
	{ 0x12F, "3" },
	{ 0x130, "4" },
	{ 0x131, "5" },
	{ 0x132, "6" },
	{ 0x133, "7" },
	{ 0x134, "8" },
	{ 0x135, "9" },
	{ 0x136, "A" },
	{ 0x137, "B" },
	{ 0x138, "C" },
	{ 0x139, "D" },
	{ 0x13A, "E" },
	{ 0x13B, "F" },
	{ 0x13D, "PRESS BUTTON OR RETURN TO CONTINUE" },
	{ 0x13E, "   ENTER ACCESS CODE" },
	{ 0x13F, "   INVALID PASSWORD !" },
	{ 0x140, "ANNULER" },
	{ 0x141, "          INSERT DISK ?" },
	{ 0x142, " SELECT SYMBOLS CORRESPONDING TO\n THE POSITION\n ON THE CODE WHEEL" },
	{ 0x143, "    LOADING..." },
	{ 0x144, "              ERROR" },
	{ 0x181, " BY" },
	{ 0x182, "ERIC CHAHI" },
	{ 0x183, "         MUSIC AND SOUND EFFECTS" },
	{ 0x184, " " },
	{ 0x185, "JEAN-FRANCOIS FREITAS" },
	{ 0x186, "IBM PC VERSION" },
	{ 0x187, "      BY" },
	{ 0x188, " DANIEL MORAIS" },
	{ 0x18B, "       THEN PRESS FIRE" },
	{ 0x18C, " PUT THE PADDLE ON THE UPPER LEFT CORNER" },
	{ 0x18D, "PUT THE PADDLE IN CENTRAL POSITION" },
	{ 0x18E, "PUT THE PADDLE ON THE LOWER RIGHT CORNER" },
	{ 0x1F4, "Over Two Years in the Making" },
	{ 0x1F5, "   A New, State\nof the Art, Polygon\n  Graphics System" },
	{ 0x1F6, "   Comes to the\nComputer With Full\n Screen Graphics" },
	{ 0x1F7, "While conducting a nuclear fission\nexperiment at your local\nparticle accelerator ..." },
	{ 0x1F8, "Nature decides to put a little\n    extra spin on the ball" },
	{ 0x1F9, "And sends you ..." },
	{ 0x1FA, "     Out of this World\nA Cinematic Action Adventure\n Coming soon to a computer\n      screen near you\n from Interplay Productions\n   coming soon to the IBM" },
	{ 0x258, "      Designed by ..... Eric Chahi" },
	{ 0x259, "    Programmed by...... Eric Chahi" },
	{ 0x25A, "      Artwork ......... Eric Chahi" },
	{ 0x25B, "Music by ........ Jean-francois Freitas" },
	{ 0x25C, "            Sound effects" },
	{ 0x25D, "        Jean-Francois Freitas\n             Eric Chahi" },
	{ 0x263, "              Thanks To" },
	{ 0x264, "           Jesus Martinez\n\n          Daniel Morais\n\n        Frederic Savoir\n\n      Cecile Chahi\n\n    Philippe Delamarre\n\n  Philippe Ulrich\n\nSebastien Berthet\n\nPierre Gousseau" },
	{ 0x265, "Now Go Out Of This World" },
	{ 0x190, "Good evening professor." },
	{ 0x191, "I see you have driven here in your\nFerrari." },
	{ 0x192, "IDENTIFICATION" },
	{ 0x193, "Monsieur est en parfaite sante." },
	{ 0x194, "Y\n" },
	{ 0x193, "AU BOULOT !!!\n" },
};

}

--- NEW FILE: systemstub.h ---
/* AWE - Another World Engine
 * Copyright (C) 2004 Gregory Montoir
 * Copyright (C) 2004 The ScummVM project
 *
 * 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */

#ifndef __SYSTEMSTUB_H__
#define __SYSTEMSTUB_H__

#include "stdafx.h"

#include "intern.h"

namespace Awe {

struct PlayerInput {
	enum {
		DIR_LEFT  = 1 << 0,
		DIR_RIGHT = 1 << 1,
		DIR_UP    = 1 << 2,
		DIR_DOWN  = 1 << 3
	};

	uint8 dirMask;
	bool button;
	bool code;
	bool pause;
	bool quit;
	char lastChar;
	bool save, load;
	bool fastMode;
	int8 stateSlot;
};

struct SystemStub {
	PlayerInput _pi;

	virtual ~SystemStub() {}

	virtual void init(const char *title) = 0;
	virtual void destroy() = 0;

	virtual void setPalette(uint8 s, uint8 n, const uint8 *buf) = 0;
	virtual void copyRect(uint16 x, uint16 y, uint16 w, uint16 h, const uint8 *buf, uint32 pitch) = 0;

	virtual void processEvents() = 0;
	virtual void sleep(uint32 duration) = 0;
	virtual uint32 getTimeStamp() = 0;
};

extern SystemStub *SystemStub_SDL_create();

}

#endif

--- NEW FILE: util.cpp ---
/* AWE - Another World Engine
 * Copyright (C) 2004 Gregory Montoir
 * Copyright (C) 2004 The ScummVM project
 *
 * 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */

#include <cstdarg>

#include "stdafx.h"

#include "util.h"

namespace Awe {

uint16 g_debugMask;

void debug(uint16 cm, const char *msg, ...) {
	char buf[1024];
	if (cm & g_debugMask) {
		va_list va;
		va_start(va, msg);
		vsprintf(buf, msg, va);
		va_end(va);
		printf("%s\n", buf);
		fflush(stdout);
	}
}

void string_lower(char *p) {
	for (; *p; ++p) {
		if (*p >= 'A' && *p <= 'Z') {
			*p += 'a' - 'A';
		}
	}
}

void string_upper(char *p) {
	for (; *p; ++p) {
		if (*p >= 'a' && *p <= 'z') {
			*p += 'A' - 'a';
		}
	}
}

}

--- NEW FILE: util.h ---
/* AWE - Another World Engine
 * Copyright (C) 2004 Gregory Montoir
 * Copyright (C) 2004 The ScummVM project
 *
 * 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */

#ifndef __UTIL_H__
#define __UTIL_H__

#include "stdafx.h"

#include "intern.h"

namespace Awe {

enum {
	DBG_LOGIC = 1 << 0,
	DBG_BANK  = 1 << 1,
	DBG_VIDEO = 1 << 2,
	DBG_INFO  = 1 << 3
};

extern uint16 g_debugMask;

extern void debug(uint16 cm, const char *msg, ...);
extern void error(const char *msg, ...);
extern void warning(const char *msg, ...);

extern void string_lower(char *p);
extern void string_upper(char *p);

}

#endif

--- NEW FILE: video.cpp ---
/* AWE - Another World Engine
 * Copyright (C) 2004 Gregory Montoir
 * Copyright (C) 2004 The ScummVM project
 *
 * 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */

#include "stdafx.h"

#include "awe.h"
#include "video.h"
#include "resource.h"
#include "serializer.h"
#include "systemstub.h"

namespace Awe {

void Polygon::init(const uint8 *p, uint16 zoom) {
	bbw = (*p++) * zoom / 64;
	bbh = (*p++) * zoom / 64;
	numPoints = *p++;
	assert((numPoints & 1) == 0 && numPoints < MAX_POINTS);
	for (int i = 0; i < numPoints; ++i) {
		Point *pt = &points[i];
		pt->x = (*p++) * zoom / 64;
		pt->y = (*p++) * zoom / 64;
	}
}

Video::Video(Resource *res, SystemStub *stub) 
	: _res(res), _stub(stub) {
}

void Video::init() {
	_newPal = 0xFF;
	for (int i = 0; i < 4; ++i) {
		_pagePtrs[i] = allocPage();
	}
	_curPagePtr3 = getPagePtr(1);
	_curPagePtr2 = getPagePtr(2);
	changePagePtr1(0xFE);
	_interpTable[0] = 0x4000;
	for (int i = 1; i < 0x400; ++i) {
		_interpTable[i] = 0x4000 / i;
	}
}

void Video::setDataBuffer(uint8 *dataBuf, uint16 offset) {
	_dataBuf = dataBuf;
	_pData.pc = dataBuf + offset;
}

void Video::drawShape(uint8 color, uint16 zoom, const Point &pt) {
	uint8 i = _pData.fetchByte();
	if (i >= 0xC0) {
		if (color & 0x80) {
			color = i & 0x3F;
		}
		_pg.init(_pData.pc, zoom);
		fillPolygon(color, zoom, pt);
	} else {
		i &= 0x3F;
		if (i == 1) {
			::warning("Video::drawShape() ec=0x%X (i != 2)", 0xF80);
		} else if (i == 2) {
			drawShapeParts(zoom, pt);
		} else {
			::warning("Video::drawShape() ec=0x%X (i != 2)", 0xFBB);
		}
	}
}

void Video::fillPolygon(uint16 color, uint16 zoom, const Point &pt) {
	if (_pg.bbw == 0 && _pg.bbh == 1 && _pg.numPoints == 4) {
		drawPoint(color, pt.x, pt.y);
		return;
	}
	
	int16 x1 = pt.x - _pg.bbw / 2;
	int16 x2 = pt.x + _pg.bbw / 2;
	int16 y1 = pt.y - _pg.bbh / 2;
	int16 y2 = pt.y + _pg.bbh / 2;

	if (x1 > 319 || x2 < 0 || y1 > 199 || y2 < 0)
		return;

	_hliney = y1;
	
	uint16 i, j;
	i = 0;
	j = _pg.numPoints - 1;
	
	x2 = _pg.points[i].x + x1;
	x1 = _pg.points[j].x + x1;

	++i;
	--j;

	drawLine pdl;
	if (color < 0x10) {
		pdl = &Video::drawLineN;
	} else if (color > 0x10) {
		pdl = &Video::drawLineP;
	} else {
		pdl = &Video::drawLineT;
	}

	uint32 cpt1 = x1 << 16;
	uint32 cpt2 = x2 << 16;

	while (1) {
		_pg.numPoints -= 2;
		if (_pg.numPoints == 0) {
			return;
		}
		uint16 h;
		int32 step1 = calcStep(_pg.points[j + 1], _pg.points[j], h);
		int32 step2 = calcStep(_pg.points[i - 1], _pg.points[i], h);

		++i;
		--j;

		cpt1 = (cpt1 & 0xFFFF0000) | 0x7FFF;
		cpt2 = (cpt2 & 0xFFFF0000) | 0x8000;

		if (h == 0) {	
			cpt1 += step1;
			cpt2 += step2;
		} else {
			for (; h != 0; --h) {
				if (_hliney >= 0) {
					x1 = cpt1 >> 16;
					x2 = cpt2 >> 16;
					if (x1 <= 319 && x2 >= 0) {
						if (x1 < 0) x1 = 0;
						if (x2 > 319) x2 = 319;
						(this->*pdl)(x1, x2, color);
					}
				}
				cpt1 += step1;
				cpt2 += step2;
				++_hliney;					
				if (_hliney > 199) return;
			}
		}
	}
}

void Video::drawShapeParts(uint16 zoom, const Point &pgc) {
	Point pt(pgc);
	pt.x -= _pData.fetchByte() * zoom / 64;
	pt.y -= _pData.fetchByte() * zoom / 64;
	int16 n = _pData.fetchByte();
	debug(DBG_VIDEO, "Video::drawShapeParts n=%d", n);
	for ( ; n >= 0; --n) {
		uint16 off = _pData.fetchWord();
		Point po(pt);
		po.x += _pData.fetchByte() * zoom / 64;
		po.y += _pData.fetchByte() * zoom / 64;
		uint16 color = 0xFF;
		uint16 _bp = off;
		off &= 0x7FFF;
		if (_bp & 0x8000) {
			color = *_pData.pc & 0x7F;
			_pData.pc += 2;
		}
		uint8 *bak = _pData.pc;
		_pData.pc = _dataBuf + off * 2;
		drawShape(color, zoom, po);
		_pData.pc = bak;
	}
}

int32 Video::calcStep(const Point &p1, const Point &p2, uint16 &dy) {
	dy = p2.y - p1.y;
	return (p2.x - p1.x) * _interpTable[dy] * 4;
}

void Video::drawString(uint8 color, uint16 x, uint16 y, uint16 strId) {
	const StrEntry *se = _stringsTableEng;
	while (se->id != 0xFFFF && se->id != strId) ++se;
	debug(DBG_VIDEO, "drawString(%d, %d, %d, '%s')", color, x, y, se->str);
	uint16 xx = x;
	int len = strlen(se->str);
	for (int i = 0; i < len; ++i) {
		if (se->str[i] == '\n') {
			y += 8;
			x = xx;
		} else {
			drawChar(se->str[i], x, y, color, _curPagePtr1);
			++x;
		}
	}
}

void Video::drawChar(uint8 c, uint16 x, uint16 y, uint8 color, uint8 *buf) {
	if (x <= 39 && y <= 192) {
		const uint8 *ft = _font + (c - 0x20) * 8;
		uint8 *p = buf + x * 4 + y * 160;
		for (int j = 0; j < 8; ++j) {
			uint8 ch = *(ft + j);
			for (int i = 0; i < 4; ++i) {
				uint8 b = *(p + i);
				uint8 cmask = 0xFF;
				uint8 colb = 0;
				if (ch & 0x80) {
					colb |= color << 4;
					cmask &= 0x0F;
				}
				ch <<= 1;
				if (ch & 0x80) {
					colb |= color;
					cmask &= 0xF0;
				}
				ch <<= 1;
				*(p + i) = (b & cmask) | colb;
			}
			p += 160;
		}
	}
}

void Video::drawPoint(uint8 color, int16 x, int16 y) {
	debug(DBG_VIDEO, "drawPoint(%d, %d, %d)", color, x, y);
	if (x >= 0 && x <= 319 && y >= 0 && y <= 199) {
		uint16 off = y * 160 + x / 2;
	
		uint8 cmasko, cmaskn;
		if (x & 1) {
			cmaskn = 0x0F;
			cmasko = 0xF0;
		} else {
			cmaskn = 0xF0;
			cmasko = 0x0F;
		}

		uint8 colb = (color << 4) | color;
		if (color == 0x10) {
			cmaskn &= 0x88;
			cmasko = ~cmaskn;
			colb = 0x88;		
		} else if (color == 0x11) {
			colb = *(_pagePtrs[0] + off);
		}
		uint8 b = *(_curPagePtr1 + off);
		*(_curPagePtr1 + off) = (b & cmasko) | (colb & cmaskn);
	}
}

void Video::drawLineT(int16 x1, int16 x2, uint8 color) {
	debug(DBG_VIDEO, "drawLineT(%d, %d, %d)", x1, x2, color);
	int16 xmax = MAX(x1, x2);
	int16 xmin = MIN(x1, x2);
	uint8 *p = _curPagePtr1 + _hliney * 160 + xmin / 2;

	uint16 w = xmax / 2 - xmin / 2 + 1;
	uint8 cmaske = 0;
	uint8 cmasks = 0;	
	if (xmin & 1) {
		--w;
		cmasks = 0xF7;
	}
	if (!(xmax & 1)) {
		--w;
		cmaske = 0x7F;
	}

	if (cmasks != 0) {
		*p = (*p & cmasks) | 0x08;
		++p;
	}
	while (w--) {
		*p = (*p & 0x77) | 0x88;
		++p;
	}
	if (cmaske != 0) {
		*p = (*p & cmaske) | 0x80;
		++p;
	}
}

void Video::drawLineN(int16 x1, int16 x2, uint8 color) {
	debug(DBG_VIDEO, "drawLineN(%d, %d, %d)", x1, x2, color);
	int16 xmax = MAX(x1, x2);
	int16 xmin = MIN(x1, x2);
	uint8 *p = _curPagePtr1 + _hliney * 160 + xmin / 2;

	uint16 w = xmax / 2 - xmin / 2 + 1;
	uint8 cmaske = 0;
	uint8 cmasks = 0;	
	if (xmin & 1) {
		--w;
		cmasks = 0xF0;
	}
	if (!(xmax & 1)) {
		--w;
		cmaske = 0x0F;
	}

	uint8 colb = ((color & 0xF) << 4) | (color & 0xF);	
	if (cmasks != 0) {
		*p = (*p & cmasks) | (colb & 0x0F);
		++p;
	}
	while (w--) {
		*p++ = colb;
	}
	if (cmaske != 0) {
		*p = (*p & cmaske) | (colb & 0xF0);
		++p;		
	}
}

void Video::drawLineP(int16 x1, int16 x2, uint8 color) {
	debug(DBG_VIDEO, "drawLineP(%d, %d, %d)", x1, x2, color);
	int16 xmax = MAX(x1, x2);
	int16 xmin = MIN(x1, x2);
	uint16 off = _hliney * 160 + xmin / 2;
	uint8 *p = _curPagePtr1 + off;
	uint8 *q = _pagePtrs[0] + off;

	uint8 w = xmax / 2 - xmin / 2 + 1;
	uint8 cmaske = 0;
	uint8 cmasks = 0;	
	if (xmin & 1) {
		--w;
		cmasks = 0xF0;
	}
	if (!(xmax & 1)) {
		--w;
		cmaske = 0x0F;
	}

	if (cmasks != 0) {
		*p = (*p & cmasks) | (*q & 0x0F);
		++p;
		++q;
	}
	while (w--) {
		*p++ = *q++;			
	}
	if (cmaske != 0) {
		*p = (*p & cmaske) | (*q & 0xF0);
		++p;
		++q;
	}
}

uint8 *Video::getPagePtr(uint8 page) {
	uint8 *p;
	if (page <= 3) {
		p = _pagePtrs[page];
	} else {
		switch (page) {
		case 0xFF:
			p = _curPagePtr3;
			break;
		case 0xFE:
			p = _curPagePtr2;
			break;
		default:
			p = _pagePtrs[0]; // XXX check
			::warning("Video::getPagePtr() p != [0,1,2,3,0xFF,0xFE] == 0x%X", page);
			break;
		}
	}
	return p;
}

void Video::changePagePtr1(uint8 page) {
	debug(DBG_VIDEO, "Video::changePagePtr1(%d)", page);
	_curPagePtr1 = getPagePtr(page);
}

void Video::fillPage(uint8 page, uint8 color) {
	debug(DBG_VIDEO, "Video::fillPage(%d, %d)", page, color);
	uint8 *p = getPagePtr(page);
	uint8 c = (color << 4) | color;
	memset(p, c, VID_PAGE_SIZE);
}

void Video::copyPage(uint8 src, uint8 dst, int16 vscroll) {
	debug(DBG_VIDEO, "Video::copyPage(%d, %d)", src, dst);
	if (src >= 0xFE || !((src &= 0xBF) & 0x80)) {
		uint8 *p = getPagePtr(src);
		uint8 *q = getPagePtr(dst);
		if (p != q) {
			memcpy(q, p, VID_PAGE_SIZE);
		}		
	} else {
		uint8 *p = getPagePtr(src & 3);
		uint8 *q = getPagePtr(dst);
		if (p != q && vscroll >= -199 && vscroll <= 199) {
			uint16 h = 200;
			if (vscroll < 0) {
				h += vscroll;
				p += -vscroll * 160;
			} else {
				h -= vscroll;
				q += vscroll * 160;
			}
			memcpy(q, p, h * 160);
		}
	}
}

void Video::copyPagePtr(const uint8 *src) {
	debug(DBG_VIDEO, "Video::copyPagePtr()");
	uint8 *dst = _pagePtrs[0];
	int h = 200;
	while (h--) {
		int w = 40;
		while (w--) {
			uint8 p[] = {
				*(src + 8000 * 3),
				*(src + 8000 * 2),
				*(src + 8000 * 1),
				*(src + 8000 * 0)
			};
			for(int j = 0; j < 4; ++j) {
				uint8 acc = 0;
				for (int i = 0; i < 8; ++i) {
					acc <<= 1;
					acc |= (p[i & 3] & 0x80) ? 1 : 0;
					p[i & 3] <<= 1;
				}
				*dst++ = acc;
			}			
			++src;
		}
	}
}

uint8 *Video::allocPage() {
	uint8 *buf = (uint8 *)malloc(VID_PAGE_SIZE);
	memset(buf, 0, VID_PAGE_SIZE);
	return buf;
}

void Video::changePal(uint8 palNum) {
	if (palNum < 32) {
		uint8 *p = _res->_segVideoPal + palNum * 32;
		uint8 pal[16 * 3];
		for (int i = 0; i < 16; ++i) {
			uint8 c1 = *(p + 0);
			uint8 c2 = *(p + 1);
			p += 2;
			pal[i * 3 + 0] = ((c1 & 0x0F) << 2) | ((c1 & 0x0F) >> 2); // r
			pal[i * 3 + 1] = ((c2 & 0xF0) >> 2) | ((c2 & 0xF0) >> 6); // g
			pal[i * 3 + 2] = ((c2 & 0x0F) >> 2) | ((c2 & 0x0F) << 2); // b
		}
		_stub->setPalette(0, 16, pal);
		_curPal = palNum;
	}
}

void Video::updateDisplay(uint8 page) {
	debug(DBG_VIDEO, "Video::updateDisplay(%d)", page);
	if (page != 0xFE) {
		if (page == 0xFF) {
			SWAP(_curPagePtr2, _curPagePtr3);
		} else {
			_curPagePtr2 = getPagePtr(page);
		}
	}
	if (_newPal != 0xFF) {
		changePal(_newPal);
		_newPal = 0xFF;
	}
	_stub->copyRect(0, 0, 320, 200, _curPagePtr2, 160);
}

void Video::saveOrLoad(Serializer &ser) {
	uint8 mask = 0;
	if (ser._mode == Serializer::SM_SAVE) {
		for (int i = 0; i < 4; ++i) {
			if (_pagePtrs[i] == _curPagePtr1)
				mask |= i << 4;
			if (_pagePtrs[i] == _curPagePtr2)
				mask |= i << 2;
			if (_pagePtrs[i] == _curPagePtr3)
				mask |= i << 0;
		}		
	}
	Serializer::Entry entries[] = {
		SE_INT(&_curPal, Serializer::SES_INT8, VER(1)),
		SE_INT(&_newPal, Serializer::SES_INT8, VER(1)),
		SE_INT(&mask, Serializer::SES_INT8, VER(1)),
		SE_ARRAY(_pagePtrs[0], Video::VID_PAGE_SIZE, Serializer::SES_INT8, VER(1)),
		SE_ARRAY(_pagePtrs[1], Video::VID_PAGE_SIZE, Serializer::SES_INT8, VER(1)),
		SE_ARRAY(_pagePtrs[2], Video::VID_PAGE_SIZE, Serializer::SES_INT8, VER(1)),
		SE_ARRAY(_pagePtrs[3], Video::VID_PAGE_SIZE, Serializer::SES_INT8, VER(1)),
		SE_END()
	};
	ser.saveOrLoadEntries(entries);
	if (ser._mode == Serializer::SM_LOAD) {
		_curPagePtr1 = _pagePtrs[(mask >> 4) & 0x3];
		_curPagePtr2 = _pagePtrs[(mask >> 2) & 0x3];
		_curPagePtr3 = _pagePtrs[(mask >> 0) & 0x3];
		changePal(_curPal);
	}
}

}

--- NEW FILE: video.h ---
/* AWE - Another World Engine
 * Copyright (C) 2004 Gregory Montoir
 * Copyright (C) 2004 The ScummVM project
 *
 * 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */

#ifndef __VIDEO_H__
#define __VIDEO_H__

#include "stdafx.h"

#include "intern.h"

namespace Awe {

struct StrEntry {
	uint16 id;
	const char *str;
};

struct Polygon {
	enum {
		MAX_POINTS = 50
	};

	uint16 bbw, bbh;
	uint8 numPoints;
	Point points[MAX_POINTS];

	void init(const uint8 *p, uint16 zoom);
};

struct Resource;
struct Serializer;
struct SystemStub;

struct Video {
	typedef void (Video::*drawLine)(int16 x1, int16 x2, uint8 col);

	enum {
		VID_PAGE_SIZE  = 320 * 200 / 2
	};

	static const uint8 _font[];
	static const StrEntry _stringsTableEng[];
	static const StrEntry _stringsTableDemo[];

	Resource *_res;
	SystemStub *_stub;

	uint8 _newPal, _curPal;
	uint8 *_pagePtrs[4];
	uint8 *_curPagePtr1, *_curPagePtr2, *_curPagePtr3;
	Polygon _pg;
	int16 _hliney;
	uint16 _interpTable[0x400];
	Ptr _pData;
	uint8 *_dataBuf;

	Video(Resource *res, SystemStub *stub);
	void init();

	void setDataBuffer(uint8 *dataBuf, uint16 offset);
	void drawShape(uint8 color, uint16 zoom, const Point &pt);
	void fillPolygon(uint16 color, uint16 zoom, const Point &pt);
	void drawShapeParts(uint16 zoom, const Point &pt);
	int32 calcStep(const Point &p1, const Point &p2, uint16 &dy);

	void drawString(uint8 color, uint16 x, uint16 y, uint16 strId);
	void drawChar(uint8 c, uint16 x, uint16 y, uint8 color, uint8 *buf);
	void drawPoint(uint8 color, int16 x, int16 y);
	void drawLineT(int16 x1, int16 x2, uint8 color);
	void drawLineN(int16 x1, int16 x2, uint8 color);
	void drawLineP(int16 x1, int16 x2, uint8 color);
	uint8 *getPagePtr(uint8 page);
	void changePagePtr1(uint8 page);
	void fillPage(uint8 page, uint8 color);
	void copyPage(uint8 src, uint8 dst, int16 vscroll);
	void copyPagePtr(const uint8 *src);
	uint8 *allocPage();
	void changePal(uint8 pal);
	void updateDisplay(uint8 page);
	
	void saveOrLoad(Serializer &ser);
};

}

#endif





More information about the Scummvm-git-logs mailing list