/* ScummVM - Scumm Interpreter
 * Copyright (C) 2001  Ludvig Strigeus
 * Copyright (C) 2001/2002 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.
 *
 * $Header$
 *
 */

#include "stdafx.h"
#include "scumm.h"
#include "sound/mixer.h"
#include "sound/mididrv.h"
#include "scumm/imuse.h"
#include "actor.h"
#include "debug.h"
#include "gameDetector.h"
#include "gui/gui.h"
#include "gui/newgui.h"
#include "object.h"
#include "resource.h"
#include "string.h"

#ifdef _WIN32_WCE
extern void GraphicsOff(void);
#endif

// Use g_scumm from error() ONLY
Scumm *g_scumm = 0;


void autosave(Scumm * scumm)
{
	scumm->_doAutosave = true;
}

void Scumm::initRandSeeds()
{
	_randSeed1 = 0xA943DE33;
	_randSeed2 = 0x37A9ED29;
}

uint Scumm::getRandomNumber(uint max)
{
	/* TODO: my own random number generator */
	_randSeed1 = 0xDEADBF03 * (_randSeed1 + 1);
	_randSeed1 = (_randSeed1 >> 13) | (_randSeed1 << 19);
	return _randSeed1 % (max + 1);
}

uint Scumm::getRandomNumberRng(uint min, uint max)
{
	return getRandomNumber(max - min) + min;
}


Scumm::Scumm (GameDetector *detector, OSystem *syst) 
	: Engine(detector, syst)
{
	OSystem::Property prop;

	// Use g_scumm from error() ONLY
	g_scumm = this;

	_debugMode = detector->_debugMode;
	_bootParam = detector->_bootParam;
	_exe_name = detector->_exe_name;
	_gameId = detector->_gameId;
	_gameText = detector->_gameText;
	_features = detector->_features;
	_soundCardType = detector->_soundCardType;
	_noSubtitles = detector->_noSubtitles;
	_cdrom = detector->_cdrom;
	_defaultTalkDelay = detector->_talkSpeed;
	_use_adlib = detector->_use_adlib;
	
	if (_gameId == GID_ZAK256) {	// FmTowns is 320x240
		_realWidth = 320;
		_realHeight = 240;
	} else {
		_realWidth = 320;
		_realHeight = 200;
	}

	_gui = new Gui();
	_gui->init(this);
	
	_newgui = new NewGui(this);
	_bundle = new Bundle(this);
	_timer = new Timer(this);
	_sound = new Sound(this);

	_sound->_sound_volume_master = 0;
	_sound->_sound_volume_sfx = detector->_sfx_volume;	
	_sound->_sound_volume_music = detector->_music_volume;	

	/* Initialize backend */
	syst->init_size(_realWidth, _realHeight);
	prop.cd_num = detector->_cdrom;
	syst->property(OSystem::PROP_OPEN_CD, &prop);

	/* Bind the mixer to the system => mixer will be invoked
	 * automatically when samples need to be generated */	
	if (!_mixer->bind_to_system(syst)) {         
		warning("Sound initialization failed");
		if (detector->_use_adlib) {
			_use_adlib = false;   
			detector->_use_adlib = false;   
			detector->_midi_driver = MD_NULL;   
			warning("Adlib music was selected, switching to midi null driver");   
		}   
	} 
	_mixer->set_volume(kDefaultSFXVolume);
	_mixer->set_music_volume(kDefaultMusicVolume);


	// Init iMuse
	if (detector->_use_adlib) {
		_imuse = IMuse::create_adlib(syst, _mixer);
	} else {
		_imuse = IMuse::create_midi(syst, detector->createMidi());
	}
	if (detector->_gameTempo != 0)
		_imuse->property(IMuse::PROP_TEMPO_BASE, detector->_gameTempo);
	_imuse->set_music_volume(_sound->_sound_volume_music);


	// Load game from specified slot, if any
	if (detector->_save_slot != -1) {
		_saveLoadSlot = detector->_save_slot;
		_saveLoadFlag = 2;
		_saveLoadCompatible = false;
	}
}

Scumm::~Scumm ()
{
	delete [] _actors;
	delete _gui;
	delete _newgui;
	delete _bundle;
	delete _timer;
	delete _sound;
}

void Scumm::scummInit()
{
	int i;
	Actor *a;

	tempMusic = 0;
	debug(9, "scummInit");

	if (_features & GF_SMALL_HEADER)
		_resourceHeaderSize = 6;
	else
		_resourceHeaderSize = 8;

	if (!(_features & GF_SMALL_NAMES))
		loadCharset(1);

	initScreens(0, 16, 320, 144);

	setShake(0);
	setupCursor();
	
	_timer->init();

	/* Allocate and initilise actors */
	_actors = new Actor[MAX_ACTORS];
	for (i = 1, a = getFirstActor(); ++a, i < NUM_ACTORS; i++) {
		a->number = i;
		a->initActorClass(this);
		a->initActor(1);
	}
	
	_vars[VAR_CHARINC] = 4;

	_numNestedScripts = 0;
	vm.cutSceneStackPointer = 0;

	memset(vm.cutScenePtr, 0, sizeof(vm.cutScenePtr));
	memset(vm.cutSceneData, 0, sizeof(vm.cutSceneData));

	for (i = 0; i < _maxVerbs; i++) {
		_verbs[i].verbid = 0;
		_verbs[i].right = 319;
		_verbs[i].oldleft = -1;
		_verbs[i].type = 0;
		_verbs[i].color = 2;
		_verbs[i].hicolor = 0;
		_verbs[i].charset_nr = 1;
		_verbs[i].curmode = 0;
		_verbs[i].saveid = 0;
		_verbs[i].center = 0;
		_verbs[i].key = 0;
	}

	if (!(_features & GF_AFTER_V7)) {
		camera._leftTrigger = 10;
		camera._rightTrigger = 30;
		camera._mode = 0;
	}
	camera._follows = 0;

	virtscr[0].xstart = 0;

	if (!(_features & GF_AFTER_V7)) {
		_vars[VAR_V5_DRAWFLAGS] = 11;
		_vars[VAR_59] = 3;

		_vars[VAR_CURRENT_LIGHTS] = LIGHTMODE_actor_base | LIGHTMODE_actor_color | LIGHTMODE_screen;
	}

	mouse.x = 104;
	mouse.y = 56;

	_ENCD_offs = 0;
	_EXCD_offs = 0;

	_currentScript = 0xFF;
	_sentenceNum = 0;

	_currentRoom = 0;
	_numObjectsInRoom = 0;
	_actorToPrintStrFor = 0;

	charset._bufPos = 0;
	_haveMsg = 0;

	_varwatch = -1;
	_screenStartStrip = 0;

	_vars[VAR_TALK_ACTOR] = 0;

	_talkDelay = 0;
	_keepText = false;

	_cursorState = 0;
	_userPut = 0;

	_newEffect = 129;
	_fullRedraw = true;

	clearDrawObjectQueue();

	for (i = 0; i < 6; i++) {
		if (_features & GF_OLD256) {
			string[i].t_xpos = 0;
			string[i].t_ypos = 0;
		} else {
			string[i].t_xpos = 2;
			string[i].t_ypos = 5;
		}
		string[i].t_right = 319;
		string[i].t_color = 0xF;
		string[i].t_center = 0;
		string[i].t_charset = 0;
	}

	_numInMsgStack = 0;

	createResource(rtTemp, 6, 500);

	initScummVars();

	if (!(_features & GF_AFTER_V6))
		_vars[VAR_V5_TALK_STRING_Y] = -0x50;

	getGraphicsPerformance();

#ifdef COMPRESSED_SOUND_FILE
	_sound->_current_cache = 0;
#endif

	_timer->installProcedure(&autosave, 5 * 60 * 1000);
}


