diff options
Diffstat (limited to 'sky')
| -rw-r--r-- | sky/control.cpp | 405 | ||||
| -rw-r--r-- | sky/control.h | 44 | ||||
| -rw-r--r-- | sky/grid.cpp | 28 | ||||
| -rw-r--r-- | sky/logic.cpp | 25 | ||||
| -rw-r--r-- | sky/logic.h | 14 | ||||
| -rw-r--r-- | sky/screen.cpp | 36 | ||||
| -rw-r--r-- | sky/screen.h | 3 | ||||
| -rw-r--r-- | sky/sky.cpp | 15 | 
8 files changed, 503 insertions, 67 deletions
diff --git a/sky/control.cpp b/sky/control.cpp index 4f2a1249ad..0126255f94 100644 --- a/sky/control.cpp +++ b/sky/control.cpp @@ -115,15 +115,17 @@ void SkyTextResource::drawToScreen(bool doMask) {  	_system->copy_rect(_screen + _y * GAME_SCREEN_WIDTH + _x, GAME_SCREEN_WIDTH, _x, _y, cpWidth, PAN_CHAR_HEIGHT);  } -SkyControl::SkyControl(SkyScreen *screen, SkyDisk *disk, SkyMouse *mouse, SkyText *text, SkyMusicBase *music, OSystem *system, const char *savePath) { +SkyControl::SkyControl(SkyScreen *screen, SkyDisk *disk, SkyMouse *mouse, SkyText *text, SkyMusicBase *music, SkyLogic *logic, OSystem *system, const char *savePath) {  	_skyScreen = screen;  	_skyDisk = disk;  	_skyMouse = mouse;  	_skyText = text;  	_skyMusic = music; +	_skyLogic = logic;  	_system = system;  	_savePath = savePath; +	_memListRoot = NULL;  }  SkyConResource *SkyControl::createResource(void *pSpData, uint32 pNSprites, uint32 pCurSprite, int16 pX, int16 pY, uint32 pText, uint8 pOnClick, uint8 panelType) { @@ -351,20 +353,24 @@ uint16 SkyControl::handleClick(SkyConResource *pButton) {  			return 0;  		case REST_GAME_PANEL: +			if (SkyState::_systemVars.systemFlags & SF_CHOOSING) +				return CANCEL_PRESSED; // can't save/restore while choosing  			animClick(pButton);  			return saveRestorePanel(false); // texts can't be edited  		case SAVE_GAME_PANEL: +			if (SkyState::_systemVars.systemFlags & SF_CHOOSING) +				return CANCEL_PRESSED; // can't save/restore while choosing  			animClick(pButton);  			return saveRestorePanel(true); // texts can be edited  		case SAVE_A_GAME:  			animClick(pButton); -			return GAME_SAVED; +			return saveGameToFile();  		case RESTORE_A_GAME:  			animClick(pButton); -			return GAME_RESTORED; +			return restoreGameFromFile();  		case SP_CANCEL:  			animClick(pButton); @@ -577,14 +583,15 @@ uint16 SkyControl::shiftUp(uint8 speed) {  	return SHIFTED;  } -uint16 SkyControl::saveRestorePanel(bool allowEdit) { +uint16 SkyControl::saveRestorePanel(bool allowSave) { +	_keyPressed = 0;  	buttonControl(NULL);  	_text->drawToScreen(WITH_MASK); // flush text restore buffer  	SkyConResource **lookList;  	uint16 cnt; -	if (allowEdit) lookList = _savePanLookList; +	if (allowSave) lookList = _savePanLookList;  	else lookList = _restorePanLookList;  	uint8 *saveGameTexts = (uint8*)malloc(MAX_SAVE_GAMES * MAX_TEXT_LEN); @@ -594,15 +601,15 @@ uint16 SkyControl::saveRestorePanel(bool allowEdit) {  	_savePanel->drawToScreen(NO_MASK);  	_quitButton->drawToScreen(NO_MASK); -	loadSaveDescriptions(saveGameTexts); -	uint16 selectedGame = 0; +	loadDescriptions(saveGameTexts); +	_selectedGame = 0;  	bool quitPanel = false;  	bool refreshNames = true;  	uint16 clickRes = 0;  	while (!quitPanel) {  		if (refreshNames) { -			setUpGameSprites(saveGameTexts, textSprites, _firstText); +			setUpGameSprites(saveGameTexts, textSprites, _firstText, _selectedGame, allowSave);  			showSprites(textSprites);  			refreshNames = false;  		} @@ -615,6 +622,10 @@ uint16 SkyControl::saveRestorePanel(bool allowEdit) {  			_mouseClicked = false;  			clickRes = CANCEL_PRESSED;  			quitPanel = true; +		} else if (allowSave && _keyPressed) { +			handleKeyPress(_keyPressed, _selectedGame * MAX_TEXT_LEN + saveGameTexts); +			refreshNames = true; +			_keyPressed = 0;  		}  		bool haveButton = false; @@ -628,11 +639,19 @@ uint16 SkyControl::saveRestorePanel(bool allowEdit) {  					clickRes = handleClick(lookList[cnt]); -			        if ((clickRes == CANCEL_PRESSED) || (clickRes == GAME_SAVED) ||  -						(clickRes == GAME_RESTORED) || (clickRes == NO_DISK_SPACE)) -						quitPanel = true; -					if (clickRes == SHIFTED) +			        if (clickRes == SHIFTED) { +						_selectedGame = _firstText;  						refreshNames = true; +					} +					if ((clickRes == CANCEL_PRESSED) || (clickRes == NO_DISK_SPACE) ||  +						(clickRes == GAME_RESTORED)) +						quitPanel = true; + +					if (clickRes == GAME_SAVED) { +						saveDescriptions(saveGameTexts); +						quitPanel = true; +					} +						   				}  			} @@ -640,7 +659,8 @@ uint16 SkyControl::saveRestorePanel(bool allowEdit) {  			if ((_mouseX >= GAME_NAME_X) && (_mouseX <= GAME_NAME_X + PAN_LINE_WIDTH) &&  				(_mouseY >= GAME_NAME_Y) && (_mouseY <= GAME_NAME_Y + PAN_CHAR_HEIGHT * MAX_ON_SCREEN)) { -					selectedGame = (_mouseY - GAME_NAME_Y) / PAN_CHAR_HEIGHT + _firstText; +					_selectedGame = (_mouseY - GAME_NAME_Y) / PAN_CHAR_HEIGHT + _firstText; +					refreshNames = true;  			}  		}  		if (!haveButton) buttonControl(NULL); @@ -654,14 +674,59 @@ uint16 SkyControl::saveRestorePanel(bool allowEdit) {      return clickRes;  } -void SkyControl::setUpGameSprites(uint8 *nameBuf, dataFileHeader **nameSprites, uint16 firstNum) { +bool SkyControl::checkKeyList(uint8 key) { +	static const uint8 charList[14] = " ,().='-&+!?\""; +	for (uint chCnt = 0; chCnt < ARRAYSIZE(charList); chCnt++) +		if (charList[chCnt] == key) return true; +	return false; +} + +void SkyControl::handleKeyPress(uint8 key, uint8 *textBuf) { + +	if (key == 8) { // backspace +		for (uint8 cnt = 0; cnt < 6; cnt++) +			if (!textBuf[cnt]) return; + +		while (textBuf[1]) +			textBuf++; +		textBuf[0] = 0; +	} else { +        if (((key >= 'A') && (key <= 'Z')) || ((key >= 'a') && (key <= 'z')) || +			((key >= '0') && (key <= '9')) || checkKeyList(key)) { +				uint8 strLen = 0; +				while (textBuf[0]) { +					textBuf++; +					strLen++; +				} +				if (strLen < MAX_TEXT_LEN) { +                    textBuf[0] = key; +					textBuf[1] = 0; +				} +		} +	} +} + +void SkyControl::setUpGameSprites(uint8 *nameBuf, dataFileHeader **nameSprites, uint16 firstNum, uint16 selectedGame, bool allowSave) {  	nameBuf += firstNum * MAX_TEXT_LEN;  	for (uint16 cnt = 0; cnt < MAX_ON_SCREEN; cnt++) { -		displayText_t textSpr = _skyText->displayText((char*)nameBuf, NULL, false, PAN_LINE_WIDTH, 37); +		displayText_t textSpr; +		if (firstNum + cnt == selectedGame) { +			char tmpLine[MAX_TEXT_LEN + 2]; +			memcpy(tmpLine, nameBuf, MAX_TEXT_LEN); +			if (allowSave) +				strcat(tmpLine,"_"); +			textSpr = _skyText->displayText(tmpLine, NULL, false, PAN_LINE_WIDTH, 0); +		} else { +			textSpr = _skyText->displayText((char*)nameBuf, NULL, false, PAN_LINE_WIDTH, 37); +		}  		nameBuf += MAX_TEXT_LEN;  		nameSprites[cnt] = (dataFileHeader*)textSpr.textData; +		if (firstNum + cnt == selectedGame) +			nameSprites[cnt]->flag = 1; +		else +			nameSprites[cnt]->flag = 0;  	}  } @@ -671,17 +736,23 @@ void SkyControl::showSprites(dataFileHeader **nameSprites) {  	for (uint16 cnt = 0; cnt < MAX_ON_SCREEN; cnt++) {  		drawResource->setSprite(nameSprites[cnt]);  		drawResource->setXY(GAME_NAME_X, GAME_NAME_Y + cnt * PAN_CHAR_HEIGHT); -		drawResource->drawToScreen(NO_MASK); +		if (nameSprites[cnt]->flag) { // name is highlighted +			for (uint16 cnty = GAME_NAME_Y + cnt * PAN_CHAR_HEIGHT; cnty < GAME_NAME_Y + (cnt + 1) * PAN_CHAR_HEIGHT - 1; cnty++) +				memset(_screenBuf + cnty * GAME_SCREEN_WIDTH + GAME_NAME_X, 37, PAN_LINE_WIDTH); +			drawResource->drawToScreen(WITH_MASK); +			_system->copy_rect(_screenBuf + (GAME_NAME_Y + cnt * PAN_CHAR_HEIGHT) * GAME_SCREEN_WIDTH + GAME_NAME_X, GAME_SCREEN_WIDTH, GAME_NAME_X, GAME_NAME_Y + cnt * PAN_CHAR_HEIGHT, PAN_LINE_WIDTH, PAN_CHAR_HEIGHT); +		} else  +			drawResource->drawToScreen(NO_MASK);  	}  	delete drawResource;  } -void SkyControl::loadSaveDescriptions(uint8 *destBuf) { +void SkyControl::loadDescriptions(uint8 *destBuf) {  	memset(destBuf, 0, MAX_SAVE_GAMES * MAX_TEXT_LEN);  	File *inf = new File(); -	inf->open("SKY.SAV",_savePath); +	inf->open("SKY-VM.SAV",_savePath);  	if (inf->isOpen()) {  		uint8 *tmpBuf = (uint8*)malloc(inf->size());  		inf->read(tmpBuf, inf->size()); @@ -706,15 +777,42 @@ void SkyControl::loadSaveDescriptions(uint8 *destBuf) {  	}  } -uint16 SkyControl::saveGameToFile(char *fName) { +void SkyControl::saveDescriptions(uint8 *srcBuf) { + +	uint8 *tmpBuf = (uint8*)malloc(MAX_SAVE_GAMES * MAX_TEXT_LEN); +	uint8 *tmpPos = tmpBuf; +	uint8 *srcPos = srcBuf; +	for (uint16 cnt = 0; cnt < MAX_SAVE_GAMES; cnt++) { +		uint8 namePos = 5; +		while (srcPos[namePos]) { +			if (srcPos[namePos] != '_') { +				*tmpPos = srcPos[namePos]; +				tmpPos++; +			} +			namePos++; +		} +		*tmpPos = 0; +		tmpPos++; +		srcPos += MAX_TEXT_LEN; +	} +	File *outf = new File(); +	outf->open("SKY-VM.SAV", _savePath, File::kFileWriteMode); +	outf->write(tmpBuf, tmpPos - tmpBuf); +	outf->close(); +	free(tmpBuf);	 +} +uint16 SkyControl::saveGameToFile(void) { + +	char fName[20]; +	sprintf(fName,"SKY-VM.%03d", _selectedGame);  	File *outf = new File();  	if (!outf->open(fName, _savePath, File::kFileWriteMode)) {  		delete outf;  		return NO_DISK_SPACE;  	} -	uint8 *saveData = (uint8*)malloc(0x20000); +	uint8 *saveData = (uint8*)malloc(0x50000);  	uint32 fSize = prepareSaveData(saveData);  	if (outf->write(saveData, fSize) != fSize) { @@ -739,6 +837,23 @@ void SkyControl::stosMegaSet(uint8 **destPos, MegaSet *mega) {  	// anims, stands, turnTable  } +void SkyControl::stosStr(uint8 **destPos, uint16 *src, bool isGraf) { +	uint16 strLen = 0; +	if (isGraf) { +		while (src[strLen] || src[strLen+2]) +			strLen++; +		strLen += 3; +	} else { +		while (src[strLen]) +			strLen++; +		strLen++; +	} +	STOSW(*destPos, strLen); +	for (uint16 cnt = 0; cnt < strLen; cnt++) { +		STOSW(*destPos, src[cnt]); +	} +} +  void SkyControl::stosCompact(uint8 **destPos, Compact *cpt) {  	uint16 saveType = 0;  	if (cpt->extCompact) { @@ -747,8 +862,17 @@ void SkyControl::stosCompact(uint8 **destPos, Compact *cpt) {  		if (cpt->extCompact->megaSet1) saveType |= SAVE_MEGA1;  		if (cpt->extCompact->megaSet2) saveType |= SAVE_MEGA2;  		if (cpt->extCompact->megaSet3) saveType |= SAVE_MEGA3; +		if (cpt->extCompact->turnProg) saveType |= SAVE_TURNP;  	} +	if (cpt->grafixProg) saveType |= SAVE_GRAFX; +  	STOSW(*destPos, saveType); + +	if (saveType & SAVE_GRAFX) +		stosStr(destPos, cpt->grafixProg, true); +	if (saveType & SAVE_TURNP) +		stosStr(destPos, cpt->extCompact->turnProg, false); +  	STOSW(*destPos, cpt->logic);  	STOSW(*destPos, cpt->status);  	STOSW(*destPos, cpt->sync); @@ -815,21 +939,13 @@ void SkyControl::stosCompact(uint8 **destPos, Compact *cpt) {  	}  } -void SkyControl::stosAR(uint8 **destPos, uint8 *arData) { - -	uint16 *data = (uint16*)arData; -	for (uint8 cnt = 0; cnt < 32; cnt++) -		STOSW(*destPos, TO_LE_16(data[cnt])); -} -  uint32 SkyControl::prepareSaveData(uint8 *destBuf) {  	uint32 cnt;  	memset(destBuf, 0, 4); // space for data size  	uint8 *destPos = destBuf + 4; -	memcpy(destPos, SAVE_HEADER, sizeof(SAVE_HEADER)); -	destPos += sizeof(SAVE_HEADER); -	//STOSD(destPos, SkyLogic::_scriptVariables[CUR_SECTION]); +	STOSD(destPos, SAVE_FILE_REVISION); +  	STOSD(destPos, _skyMusic->giveCurrentMusic());  	//TODO: save queued sfx @@ -846,9 +962,6 @@ uint32 SkyControl::prepareSaveData(uint8 *destBuf) {  	for (cnt = 0; cnt < ARRAYSIZE(_saveLoadCpts); cnt++)  		stosCompact(&destPos, _saveLoadCpts[cnt]); -	for (cnt = 0; cnt < ARRAYSIZE(_saveLoadARs); cnt++) -		stosAR(&destPos, _saveLoadARs[cnt]); -  	for (cnt = 0; cnt < 3; cnt++)  		STOSW(destPos, SkyCompact::park_table[cnt]); @@ -862,6 +975,232 @@ uint32 SkyControl::prepareSaveData(uint8 *destBuf) {  #undef STOSD  #undef STOSW +void SkyControl::appendMemList(uint16 *pMem) { +	AllocedMem *newMem = new AllocedMem; +	newMem->mem = pMem; +	newMem->next = _memListRoot; +	_memListRoot = newMem; +} + +void SkyControl::freeMemList(void) { +	AllocedMem *block = _memListRoot; +	AllocedMem *temp; +	while (block) { +		temp = block; +		free(block->mem); +		block = block->next; +		delete temp; +	} +	_memListRoot = NULL; +} + + +#define LODSD(strPtr, val) { val = READ_LE_UINT32(strPtr); (strPtr) += 4; } +#define LODSW(strPtr, val) { val = READ_LE_UINT16(strPtr); (strPtr) += 2; } + +void SkyControl::lodsMegaSet(uint8 **srcPos, MegaSet *mega) { +	LODSW(*srcPos, mega->gridWidth); +	LODSW(*srcPos, mega->colOffset); +	LODSW(*srcPos, mega->colWidth); +	LODSW(*srcPos, mega->lastChr); +	// anims, stands, turnTable +} + +void SkyControl::lodsCompact(uint8 **srcPos, Compact *cpt) { + +	uint16 saveType, cnt; +	LODSW(*srcPos, saveType); +	if ((saveType & (SAVE_EXT | SAVE_TURNP)) && (cpt->extCompact == NULL)) +		error("Can't restore! SaveData is SAVE_EXT for Compact"); +	if ((saveType & SAVE_MEGA0) && (cpt->extCompact->megaSet0 == NULL)) +		error("Can't restore! SaveData is SAVE_MEGA0 for Compact"); +	if ((saveType & SAVE_MEGA1) && (cpt->extCompact->megaSet1 == NULL)) +		error("Can't restore! SaveData is SAVE_MEGA1 for Compact"); +	if ((saveType & SAVE_MEGA2) && (cpt->extCompact->megaSet2 == NULL)) +		error("Can't restore! SaveData is SAVE_MEGA2 for Compact"); +	if ((saveType & SAVE_MEGA3) && (cpt->extCompact->megaSet3 == NULL)) +		error("Can't restore! SaveData is SAVE_MEGA3 for Compact"); + +	if (saveType & SAVE_GRAFX) { +		uint16 grafxLen; +		LODSW(*srcPos, grafxLen); +		cpt->grafixProg = (uint16*)malloc(grafxLen << 1); +		appendMemList(cpt->grafixProg); +		for (cnt = 0; cnt < grafxLen; cnt++) { +			LODSW(*srcPos, cpt->grafixProg[cnt]); +		} +	} else +		cpt->grafixProg = NULL; + +	if (saveType & SAVE_TURNP) { +		uint16 turnLen; +		LODSW(*srcPos, turnLen); +		cpt->extCompact->turnProg = (uint16*)malloc(turnLen << 1); +		appendMemList(cpt->extCompact->turnProg); +		for (cnt = 0; cnt < turnLen; cnt++) +			LODSW(*srcPos, cpt->extCompact->turnProg[cnt]); +	} else if (cpt->extCompact) +		cpt->extCompact->turnProg = NULL; + +	LODSW(*srcPos, cpt->logic); +	LODSW(*srcPos, cpt->status); +	LODSW(*srcPos, cpt->sync); +	LODSW(*srcPos, cpt->screen); +	LODSW(*srcPos, cpt->place); +	// getToTable +	LODSW(*srcPos, cpt->xcood); +	LODSW(*srcPos, cpt->ycood); +	LODSW(*srcPos, cpt->frame); +	LODSW(*srcPos, cpt->cursorText); +	LODSW(*srcPos, cpt->mouseOn); +	LODSW(*srcPos, cpt->mouseOff); +	LODSW(*srcPos, cpt->mouseClick); +	LODSW(*srcPos, cpt->mouseRelX); +	LODSW(*srcPos, cpt->mouseRelY); +	LODSW(*srcPos, cpt->mouseSizeX); +	LODSW(*srcPos, cpt->mouseSizeY); +	LODSW(*srcPos, cpt->actionScript); +	LODSW(*srcPos, cpt->upFlag); +	LODSW(*srcPos, cpt->downFlag); +	LODSW(*srcPos, cpt->getToFlag); +	LODSW(*srcPos, cpt->flag); +	LODSW(*srcPos, cpt->mood); +	// grafixProg +	LODSW(*srcPos, cpt->offset); +	LODSW(*srcPos, cpt->mode); +	LODSW(*srcPos, cpt->baseSub); +	LODSW(*srcPos, cpt->baseSub_off); +	if (saveType & SAVE_EXT) { +		LODSW(*srcPos, cpt->extCompact->actionSub); +		LODSW(*srcPos, cpt->extCompact->actionSub_off); +		LODSW(*srcPos, cpt->extCompact->getToSub); +		LODSW(*srcPos, cpt->extCompact->getToSub_off); +		LODSW(*srcPos, cpt->extCompact->extraSub); +		LODSW(*srcPos, cpt->extCompact->extraSub_off); +		LODSW(*srcPos, cpt->extCompact->dir); +		LODSW(*srcPos, cpt->extCompact->stopScript); +		LODSW(*srcPos, cpt->extCompact->miniBump); +		LODSW(*srcPos, cpt->extCompact->leaving); +		LODSW(*srcPos, cpt->extCompact->atWatch); +		LODSW(*srcPos, cpt->extCompact->atWas); +		LODSW(*srcPos, cpt->extCompact->alt); +		LODSW(*srcPos, cpt->extCompact->request); +		LODSW(*srcPos, cpt->extCompact->spWidth_xx); +		LODSW(*srcPos, cpt->extCompact->spColour); +		LODSW(*srcPos, cpt->extCompact->spTextId); +		LODSW(*srcPos, cpt->extCompact->spTime); +		LODSW(*srcPos, cpt->extCompact->arAnimIndex); +		// turnProg +		LODSW(*srcPos, cpt->extCompact->waitingFor); +		LODSW(*srcPos, cpt->extCompact->arTargetX); +		LODSW(*srcPos, cpt->extCompact->arTargetY); +		// animScratch +		LODSW(*srcPos, cpt->extCompact->megaSet); + +		if (saveType & SAVE_MEGA0) +			lodsMegaSet(srcPos, cpt->extCompact->megaSet0); +		if (saveType & SAVE_MEGA1) +			lodsMegaSet(srcPos, cpt->extCompact->megaSet1); +		if (saveType & SAVE_MEGA2) +			lodsMegaSet(srcPos, cpt->extCompact->megaSet2); +		if (saveType & SAVE_MEGA3) +			lodsMegaSet(srcPos, cpt->extCompact->megaSet3); +	} +} + +uint16 SkyControl::parseSaveData(uint8 *srcBuf) { + +	uint32 reloadList[60]; +	uint32 oldSection = SkyLogic::_scriptVariables[CUR_SECTION]; +	 +	uint32 cnt; +	uint8 *srcPos = srcBuf; +	uint32 size; +	uint32 saveRev; + +	LODSD(srcPos, size); +	LODSD(srcPos, saveRev); +	if (saveRev != SAVE_FILE_REVISION) { +		warning("Unknown save file revision (%d)",saveRev); +		return RESTORE_FAILED; +	} +	 +	freeMemList(); // memory from last restore isn't needed anymore + +	uint32 music, charSet, mouseType, palette; +	LODSD(srcPos, music); +	LODSD(srcPos, charSet); +	LODSD(srcPos, mouseType); +	LODSD(srcPos, palette); + +	for (cnt = 0; cnt < 838; cnt++) +		LODSD(srcPos, SkyLogic::_scriptVariables[cnt]); + +	for (cnt = 0; cnt < 60; cnt++) +		LODSD(srcPos, reloadList[cnt]); + +	for (cnt = 0; cnt < ARRAYSIZE(_saveLoadCpts); cnt++) +		lodsCompact(&srcPos, _saveLoadCpts[cnt]); + +	for (cnt = 0; cnt < 3; cnt++) +		LODSW(srcPos, SkyCompact::park_table[cnt]); + +	for (cnt = 0; cnt < 13; cnt++) +		LODSW(srcPos, SkyCompact::high_floor_table[cnt]); + +	if (srcPos - srcBuf != size) +		error("Restore failed! Savegame data = %d bytes. Expected size: %d.\n", srcPos-srcBuf, size); + +	_skyLogic->fnLeaveSection(oldSection, 0, 0); +	_skyLogic->fnEnterSection(SkyLogic::_scriptVariables[CUR_SECTION], 0, 0); +	_skyDisk->refreshFilesList(reloadList); +	_skyMusic->startMusic((uint16)music); +	_skyText->fnSetFont(charSet); +	_skyMouse->spriteMouse((uint16)mouseType, 0, 0); +	SkyState::_systemVars.currentPalette = palette; // will be set when doControlPanel ends +	SkyState::_systemVars.systemFlags |= SF_GAME_RESTORED; // what's that for? + +	return GAME_RESTORED; +} + +#undef LODSD +#undef LODSW + +uint16 SkyControl::restoreGameFromFile(void) { +	 +	char fName[20]; +	sprintf(fName,"SKY-VM.%03d", _selectedGame); +	File *inf = new File(); +	if (!inf->open(fName, _savePath)) { +		delete inf; +		return RESTORE_FAILED; +	} + +	uint32 fSize = inf->size(); +	uint8 *saveData = (uint8*)malloc(fSize); +	uint32 infSize = inf->readUint32LE(); +	inf->seek(0, SEEK_SET); + +	if (fSize != infSize) { +		warning("File size doesn't match expected data size!"); +		delete inf; +		free(saveData); +		return RESTORE_FAILED; +	} +	if (inf->read(saveData, fSize) != fSize) { +		warning("Can't read from file!"); +		delete inf; +		free(saveData); +		return RESTORE_FAILED; +	} + +	uint16 res = parseSaveData(saveData); +	inf->close(); +	delete inf; +	free(saveData); +	return res; +} +  void SkyControl::delay(unsigned int amount) {  	OSystem::Event event; diff --git a/sky/control.h b/sky/control.h index 62ccdc604d..ab025fbb0f 100644 --- a/sky/control.h +++ b/sky/control.h @@ -29,6 +29,7 @@  #include "sky/screen.h"  #include "sky/disk.h"  #include "sky/mouse.h" +#include "sky/logic.h"  #define MAX_SAVE_GAMES 999  #define MAX_TEXT_LEN 80 @@ -48,8 +49,6 @@  #define MAX_ON_SCREEN ((SP_HEIGHT - SP_TOP_GAP - SP_BOT_GAP) / PAN_CHAR_HEIGHT) // no of save games on screen  #define CP_PANEL 60400 // main panel sprite -#define CHARACTER_LIST " ,().='-&+!?\"" // list of allowed characters -  #define MAINPANEL 0  #define SAVEPANEL 1 @@ -100,8 +99,15 @@  #define SAVE_MEGA1	 4  #define SAVE_MEGA2	 8  #define SAVE_MEGA3	16 +#define SAVE_GRAFX	32 +#define SAVE_TURNP	64 + +#define SAVE_FILE_REVISION 1 -#define SAVE_HEADER "(C) Revolution Software Ltd 1993.\x00System 2 written by David Sykes and Tony Warriner\x0D\x0APortable implementation done by the ScummVM team\x0D\x0ASave File Revision 1\x00" +struct AllocedMem { +	uint16 *mem; +	AllocedMem *next; +};  class SkyConResource {  public: @@ -135,7 +141,7 @@ private:  class SkyControl {  public: -	SkyControl(SkyScreen *screen, SkyDisk *disk, SkyMouse *mouse, SkyText *text, SkyMusicBase *music, OSystem *system, const char *savePath); +	SkyControl(SkyScreen *screen, SkyDisk *disk, SkyMouse *mouse, SkyText *text, SkyMusicBase *music, SkyLogic *logic, OSystem *system, const char *savePath);  	void doControlPanel(void);  	void showGameQuitMsg(bool useScreen = true); @@ -145,9 +151,14 @@ private:  	void drawMainPanel(void);  	void delay(unsigned int amount);  	void buttonControl(SkyConResource *pButton); -	void loadSaveDescriptions(uint8 *destBuf); -	void setUpGameSprites(uint8 *nameBuf, dataFileHeader **nameSprites, uint16 firstNum); + +	void loadDescriptions(uint8 *destBuf); +	void saveDescriptions(uint8 *srcBuf); +	void setUpGameSprites(uint8 *nameBuf, dataFileHeader **nameSprites, uint16 firstNum, uint16 selectedGame, bool allowSave);  	void showSprites(dataFileHeader **nameSprites); +	bool checkKeyList(uint8 key); +	void handleKeyPress(uint8 key, uint8 *textBuf); +  	void animClick(SkyConResource *pButton);  	bool getYesNo(void);  	uint16 doMusicSlide(void); @@ -159,22 +170,33 @@ private:  	uint16 shiftUp(uint8 speed);  	const char *_savePath; -	uint16 saveGameToFile(char *fName); +	void appendMemList(uint16 *pMem); +	void freeMemList(void); + +	uint16 _selectedGame; +	uint16 saveGameToFile(void);  	void stosMegaSet(uint8 **destPos, MegaSet *mega);  	void stosCompact(uint8 **destPos, Compact *cpt); -	void stosAR(uint8 **destPos, uint8 *arData); +	void stosStr(uint8 **destPos, uint16 *src, bool isGraph);  	uint32 prepareSaveData(uint8 *destBuf); -	uint16 restoreGameFromFile(char *fName); + +	uint16 restoreGameFromFile(void); +	void lodsMegaSet(uint8 **srcPos, MegaSet *mega); +	void lodsCompact(uint8 **srcPos, Compact *cpt); +	void lodsStr(uint8 **srcPos, uint16 *src); +	uint16 parseSaveData(uint8 *srcBuf); +  	static Compact *_saveLoadCpts[833]; // \  moved to sky/compacts/savedata.cpp  	static uint8 *_saveLoadARs[18];     // / -	uint16 saveRestorePanel(bool allowEdit); +	uint16 saveRestorePanel(bool allowSave);  	SkyScreen *_skyScreen;  	SkyDisk *_skyDisk;  	SkyMouse *_skyMouse;  	SkyText *_skyText;  	SkyMusicBase *_skyMusic; +	SkyLogic *_skyLogic;  	OSystem *_system;  	int _mouseX, _mouseY;  	bool _mouseClicked; @@ -195,6 +217,8 @@ private:  		uint8 *musicBodge;  	} _sprites; +	AllocedMem *_memListRoot; +  	uint8 *_screenBuf;  	int _lastButton;  	uint32 _curButtonText; diff --git a/sky/grid.cpp b/sky/grid.cpp index db08bfa9fc..4f4e4886b0 100644 --- a/sky/grid.cpp +++ b/sky/grid.cpp @@ -161,23 +161,25 @@ bool SkyGrid::getGridValues(uint32 x, uint32 y, uint32 width, Compact *cpt, uint  	if (y < TOP_LEFT_Y) return false; // off screen  	y -= TOP_LEFT_Y;  	y >>= 3; // convert to blocks -	if (y >= GRID_Y) return false; // off screen +	if (y >= GAME_SCREEN_HEIGHT >> 3) return false; // off screen  	bitPos = y * 40;  	width++;  	x >>= 3; // convert to blocks -	int32 x_signed = (x - (TOP_LEFT_X >> 3)); -	if (x_signed < 0) { // at least partially off screen -		if (x_signed + width <= 0) return false; // completely off screen -		else width += x_signed; // adjust width to visible part and continue -			                    // x_signed is negative, so it's += -	} -    if ((GAME_SCREEN_WIDTH >> 3) <= x_signed) return false; // off screen -	if ((GAME_SCREEN_WIDTH >> 3) < x_signed + width) { // at least partially of screen -		if ((uint32)((GAME_SCREEN_WIDTH >> 3) - x_signed) >= width) return false; // off screen -		else width -= (GAME_SCREEN_WIDTH >> 3) - x_signed; // adjust width -	} -    bitPos += x_signed; +	if (x < (TOP_LEFT_X >> 3)) { // at least partially off screen +		if (x + width < (TOP_LEFT_X >> 3)) return false; // completely off screen +		else { +			width -= (TOP_LEFT_X >> 3) - x; +			x = 0; +		} +	} else +		x -= TOP_LEFT_X >> 3; + +    if ((GAME_SCREEN_WIDTH >> 3) <= x) return false; // off screen +	if ((GAME_SCREEN_WIDTH >> 3) < x + width) // partially off screen +		width = (GAME_SCREEN_WIDTH >> 3) - x; + +    bitPos += x;  	int32 screenGridOfs = _gridConvertTable[cpt->screen] * GRID_SIZE;  	bitPos += (screenGridOfs << 3); // convert to bits  	uint32 tmpBits = 0x1F - (bitPos&0x1F); diff --git a/sky/logic.cpp b/sky/logic.cpp index c18ca5b6ec..e8a0684c0f 100644 --- a/sky/logic.cpp +++ b/sky/logic.cpp @@ -2237,8 +2237,29 @@ bool SkyLogic::fnLookAt(uint32 a, uint32 b, uint32 c) {  	return true;  } -bool SkyLogic::fnLincTextModule(uint32 a, uint32 b, uint32 c) { -	error("Stub: fnLincTextModule"); +bool SkyLogic::fnLincTextModule(uint32 textPos, uint32 textNo, uint32 buttonAction) { + +	uint16 cnt; +	if (buttonAction & 0x8000) +		for (cnt = LINC_DIGIT_0; cnt <= LINC_DIGIT_9; cnt++) +			_scriptVariables[cnt] = 0; +	buttonAction &= 0x7FFF; +	if (buttonAction < 10) +		_scriptVariables[LINC_DIGIT_0 + buttonAction] = textNo; + +	lowTextManager_t text = _skyText->lowTextManager(textNo, 220, 0, 215, false); + +	Compact *textCpt = SkyState::fetchCompact(text.compactNum); + +	if (textPos < 20) { // line number (for text) +		textCpt->xcood = 152; +		textCpt->ycood = (uint16)textPos * 13 + 170; +	} else if (textPos > 20) { // x coordinate (for numbers) +		textCpt->xcood = (uint16)textPos; +		textCpt->ycood = 214; +	} else warning("::fnLincTextModule: textPos == 20"); +	textCpt->getToFlag = (uint16)textNo; +	return true;  }  bool SkyLogic::fnTextKill2(uint32 a, uint32 b, uint32 c) { diff --git a/sky/logic.h b/sky/logic.h index 1167bda185..96349e3f2b 100644 --- a/sky/logic.h +++ b/sky/logic.h @@ -64,7 +64,17 @@ enum scriptVariableOffsets {  	MENU = 102,  	RND = 115,  	CUR_SECTION = 143, -	REICH_DOOR_FLAG = 470 +	REICH_DOOR_FLAG = 470, +	LINC_DIGIT_0 = 646, +	LINC_DIGIT_1 = 647, +	LINC_DIGIT_2 = 648, +	LINC_DIGIT_3 = 649, +	LINC_DIGIT_4 = 650, +	LINC_DIGIT_5 = 651, +	LINC_DIGIT_6 = 651, +	LINC_DIGIT_7 = 653, +	LINC_DIGIT_8 = 654, +	LINC_DIGIT_9 = 655,  };  class SkyAutoRoute; @@ -215,6 +225,7 @@ public:  	void stdSpeak(Compact *target, uint32 textNum, uint32 animNum, uint32 base);  	static uint32 _scriptVariables[838]; +	SkyGrid *_skyGrid;  protected:  	void push(uint32); @@ -241,7 +252,6 @@ protected:  	SkyScreen *_skyScreen;  	SkyDisk *_skyDisk; -	SkyGrid *_skyGrid;  	SkyText *_skyText;  	SkyMusicBase *_skyMusic;  	SkySound *_skySound; diff --git a/sky/screen.cpp b/sky/screen.cpp index 324ed0500e..f10a9e3757 100644 --- a/sky/screen.cpp +++ b/sky/screen.cpp @@ -300,9 +300,7 @@ void SkyScreen::fnFadeUp(uint32 palNum, uint32 scroll) {  	//_currentScreen points to new screen,  	//_scrollScreen points to graphic showing old room -	if (scroll == 13) scroll = 123; // script bug (?) in lower area -	if ((scroll != 123) && (scroll != 321) && (scroll)) { -		warning("unknown scroll parameter %d",scroll); +	if ((scroll != 123) && (scroll != 321)) {  		scroll = 0;  	} @@ -728,3 +726,35 @@ void SkyScreen::verticalMask(void) {  	}  } +void SkyScreen::paintBox(uint16 x, uint16 y) { + +	uint8 *screenPos = _currentScreen + y * GAME_SCREEN_WIDTH + x; +	memset(screenPos, 255, 8); +	for (uint8 cnt = 1; cnt < 8; cnt++) { +		*(screenPos + cnt * GAME_SCREEN_WIDTH) = 255; +		*(screenPos + cnt * GAME_SCREEN_WIDTH + 7) = 255; +	} +	memset(screenPos + 7 * GAME_SCREEN_WIDTH, 255, 7); +} + +void SkyScreen::showGrid(uint8 *gridBuf) { + +	uint32 gridData = 0; +	uint8 bitsLeft = 0; +	for (uint16 cnty = 0; cnty < GAME_SCREEN_HEIGHT >> 3; cnty++) {  +		for (uint16 cntx = 0; cntx < GAME_SCREEN_WIDTH >> 3; cntx++) { +			if (!bitsLeft) { +				bitsLeft = 32; +				gridData = *(uint32*)gridBuf; +				gridBuf += 4; +			} +			if (gridData & 0x80000000) +				paintBox(cntx << 3, cnty << 3); +			bitsLeft--; +			gridData <<= 1; +		} +	} +	_system->copy_rect(_currentScreen, GAME_SCREEN_WIDTH, 0, 0, GAME_SCREEN_WIDTH, GAME_SCREEN_HEIGHT); + +} + diff --git a/sky/screen.h b/sky/screen.h index 53348ccac3..8b76de246b 100644 --- a/sky/screen.h +++ b/sky/screen.h @@ -81,6 +81,9 @@ public:  	void spriteEngine(void); +	void paintBox(uint16 x, uint16 y); +	void showGrid(uint8 *gridBuf); +  private:  	OSystem *_system;  	SkyDisk *_skyDisk; diff --git a/sky/sky.cpp b/sky/sky.cpp index 1f32882c08..c62064ed18 100644 --- a/sky/sky.cpp +++ b/sky/sky.cpp @@ -105,15 +105,22 @@ void SkyState::go() {  	while (1) {  		delay(_systemVars.gameSpeed); +		/*if (_key_pressed == 'g') { +			warning("loading grid"); +			_skyLogic->_skyGrid->loadGrids(); +			_key_pressed = 0; +		}*/  		if ((_key_pressed == 27) || (_key_pressed == 63)) { // 27 = escape, 63 = F5  			_key_pressed = 0;  			_skyControl->doControlPanel();  		}  		_skyMouse->mouseEngine((uint16)_sdl_mouse_x, (uint16)_sdl_mouse_y);  		_skyLogic->engine(); +		//_skyScreen->forceRefresh();  		_skyScreen->recreate();  		_skyScreen->spriteEngine();  		_skyScreen->flip(); +		//_skyScreen->showGrid(_skyLogic->_skyGrid->giveGrid(SkyLogic::_scriptVariables[SCREEN]));  		_system->update_screen();  	}  } @@ -127,13 +134,13 @@ void SkyState::initialise(void) {  	if (_detector->getMidiDriverType() == MD_ADLIB) {  		_systemVars.systemFlags |= SF_SBLASTER; -		_skyMusic = new SkyAdlibMusic(_mixer, _skyDisk); +		_skyMusic = new SkyAdlibMusic(_mixer, _skyDisk, _system);  	} else {  		_systemVars.systemFlags |= SF_ROLAND;  		if (_detector->_native_mt32) -			_skyMusic = new SkyMT32Music(_detector->createMidi(), _skyDisk); +			_skyMusic = new SkyMT32Music(_detector->createMidi(), _skyDisk, _system);  		else -			_skyMusic = new SkyGmMusic(_detector->createMidi(), _skyDisk); +			_skyMusic = new SkyGmMusic(_detector->createMidi(), _skyDisk, _system);  	}  	if (isCDVersion())  		_systemVars.systemFlags |= SF_ALLOW_SPEECH; @@ -156,7 +163,7 @@ void SkyState::initialise(void) {  	_timer = Engine::_timer; // initialize timer *after* _skyScreen has been initialized.  	_timer->installProcedure(&timerHandler, 1000000 / 50); //call 50 times per second -	_skyControl = new SkyControl(_skyScreen, _skyDisk, _skyMouse, _skyText, _skyMusic, _system, getSavePath()); +	_skyControl = new SkyControl(_skyScreen, _skyDisk, _skyMouse, _skyText, _skyMusic, _skyLogic, _system, getSavePath());  }  void SkyState::initItemList() {  | 