void Scumm::initScummVars()
{
	if (!(_features & GF_AFTER_V7)) {
		_vars[VAR_CURRENTDRIVE] = _currentDrive;
		_vars[VAR_FIXEDDISK] = checkFixedDisk();
		_vars[VAR_SOUNDCARD] = _soundCardType;
		_vars[VAR_VIDEOMODE] = 0x13;
		_vars[VAR_HEAPSPACE] = 630;
		_vars[VAR_MOUSEPRESENT] = _mousePresent;
		_vars[VAR_SOUNDPARAM] = _soundParam;
		_vars[VAR_SOUNDPARAM2] = _soundParam2;
		_vars[VAR_SOUNDPARAM3] = _soundParam3;
		if (_features & GF_AFTER_V6)
			_vars[VAR_V6_EMSSPACE] = 10000;
	}
}

void Scumm::checkRange(int max, int min, int no, const char *str)
{
	if (no < min || no > max) {
		error("Value %d is out of bounds (%d,%d) int script(%d) msg %s", no, min,
					max, vm.slot[_curExecScript].number, str);
	}
}

int Scumm::scummLoop(int delta)
{
	static int counter = 0;

#ifndef _WIN32_WCE
	if (_debugger)
		_debugger->on_frame();
#endif

	// Randomize the PRNG by calling it at regular intervals. This ensures
	// that it will be in a different state each time you run the program.
	getRandomNumber(2);

	_vars[VAR_TMR_1] += delta;
	_vars[VAR_TMR_2] += delta;
	_vars[VAR_TMR_3] += delta;
	_vars[VAR_TMR_4] += delta;

	if (delta > 15)
		delta = 15;

	decreaseScriptDelay(delta);

	_talkDelay -= delta;
	if (_talkDelay < 0)
		_talkDelay = 0;

	processKbd();

	if (_features & GF_AFTER_V7) {
		_vars[VAR_CAMERA_POS_X] = camera._cur.x;
		_vars[VAR_CAMERA_POS_Y] = camera._cur.y;
	} else {
		_vars[VAR_CAMERA_POS_X] = camera._cur.x;
	}
	_vars[VAR_HAVE_MSG] = (_haveMsg == 0xFE) ? 0xFF : _haveMsg;
	_vars[VAR_VIRT_MOUSE_X] = _virtual_mouse_x;
	_vars[VAR_VIRT_MOUSE_Y] = _virtual_mouse_y;
	_vars[VAR_MOUSE_X] = mouse.x;
	_vars[VAR_MOUSE_Y] = mouse.y;
	_vars[VAR_DEBUGMODE] = _debugMode;

	if (_features & GF_AUDIOTRACKS) {		
		if (delta) {
			if (++counter != 2)
				_vars[VAR_MI1_TIMER] += 5;
			else {
				counter = 0;
				_vars[VAR_MI1_TIMER] += 6;
			}				
		}
	} else if (_features & GF_OLD256) {

		if(tempMusic == 3) {
			tempMusic = 0;
			_vars[VAR_MUSIC_FLAG]++;
		} else {
			tempMusic ++;
		}
	}


	if (_saveLoadFlag) {
		if (_saveLoadFlag == 1) {
			saveState(_saveLoadSlot, _saveLoadCompatible);
			// Ender: Disabled for small_header games, as
			// can overwrite game variables (eg, Zak256 cashcards)
			if (_saveLoadCompatible && !(_features & GF_SMALL_HEADER))
 				_vars[VAR_GAME_LOADED] = 201;
		} else {
			loadState(_saveLoadSlot, _saveLoadCompatible);
			// Ender: Disabled for small_header games, as
			// can overwrite game variables (eg, Zak256 cashcards)
 			if (_saveLoadCompatible && !(_features & GF_SMALL_HEADER))
				_vars[VAR_GAME_LOADED] = 203;
		}
		_saveLoadFlag = 0;
	}

	if (_doAutosave) {
		_saveLoadSlot = 0;
		sprintf(_saveLoadName, "Autosave %d", _saveLoadSlot);
		_saveLoadFlag = 1;
		_saveLoadCompatible = false;
		_doAutosave = false;
	}

	if (_completeScreenRedraw) {
		_completeScreenRedraw = false;
		gdi.clearUpperMask();
		charset._hasMask = false;
		redrawVerbs();
		_fullRedraw = true;
	}

	runAllScripts();
	checkExecVerbs();
	checkAndRunVar33();

	if (_currentRoom == 0) {
		gdi._cursorActive = 0;
		CHARSET_1();
		drawDirtyScreenParts();
		_sound->processSoundQues();
		camera._last = camera._cur;
	} else {
		walkActors();
		moveCamera();
		fixObjectFlags();
		CHARSET_1();

		if (camera._cur.x != camera._last.x || _BgNeedsRedraw || _fullRedraw
				|| (_features & GF_AFTER_V7 && camera._cur.y != camera._last.y)) {
			redrawBGAreas();
		}

		processDrawQue();
		setActorRedrawFlags();
		resetActorBgs();

		if (!(_vars[VAR_CURRENT_LIGHTS] & LIGHTMODE_screen) &&
		      _vars[VAR_CURRENT_LIGHTS] & LIGHTMODE_flashlight) {
			drawFlashlight();
			setActorRedrawFlags();
		}

		processActors();
		clear_fullRedraw();
		cyclePalette();
		palManipulate();

		if (_doEffect) {
			_doEffect = false;
			fadeIn(_newEffect);
			clearClickedStatus();
		}

		if (_cursorState > 0) {
			verbMouseOver(checkMouseOver(mouse.x, mouse.y));
		}

		drawBlastObjects();
		drawDirtyScreenParts();
		removeBlastObjects();

		if (!(_features & GF_AFTER_V6))
			playActorSounds();

		_sound->processSoundQues();
		camera._last = camera._cur;
	}

	if (!(++_expire_counter)) {
		increaseResourceCounter();
	}

	animateCursor();
	
	/* show or hide mouse */
	_system->show_mouse(_cursorState > 0);

	_vars[VAR_TIMER] = 0;
	return _vars[VAR_TIMER_NEXT];

}

void Scumm::startScene(int room, Actor * a, int objectNr)
{
	int i, where;
	Actor *at;

	CHECK_HEAP debug(1, "Loading room %d", room);

	clearMsgQueue();

	fadeOut(_switchRoomEffect2);
	_newEffect = _switchRoomEffect;

	if (_currentScript != 0xFF) {
		if (vm.slot[_currentScript].where == WIO_ROOM ||
				vm.slot[_currentScript].where == WIO_FLOBJECT) {
			if (vm.slot[_currentScript].cutsceneOverride != 0)
				error("Object %d stopped with active cutscene/override in exit",
							vm.slot[_currentScript].number);
			_currentScript = 0xFF;
		} else if (vm.slot[_currentScript].where == WIO_LOCAL) {
			if (vm.slot[_currentScript].cutsceneOverride != 0)
				error("Script %d stopped with active cutscene/override in exit",
							vm.slot[_currentScript].number);
			_currentScript = 0xFF;
		}
	}

	if (!(_features & GF_SMALL_HEADER))  // Disable for SH games. Overwrites
		_vars[VAR_NEW_ROOM] = room; // gamevars, eg Zak cashcards

	runExitScript();
	killScriptsAndResources();
	clearEnqueue();
	stopCycle(0);

	for (i = 1, at = getFirstActor(); ++at, i < NUM_ACTORS; i++) {
		at->hideActor();
	}

	if (!(_features & GF_AFTER_V7)) {
		for (i = 0; i < 0x100; i++)
			_shadowPalette[i] = i;
	}

	clearDrawObjectQueue();

	_vars[VAR_ROOM] = room;
	_fullRedraw = true;

	increaseResourceCounter();

	_currentRoom = room;
	_vars[VAR_ROOM] = room;

	if (room >= 0x80)
		_roomResource = _resourceMapper[room & 0x7F];
	else
		_roomResource = room;

	_vars[VAR_ROOM_RESOURCE] = _roomResource;

	if (room != 0)
		ensureResourceLoaded(1, room);

	if (_currentRoom == 0) {
		_ENCD_offs = _EXCD_offs = 0;
		_numObjectsInRoom = 0;
		return;
	}

	initRoomSubBlocks();
	if (_features & GF_SMALL_HEADER)
		loadRoomObjectsSmall();
	else
		loadRoomObjects();

	if (!(_features & GF_AFTER_V7)) {
		camera._mode = CM_NORMAL;
		camera._cur.x = camera._dest.x = 160;
		camera._cur.y = camera._dest.y = 100;
	}

	if (_features & GF_AFTER_V6) {
		_vars[VAR_V6_SCREEN_WIDTH] = _scrWidth;
		_vars[VAR_V6_SCREEN_HEIGHT] = _scrHeight;
	}

	if (_features & GF_AFTER_V7) {
		_vars[VAR_CAMERA_MIN_X] = 160;
		_vars[VAR_CAMERA_MAX_X] = _scrWidth - 160;
		_vars[VAR_CAMERA_MIN_Y] = 100;
		_vars[VAR_CAMERA_MAX_Y] = _scrHeight - 100;
		setCameraAt(160, 100);
	} else {
		_vars[VAR_CAMERA_MAX_X] = _scrWidth - 160;
		_vars[VAR_CAMERA_MIN_X] = 160;
	}

	if (_roomResource == 0)
		return;


	memset(gfxUsageBits, 0, sizeof(gfxUsageBits));

	if (a) {
		where = whereIsObject(objectNr);
		if (where != WIO_ROOM && where != WIO_FLOBJECT)
			error("startScene: Object %d is not in room %d", objectNr,
						_currentRoom);
		int x, y, dir;
		getObjectXYPos(objectNr, x, y, dir);
		a->putActor(x, y, _currentRoom);
		a->setDirection(dir + 180);
		a->moving = 0;
	}

	showActors();

	_egoPositioned = false;
	runEntryScript();

	if (!(_features & GF_AFTER_V7)) {
		if (a && !_egoPositioned) {
			int x, y;
			getObjectXYPos(objectNr, x, y);
			a->putActor(x, y, _currentRoom);
			a->moving = 0;
		}
	} else {
		if (camera._follows) {
			Actor *a = derefActorSafe(camera._follows, "startScene: follows");
			setCameraAt(a->x, a->y);
		}
	}

	_doEffect = true;

	CHECK_HEAP;
}

void Scumm::initRoomSubBlocks()
{
	int i, offs;
	byte *ptr;
	byte *roomptr, *searchptr;
	RoomHeader *rmhd;

	_ENCD_offs = 0;
	_EXCD_offs = 0;
	_CLUT_offs = 0;
	_PALS_offs = 0;

	nukeResource(rtMatrix, 1);
	nukeResource(rtMatrix, 2);

	for (i = 1; i < _maxScaleTable; i++)
		nukeResource(rtScaleTable, i);

	roomptr = getResourceAddress(rtRoom, _roomResource);

	rmhd = (RoomHeader *)findResourceData(MKID('RMHD'), roomptr);

	if (_features & GF_AFTER_V7) {
		_scrWidth = READ_LE_UINT16(&(rmhd->v7.width));
		_scrHeight = READ_LE_UINT16(&(rmhd->v7.height));
	} else {
		_scrWidth = READ_LE_UINT16(&(rmhd->old.width));
		_scrHeight = READ_LE_UINT16(&(rmhd->old.height));
	}


	if (_features & GF_SMALL_HEADER)
		_IM00_offs = findResourceData(MKID('IM00'), roomptr) - roomptr;
	else
		_IM00_offs =
			findResource(MKID('IM00'),
									 findResource(MKID('RMIM'), roomptr)) - roomptr;

	ptr = findResourceData(MKID('EXCD'), roomptr);
	if (ptr) {
		_EXCD_offs = ptr - roomptr;
#ifdef DUMP_SCRIPTS
		dumpResource("exit-", _roomResource, ptr - 8);
#endif
	}

	ptr = findResourceData(MKID('ENCD'), roomptr);
	if (ptr) {
		_ENCD_offs = ptr - roomptr;
#ifdef DUMP_SCRIPTS
		dumpResource("entry-", _roomResource, ptr - 8);
#endif
	}

	if (_features & GF_SMALL_HEADER) {
		ptr = findResourceData(MKID('BOXD'), roomptr);
		if (ptr) {
			byte numOfBoxes = *(ptr);
			int size;
			if (_features & GF_OLD256)
				size = numOfBoxes * (SIZEOF_BOX - 2) + 1;
			else
				size = numOfBoxes * SIZEOF_BOX + 1;


			createResource(rtMatrix, 2, size);
			memcpy(getResourceAddress(rtMatrix, 2), ptr, size);
			ptr += size;
			size = getResourceDataSize(ptr - size - 6) - size;

			if (size >= 0) {					// do this :)
				createResource(rtMatrix, 1, size);
				memcpy(getResourceAddress(rtMatrix, 1), ptr, size);
			}

		}
	} else {
		ptr = findResourceData(MKID('BOXD'), roomptr);
		if (ptr) {
			int size = getResourceDataSize(ptr);
			createResource(rtMatrix, 2, size);
			roomptr = getResourceAddress(rtRoom, _roomResource);
			ptr = findResourceData(MKID('BOXD'), roomptr);
			memcpy(getResourceAddress(rtMatrix, 2), ptr, size);
		}

		ptr = findResourceData(MKID('BOXM'), roomptr);
		if (ptr) {
			int size = getResourceDataSize(ptr);
			createResource(rtMatrix, 1, size);
			roomptr = getResourceAddress(rtRoom, _roomResource);
			ptr = findResourceData(MKID('BOXM'), roomptr);
			memcpy(getResourceAddress(rtMatrix, 1), ptr, size);
		}
	}

	ptr = findResourceData(MKID('SCAL'), roomptr);
	if (ptr) {
		offs = ptr - roomptr;
		for (i = 1; i < _maxScaleTable; i++, offs += 8) {
			int a = READ_LE_UINT16(roomptr + offs);
			int b = READ_LE_UINT16(roomptr + offs + 2);
			int c = READ_LE_UINT16(roomptr + offs + 4);
			int d = READ_LE_UINT16(roomptr + offs + 6);
			if (a || b || c || d) {
				setScaleItem(i, b, a, d, c);
				roomptr = getResourceAddress(rtRoom, _roomResource);
			}
		}
	}
	memset(_localScriptList, 0, sizeof(_localScriptList));

	searchptr = roomptr = getResourceAddress(rtRoom, _roomResource);
	if (_features & GF_SMALL_HEADER) {
		while ((ptr = findResourceSmall(MKID('LSCR'), searchptr)) != NULL) {
			int id = 0;
			ptr += _resourceHeaderSize;	/* skip tag & size */
			id = ptr[0];
#ifdef DUMP_SCRIPTS
			do {
				char buf[32];
				sprintf(buf, "room-%d-", _roomResource);
				dumpResource(buf, id, ptr - 6);
			} while (0);
#endif
			_localScriptList[id - _numGlobalScripts] = ptr + 1 - roomptr;
			searchptr = NULL;
		}
	} else {
		while ((ptr = findResource(MKID('LSCR'), searchptr)) != NULL) {
			int id = 0;

			ptr += _resourceHeaderSize;	/* skip tag & size */

			if (_features & GF_AFTER_V7) {
				id = READ_LE_UINT16(ptr);
				checkRange(2050, 2000, id, "Invalid local script %d");
				_localScriptList[id - _numGlobalScripts] = ptr + 2 - roomptr;
			} else {
				id = ptr[0];
				_localScriptList[id - _numGlobalScripts] = ptr + 1 - roomptr;
			}
#ifdef DUMP_SCRIPTS
			do {
				char buf[32];
				sprintf(buf, "room-%d-", _roomResource);
				dumpResource(buf, id, ptr - 8);
			} while (0);
#endif
			searchptr = NULL;
		}
	}

	if (_features & GF_SMALL_HEADER)
		ptr = findResourceSmall(MKID('EPAL'), roomptr);
	else
		ptr = findResource(MKID('EPAL'), roomptr);

	if (ptr)
		_EPAL_offs = ptr - roomptr;

	if (_features & GF_SMALL_HEADER)
		ptr = findResourceSmall(MKID('CLUT'), roomptr);
	else
		ptr = findResourceData(MKID('CLUT'), roomptr);

	if (ptr) {
		_CLUT_offs = ptr - roomptr;
		setPaletteFromRes();
	}

	if (_features & GF_AFTER_V6) {
		ptr = findResource(MKID('PALS'), roomptr);
		if (ptr) {
			_PALS_offs = ptr - roomptr;
			setPalette(0);
		}
	}

	if (_features & GF_SMALL_HEADER)
		ptr = findResourceData(MKID('CYCL'), roomptr);
	else
		ptr = findResourceData(MKID('CYCL'), roomptr);

	if (ptr)
		initCycl(findResourceData(MKID('CYCL'), roomptr));

	ptr = findResourceData(MKID('TRNS'), roomptr);
	if (ptr)
		gdi._transparency = ptr[0];
	else
		gdi._transparency = 255;

	initBGBuffers(_scrHeight);

	memset(_extraBoxFlags, 0, sizeof(_extraBoxFlags));
}

void Scumm::setScaleItem(int slot, int a, int b, int c, int d)
{
	byte *ptr;
	int cur, amounttoadd, i, tmp;

	ptr = createResource(rtScaleTable, slot, 200);

	if (a == c)
		return;

	cur = (b - d) * a;
	amounttoadd = d - b;

	for (i = 200; i > 0; i--) {
		tmp = cur / (c - a) + b;
		if (tmp < 1)
			tmp = 1;
		if (tmp > 255)
			tmp = 255;
		*ptr++ = tmp;
		cur += amounttoadd;
	}
}

void Scumm::dumpResource(char *tag, int idx, byte *ptr)
{
	char buf[256];
	FILE *out;

	uint32 size;
	if (_features & GF_SMALL_HEADER)
		size = READ_LE_UINT32(ptr);
	else
		size = READ_BE_UINT32_UNALIGNED(ptr + 4);

#if defined(MACOS_CARBON)
	sprintf(buf, ":dumps:%s%d.dmp", tag, idx);
#else
	sprintf(buf, "dumps/%s%d.dmp", tag, idx);
#endif

	out = fopen(buf, "rb");
	if (!out) {
		out = fopen(buf, "wb");
		if (!out)
			return;
		fwrite(ptr, size, 1, out);
	}
	fclose(out);
}


void Scumm::clear_fullRedraw()
{
	_fullRedraw = 0;
}

void Scumm::clearClickedStatus()
{
	checkKeyHit();
	_mouseButStat = 0;
	_leftBtnPressed = 0;
	_rightBtnPressed = 0;
}

int Scumm::checkKeyHit()
{
	int a = _keyPressed;
	_keyPressed = 0;
	return a;
}

void Scumm::unkRoomFunc3(int unk1, int unk2, int rfact, int gfact, int bfact)
{
	byte *pal = _currentPalette;
	byte *table = _shadowPalette;
	int i;

	warning("unkRoomFunc3(%d,%d,%d,%d,%d): not fully implemented", unk1, unk2, rfact, gfact, bfact);

	// TODO - correctly implement this function (see also patch #588501)
	//
	// Some "typical" examples of how this function is being invoked in real life:
	//
	// unkRoomFunc3(16, 255, 200, 200, 200)
	//
	// FOA: Sets up the colors for the boat and submarine shadows in the
	// diving scene. Are the shadows too light? Maybe unk1 is used to
	// darken the colors?
	//
	// unkRoomFunc3(0, 255, 700, 700, 700)
	//
	// FOA: Sets up the colors for the subway car headlight when it first
	// goes on. This seems to work ok.
	//
	// unkRoomFunc3(160, 191, 300, 300, 300)
	// unkRoomFunc3(160, 191, 289, 289, 289)
	//     ...
	// unkRoomFunc3(160, 191, 14, 14, 14)
	// unkRoomFunc3(160, 191, 3, 3, 3)
	//
	// FOA: Sets up the colors for the subway car headlight for the later
	// half of the trip, where it fades out. This currently doesn't work
	// at all. The colors are too dark to be brightened. At first I thought
	// unk1 and unk2 were used to tell which color interval to manipulate,
	// but as far as I can tell the colors 160-191 aren't used at all to
	// draw the light, that can't be it. Apparently unk1 and/or unk2 are
	// used to brighten the colors.
	
	for (i = 0; i <= 255; i++) {
		int r = (int) (*pal++ * rfact) >> 8;
		int g = (int) (*pal++ * gfact) >> 8;
		int b = (int) (*pal++ * bfact) >> 8;

		*table++ = remapPaletteColor(r, g, b, (uint) -1);
	}
}


void Scumm::palManipulate(int start, int end, int d, int time, int e)
{
	// TODO - correctly implement this function (see also bug #558245)
	//
	// The only place I know of where this function is being called is in the 
	// FOA extro, to change the color to match the sinking sun. The following
	// three calls (with some pauses between them) are issued:
	//
	// palManipulate(16, 190, 32, 180, 1)
	// palManipulate(16, 190, 32, 1, 1)
	// palManipulate(16, 190, 32, 800, 1)
	//
	// The first two parameters seem to specify a palette range (as the colors
	// from 16 to 190 are the ones that make up water & sky).
	//
	// Maybe the change has to be done over a period of time, possibly specified
	// by the second last parameter - between call 1 and 2, about 17-18 seconds
	// seem to pass (well using get_msecs, I measured 17155 ms, 17613 ms, 17815 ms).
	//
	// No clue about the third and fifth parameter right now, they just always
	// are 32 and 1 - possibly finding another example of this function being
	// used would help a lot. Also, I can't currently compare it with the original,
	// doing that (and possibly, taking screenshots of it for analysis!) would 
	// help a lot.
	
	static int sys_time = 0;
	int new_sys_time = _system->get_msecs();
	
	warning("palManipulate(%d, %d, %d, %d, %d): not implemented", start, end, d, time, e);
	if (sys_time != 0)
		printf("Time since last call: %d\n", new_sys_time-sys_time);
	sys_time = new_sys_time;
	
	{
		int redScale = 0xFF;
		int greenScale = 0xFF - d;
		int blueScale = 0xFF - d;
		byte *cptr;
		byte *cur;
		int num;
		int color;
	
		cptr = _currentPalette + start * 3;
		cur = _currentPalette + start * 3;
		num = end - start + 1;

		do {
			color = *cptr++;
			if (redScale != 0xFF)
				color = color * redScale / 0xFF;
			if (color > 255)
				color = 255;
			*cur++ = color;

			color = *cptr++;
			if (greenScale != 0xFF)
				color = color * greenScale / 0xFF;
			if (color > 255)
				color = 255;
			*cur++ = color;

			color = *cptr++;
			if (blueScale != 0xFF)
				color = color * blueScale / 0xFF;
			if (color > 255)
				color = 255;
			*cur++ = color;
		} while (--num);
		setDirtyColors(start, end);
	}
}

void Scumm::pauseGame(bool user)
{
	//_gui->pause();
	_newgui->pauseDialog();
}

void Scumm::setOptions()
{
	_gui->options();
	//_newgui->optionsDialog();
}

void Scumm::shutDown(int i)
{
	/* TODO: implement this */
	warning("shutDown: not implemented");
}

void Scumm::processKbd()
{
	int saveloadkey;
	getKeyInput(0);

	if (_features & GF_OLD256) /* FIXME: Support ingame screen */
		saveloadkey = 319;
	else
		saveloadkey = _vars[VAR_SAVELOADDIALOG_KEY];

	_virtual_mouse_x = mouse.x + virtscr[0].xstart;



	if(_features & GF_AFTER_V7)
		_virtual_mouse_y = mouse.y + camera._cur.y-100;
	else
		_virtual_mouse_y = mouse.y;

	if (!(_features & GF_OLD256))
		_virtual_mouse_y += virtscr[0].topline;
	else
		_virtual_mouse_y -= 16;

	if (_virtual_mouse_y < 0)
		_virtual_mouse_y = -1;

	if (_features & GF_OLD256) {
		if (_virtual_mouse_y >= virtscr[0].height + virtscr[0].topline)
			_virtual_mouse_y = -1;
	} else {
		if (_virtual_mouse_y >= virtscr[0].height)
			_virtual_mouse_y = -1;
	}

	if (!_lastKeyHit)
		return;

	if (_lastKeyHit == KEY_SET_OPTIONS) {
		setOptions();
		return;
	}

	if (_lastKeyHit == _vars[VAR_RESTART_KEY]) {
		warning("Restart not implemented");
//    pauseGame(true);
		return;
	}

	if (_lastKeyHit == _vars[VAR_PAUSE_KEY]) {
		pauseGame(true);
		/* pause */
		return;
	}

	if (_lastKeyHit == _vars[VAR_CUTSCENEEXIT_KEY]) {
		if (_insaneState) {
			videoFinished = 1;
		} else
			exitCutscene();
	} else if (_lastKeyHit == saveloadkey
						 && _currentRoom != 0) {
		if (_features & GF_AFTER_V7)
			runScript(_vars[VAR_UNK_SCRIPT], 0, 0, 0);
		_gui->saveLoadDialog();
		if (_features & GF_AFTER_V7)
			runScript(_vars[VAR_UNK_SCRIPT_2], 0, 0, 0);
	} else if (_lastKeyHit == _vars[VAR_TALKSTOP_KEY]) {
		_talkDelay = 0;
		if (_sound->_sfxMode == 2)
			stopTalk();
		return;
	} else if (_lastKeyHit == '[') { // [, eg volume down
		_sound->_sound_volume_master-=5;
		if (_sound->_sound_volume_master < 0)
			_sound->_sound_volume_master = 0;
		_imuse->set_master_volume(_sound->_sound_volume_master);
	} else if (_lastKeyHit == ']') { // ], eg volume down
		_sound->_sound_volume_master+=5;
		if (_sound->_sound_volume_master > 128)
			_sound->_sound_volume_master = 128;		
		_imuse->set_master_volume(_sound->_sound_volume_master);
	} else if (_lastKeyHit == '-') { // -, eg text speed down
		_defaultTalkDelay+=5;
		if (_defaultTalkDelay > 90)
			_defaultTalkDelay = 90;

		_vars[VAR_CHARINC] = _defaultTalkDelay / 20;
	} else if (_lastKeyHit == '+') { // +, eg text speed up
		_defaultTalkDelay-=5;
		if (_defaultTalkDelay < 5)
			_defaultTalkDelay = 5;

		_vars[VAR_CHARINC] = _defaultTalkDelay / 20;
	} else if (_lastKeyHit == 321) { // F7, display new GUI
		_newgui->saveloadDialog();
	}
			
	_mouseButStat = _lastKeyHit;
}

int Scumm::getKeyInput(int a)
{
	_mouseButStat = 0;

	_lastKeyHit = checkKeyHit();
	if (a == 0)
		convertKeysToClicks();

	if (mouse.x < 0)
		mouse.x = 0;
	if (mouse.x > _realWidth-1)
		mouse.x = _realWidth-1;
	if (mouse.y < 0)
		mouse.y = 0;
	if (mouse.y > _realHeight-1)
		mouse.y = _realHeight-1;

	if (_leftBtnPressed & msClicked && _rightBtnPressed & msClicked) {
		_mouseButStat = 0;
		_lastKeyHit = _vars[VAR_CUTSCENEEXIT_KEY];
	} else if (_leftBtnPressed & msClicked) {
		_mouseButStat = MBS_LEFT_CLICK;
	} else if (_rightBtnPressed & msClicked) {
		_mouseButStat = MBS_RIGHT_CLICK;
	}

	if (_features & GF_AFTER_V7) {
//    _vars[VAR_LEFTBTN_DOWN] = (_leftBtnPressed&msClicked) != 0;
		_vars[VAR_LEFTBTN_HOLD] = (_leftBtnPressed & msDown) != 0;
//    _vars[VAR_RIGHTBTN_DOWN] = (_rightBtnPressed&msClicked) != 0;
		_vars[VAR_RIGHTBTN_HOLD] = (_rightBtnPressed & msDown) != 0;
	}

	_leftBtnPressed &= ~msClicked;
	_rightBtnPressed &= ~msClicked;

	return _lastKeyHit;
}

void Scumm::convertKeysToClicks()
{
	if (_lastKeyHit && _cursorState > 0) {
		if (_lastKeyHit == 9) {
			_mouseButStat = MBS_RIGHT_CLICK;
		} else if (_lastKeyHit == 13) {
			_mouseButStat = MBS_LEFT_CLICK;
		} else
			return;
		_lastKeyHit = 0;
	}
}

Actor *Scumm::derefActor(int id)
{
	return &_actors[id];
}

Actor *Scumm::derefActorSafe(int id, const char *errmsg)
{
	if (id < 1 || id >= NUM_ACTORS) {
		if (_debugMode)
		warning
			("Invalid actor %d in %s (script %d, opcode 0x%x) - This is potentially a BIG problem.",
			 id, errmsg, vm.slot[_curExecScript].number, _opcode);
		return NULL;
	}
	return derefActor(id);
}

void Scumm::makeCursorColorTransparent(int a)
{
	int i, size;

	size = _cursorWidth * _cursorHeight;

	for (i = 0; i < size; i++)
		if (_grabbedCursor[i] == (byte)a)
			_grabbedCursor[i] = 0xFF;

	updateCursor();
}

void Scumm::setStringVars(int slot)
{
	StringTab *st = &string[slot];
	st->xpos = st->t_xpos;
	st->ypos = st->t_ypos;
	st->center = st->t_center;
	st->overhead = st->t_overhead;
	st->no_talk_anim = st->t_no_talk_anim;
	st->right = st->t_right;
	st->color = st->t_color;
	st->charset = st->t_charset;
}

void Scumm::unkMiscOp9()
{
	warning("stub unkMiscOp9()");
}

void Scumm::startManiac()
{
	warning("stub startManiac()");
}

void Scumm::destroy()
{
	freeResources();

	free(_objectStateTable);
	free(_objectRoomTable);
	free(_objectOwnerTable);
	free(_inventory);
	free(_arrays);
	free(_verbs);
	free(_objs);
	free(_vars);
	free(_bitVars);
	free(_newNames);
	free(_classData);
}

const int new_dir_table[4] = {
	270,
	90,
	180,
	0,
};

const int16 many_direction_tab[16] = {71, 109, 251, 289, -1, -1, -1, -1, 22, 72, 107, 157, 202, 252, 287, 337};

int newDirToOldDir(int dir)
{
	if (dir >= 71 && dir <= 109)
		return 1;
	if (dir >= 109 && dir <= 251)
		return 2;
	if (dir >= 251 && dir <= 289)
		return 0;
	return 3;
}

int oldDirToNewDir(int dir)
{
	return new_dir_table[dir];
}


int numSimpleDirDirections(int dirType)
{
	return dirType ? 8 : 4;
}


/* Convert an angle to a simple direction */
int toSimpleDir(int dirType, int dir)
{
	int num = dirType ? 8 : 4;
	const int16 *dirtab = &many_direction_tab[dirType * 8];
	for (int i = 1; i < num; i++, dirtab++) {
		if (dir >= dirtab[0] && dir <= dirtab[1])
			return i;
	}
	return 0;

}

/* Convert a simple direction to an angle */
int fromSimpleDir(int dirType, int dir)
{
	if (!dirType)
		return dir * 90;
	else
		return dir * 45;
}


int normalizeAngle(int angle)
{
	int temp;

	temp = (angle + 360) % 360;

	return toSimpleDir(1, temp) * 45;
}

void NORETURN CDECL error(const char *s, ...)
{
	char buf[1024];
#if defined( USE_WINDBG ) || defined ( _WIN32_WCE )
	char buf2[1024];
#if defined( _WIN32_WCE )
	TCHAR buf2w[2048];
#endif
#endif

	va_list va;

	va_start(va, s);
	vsprintf(buf, s, va);
	va_end(va);

	if (g_scumm && g_scumm->_currentScript != 0xFF) {
		ScriptSlot *ss = &g_scumm->vm.slot[g_scumm->_currentScript];
		fprintf(stderr, "Error(%d:%d:0x%X): %s!\n",
						g_scumm->_roomResource,
						ss->number,
						g_scumm->_scriptPointer - g_scumm->_scriptOrgPointer, buf);
#if defined( USE_WINDBG ) || defined( _WIN32_WCE )
		sprintf(buf2, "Error(%d:%d:0x%X): %s!\n",
			g_scumm->_roomResource,
			ss->number,
			g_scumm->_scriptPointer - g_scumm->_scriptOrgPointer,
			buf);
#if defined ( _WIN32_WCE )	
			MultiByteToWideChar(CP_ACP, 0, buf2, strlen(buf2) + 1, buf2w, sizeof(buf2w));
			GraphicsOff();
			MessageBox(NULL, buf2w, TEXT("ScummVM error"), MB_OK);
#else
			OutputDebugString(buf2);
#endif
#endif

	} else {
		fprintf(stderr, "Error: %s!\n", buf);
#if defined( USE_WINDBG ) || defined( _WIN32_WCE )
		sprintf(&buf[strlen(buf)], "\n");
#if defined ( _WIN32_WCE )	
			MultiByteToWideChar(CP_ACP, 0, buf, strlen(buf) + 1, buf2w, sizeof(buf2w));
			GraphicsOff();
			MessageBox(NULL, buf2w, TEXT("ScummVM error"), MB_OK);
#else
			OutputDebugString(buf);
#endif
#endif
	}
	// Doesn't wait for any keypress!! Is it intended to?
	exit(1);
}

void CDECL warning(const char *s, ...)
{
	char buf[1024];
	va_list va;

	va_start(va, s);
	vsprintf(buf, s, va);
	va_end(va);

	fprintf(stderr, "WARNING: %s!\n", buf);
#if defined( USE_WINDBG )
	sprintf(&buf[strlen(buf)], "\n");
	OutputDebugString(buf);
#endif
}

uint16 _debugLevel = 1;

void CDECL debug(int level, const char *s, ...)
{
	char buf[1024];
	va_list va;

	if (level > _debugLevel)
		return;

	va_start(va, s);
	vsprintf(buf, s, va);
	va_end(va);
	printf("%s\n", buf);

#if defined( USE_WINDBG )
	sprintf(&buf[strlen(buf)], "\n");
	OutputDebugString(buf);
#endif

	fflush(stdout);
}

void checkHeap()
{
#if defined(WIN32)
	if (_heapchk() != _HEAPOK) {
		error("Heap is invalid!");
	}
#endif
}

ScummDebugger g_debugger;

void Scumm::waitForTimer(int msec_delay) {
	OSystem::Event event;
	uint32 start_time;

	if (_fastMode&2)
		msec_delay = 0;
	else if (_fastMode&1)
		msec_delay = 10;

	start_time = _system->get_msecs();

	for(;;) {
		while (_system->poll_event(&event)) {

			// if newgui is running, copy event to EventList, and let the GUI handle it itself
			// we might consider this approach for ScummLoop as well, and clean up the current mess
			if (_newgui->isActive()) {
				if (event.event_code == OSystem::EVENT_MOUSEMOVE) {
					mouse.x = event.mouse.x;
					mouse.y = event.mouse.y;
					_system->set_mouse_pos(event.mouse.x, event.mouse.y);
					_system->update_screen();
				}
				_newgui->handleEvent(event);
				continue;
			}

			switch(event.event_code) {
			case OSystem::EVENT_KEYDOWN:
				if (event.kbd.keycode >= '0' && event.kbd.keycode<='9'
					&& (event.kbd.flags == OSystem::KBD_SHIFT ||
						event.kbd.flags == OSystem::KBD_CTRL)) {
					_saveLoadSlot = event.kbd.keycode - '0';
					sprintf(_saveLoadName, "Quicksave %d", _saveLoadSlot);
					_saveLoadFlag = (event.kbd.flags == OSystem::KBD_SHIFT) ? 1 : 2;
					_saveLoadCompatible = false;
				} else if (event.kbd.flags==OSystem::KBD_CTRL) {
					if (event.kbd.keycode=='f')
						_fastMode ^= 1;
					else if (event.kbd.keycode=='g')
						_fastMode ^= 2;
					else if ((event.kbd.keycode=='d') && (!_system->property(OSystem::PROP_GET_FULLSCREEN, 0)))
						g_debugger.attach(this);
					else if (event.kbd.keycode=='s')
						resourceStats();
				} else
					_keyPressed = event.kbd.ascii;	// Normal key press, pass on to the game.
				break;

			case OSystem::EVENT_MOUSEMOVE:
				mouse.x = event.mouse.x;
				mouse.y = event.mouse.y;
				_system->set_mouse_pos(event.mouse.x, event.mouse.y);
				_system->update_screen();
				break;

			case OSystem::EVENT_LBUTTONDOWN:
				_leftBtnPressed |= msClicked|msDown;
#ifdef _WIN32_WCE
				mouse.x = event.mouse.x;
				mouse.y = event.mouse.y;
#endif
				break;

			case OSystem::EVENT_RBUTTONDOWN:
				_rightBtnPressed |= msClicked|msDown;
#ifdef _WIN32_WCE
				mouse.x = event.mouse.x;
				mouse.y = event.mouse.y;
#endif
				break;

			case OSystem::EVENT_LBUTTONUP:
				_leftBtnPressed &= ~msDown;
				break;

			case OSystem::EVENT_RBUTTONUP:
				_rightBtnPressed &= ~msDown;
				break;
			}
		}
#ifdef COMPRESSED_SOUND_FILE
		if (_sound->updateMP3CD() == -1)
#endif
			_system->update_cdrom(); /* Loop CD Audio if needed */
		if (_system->get_msecs() >= start_time + msec_delay)
			break;
		_system->delay_msecs(10);
	}
}


void Scumm::updatePalette() {
	if (_palDirtyMax == -1)
		return;
	
	int first = _palDirtyMin;
	int num = _palDirtyMax - first + 1;
	int i;

	byte palette_colors[1024],*p = palette_colors;

	// Sam & Max film noir mode
	if (_gameId == GID_SAMNMAX && readVar(0x8000))
		desaturatePalette();

	for (i = _palDirtyMin; i <= _palDirtyMax; i++) {
		byte *data;

		if (_features & GF_SMALL_HEADER)
			data = _currentPalette + _shadowPalette[i] * 3;
		else
			data = _currentPalette + i * 3;

		*p++ = data[0];
		*p++ = data[1];
		*p++ = data[2];
		*p++ = 0;

	}
	
	_system->set_palette(palette_colors, first, num);

	_palDirtyMax = -1;
	_palDirtyMin = 256;
}

void Scumm::mainRun()
{
	int delta = 0;
	int last_time = _system->get_msecs(); 
	int new_time;

	for(;;) {
		
		updatePalette();
		
		_system->update_screen();		
		new_time = _system->get_msecs();
		waitForTimer(delta * 15 + last_time - new_time);
		last_time = _system->get_msecs();
		if (_gui->isActive()) {
			_gui->loop();
			delta = 5;
		} else if (_newgui->isActive()) {
			_newgui->loop();
			delta = 5;
		} else {
			delta = scummLoop(delta);
			if (delta < 1)	// Ensure we don't get into a loop
				delta = 1;  // by not decreasing sleepers.
		}
	}
}

void Scumm::launch()
{
	charset._vm = this;
	gdi._vm = this;
	_fileHandle = NULL;

	_maxHeapThreshold = 450000;
	_minHeapThreshold = 400000;

	/* Create a primary virtual screen */
	_videoBuffer = (byte *)calloc(328*200, 1);

	allocResTypeData(rtBuffer, MKID('NONE'), 10, "buffer", 0);
	initVirtScreen(0, 0, 0, 320, 200, false, false);

	if (_features & GF_AFTER_V7)
		setupScummVarsNew();
	else
		setupScummVarsOld();

	if ((_features & GF_AFTER_V7) || (_gameId == GID_SAMNMAX))
		NUM_ACTORS = 30;
	else
		NUM_ACTORS = 13;

	if (_features & GF_AFTER_V7)
		OF_OWNER_ROOM = 0xFF;
	else
		OF_OWNER_ROOM = 0x0F;

	// if (_gameId==GID_MONKEY2 && _bootParam == 0)
	//	_bootParam = 10001;

	if (_gameId == GID_INDY4 && _bootParam == 0) {
		_bootParam = -7873;
	}

	readIndexFile();

	initRandSeeds();

	if (_features & GF_NEW_OPCODES)
		setupOpcodes2();
	else
		setupOpcodes();

	scummInit();

	if (!(_features & GF_AFTER_V7))
		_vars[VAR_VERSION] = 21;

	_vars[VAR_DEBUGMODE] = _debugMode;

	if (_gameId == GID_MONKEY)
		_vars[74] = 1225;

	_sound->setupSound();

	runScript(1, 0, 0, &_bootParam);

//  _scummTimer = 0;
}

void Scumm::go() {
	launch();
	setupGUIColors();
	mainRun();
}


byte Scumm::getDefaultGUIColor(int color)
{
	/* FIXME: strange IF line? */
	if ((_features & GF_AFTER_V7) || (_features & GF_SMALL_HEADER))
		return 0;
	if (_features & GF_AFTER_V6) {
		if (color == 8)
			color = 1;
		return readArray(110, 0, color);
	} else {
		return getStringAddress(21)[color];
	}
}

void Scumm::setupGUIColors() {

	/* FIXME: strange IF line? */
	if (_gameId && !(_features & GF_SMALL_HEADER)	&& !(_features & GF_AFTER_V7)) {
		_gui->_bgcolor = getDefaultGUIColor(0);
		_gui->_color = getDefaultGUIColor(1);
		_gui->_textcolor = getDefaultGUIColor(2);
		_gui->_textcolorhi = getDefaultGUIColor(6);
		_gui->_shadowcolor = getDefaultGUIColor(8);

		_newgui->_bgcolor = _gui->_bgcolor;
		_newgui->_color = _gui->_color;
		_newgui->_textcolor = _gui->_textcolor;
		_newgui->_textcolorhi = _gui->_textcolorhi;
		_newgui->_shadowcolor = _gui->_shadowcolor;
	}
}