diff options
| author | Eugene Sandulenko | 2013-09-08 14:00:33 -0700 | 
|---|---|---|
| committer | Eugene Sandulenko | 2013-09-08 14:00:33 -0700 | 
| commit | 55e88c9e43d854fc2b5082d33db57147ca4fd913 (patch) | |
| tree | cb3a465b512aaf7f8808e7c928a27bf6b42004c2 | |
| parent | 7d7bd8b8f362affd39edb7e18120f7cf76e0b771 (diff) | |
| parent | 747e70a38ebd08450714fdb01dd45139ac9504a1 (diff) | |
| download | scummvm-rg350-55e88c9e43d854fc2b5082d33db57147ca4fd913.tar.gz scummvm-rg350-55e88c9e43d854fc2b5082d33db57147ca4fd913.tar.bz2 scummvm-rg350-55e88c9e43d854fc2b5082d33db57147ca4fd913.zip | |
Merge pull request #388 from sev-/fullpipe
FULLPIPE: Merge The Full Pipe engine
43 files changed, 12680 insertions, 0 deletions
| diff --git a/engines/configure.engines b/engines/configure.engines index 963b9f774f..195cdda6c7 100644 --- a/engines/configure.engines +++ b/engines/configure.engines @@ -13,6 +13,7 @@ add_engine cruise "Cinematique evo 2" yes  add_engine draci "Dragon History" yes  add_engine drascula "Drascula: The Vampire Strikes Back" yes  add_engine dreamweb "Dreamweb" yes +add_engine fullpipe "Full Pipe" yes  add_engine gob "Gobli*ns" yes  add_engine groovie "Groovie" yes "groovie2" "7th Guest"  add_engine groovie2 "Groovie 2 games" no diff --git a/engines/engines.mk b/engines/engines.mk index f58dba0d6d..5b3eeea61c 100644 --- a/engines/engines.mk +++ b/engines/engines.mk @@ -61,6 +61,11 @@ DEFINES += -DENABLE_DREAMWEB=$(ENABLE_DREAMWEB)  MODULES += engines/dreamweb  endif +ifdef ENABLE_FULLPIPE +DEFINES += -DENABLE_FULLPIPE=$(ENABLE_FULLPIPE) +MODULES += engines/fullpipe +endif +  ifdef ENABLE_GOB  DEFINES += -DENABLE_GOB=$(ENABLE_GOB)  MODULES += engines/gob diff --git a/engines/fullpipe/behavior.cpp b/engines/fullpipe/behavior.cpp new file mode 100644 index 0000000000..6bfb400c24 --- /dev/null +++ b/engines/fullpipe/behavior.cpp @@ -0,0 +1,315 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "fullpipe/fullpipe.h" + +#include "fullpipe/objects.h" +#include "fullpipe/behavior.h" +#include "fullpipe/statics.h" +#include "fullpipe/messages.h" + +namespace Fullpipe { + +BehaviorManager::BehaviorManager() { +	_scene = 0; +	_isActive = 1; +} + +BehaviorManager::~BehaviorManager() { +	clear(); +} + +void BehaviorManager::clear() { +	for (uint i = 0; i < _behaviors.size(); i++) { +		for (int j = 0; j < _behaviors[i]->_itemsCount; j++) +			delete _behaviors[i]->_bheItems[j]; + +		delete _behaviors[i]; +	} +	_behaviors.clear(); +} + +void BehaviorManager::initBehavior(Scene *sc, CGameVar *var) { +	clear(); +	_scene = sc; + +	BehaviorInfo *behinfo; + +	CGameVar *behvar = var->getSubVarByName("BEHAVIOR"); +	if (!behvar) +		return; + +	for (CGameVar *subvar = behvar->_subVars; subvar; subvar = subvar->_nextVarObj) { +		if (!strcmp(subvar->_varName, "AMBIENT")) { +			behinfo = new BehaviorInfo; +			behinfo->initAmbientBehavior(subvar, sc); + +			_behaviors.push_back(behinfo); +		} else { +			StaticANIObject *ani = sc->getStaticANIObject1ByName(subvar->_varName, -1); +			if (ani) +				for (uint i = 0; i < sc->_staticANIObjectList1.size(); i++) +					if (((StaticANIObject *)sc->_staticANIObjectList1[i])->_id == ani->_id) { +						behinfo = new BehaviorInfo; +						behinfo->initObjectBehavior(subvar, sc, ani); +						behinfo->_ani = (StaticANIObject *)sc->_staticANIObjectList1[i]; + +						_behaviors.push_back(behinfo); +					} +		} +	} +} + +void BehaviorManager::updateBehaviors() { +	if (!_isActive) +		return; + +	debug(0, "BehaviorManager::updateBehaviors()"); +	for (uint i = 0; i < _behaviors.size(); i++) { +		BehaviorInfo *beh = _behaviors[i]; + +		if (!beh->_ani) { +			beh->_counter++; +			if (beh->_counter >= beh->_counterMax) +				updateBehavior(beh, beh->_bheItems[0]); + +			continue; +		} + +		if (beh->_ani->_movement || !(beh->_ani->_flags & 4) || (beh->_ani->_flags & 2)) { +			beh->_staticsId = 0; +			continue; +		} + +		if (beh->_ani->_statics->_staticsId == beh->_staticsId) { +			beh->_counter++; +			if (beh->_counter >= beh->_counterMax) { +				if (beh->_subIndex >= 0 && !(beh->_flags & 1) && beh->_ani->_messageQueueId <= 0) +					updateStaticAniBehavior(beh->_ani, beh->_counter, beh->_bheItems[beh->_subIndex]); +			} +		} else { +			beh->_staticsId = beh->_ani->_statics->_staticsId; +			beh->_counter = 0; +			beh->_subIndex = -1; + +			for (int j = 0; j < beh->_itemsCount; j++) +				if (beh->_bheItems[j]->_staticsId == beh->_staticsId) { +					beh->_subIndex = j; +					break; +				} + +		} +	} +} + +void BehaviorManager::updateBehavior(BehaviorInfo *behaviorInfo, BehaviorEntry *entry) { +	debug(0, "BehaviorManager::updateBehavior() %d", entry->_itemsCount); +	for (int i = 0; i < entry->_itemsCount; i++) { +		BehaviorEntryInfo *bhi = entry->_items[i]; +		if (!(bhi->_flags & 1)) { +			if (bhi->_flags & 2) { +				MessageQueue *mq = new MessageQueue(bhi->_messageQueue, 0, 1); + +				mq->sendNextCommand(); + +				bhi->_flags &= 0xFFFFFFFD; +			} else if (behaviorInfo->_counter >= bhi->_delay && bhi->_percent && g_fullpipe->_rnd->getRandomNumber(32767) <= entry->_items[i]->_percent) { +				MessageQueue *mq = new MessageQueue(bhi->_messageQueue, 0, 1); + +				mq->sendNextCommand(); + +				behaviorInfo->_counter = 0; +			} +		} +	} +} + +void BehaviorManager::updateStaticAniBehavior(StaticANIObject *ani, int delay, BehaviorEntry *bhe) { +	debug(0, "BehaviorManager::updateStaticAniBehavior(%s)", transCyrillic((byte *)ani->_objectName)); + +	MessageQueue *mq = 0; + +	if (bhe->_flags & 1) { +		uint rnd = g_fullpipe->_rnd->getRandomNumber(32767); +		uint runPercent = 0; +		for (int i = 0; i < bhe->_itemsCount; i++) { +			if (!(bhe->_items[i]->_flags & 1) && bhe->_items[i]->_percent) { +				if ((rnd >= runPercent && rnd <= runPercent + bhe->_items[i]->_percent) || i == bhe->_itemsCount - 1) { +					mq = new MessageQueue(bhe->_items[i]->_messageQueue, 0, 1); +					break; +				} +				runPercent += bhe->_items[i]->_percent; +			} +		} +	} else { +		for (int i = 0; i < bhe->_itemsCount; i++) { +			if (!(bhe->_items[i]->_flags & 1) && delay >= bhe->_items[i]->_delay) { +				if (bhe->_items[i]->_percent) { +					if (g_fullpipe->_rnd->getRandomNumber(32767) <= bhe->_items[i]->_percent) { +						mq = new MessageQueue(bhe->_items[i]->_messageQueue, 0, 1); +						break; +					} +				} +			} +		} +	} + +	if (mq) { +		mq->replaceKeyCode(-1, ani->_okeyCode); +		mq->chain(ani); +	} +} + +void BehaviorInfo::clear() { +	_ani = 0; +	_staticsId = 0; +	_counter = 0; +	_counterMax = 0; +	_flags = 0; +	_subIndex = 0; +	_itemsCount = 0; + +	_bheItems.clear(); +} + +void BehaviorInfo::initAmbientBehavior(CGameVar *var, Scene *sc) { +	debug(0, "BehaviorInfo::initAmbientBehavior(%s)", transCyrillic((byte *)var->_varName)); + +	clear(); +	_itemsCount = 1; +	_counterMax = -1; + +	BehaviorEntry *bi = new BehaviorEntry(); + +	_bheItems.push_back(bi); + +	bi->_itemsCount = var->getSubVarsCount(); + +	bi->_items = (BehaviorEntryInfo**)calloc(bi->_itemsCount, sizeof(BehaviorEntryInfo *)); + +	for (int i = 0; i < bi->_itemsCount; i++) { +		int delay; +		bi->_items[i] = new BehaviorEntryInfo(var->getSubVarByIndex(i), sc, &delay); + +		if (bi->_items[i]->_delay <_counterMax) +			_counterMax = bi->_items[i]->_delay; +	} +} + +void BehaviorInfo::initObjectBehavior(CGameVar *var, Scene *sc, StaticANIObject *ani) { +	debug(0, "BehaviorInfo::initObjectBehavior(%s)", transCyrillic((byte *)var->_varName)); + +	clear(); + +	_itemsCount = var->getSubVarsCount(); +	_counterMax = -1; + +	while (var->_varType == 2) { +		if (strcmp(var->_value.stringValue, "ROOT")) +			break; + +		CGameVar *v1 = g_fullpipe->getGameLoaderGameVar()->getSubVarByName("BEHAVIOR")->getSubVarByName(ani->getName()); +		if (v1 == var) +			return; + +		sc = g_fullpipe->accessScene(ani->_sceneId); +		clear(); +		var = v1; +		_itemsCount = var->getSubVarsCount(); +		_counterMax = -1; +	} + +	for (int i = 0; i < _itemsCount; i++) { +		int maxDelay; + +		_bheItems.push_back(new BehaviorEntry(var->getSubVarByIndex(i), sc, ani, &maxDelay)); + +		if (maxDelay < _counterMax) +			_counterMax = maxDelay; +	} +} + +BehaviorEntry::BehaviorEntry() { +	_staticsId = 0; +	_itemsCount = 0; +	_flags = 0; +	_items = 0; +} + +BehaviorEntry::BehaviorEntry(CGameVar *var, Scene *sc, StaticANIObject *ani, int *minDelay) { +	_staticsId = 0; +	_itemsCount = 0; + +	*minDelay = 100000000; + +	int totalPercent = 0; +	_flags = 0; +	_items = 0; + +	Statics *st = ani->getStaticsByName(var->_varName); +	if (st) +		_staticsId = st->_staticsId; + +	_itemsCount = var->getSubVarsCount(); +	if (_itemsCount) { +		_items = (BehaviorEntryInfo**)calloc(_itemsCount, sizeof(BehaviorEntryInfo *)); + +		for (int i = 0; i < _itemsCount; i++) { +			CGameVar *subvar = var->getSubVarByIndex(i); +			int delay; + +			_items[i] = new BehaviorEntryInfo(subvar, sc, &delay); +			totalPercent += delay; + +			if (_items[i]->_delay < *minDelay) +				*minDelay = _items[i]->_delay; +		} + +		if (!*minDelay && totalPercent == 1000) +			_flags |= 1; +	} +} + +BehaviorEntryInfo::BehaviorEntryInfo(CGameVar *subvar, Scene *sc, int *delay) { +	_messageQueue = 0; +	_delay = 0; +	_percent = 0; +	_flags = 0; +	_messageQueue = sc->getMessageQueueByName(subvar->_varName); + +	CGameVar *vart = subvar->getSubVarByName("dwDelay"); +	if (vart) +		_delay = vart->_value.intValue; + +	*delay = 0; +	vart = subvar->getSubVarByName("dwPercent"); +	if (vart) { +		_percent = 0x7FFF * vart->_value.intValue / 1000; +		*delay = vart->_value.intValue; +	} + +	vart = subvar->getSubVarByName("dwFlags"); +	if (vart && vart->_varType == 2 && strstr(vart->_value.stringValue, "QDESC_AUTOSTART")) +		_flags |= 2; +} + +} // End of namespace Fullpipe diff --git a/engines/fullpipe/behavior.h b/engines/fullpipe/behavior.h new file mode 100644 index 0000000000..d9375d4d01 --- /dev/null +++ b/engines/fullpipe/behavior.h @@ -0,0 +1,84 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef FULLPIPE_BEHAVIOR_H +#define FULLPIPE_BEHAVIOR_H + +namespace Fullpipe { + +struct BehaviorEntryInfo { +	MessageQueue *_messageQueue; +	int _delay; +	uint32 _percent; +	int _flags; + +	BehaviorEntryInfo(CGameVar *subvar, Scene *sc, int *delay); +}; + +struct BehaviorEntry { +	int _staticsId; +	int _itemsCount; +	int _flags; +	BehaviorEntryInfo **_items; + +	BehaviorEntry(); +	BehaviorEntry(CGameVar *var, Scene *sc, StaticANIObject *ani, int *minDelay); +}; + +struct BehaviorInfo { +	StaticANIObject *_ani; +	int _staticsId; +	int _counter; +	int _counterMax; +	int _flags; +	int _subIndex; +	int _itemsCount; +	Common::Array<BehaviorEntry *> _bheItems; + +	BehaviorInfo() { clear(); } + +	void clear(); +	void initAmbientBehavior(CGameVar *var, Scene *sc); +	void initObjectBehavior(CGameVar *var, Scene *sc, StaticANIObject *ani); +}; + +class BehaviorManager : public CObject { +	Common::Array<BehaviorInfo *> _behaviors; +	Scene *_scene; +	bool _isActive; + +  public: +	BehaviorManager(); +	~BehaviorManager(); + +	void clear(); + +	void initBehavior(Scene *scene, CGameVar *var); + +	void updateBehaviors(); +	void updateBehavior(BehaviorInfo *behaviorInfo, BehaviorEntry *entry); +	void updateStaticAniBehavior(StaticANIObject *ani, int delay, BehaviorEntry *beh); +}; + +} // End of namespace Fullpipe + +#endif /* FULLPIPE_BEHAVIOR_H */ diff --git a/engines/fullpipe/constants.h b/engines/fullpipe/constants.h new file mode 100644 index 0000000000..5048bf9795 --- /dev/null +++ b/engines/fullpipe/constants.h @@ -0,0 +1,177 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef FULLPIPE_CONSTANTS_H +#define FULLPIPE_CONSTANTS_H + +namespace Fullpipe { + +#define ANI_BOOT_1 4231 +#define ANI_IN1MAN 5110 +#define ANI_INV_MAP 5321 +#define ANI_LIFTBUTTON 2751 +#define ANI_MAN 322 +#define MSG_DISABLESAVES 5201 +#define MSG_ENABLESAVES 5202 +#define MSG_HMRKICK_METAL 4764 +#define MSG_HMRKICK_STUCCO 4765 +#define MSG_MANSHADOWSOFF 5196 +#define MSG_MANSHADOWSON 5197 +#define MSG_SC1_SHOWOSK 1019 +#define MSG_SC1_SHOWOSK2 468 +#define MSG_SC1_UTRUBACLICK 1100 +#define MV_MAN_GOLADDER 451 +#define MV_MAN_GOLADDER2 2844 +#define MV_MAN_LOOKUP 4773 +#define MV_MAN_STARTLADDER 452 +#define MV_MAN_STARTLADDER2 2842 +#define MV_MAN_STOPLADDER 454 +#define MV_MAN_STOPLADDER2 2845 +#define MV_MAN_TOLADDER 448 +#define MV_MAN_TOLADDER2 2841 +#define MV_MAN_TURN_LU 486 +#define PIC_CMN_EVAL 3468 +#define PIC_CSR_DEFAULT 4891 +#define PIC_CSR_DEFAULT_INV 4892 +#define PIC_CSR_ITN 4893 +#define PIC_CSR_ITN_INV 4894 +#define PIC_CSR_GOFAR_L 4895 +#define PIC_CSR_GOFAR_R 4896 +#define PIC_CSR_ARCADE1 4901 +#define PIC_CSR_ARCADE2 4902 +#define PIC_CSR_ARCADE2_D 4903 +#define PIC_CSR_ARCADE3 4904 +#define PIC_CSR_ARCADE4 4905 +#define PIC_CSR_ARCADE5 4906 +#define PIC_CSR_ARCADE6 4907 +#define PIC_CSR_ARCADE6_D 4908 +#define PIC_CSR_ARCADE7 4909 +#define PIC_CSR_ARCADE7_D 4910 +#define PIC_CSR_ARCADE8 4911 +#define PIC_CSR_DEFAULT 4891 +#define PIC_CSR_DEFAULT_INV 4892 +#define PIC_CSR_GOD 4900 +#define PIC_CSR_GOFAR_L 4895 +#define PIC_CSR_GOFAR_R 4896 +#define PIC_CSR_GOL 4897 +#define PIC_CSR_GOR 4898 +#define PIC_CSR_GOU 4899 +#define PIC_CSR_HELPERBGR 5331 +#define PIC_CSR_ITN 4893 +#define PIC_CSR_ITN_GREEN 5330 +#define PIC_CSR_ITN_INV 4894 +#define PIC_CSR_ITN_RED 5329 +#define PIC_CSR_LIFT 5176 +#define PIC_CSR_MAP 5339 +#define PIC_IN1_PIPETITLE 5167 +#define PIC_INV_MENU 991 +#define PIC_MAP_A13 5275 +#define PIC_MAP_S01 5223 +#define PIC_SC1_KUCHKA 1321 +#define PIC_SC1_LADDER 1091 +#define PIC_SC1_OSK 1018 +#define PIC_SC1_OSK2 2932 +#define SC_1 301 +#define SC_10 653 +#define SC_11 654 +#define SC_12 655 +#define SC_13 1137 +#define SC_14 1138 +#define SC_15 1139 +#define SC_16 1140 +#define SC_17 1141 +#define SC_18 1142 +#define SC_19 1143 +#define SC_2 302 +#define SC_20 1144 +#define SC_21 1546 +#define SC_22 1547 +#define SC_23 1548 +#define SC_24 1549 +#define SC_25 1550 +#define SC_26 1551 +#define SC_27 1552 +#define SC_28 2062 +#define SC_29 2063 +#define SC_3 303 +#define SC_30 2064 +#define SC_31 2065 +#define SC_32 2066 +#define SC_33 2067 +#define SC_34 2068 +#define SC_35 2069 +#define SC_36 2070 +#define SC_37 2071 +#define SC_38 2072 +#define SC_4 304 +#define SC_5 305 +#define SC_6 649 +#define SC_7 650 +#define SC_8 651 +#define SC_9 652 +#define SC_COMMON 321 +#define SC_DBGMENU 726 +#define SC_FINAL1 4999 +#define SC_FINAL2 5000 +#define SC_FINAL3 5001 +#define SC_FINAL4 2460 +#define SC_INTRO1 3896 +#define SC_INTRO2 3907 +#define SC_INV 858 +#define SC_LDR 635 +#define SC_MAINMENU 4620 +#define SC_MAP 5222 +#define SC_TEST 903 +#define SC_TITLES 5166 +#define SND_CMN_031 3516 +#define SND_CMN_070 5199 +#define ST_LBN_0N 2832 +#define ST_LBN_0P 2833 +#define ST_LBN_1N 2753 +#define ST_LBN_1P 2754 +#define ST_LBN_2N 2756 +#define ST_LBN_2P 2757 +#define ST_LBN_3N 2759 +#define ST_LBN_3P 2760 +#define ST_LBN_4N 2762 +#define ST_LBN_4P 2763 +#define ST_LBN_5N 2765 +#define ST_LBN_5P 2766 +#define ST_LBN_6N 2768 +#define ST_LBN_6P 2769 +#define ST_LBN_7N 2771 +#define ST_LBN_7P 2772 +#define ST_LBN_8N 2774 +#define ST_LBN_8P 2775 +#define ST_LBN_9N 2777 +#define ST_LBN_9P 2778 +#define ST_MAN_EMPTY 476 +#define ST_MAN_RIGHT 325 +#define TrubaDown 697 +#define TrubaLeft 474 +#define TrubaRight 696 +#define TrubaUp 680 +#define rMV_MAN_LOOKUP 4775 + +} // End of namespace Fullpipe + +#endif /* FULLPIPE_CONSTANTS_H */ diff --git a/engines/fullpipe/detection.cpp b/engines/fullpipe/detection.cpp new file mode 100644 index 0000000000..4cb46ba1c5 --- /dev/null +++ b/engines/fullpipe/detection.cpp @@ -0,0 +1,112 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "base/plugins.h" + +#include "engines/advancedDetector.h" +#include "common/file.h" + +#include "fullpipe/fullpipe.h" + + +namespace Fullpipe { + +const char *FullpipeEngine::getGameId() const { +	return _gameDescription->gameid; +} + +} + +static const PlainGameDescriptor fullpipeGames[] = { +	{"fullpipe", "Full Pipe"}, +	{0, 0} +}; + +namespace Fullpipe { + +static const ADGameDescription gameDescriptions[] = { + +	// Fullpipe Russian version +	{ +		"fullpipe", +		0, +		AD_ENTRY1s("0654.sc2", "099f54f86d33ad2395f3b854b7e05058", 2272), +		Common::RU_RUS, +		Common::kPlatformWindows, +		ADGF_NO_FLAGS, +		GUIO1(GUIO_NONE) +	}, + +	// Fullpipe German version +	{ +		"fullpipe", +		0, +		AD_ENTRY1s("0654.sc2", "d8743351fc53d205f42d91f6d791e51b", 2272), +		Common::RU_RUS, +		Common::kPlatformWindows, +		ADGF_NO_FLAGS, +		GUIO1(GUIO_NONE) +	}, + +	AD_TABLE_END_MARKER +}; + +} // End of namespace Fullpipe + +class FullpipeMetaEngine : public AdvancedMetaEngine { +public: +	FullpipeMetaEngine() : AdvancedMetaEngine(Fullpipe::gameDescriptions, sizeof(ADGameDescription), fullpipeGames) { +		_singleid = "fullpipe"; +	} + +	virtual const char *getName() const { +		return "Fullpipe Engine"; +	} + +	virtual const char *getOriginalCopyright() const { +		return "Fullpipe Engine (C) Pipe Studio"; +	} + +	virtual bool hasFeature(MetaEngineFeature f) const; +	virtual bool createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const; +}; + +bool FullpipeMetaEngine::hasFeature(MetaEngineFeature f) const { +	return false; +} + +bool Fullpipe::FullpipeEngine::hasFeature(EngineFeature f) const { +	return false; +} + +bool FullpipeMetaEngine::createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const { +	if (desc) { +		*engine = new Fullpipe::FullpipeEngine(syst, desc); +	} +	return desc != 0; +} + +#if PLUGIN_ENABLED_DYNAMIC(FULLPIPE) +	REGISTER_PLUGIN_DYNAMIC(FULLPIPE, PLUGIN_TYPE_ENGINE, FullpipeMetaEngine); +#else +	REGISTER_PLUGIN_STATIC(FULLPIPE, PLUGIN_TYPE_ENGINE, FullpipeMetaEngine); +#endif diff --git a/engines/fullpipe/fullpipe.cpp b/engines/fullpipe/fullpipe.cpp new file mode 100644 index 0000000000..11808e95c2 --- /dev/null +++ b/engines/fullpipe/fullpipe.cpp @@ -0,0 +1,441 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "base/plugins.h" + +#include "common/archive.h" +#include "common/config-manager.h" + +#include "engines/util.h" + +#include "fullpipe/fullpipe.h" +#include "fullpipe/gameloader.h" +#include "fullpipe/messages.h" +#include "fullpipe/behavior.h" +#include "fullpipe/modal.h" +#include "fullpipe/input.h" +#include "fullpipe/scenes.h" + +namespace Fullpipe { + +FullpipeEngine *g_fullpipe = 0; +Vars *g_vars = 0; + +FullpipeEngine::FullpipeEngine(OSystem *syst, const ADGameDescription *gameDesc) : Engine(syst), _gameDescription(gameDesc) { +	// Setup mixer +	if (!_mixer->isReady()) { +		warning("Sound initialization failed."); +	} + +	_mixer->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, ConfMan.getInt("sfx_volume")); +	_mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, ConfMan.getInt("music_volume")); + +	_rnd = new Common::RandomSource("fullpipe"); + +	_gameProjectVersion = 0; +	_pictureScale = 8; +	_scrollSpeed = 0; +	_currSoundListCount = 0; +	_globalPalette = 0; + +	_updateTicks = 0; +	_lastInputTicks = 0; +	_lastButtonUpTicks = 0; + +	_currArchive = 0; + +	_soundEnabled = true; +	_flgSoundList = true; + +	_sfxVolume = 0; + +	_inputController = 0; +	_inputDisabled = false; + +	_modalObject = 0; + +	_gameContinue = true; +	_needRestart = false; +	_flgPlayIntro = false; +	_gamePaused = false; +	_inputArFlag = false; +	_recordEvents = false; + +	_flgGameIsRunning = true; + +	_isProcessingMessages = false; + +	_musicAllowed = -1; + +	_aniMan = 0; +	_aniMan2 = 0; +	_currentScene = 0; +	_scene2 = 0; +	_movTable = 0; + +	_globalMessageQueueList = 0; +	_messageHandlers = 0; + +	_updateScreenCallback = 0; +	_updateCursorCallback = 0; + +	_msgX = 0; +	_msgY = 0; +	_msgObjectId2 = 0; +	_msgId = 0; +	_mouseVirtX = 0; +	_mouseVirtY = 0; + +	_currSelectedInventoryItemId = 0; + +	_behaviorManager = 0; + +	_cursorId = 0; + +	_keyState = Common::KEYCODE_INVALID; +	_buttonState = 0; + +	_gameLoader = 0; +	_gameProject = 0; + +	_updateFlag = true; +	_flgCanOpenMap = true; + +	_sceneWidth = 1; +	_sceneHeight = 1; + +	for (int i = 0; i < 11; i++) +		_currSoundList1[i] = 0; +	 +	for (int i = 0; i < 200; i++) +		_mapTable[i] = 0; + +	_inventoryScene = 0; +	_inventory = 0; + +	_minCursorId = 0xffff; +	_maxCursorId = 0; +	_objectAtCursor = 0; +	_objectIdAtCursor = 0; + +	_isSaveAllowed = true; + +	g_fullpipe = this; +	g_vars = new Vars; +} + +FullpipeEngine::~FullpipeEngine() { +	delete _rnd; +	delete _globalMessageQueueList; +} + +void FullpipeEngine::initialize() { +	_globalMessageQueueList = new GlobalMessageQueueList; +	_behaviorManager = new BehaviorManager; + +	_sceneRect.left = 0; +	_sceneRect.top = 0; +	_sceneRect.right = 799; +	_sceneRect.bottom = 599; +} + +Common::Error FullpipeEngine::run() { +	const Graphics::PixelFormat format(2, 5, 6, 5, 0, 11, 5, 0, 0); +	// Initialize backend +	initGraphics(800, 600, true, &format); + +	_backgroundSurface.create(800, 600, format); + +	initialize(); + +	_isSaveAllowed = false; + +	int scene = 0; +	if (ConfMan.hasKey("boot_param")) +		scene = ConfMan.getInt("boot_param"); + +	if (!loadGam("fullpipe.gam", scene)) +		return Common::kNoGameDataFoundError; + +#if 0 +	loadAllScenes(); +#endif + +	_gameContinue = true; + +	while (_gameContinue) { +		updateEvents(); + +		updateScreen(); + +		if (_needRestart) { +			if (_modalObject) { +				delete _modalObject; +				_modalObject = 0; +			} + +			freeGameLoader(); +			_currentScene = 0; +			_updateTicks = 0; +			 +			loadGam("fullpipe.gam"); +			_needRestart = false; +		} + +		_system->delayMillis(10); +		_system->updateScreen(); +	} + +	freeGameLoader(); + +	cleanup(); + +	return Common::kNoError; +} + +void FullpipeEngine::updateEvents() { +	Common::Event event; +	Common::EventManager *eventMan = _system->getEventManager(); +	ExCommand *ex; + +	while (eventMan->pollEvent(event)) { +		switch (event.type) { +		case Common::EVENT_KEYDOWN: +			_keyState = event.kbd.keycode; + +			switch (event.kbd.keycode) { +			case Common::KEYCODE_SPACE: +				if (_gamePaused) { +					if (_modalObject) { +						if (_modalObject->init(42)) { +							_modalObject->update(); +						} else { +							_modalObject->saveload(); +							CBaseModalObject *obj = _modalObject->_parentObj; +							if (obj) +								delete _modalObject; +							_modalObject = obj; +						} +					} else { +						_gameLoader->updateSystems(42); +					} +					return; +				} + +				ex = new ExCommand(0, 17, 36, 0, 0, 0, 1, 0, 0, 0); +				ex->_keyCode = 32; +				ex->_excFlags |= 3; +				ex->handle(); +				break; +			case Common::KEYCODE_s: +				if (_gamePaused) { +					_gamePaused = 0; +					_flgGameIsRunning = true; +					return; +				} + +				ex = new ExCommand(0, 17, 36, 0, 0, 0, 1, 0, 0, 0); +				ex->_keyCode = 83; +				ex->_excFlags |= 3; +				ex->handle(); +				break; +			case Common::KEYCODE_q: +				return; +				break; +			default: +				ex = new ExCommand(0, 17, 36, 0, 0, 0, 1, 0, 0, 0); +				ex->_keyCode = event.kbd.keycode; +				ex->_excFlags |= 3; +				ex->handle(); +				break; +			} +			break; +		case Common::EVENT_KEYUP: +			if (!_inputArFlag) { +				ex = new ExCommand(0, 17, 37, 0, 0, 0, 1, 0, 0, 0); +				ex->_excFlags |= 3; +				ex->handle(); +			} +			_keyState = Common::KEYCODE_INVALID; +			break; +		case Common::EVENT_MOUSEMOVE: +			if (_recordEvents) { +				ex = new ExCommand(0, 17, 31, event.mouse.x, event.mouse.y, 0, 1, 0, 0, 0); +				ex->_excFlags |= 3; +				ex->handle(); +			} + +			_mouseScreenPos = event.mouse; +			break; +		case Common::EVENT_QUIT: +			_gameContinue = false; +			break; +			case Common::EVENT_RBUTTONDOWN: +			if (!_inputArFlag && (_updateTicks - _lastInputTicks) >= 2) { +				ex = new ExCommand(0, 17, 107, event.mouse.x, event.mouse.y, 0, 1, 0, 0, 0); +				ex->_excFlags |= 3; +				_lastInputTicks = _updateTicks; +				ex->handle(); +			} +			break; +		case Common::EVENT_LBUTTONDOWN: +			if (!_inputArFlag && (_updateTicks - _lastInputTicks) >= 2) { +				ex = new ExCommand(0, 17, 29, event.mouse.x, event.mouse.y, 0, 1, 0, 0, 0); + +				ex->_sceneClickX = _sceneRect.left + ex->_x; +				ex->_sceneClickY = _sceneRect.top + ex->_y; +				ex->_keyCode = getGameLoaderInventory()->getSelectedItemId(); +				ex->_excFlags |= 3; +				_lastInputTicks = _updateTicks; +				ex->handle(); +			} +			break; +		case Common::EVENT_LBUTTONUP: +			if (!_inputArFlag && (_updateTicks - _lastButtonUpTicks) >= 2) { +				ex = new ExCommand(0, 17, 30, 0, 0, 0, 1, 0, 0, 0); +				ex->_excFlags |= 3; +				_lastButtonUpTicks = _updateTicks; +				ex->handle(); +			} +			break; +		default: +			break; +		} +	} + +		 +#if 0 +	warning("STUB: FullpipeEngine::updateEvents() <mainWindowProc>"); +	if (Msg == MSG_SC11_SHOWSWING && _modalObject) { +		_modalObject->method14(); +	} +#endif +} + +void FullpipeEngine::freeGameLoader() { +	warning("STUB: FullpipeEngine::freeGameLoader()"); +} + +void FullpipeEngine::cleanup() { +	warning("STUB: FullpipeEngine::cleanup()"); +} + +void FullpipeEngine::updateScreen() { +	debug(4, "FullpipeEngine::updateScreen()"); + +	_mouseVirtX = _mouseScreenPos.x + _sceneRect.left; +	_mouseVirtY = _mouseScreenPos.y + _sceneRect.top; + +	//if (inputArFlag) +	//	updateGame_inputArFlag(); + +	if (_modalObject || (_flgGameIsRunning && (_gameLoader->updateSystems(42), _modalObject != 0))) { +		if (_flgGameIsRunning) { +			if (_modalObject->init(42)) { +				_modalObject->update(); +			} else { +				_modalObject->saveload(); +				CBaseModalObject *tmp = _modalObject->_parentObj; + +				delete _modalObject; + +				_modalObject = tmp; +			} +		} +	} else if (_currentScene) { +		_currentScene->draw(); + +		if (_inventoryScene) +			_inventory->draw(); + +		if (_updateScreenCallback) +			_updateScreenCallback(); + +		//if (inputArFlag && _currentScene) { +		//	vrtTextOut(*(_DWORD *)g_vrtHandle, smallNftData, "DEMO", 4, 380, 580); +		//	vrtTextOut(*(_DWORD *)g_vrtHandle, smallNftData, "Alt+F4 - exit", 14, 695, 580); +		//} +	} else { +		//vrtRectangle(*(_DWORD *)g_vrtHandle, 0, 0, 0, 800, 600); +	} +	_inputController->drawCursor(_mouseScreenPos.x, _mouseScreenPos.y); + +	++_updateTicks; +} + +int FullpipeEngine::getObjectEnumState(const char *name, const char *state) { +	CGameVar *var = _gameLoader->_gameVar->getSubVarByName("OBJSTATES"); + +	if (!var) { +		var = _gameLoader->_gameVar->addSubVarAsInt("OBJSTATES", 0); +	} + +	var = var->getSubVarByName(name); +	if (var) { +		var = var->getSubVarByName("ENUMSTATES"); +		if (var) +			return var->getSubVarAsInt(state); +	} + +	return 0; +} + +int FullpipeEngine::getObjectState(const char *objname) { +	CGameVar *var = _gameLoader->_gameVar->getSubVarByName("OBJSTATES"); + +	if (var) +		return var->getSubVarAsInt(objname); + +  return 0; +} + +void FullpipeEngine::setObjectState(const char *name, int state) { +	CGameVar *var = _gameLoader->_gameVar->getSubVarByName("OBJSTATES"); + +	if (!var) { +		var = _gameLoader->_gameVar->addSubVarAsInt("OBJSTATES", 0); +	} + +	var->setSubVarAsInt(name, state); +} + +void FullpipeEngine::updateMapPiece(int mapId, int update) { +	for (int i = 0; i < 200; i++) { +		int hiWord = (_mapTable[i] >> 16) & 0xffff; + +		if (hiWord == mapId) { +			_mapTable[i] |= update; +			return; +		} +		if (!hiWord) { +			_mapTable[i] = (mapId << 16) | update; +			return; +		} +	} +} + +void FullpipeEngine::disableSaves(ExCommand *ex) { +	warning("STUB: FullpipeEngine::disableSaves()"); +} + + +} // End of namespace Fullpipe diff --git a/engines/fullpipe/fullpipe.h b/engines/fullpipe/fullpipe.h new file mode 100644 index 0000000000..5d9bdcc045 --- /dev/null +++ b/engines/fullpipe/fullpipe.h @@ -0,0 +1,241 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef FULLPIPE_FULLPIPE_H +#define FULLPIPE_FULLPIPE_H + +#include "common/scummsys.h" +#include "common/events.h" +#include "common/keyboard.h" +#include "common/random.h" +#include "common/savefile.h" +#include "common/system.h" + +#include "audio/mixer.h" + +#include "graphics/surface.h" + +#include "engines/engine.h" + +struct ADGameDescription; + +namespace Fullpipe { + +enum FullpipeGameFeatures { +}; + +class BehaviorManager; +class CBaseModalObject; +class CGameLoader; +class CGameVar; +class CInputController; +class CInventory2; +struct CursorInfo; +class EntranceInfo; +class ExCommand; +class GameProject; +class GameObject; +class GlobalMessageQueueList; +class MessageHandler; +struct MovTable; +class NGIArchive; +class Scene; +class SoundList; +class StaticANIObject; +class Vars; + +int global_messageHandler1(ExCommand *cmd); +int global_messageHandler2(ExCommand *cmd); +int global_messageHandler3(ExCommand *cmd); +int global_messageHandler4(ExCommand *cmd); +void global_messageHandler_handleSound(ExCommand *cmd); + + +class FullpipeEngine : public ::Engine { +protected: + +	Common::Error run(); + +public: +	FullpipeEngine(OSystem *syst, const ADGameDescription *gameDesc); +	virtual ~FullpipeEngine(); + +	void initialize(); + +	void setMusicAllowed(int val) { _musicAllowed = val; } + +	// Detection related functions +	const ADGameDescription *_gameDescription; +	const char *getGameId() const; +	Common::Platform getPlatform() const; +	bool hasFeature(EngineFeature f) const; + +	Common::RandomSource *_rnd; + +	Common::KeyCode _keyState; +	uint16 _buttonState; + +	void updateEvents(); + +	Graphics::Surface _backgroundSurface; + +	CGameLoader *_gameLoader; +	GameProject *_gameProject; +	bool loadGam(const char *fname, int scene = 0); + +	CGameVar *getGameLoaderGameVar(); +	CInputController *getGameLoaderInputController(); + +	int _gameProjectVersion; +	int _pictureScale; +	int _scrollSpeed; +	bool _updateFlag; +	bool _flgCanOpenMap; +	bool _gamePaused; +	bool _flgGameIsRunning; +	bool _inputArFlag; +	bool _recordEvents; + +	Common::Rect _sceneRect; +	int _sceneWidth; +	int _sceneHeight; +	Scene *_currentScene; +	Scene *_scene2; +	StaticANIObject *_aniMan; +	StaticANIObject *_aniMan2; +	byte *_globalPalette; + +	CInputController *_inputController; +	bool _inputDisabled; + +	void defHandleKeyDown(int key); + +	SoundList *_currSoundList1[11]; +	int _currSoundListCount; +	bool _soundEnabled; +	bool _flgSoundList; + +	void stopAllSounds(); +	void toggleMute(); +	void playSound(int id, int flag); +	void startSceneTrack(); + +	int _sfxVolume; + +	GlobalMessageQueueList *_globalMessageQueueList; +	MessageHandler *_messageHandlers; + +	int _msgX; +	int _msgY; +	int _msgObjectId2; +	int _msgId; + +	Common::List<ExCommand *> _exCommandList; +	bool _isProcessingMessages; + +	int _mouseVirtX; +	int _mouseVirtY; +	Common::Point _mouseScreenPos; + +	BehaviorManager *_behaviorManager; + +	MovTable *_movTable; + +	void initMap(); +	void updateMapPiece(int mapId, int update); +	void updateScreen(); + +	void freeGameLoader(); +	void cleanup(); + +	bool _gameContinue; +	bool _needRestart; +	bool _flgPlayIntro; +	int _musicAllowed; + +	void enableSaves() { _isSaveAllowed = true; } +	void disableSaves(ExCommand *ex); + +	void initObjectStates(); +	void setLevelStates(); +	void setSwallowedEggsState(); +	void loadAllScenes(); + +	void initCursors(); +	void addCursor(CursorInfo *cursorInfo, Scene *inv, int pictureId, int hotspotX, int hotspotY, int itemPictureOffsX, int itemPictureOffsY); + +	int32 _mapTable[200]; + +	Scene *_inventoryScene; +	CInventory2 *_inventory; +	int _currSelectedInventoryItemId; + +	int32 _updateTicks; +	int32 _lastInputTicks; +	int32 _lastButtonUpTicks; + +	CBaseModalObject *_modalObject; + +	int (*_updateScreenCallback)(); +	int (*_updateCursorCallback)(); + +	int _cursorId; +	int _minCursorId; +	int _maxCursorId; +	Common::Array<int> _objectIdCursors; +	GameObject *_objectAtCursor; +	int _objectIdAtCursor; + +	void setCursor(int id); +	void updateCursorsCommon(); + +	int getObjectState(const char *objname); +	void setObjectState(const char *name, int state); +	int getObjectEnumState(const char *name, const char *state); + +	bool sceneSwitcher(EntranceInfo *entrance); +	Scene *accessScene(int sceneId); +	void setSceneMusicParameters(CGameVar *var); + +	NGIArchive *_currArchive; + +	void openMap(); +	void openHelp(); +	void openMainMenu(); + +	int lift_getButtonIdP(int objid); + +public: + +	bool _isSaveAllowed; + +	bool canLoadGameStateCurrently() { return _isSaveAllowed; } +	bool canSaveGameStateCurrently() { return _isSaveAllowed; } + +}; + +extern FullpipeEngine *g_fullpipe; +extern Vars *g_vars; + +} // End of namespace Fullpipe + +#endif /* FULLPIPE_FULLPIPE_H */ diff --git a/engines/fullpipe/gameloader.cpp b/engines/fullpipe/gameloader.cpp new file mode 100644 index 0000000000..f48c407a57 --- /dev/null +++ b/engines/fullpipe/gameloader.cpp @@ -0,0 +1,339 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "fullpipe/fullpipe.h" + +#include "fullpipe/gameloader.h" +#include "fullpipe/scene.h" +#include "fullpipe/input.h" +#include "fullpipe/statics.h" +#include "fullpipe/interaction.h" + +namespace Fullpipe { + +CInventory2 *getGameLoaderInventory() { +	return &g_fullpipe->_gameLoader->_inventory; +} + +CMctlCompound *getSc2MctlCompoundBySceneId(int16 sceneId) { +	for (uint i = 0; i < g_fullpipe->_gameLoader->_sc2array.size(); i++) +		if (g_fullpipe->_gameLoader->_sc2array[i]._sceneId == sceneId) +			return (CMctlCompound *)g_fullpipe->_gameLoader->_sc2array[i]._motionController; + +	return 0; +} + +CInteractionController *getGameLoaderInteractionController() { +	return g_fullpipe->_gameLoader->_interactionController; +} + +CGameLoader::CGameLoader() { +	_interactionController = new CInteractionController(); +	_inputController = new CInputController(); + +	_gameProject = 0; +	_gameName = 0; + +	addMessageHandlerByIndex(global_messageHandler2, 0, 0); +	insertMessageHandler(global_messageHandler3, 0, 128); +	insertMessageHandler(global_messageHandler4, 0, 1); + +	_field_FA = 0; +	_field_F8 = 0; +	_sceneSwitcher = 0; +	_preloadCallback = 0; +	_readSavegameCallback = 0; +	_gameVar = 0; +	_preloadSceneId = 0; +	_preloadEntranceId = 0; +	_updateCounter = 0; + +	g_fullpipe->_msgX = 0; +	g_fullpipe->_msgY = 0; +	g_fullpipe->_msgObjectId2 = 0; +	g_fullpipe->_msgId = 0; +} + +CGameLoader::~CGameLoader() { +	free(_gameName); +	delete _gameProject; +	delete _interactionController; +	delete _inputController; +} + +bool CGameLoader::load(MfcArchive &file) { +	debug(5, "CGameLoader::load()"); + +	_gameName = file.readPascalString(); +	debug(6, "_gameName: %s", _gameName); + +	_gameProject = new GameProject(); + +	_gameProject->load(file); + +	g_fullpipe->_gameProject = _gameProject; + +	if (g_fullpipe->_gameProjectVersion < 12) { +		error("Old gameProjectVersion: %d", g_fullpipe->_gameProjectVersion); +	} + +	_gameName = file.readPascalString(); +	debug(6, "_gameName: %s", _gameName); + +	_inventory.load(file); + +	_interactionController->load(file); + +	debug(6, "sceneTag count: %d", _gameProject->_sceneTagList->size()); + +	_sc2array.resize(_gameProject->_sceneTagList->size()); + +	int i = 0; +	for (SceneTagList::const_iterator it = _gameProject->_sceneTagList->begin(); it != _gameProject->_sceneTagList->end(); ++it, i++) { +		char tmp[12]; + +		snprintf(tmp, 11, "%04d.sc2", it->_sceneId); + +		debug(2, "sc: %s", tmp); + +		_sc2array[i].loadFile((const char *)tmp); +	} + +	_preloadItems.load(file); + +	_field_FA = file.readUint16LE(); +	_field_F8 = file.readUint16LE(); + +	_gameVar = (CGameVar *)file.readClass(); + +	return true; +} + +bool CGameLoader::loadScene(int sceneId) { +	SceneTag *st; + +	int idx = getSceneTagBySceneId(sceneId, &st); + +	if (idx < 0) +		return false; + +	if (!st->_scene) +		st->loadScene(); + +	if (st->_scene) { +		st->_scene->init(); + +		applyPicAniInfos(st->_scene, _sc2array[idx]._defPicAniInfos, _sc2array[idx]._defPicAniInfosCount); +		applyPicAniInfos(st->_scene, _sc2array[idx]._picAniInfos, _sc2array[idx]._picAniInfosCount); + +		_sc2array[idx]._scene = st->_scene; +		_sc2array[idx]._isLoaded = 1; + +		return true; +	} + +	return false; +} + +bool CGameLoader::gotoScene(int sceneId, int entranceId) { +	SceneTag *st; + +	int sc2idx = getSceneTagBySceneId(sceneId, &st); + +	if (sc2idx < 0) +		return false; + +	if (!_sc2array[sc2idx]._isLoaded) +		return 0; + +	if (_sc2array[sc2idx]._entranceDataCount < 1) { +		g_fullpipe->_currentScene = st->_scene; +		return true; +	} + +	if (_sc2array[sc2idx]._entranceDataCount <= 0) +		return false; + +	int entranceIdx; +	for (entranceIdx = 0; _sc2array[sc2idx]._entranceData[entranceIdx]->_field_4 != entranceId; entranceIdx++) { +		if (entranceIdx >= _sc2array[sc2idx]._entranceDataCount) +			return false; +	} + +	CGameVar *sg = _gameVar->getSubVarByName("OBJSTATES")->getSubVarByName("SAVEGAME"); + +	if (sg || (sg = _gameVar->getSubVarByName("OBJSTATES")->addSubVarAsInt("SAVEGAME", 0)) != 0) +		sg->setSubVarAsInt("Entrance", entranceId); + +	if (!g_fullpipe->sceneSwitcher(_sc2array[sc2idx]._entranceData[entranceIdx])) +		return false; + +	g_fullpipe->_msgObjectId2 = 0; +	g_fullpipe->_msgY = -1; +	g_fullpipe->_msgX = -1; + +	g_fullpipe->_currentScene = st->_scene; + +	MessageQueue *mq1 = g_fullpipe->_currentScene->getMessageQueueById(_sc2array[sc2idx]._entranceData[entranceIdx]->_messageQueueId); +	if (mq1) { +		MessageQueue *mq = new MessageQueue(mq1, 0, 0); + +		StaticANIObject *stobj = g_fullpipe->_currentScene->getStaticANIObject1ById(_field_FA, -1); +		if (stobj) { +			stobj->_flags &= 0x100; + +			ExCommand *ex = new ExCommand(stobj->_id, 34, 256, 0, 0, 0, 1, 0, 0, 0); + +			ex->_field_14 = 256; +			ex->_messageNum = 0; +			ex->_excFlags |= 3; + +			mq->_exCommands.push_back(ex); +		} + +		mq->setFlags(mq->getFlags() | 1); + +		if (!mq->chain(0)) { +			delete mq; + +			return false; +		} +	} else { +		StaticANIObject *stobj = g_fullpipe->_currentScene->getStaticANIObject1ById(_field_FA, -1); +		if (stobj) +			stobj->_flags &= 0xfeff; +	} + +	return true; +} + +bool CGameLoader::preloadScene(int sceneId, int entranceId) { +	warning("STUB: preloadScene(%d, %d), ", sceneId, entranceId); + +	return true; +} + +int CGameLoader::getSceneTagBySceneId(int sceneId, SceneTag **st) { +	if (_sc2array.size() > 0 && _gameProject->_sceneTagList->size() > 0) { +		for (uint i = 0; i < _sc2array.size(); i++) { +			if (_sc2array[i]._sceneId == sceneId) { +				int num = 0; +				for (SceneTagList::iterator s = _gameProject->_sceneTagList->begin(); s != _gameProject->_sceneTagList->end(); ++s, num++) { +					if (s->_sceneId == sceneId) { +						*st = &(*s); +						return num; +					} +				} +			} +		} +	} + +	*st = 0; +	return -1; +} + +void CGameLoader::applyPicAniInfos(Scene *sc, PicAniInfo **picAniInfo, int picAniInfoCount) { +	if (picAniInfoCount <= 0) +		return; + +	debug(0, "CGameLoader::applyPicAniInfos(sc, ptr, %d)", picAniInfoCount); + +	PictureObject *pict; +	StaticANIObject *ani; + +	for (int i = 0; i < picAniInfoCount; i++) { +		debug(7, "PicAniInfo: id: %d type: %d", picAniInfo[i]->objectId, picAniInfo[i]->type); +		if (picAniInfo[i]->type & 2) { +			pict = sc->getPictureObjectById(picAniInfo[i]->objectId, picAniInfo[i]->field_8); +			if (pict) { +				pict->setPicAniInfo(picAniInfo[i]); +				continue; +			} +			pict = sc->getPictureObjectById(picAniInfo[i]->objectId, 0); +			if (pict) { +				PictureObject *pictNew = new PictureObject(pict); + +				sc->_picObjList.push_back(pictNew); +				pictNew->setPicAniInfo(picAniInfo[i]); +				continue; +			} +		} else { +			if (!(picAniInfo[i]->type & 1)) +				continue; + +			Scene *scNew = g_fullpipe->accessScene(picAniInfo[i]->sceneId); +			if (!scNew) +				continue; + +			ani = sc->getStaticANIObject1ById(picAniInfo[i]->objectId, picAniInfo[i]->field_8); +			if (ani) { +				ani->setPicAniInfo(picAniInfo[i]); +				continue; +			} + +			ani = scNew->getStaticANIObject1ById(picAniInfo[i]->objectId, 0); +			if (ani) { +				StaticANIObject *aniNew = new StaticANIObject(ani); + +				sc->addStaticANIObject(aniNew, 1); + +				aniNew->setPicAniInfo(picAniInfo[i]); +				continue; +			} +		} +	} +} + +void CGameLoader::updateSystems(int counterdiff) { +	if (g_fullpipe->_currentScene) { +		g_fullpipe->_currentScene->update(counterdiff); + +		_exCommand._messageKind = 17; +		_updateCounter++; +		_exCommand._messageNum = 33; +		_exCommand._excFlags = 0; +		_exCommand.postMessage(); +	} + +	processMessages(); + +	if (_preloadSceneId) { +		processMessages(); +		preloadScene(_preloadSceneId, _preloadEntranceId); +	} +} + +CGameVar *FullpipeEngine::getGameLoaderGameVar() { +	if (_gameLoader) +		return _gameLoader->_gameVar; +	else +		return 0; +} + +CInputController *FullpipeEngine::getGameLoaderInputController() { +	if (_gameLoader) +		return _gameLoader->_inputController; +	else +		return 0; +} + +} // End of namespace Fullpipe diff --git a/engines/fullpipe/gameloader.h b/engines/fullpipe/gameloader.h new file mode 100644 index 0000000000..a8d51cd794 --- /dev/null +++ b/engines/fullpipe/gameloader.h @@ -0,0 +1,77 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef FULLPIPE_GAMELOADER_H +#define FULLPIPE_GAMELOADER_H + +#include "fullpipe/objects.h" +#include "fullpipe/inventory.h" +#include "fullpipe/messages.h" + +namespace Fullpipe { + +class SceneTag; +class CMctlCompound; +class CInputController; +class CInteractionController; + +class CGameLoader : public CObject { + public: +	CGameLoader(); +	virtual ~CGameLoader(); + +	virtual bool load(MfcArchive &file); +	bool loadScene(int sceneId); +	bool gotoScene(int sceneId, int entranceId); +	bool preloadScene(int sceneId, int entranceId); + +	void updateSystems(int counterdiff); + +	int getSceneTagBySceneId(int sceneId, SceneTag **st); +	void applyPicAniInfos(Scene *sc, PicAniInfo **picAniInfo, int picAniInfoCount); + +	GameProject *_gameProject; +	CInteractionController *_interactionController; +	CInputController *_inputController; +	CInventory2 _inventory; +	Sc2Array _sc2array; +	void *_sceneSwitcher; +	void *_preloadCallback; +	void *_readSavegameCallback; +	int16 _field_F8; +	int16 _field_FA; +	PreloadItems _preloadItems; +	CGameVar *_gameVar; +	char *_gameName; +	ExCommand _exCommand; +	int _updateCounter; +	int _preloadSceneId; +	int _preloadEntranceId; +}; + +CInventory2 *getGameLoaderInventory(); +CInteractionController *getGameLoaderInteractionController(); +CMctlCompound *getSc2MctlCompoundBySceneId(int16 sceneId); + +} // End of namespace Fullpipe + +#endif /* FULLPIPE_GAMELOADER_H */ diff --git a/engines/fullpipe/gfx.cpp b/engines/fullpipe/gfx.cpp new file mode 100644 index 0000000000..c6024d15e0 --- /dev/null +++ b/engines/fullpipe/gfx.cpp @@ -0,0 +1,1258 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "fullpipe/fullpipe.h" + +#include "fullpipe/objects.h" +#include "fullpipe/gfx.h" +#include "fullpipe/statics.h" +#include "fullpipe/scene.h" +#include "fullpipe/interaction.h" +#include "fullpipe/gameloader.h" + +#include "common/memstream.h" + +namespace Fullpipe { + +Bitmap::Bitmap() { +	_x = 0; +	_y = 0; +	_width = 0; +	_height = 0; +	_pixels = 0; +	_type = 0; +	_dataSize = 0; +	_flags = 0; +} + +Bitmap::Bitmap(Bitmap *src) { +	_x = src->_x; +	_y = src->_y; +	_flags = src->_flags; +	_dataSize = src->_dataSize; +	_type = src->_type; +	_width = src->_width; +	_height = src->_height; +	_pixels = src->_pixels; +} + +Bitmap::~Bitmap() { +	if (_pixels) +		free(_pixels); +} + +void Bitmap::load(Common::ReadStream *s) { +	debug(5, "Bitmap::load()"); + +	_x = s->readUint32LE(); +	_y = s->readUint32LE(); +	_width = s->readUint32LE(); +	_height = s->readUint32LE(); +	s->readUint32LE(); // pixels +	_type = s->readUint32LE(); +	_dataSize = s->readUint32LE(); +	_flags = s->readUint32LE(); + +	debug(8, "Bitmap: x: %d y: %d w: %d h: %d dataSize: 0x%x", _x, _y, _width, _height, _dataSize); +	debug(8, "Bitmap: type: %s (0x%04x) flags: 0x%x", Common::tag2string(_type).c_str(), _type, _flags); +} + +Background::Background() { +	_x = 0; +	_y = 0; +	_messageQueueId = 0; +	_bigPictureArray1Count = 0; +	_bigPictureArray2Count = 0; +	_bigPictureArray = 0; +	_bgname = 0; +	_palette = 0; +} + +bool Background::load(MfcArchive &file) { +	debug(5, "Background::load()"); +	_bgname = file.readPascalString(); + +	int count = file.readUint16LE(); + +	for (int i = 0; i < count; i++) { +		PictureObject *pct = new PictureObject(); + +		pct->load(file, i == 0); +		addPictureObject(pct); +	} + +	assert(g_fullpipe->_gameProjectVersion >= 4); + +	_bigPictureArray1Count = file.readUint32LE(); + +	assert(g_fullpipe->_gameProjectVersion >= 5); + +	_bigPictureArray2Count = file.readUint32LE(); + +	_bigPictureArray = (BigPicture ***)calloc(_bigPictureArray1Count, sizeof(BigPicture **)); + +	debug(6, "bigPictureArray[%d][%d]", _bigPictureArray1Count, _bigPictureArray2Count); + +	for (int i = 0; i < _bigPictureArray1Count; i++) { +		_bigPictureArray[i] = (BigPicture **)calloc(_bigPictureArray2Count, sizeof(BigPicture *)); +		for (int j = 0; j < _bigPictureArray2Count; j++) { +			_bigPictureArray[i][j] = new BigPicture(); + +			_bigPictureArray[i][j]->load(file); +		} +	} + +	return true; +} + +void Background::addPictureObject(PictureObject *pct) { +	if (pct->_okeyCode) +		pct->renumPictures(&_picObjList); + +	bool inserted = false; +	for (uint i = 0; i < _picObjList.size(); i++) { +		if (((PictureObject *)_picObjList[i])->_priority == pct->_priority) { +			_picObjList.insert_at(i, pct); +			inserted = true; +			break; +		} +	} + +	if (!inserted) { +		_picObjList.push_back(pct); +	} +} + +PictureObject::PictureObject() { +	_ox = 0; +	_oy = 0; +	_picture = 0; +	_ox2 = 0; +	_oy2 = 0; +	_pictureObject2List = 0; +	_objtype = kObjTypePictureObject; +} + +PictureObject::PictureObject(PictureObject *src) : GameObject(src) { +	_picture = src->_picture; +	_ox2 = _ox; +	_oy2 = _oy; +	_pictureObject2List = src->_pictureObject2List; +	_objtype = kObjTypePictureObject; +} + +bool PictureObject::load(MfcArchive &file, bool bigPicture) { +	debug(5, "PictureObject::load()"); +	GameObject::load(file); + +	if (bigPicture) +		_picture = new BigPicture(); +	else +		_picture = new Picture(); + +	_picture->load(file); + +	_pictureObject2List = new CPtrList(); + +	int count = file.readUint16LE(); + +	if (count > 0) { +		GameObject *o = new GameObject(); +		 +		o->load(file); +		_pictureObject2List->push_back(o); +	} + +	_ox2 = _ox; +	_oy2 = _oy; + +#if 0 +	_picture->displayPicture(); +#endif + +	return true; +} + +Common::Point *PictureObject::getDimensions(Common::Point *p) { +	_picture->getDimensions(p); + +	return p; +} + +void PictureObject::draw() { +	if (_flags & 1) +		_picture->draw(_ox, _oy, 2, 0); +	else +		_picture->draw(_ox, _oy, 0, 0); +} + +void PictureObject::drawAt(int x, int y) { +	if (x == -1) +		x = _ox; +	if (y == -1) +		y = _oy; + +	_picture->_x = x; +	_picture->_y = y; + +	if (_flags & 1) +		_picture->draw(x, y, 2, 0); +	else +		_picture->draw(x, y, 0, 0); +} + +bool PictureObject::setPicAniInfo(PicAniInfo *picAniInfo) { +	if (!(picAniInfo->type & 2) || (picAniInfo->type & 1)) { +		error("Picture::setPicAniInfo(): Wrong type: %d", picAniInfo->type); + +		return false; +	} + +	if (picAniInfo->type & 2) { +		setOXY(picAniInfo->ox, picAniInfo->oy); +		_priority = picAniInfo->priority; +		_okeyCode = picAniInfo->field_8; +		setFlags(picAniInfo->flags); +		_field_8 = picAniInfo->field_24; + +		return true; +	} + +	return false; +} + +bool PictureObject::isPointInside(int x, int y) { +	bool res; +	int oldx = _picture->_x; +	int oldy = _picture->_y; + +	_picture->_x = _ox; +	_picture->_y = _oy; + +	res = _picture->isPointInside(x, y); + +	_picture->_x = oldx; +	_picture->_y = oldy; + +	return res; +} + +bool PictureObject::isPixelHitAtPos(int x, int y) { +	int oldx = _picture->_x; +	int oldy = _picture->_y; + +	_picture->_x = _ox; +	_picture->_y = _oy; +	bool res = _picture->isPixelHitAtPos(x, y); +	_picture->_x = oldx; +	_picture->_y = oldy; + +	return res; +} + +GameObject::GameObject() { +	_okeyCode = 0; +	_flags = 0; +	_id = 0; +	_ox = 0; +	_oy = 0; +	_priority = 0; +	_field_20 = 0; +	_field_8 = 0; +	_objectName = 0; +} + +GameObject::GameObject(GameObject *src) { +	_okeyCode = 1; +	_flags = 0; +	_id = src->_id; + +	_objectName = (char *)calloc(strlen(src->_objectName) + 1, 1); +	strncpy(_objectName, src->_objectName, strlen(src->_objectName)); + +	_ox = src->_ox; +	_oy = src->_oy; +	_priority = src->_priority; +	_field_20 = 1; +	_field_8 = src->_field_8; +} + +GameObject::~GameObject() { +	free(_objectName); +} + +bool GameObject::load(MfcArchive &file) { +	debug(5, "GameObject::load()"); +	_okeyCode = 0; +	_flags = 0; +	_field_20 = 0; +	 +	_id = file.readUint16LE(); +	 +	_objectName = file.readPascalString(); +	_ox = file.readUint32LE(); +	_oy = file.readUint32LE(); +	_priority = file.readUint16LE(); + +	if (g_fullpipe->_gameProjectVersion >= 11) { +		_field_8 = file.readUint32LE(); +	} + +	return true; +} + +void GameObject::setOXY(int x, int y) { +	_ox = x; +	_oy = y; +} + +void GameObject::renumPictures(CPtrList *lst) { +	int *buf = (int *)calloc(lst->size() + 2, sizeof(int)); + +	for (uint i = 0; i < lst->size(); i++) { +		if (_id == ((PictureObject *)((*lst)[i]))->_id) +			buf[((PictureObject *)((*lst)[i]))->_okeyCode] = 1; +	} + +	if (buf[_okeyCode]) { +		uint count; +		for (count = 1; buf[count] && count < lst->size() + 2; count++) +			; +		_okeyCode = count; +	} + +	free(buf); +} + +bool GameObject::canInteractAny(GameObject *obj2, int invId) { +	int sceneId = 0; + +	if (g_fullpipe->_currentScene) +		sceneId = g_fullpipe->_currentScene->_sceneId; + +	CInteractionController *intC = getGameLoaderInteractionController(); +	for (CObList::iterator i = intC->_interactions.begin(); i != intC->_interactions.end(); ++i) { +		CInteraction *intr = (CInteraction *)*i; + +		if (intr->_sceneId > 0 && intr->_sceneId != sceneId) +			break; + +		if (invId == -3) { +			invId = getGameLoaderInventory()->getSelectedItemId(); +		} +		if (intr->canInteract(this, obj2, invId)) +			return true; +	} +	return false; +} + +bool GameObject::getPicAniInfo(PicAniInfo *info) { +	if (_objtype == kObjTypePictureObject) { +		info->type = 2; +		info->objectId = _id; +		info->sceneId = 0; +		info->field_8 = _okeyCode; +		info->flags = _flags; +		info->field_24 = _field_8; +		info->ox = _ox; +		info->oy = _oy; +		info->priority = _priority; + +		return true; +	} + +	if (_objtype == kObjTypeStaticANIObject) { +		StaticANIObject *ani = (StaticANIObject *)this; + +		info->type = (ani->_messageQueueId << 16) | 1; +		info->objectId = ani->_id; +		info->field_8 = ani->_okeyCode; +		info->sceneId = ani->_sceneId; +		info->flags = ani->_flags; +		info->field_24 = ani->_field_8; +		if (ani->_movement) { +			info->ox = ani->_movement->_ox; +			info->oy = ani->_movement->_oy; +		} else { +			info->ox = ani->_ox; +			info->oy = ani->_oy; +		} +		info->priority = ani->_priority; + +		if (ani->_statics) +			info->staticsId = ani->_statics->_staticsId; + +		if (ani->_movement) { +			info->movementId = ani->_movement->_id; +			info->dynamicPhaseIndex = ani->_movement->_currDynamicPhaseIndex; +		} + +		info->someDynamicPhaseIndex = ani->_someDynamicPhaseIndex; + +		return true; +	} + +	return false; +} + +bool GameObject::setPicAniInfo(PicAniInfo *picAniInfo) { +	if (!(picAniInfo->type & 3)) { +		warning("StaticANIObject::setPicAniInfo(): Wrong type: %d", picAniInfo->type); + +		return false; +	} + +	if (picAniInfo->type & 3) { +		setOXY(picAniInfo->ox, picAniInfo->oy); +		_priority = picAniInfo->priority; +		_okeyCode = picAniInfo->field_8; +		setFlags(picAniInfo->flags); +		_field_8 = picAniInfo->field_24; +	} + +	if (picAniInfo->type & 1) { +		StaticANIObject *ani = (StaticANIObject *)this; + +		ani->_messageQueueId = (picAniInfo->type >> 16) & 0xffff; + +		if (picAniInfo->staticsId) { +			ani->_statics = ani->getStaticsById(picAniInfo->staticsId); +		} else { +			ani->_statics = 0; +		} + +		if (picAniInfo->movementId) { +			ani->_movement = ani->getMovementById(picAniInfo->movementId); +			if (ani->_movement) +				ani->_movement->setDynamicPhaseIndex(picAniInfo->dynamicPhaseIndex); +		} else { +			ani->_movement = 0; +		} + +		ani->setSomeDynamicPhaseIndex(picAniInfo->someDynamicPhaseIndex); +	} + +	return true; +} + +Picture::Picture() { +	_x = 0; +	_y = 0; +	_field_44 = 0; +	_field_54 = 0; +	_bitmap = 0; +	_alpha = -1; +	_paletteData = 0; +	_convertedBitmap = 0; +	_memoryObject2 = 0; +	_width = 0; +	_height = 0; +} + +Picture::~Picture() { +	freePicture(); + +	_bitmap = 0; + +	if (_memoryObject2) +		delete _memoryObject2; + +	if (_paletteData) +		free(_paletteData); + +	if (_convertedBitmap) { +		delete _convertedBitmap; +		_convertedBitmap = 0; +	} +} + +void Picture::freePicture() { +	if (_bitmap) { +		if (testFlags() && !_field_54) { +			freeData(); +			delete _bitmap; +			_bitmap = 0; +		} +	} + +	if (_bitmap) { +		_bitmap = 0; +		_data = 0; +	} + +	if (_convertedBitmap) { +		free(_convertedBitmap->_pixels); +		delete _convertedBitmap; +		_convertedBitmap = 0; +	} +} + +bool Picture::load(MfcArchive &file) { +	debug(5, "Picture::load()"); +	MemoryObject::load(file); + +	_x = file.readUint32LE(); +	_y = file.readUint32LE(); +	_field_44 = file.readUint16LE(); +	 +	assert(g_fullpipe->_gameProjectVersion >= 2); + +	_width = file.readUint32LE(); +	_height = file.readUint32LE(); + +	_mflags |= 1; + +	_memoryObject2 = new MemoryObject2; +	_memoryObject2->load(file); + +	if (_memoryObject2->_data) { +		setAOIDs(); +	} + +	assert (g_fullpipe->_gameProjectVersion >= 12); + +	_alpha = file.readUint32LE() & 0xff; + +	int havePal = file.readUint32LE(); + +	if (havePal > 0) { +		_paletteData = (byte *)calloc(1024, 1); +		file.read(_paletteData, 1024); +	} + +	getData(); + +	debug(5, "Picture::load: <%s>", _memfilename); + +	return true; +} + +void Picture::setAOIDs() { +	int w = (g_fullpipe->_pictureScale + _width - 1) / g_fullpipe->_pictureScale; +	int h = (g_fullpipe->_pictureScale + _height - 1) / g_fullpipe->_pictureScale; + +	_memoryObject2->_rows = (byte **)malloc(w * sizeof(int *)); + +	int pitch = 2 * h; +	byte *ptr = _memoryObject2->getData(); +	for (int i = 0; i < w; i++) { +		_memoryObject2->_rows[i] = ptr; +		ptr += pitch; +	} +} + +void Picture::init() { +	_bitmap = new Bitmap(); + +	getDibInfo(); + +	_bitmap->_flags |= 0x1000000; +} + +Common::Point *Picture::getDimensions(Common::Point *p) { +	p->x = _width; +	p->y = _height; + +	return p; +} + +void Picture::getDibInfo() { +	int off = _dataSize & ~0xf; + +	debug(9, "Picture::getDibInfo: _dataSize: %d", _dataSize); + +	if (!_dataSize) { +		warning("Picture::getDibInfo(): Empty data size"); +		return; +	} + +	if (_dataSize != off) { +		warning("Uneven data size: 0x%x", _dataSize); +	} + +	Common::MemoryReadStream *s = new Common::MemoryReadStream(_data + off - 32, 32); + +	_bitmap->load(s); +	_bitmap->_pixels = _data; +} + +Bitmap *Picture::getPixelData() { +	if (!_bitmap) +		init(); + +	return _bitmap; +} + +void Picture::draw(int x, int y, int style, int angle) { +	int x1 = x; +	int y1 = y; + +	debug(0, "Picture::draw(%d, %d, %d, %d) (%s)", x, y, style, angle, _memfilename); + +	if (x != -1) +		x1 = x; + +	if (y != -1) +		y1 = y; + +	if (!_bitmap) +		init(); + +	if (!_bitmap) +		return; + +	if ((_alpha & 0xff) < 0xff) { +		debug(0, "Picture:draw: alpha = %0x", _alpha); +	} + +	byte *pal = _paletteData; + +	if (!pal) { +		//warning("Picture:draw: using global palette"); +		pal = g_fullpipe->_globalPalette; +	} + +	Common::Point point; + +	switch (style) { +	case 1: +		//flip +		getDimensions(&point); +		_bitmap->flipVertical()->drawShaded(1, x1, y1 + 30 + point.y, pal); +		break; +	case 2: +		//vrtSetFadeRatio(g_vrtDrawHandle, 0.34999999); +		//vrtSetFadeTable(g_vrtDrawHandle, &unk_477F88, 1.0, 1000.0, 0, 0); +		_bitmap->drawShaded(2, x1, y1, pal); +		//vrtSetFadeRatio(g_vrtDrawHandle, 0.0); +		//vrtSetFadeTable(g_vrtDrawHandle, &unk_477F90, 1.0, 1000.0, 0, 0); +		break; +	default: +		if (angle) +			drawRotated(x1, y1, angle); +		else { +			_bitmap->putDib(x1, y1, (int32 *)pal); +		} +	} +} + +void Picture::drawRotated(int x, int y, int angle) { +	warning("STUB: Picture::drawRotated(%d, %d, %d)", x, y, angle); +} + +void Picture::displayPicture() { +	if (!g_fullpipe->_gameContinue) +		return; + +	getData(); +	init(); + +	if (!_dataSize) +		return; + +	g_fullpipe->_backgroundSurface.fillRect(Common::Rect(0, 0, 799, 599), 0); +	g_fullpipe->_system->copyRectToScreen(g_fullpipe->_backgroundSurface.getBasePtr(0, 0), g_fullpipe->_backgroundSurface.pitch, 0, 0, 799, 599); + +	draw(0, 0, 0, 0); + +	g_fullpipe->updateEvents(); +	g_fullpipe->_system->delayMillis(10); +	g_fullpipe->_system->updateScreen(); + +	while (g_fullpipe->_gameContinue) { +		g_fullpipe->updateEvents(); +		g_fullpipe->_system->delayMillis(10); +		g_fullpipe->_system->updateScreen(); + +		if (g_fullpipe->_keyState == ' ') { +			g_fullpipe->_keyState = Common::KEYCODE_INVALID; +			break; +		} +	} +} + +void Picture::setPaletteData(byte *pal) { +	if (_paletteData) +		free(_paletteData); + +	if (pal) { +		_paletteData = (byte *)malloc(1024); +		memcpy(_paletteData, pal, 1024); +	} +} + +void Picture::copyMemoryObject2(Picture *src) { +	if (_width == src->_width && _height == src->_height) { +		if (src->_memoryObject2 && src->_memoryObject2->_rows && _memoryObject2) { +			byte *data = loadData(); +			_memoryObject2->copyData(data, _dataSize); +			setAOIDs(); +		} +	} +} + +bool Picture::isPointInside(int x, int y) { +	if (x >= _x) { +		if (y >= _y && x < _x + _width && y < _y + _height) +			return true; +	} +	return false; +} + +bool Picture::isPixelHitAtPos(int x, int y) { +	if (x < _x || y < _y || x >= _x + _width || y >= _y + _height) +		return false; + +	if (!_bitmap) +		init(); + +	_bitmap->_x = _x; +	_bitmap->_y = _y; + +	return _bitmap->isPixelHitAtPos(x, y); +} + +int Picture::getPixelAtPos(int x, int y) { +	return getPixelAtPosEx(x / g_fullpipe->_pictureScale, y / g_fullpipe->_pictureScale); + +	return false; +} + +int Picture::getPixelAtPosEx(int x, int y) { +	if (x < 0 || y < 0) +		return 0; + +	if (x < (g_fullpipe->_pictureScale + _width - 1) / g_fullpipe->_pictureScale && +			y < (g_fullpipe->_pictureScale + _height - 1) / g_fullpipe->_pictureScale && +			_memoryObject2 != 0 && _memoryObject2->_rows != 0) +		return _memoryObject2->_rows[x][2 * y]; + +	return 0; +} + +bool Bitmap::isPixelHitAtPos(int x, int y) { +	if (x < _x || x >= _width + _x || y < _y || y >= _y + _height) +		return false; + +	int off; + +	if (_type == 'CB\x05e') +		off = 2 * ((_width + 1) / 2); +	else +		off = 4 * ((_width + 3) / 4); + +	off = x + off * (_y + _height - y - 1) - _x; + +	if (_flags & 0x1000000) { +		switch (_type) { +		case 'CB\0\0': +			if (_pixels[off] == (_flags & 0xff)) +				return false; +			break; +		case 'CB\x05e': +			if (!*(int16 *)&_pixels[2 * off]) +				return false; +			break; +		case 'RB\0\0': +			return isPixelAtHitPosRB(x, y); +		} +	} +	return true; +} + +bool Bitmap::isPixelAtHitPosRB(int x, int y) { +	int ox = _x; +	int oy = _y; + +	_x = _y = 0; + +	bool res = putDibRB(0, x, y); +	_x = ox; +	_y = oy; + +	return res; +} + +void Bitmap::putDib(int x, int y, int32 *palette) { +	debug(0, "Bitmap::putDib(%d, %d)", x, y); + +	_x = x - g_fullpipe->_sceneRect.left; +	_y = y - g_fullpipe->_sceneRect.top; + +	if (_type == MKTAG('R', 'B', '\0', '\0')) +		putDibRB(palette); +	else +		putDibCB(palette); +} + +bool Bitmap::putDibRB(int32 *palette, int pX, int pY) { +	uint16 *curDestPtr; +	int endy; +	int x; +	int start1; +	int fillLen; +	uint16 pixel; +	int endx; +	int y; +	uint16 *srcPtr2; +	uint16 *srcPtr; + +	if (!palette && pX == -1) +		error("Bitmap::putDibRB(): Both global and local palettes are empty"); + +	debug(8, "Bitmap::putDibRB()"); + +	endx = _width + _x - 1; +	endy = _height + _y - 1; + +	if (_x > 799 || endx < 0 || _y > 599 || endy < 0) +		return false; + +	if (pX == -1) { +		if (endy > 599) +			endy = 599; + +		if (endx > 799) +			endx = 799; +	} + +	int startx = _x; +	if (startx < 0) +		startx = 0; + +	int starty = _y; +	if (starty < 0) +		starty = 0; + +	y = endy; + +	srcPtr = (uint16 *)_pixels; + +	bool breakup = false; +	for (y = endy; y >= starty && !breakup; y--) { +		x = startx; + +		while ((pixel = *srcPtr++) != 0) { +			if (pixel == 0x100) { +				breakup = true; +				break; +			} + +			while (pixel == 0x200 && y >= starty) { +				uint16 value = *srcPtr++; + +				x += (byte)(value & 0xff); +				y -= (byte)((value >> 8) & 0xff); + +				pixel = *srcPtr++; +			} + +			if (y < starty || pixel == 0) +				break; + +			start1 = x; +			fillLen = (byte)(pixel & 0xff); + +			if (fillLen) { +				x += fillLen; + +				if (start1 < 0) { +					fillLen += start1; + +					if (fillLen > 0) +						start1 = 0; +				} + +				if (fillLen > 0 || start1 >= 0) { +					if (x <= 799 + 1 || (fillLen += 799 - x + 1, fillLen > 0)) { +						if (y <= endy) { +							if (pX == -1) { +								int bgcolor = palette[(pixel >> 8) & 0xff]; +								curDestPtr = (uint16 *)g_fullpipe->_backgroundSurface.getBasePtr(start1, y); +								colorFill(curDestPtr, fillLen, bgcolor); +							} else { +								if (y == pY && pX >= start1 && pX < start1 + fillLen) +									return true; +							} +						} +					} +				} +			} else { +				fillLen = (pixel >> 8) & 0xff; +				srcPtr2 = srcPtr; +				x += fillLen; +				srcPtr += (fillLen + 1) >> 1; + +				if (start1 < 0) { +					fillLen += start1; +					if (fillLen > 0) { +						srcPtr2 = (uint16 *)((byte *)srcPtr2 - start1); +						start1 = 0; +					} +				} + +				if (x > 799 + 1) { +					fillLen += 799 - x + 1; +					if (fillLen <= 0) +						continue; +				} + +				if (y <= endy) { +					if (pX == -1) { +						curDestPtr = (uint16 *)g_fullpipe->_backgroundSurface.getBasePtr(start1, y); +						paletteFill(curDestPtr, (byte *)srcPtr2, fillLen, (int32 *)palette); +					} else { +						if (y == pY && pX >= start1 && pX < start1 + fillLen) +							return true; +					} +				} +			} +		} +	} + +	if (pX == -1) +		g_fullpipe->_system->copyRectToScreen(g_fullpipe->_backgroundSurface.getBasePtr(startx, starty), g_fullpipe->_backgroundSurface.pitch, startx, starty, endx + 1 - startx, endy + 1 - starty); + +	return false; +} + +void Bitmap::putDibCB(int32 *palette) { +	uint16 *curDestPtr; +	int endx; +	int endy; +	int bpp; +	uint pitch; +	bool cb05_format; + +	endx = _width + _x - 1; +	endy = _height + _y - 1; + +	debug(8, "Bitmap::putDibCB(): %d, %d, %d, %d [%d, %d]", _x, _y, endx, endy, _width, _height); + +	if (_x > 799 || endx < 0 || _y > 599 || endy < 0) +		return; + +	if (endy > 599) +		endy = 599; + +	if (endx > 799) +		endx = 799; + +	cb05_format = (_type == MKTAG('C', 'B', '\05', 'e')); + +	if (!palette && !cb05_format) +		error("Bitmap::putDibCB(): Both global and local palettes are empty"); + +	bpp = cb05_format ? 2 : 1; +	pitch = (bpp * _width + 3) & 0xFFFFFFFC; + +	byte *srcPtr = &_pixels[pitch * (endy - _y)]; + +	int starty = _y; +	if (starty < 0) { +		starty = 0; +		srcPtr = &_pixels[pitch * (_height + _y)]; +	} + +	int startx = _x; +	if (startx < 0) { +		srcPtr += bpp * -_x; +		startx = 0; +	} + +	if (_flags & 0x1000000) { +		for (int y = starty; y < endy; srcPtr -= pitch, y++) { +			curDestPtr = (uint16 *)g_fullpipe->_backgroundSurface.getBasePtr(startx, y); +			copierKeyColor(curDestPtr, srcPtr, endx - startx + 1, _flags & 0xff, (int32 *)palette, cb05_format); +		} +	} else { +		for (int y = starty; y <= endy; srcPtr -= pitch, y++) { +			curDestPtr = (uint16 *)g_fullpipe->_backgroundSurface.getBasePtr(startx, y); +			copier(curDestPtr, srcPtr, endx - startx + 1, (int32 *)palette, cb05_format); +		} +	} + +	g_fullpipe->_system->copyRectToScreen(g_fullpipe->_backgroundSurface.getBasePtr(startx, starty), g_fullpipe->_backgroundSurface.pitch, startx, starty, endx + 1 - startx, endy + 1 - starty); +} + +void Bitmap::colorFill(uint16 *dest, int len, int32 color) { +#if 0 +	if (blendMode) { +		if (blendMode != 1) +			error("vrtPutDib : RLE Fill : Invalid alpha blend mode"); + +		colorFill = ptralphaFillColor16bit; +	} else { +		colorFill = ptrfillColor16bit; +	} +#endif + +	for (int i = 0; i < len; i++) +		*dest++ = (int16)(color & 0xffff); +} + +void Bitmap::paletteFill(uint16 *dest, byte *src, int len, int32 *palette) { +#if 0 +	if (blendMode) { +		if (blendMode != 1) +			error("vrtPutDib : RLE Fill : Invalid alpha blend mode"); + +		paletteFill = ptrcopierWithPaletteAlpha; +	} else { +		paletteFill = ptrcopierWithPalette; +	} +#endif + +	for (int i = 0; i < len; i++) +		*dest++ = READ_LE_UINT32(&palette[*src++]) & 0xffff; +} + +void Bitmap::copierKeyColor(uint16 *dest, byte *src, int len, int keyColor, int32 *palette, bool cb05_format) { +#if 0 +	if (blendMode) { +		if (blendMode == 1) { +			if (cb05_format) +				copierKeyColor = ptrcopier16bitKeycolorAlpha; +			else +				copierKeyColor = ptrcopierKeycolorAlpha; +		} else { +			copier = 0; +		} +	} else if (cb05_format) { +		copierKeyColor = ptrcopier16bitKeycolor; +	} else { +		copierKeyColor = ptrkeyColor16bit; +	} +#endif + +	if (!cb05_format) { +		for (int i = 0; i < len; i++) { +			if (*src != keyColor) +				*dest = READ_LE_UINT32(&palette[*src]) & 0xffff; + +			dest++; +			src++; +		} +	} else { +		int16 *src16 = (int16 *)src; + +		for (int i = 0; i < len; i++) { +			if (*src16 != 0) +				*dest = *src16; + +			dest++; +			src16++; +		} +	} +} + +void Bitmap::copier(uint16 *dest, byte *src, int len, int32 *palette, bool cb05_format) { +#if 0 +	if (blendMode) { +		if (blendMode == 1) { +			if (cb05_format) +				copier = ptrcopier16bitAlpha; +			else +				copier = ptrcopierWithPaletteAlpha; +		} else { +			copier = 0; +		} +	} else if (cb05_format) { +		copier = ptrcopier16bit; +	} else { +		copier = ptrcopierWithPalette; +	} +#endif + +	if (!cb05_format) { +		for (int i = 0; i < len; i++) +			*dest++ = READ_LE_UINT32(&palette[*src++]) & 0xffff; +	} else { +		int16 *src16 = (int16 *)src; + +		for (int i = 0; i < len; i++) +			*dest++ = *src16++; +	} +} + +Bitmap *Bitmap::reverseImage() { +	switch (_type) { +	case MKTAG('R', 'B', '\0', '\0'): +		return reverseImageRB(); +	case MKTAG('C', 'B', '\0', '\0'): +		return reverseImageCB(); +	case MKTAG('C', 'B', '\05', 'e'): +		return reverseImageCB05(); +	default: +		error("Bitmap::reverseImage: Unknown image type: %x", _type); +	} + +	return 0; +} + +Bitmap *Bitmap::reverseImageRB() { +	uint16 *newpixels = (uint16 *)calloc(((_dataSize + 15) & 0xfffffff0) + sizeof(Bitmap), 1); +	uint16 *srcPtr = (uint16 *)_pixels; + +	int idx = 0; +	while (srcPtr[idx] != 0x100) { +		uint16 *srcPtr2 = &srcPtr[idx]; + +		int prevIdx = idx; +		int i = idx; + +		while (*srcPtr2) { +			++srcPtr2; +			++idx; +		} + +		int idx2 = idx; + +		newpixels[idx] = srcPtr[idx]; + +		while (i != idx) { +			int fillLen = 2 - ((srcPtr[prevIdx] & 0xff) != 0 ? 1 : 0); +			idx2 -= fillLen; +			memcpy(&newpixels[idx2], &srcPtr[prevIdx], 2 * fillLen); +			prevIdx = fillLen + i; +			i += fillLen; +		} +		++idx; +	} +	newpixels[idx] = 256; + +	int oldBmp = ((_dataSize + 15) >> 1) & 0x7FFFFFF8; +	memcpy(&newpixels[oldBmp], &srcPtr[oldBmp], sizeof(Bitmap)); + +	Bitmap *res = new Bitmap(this); +	res->_pixels = (byte *)newpixels; + +	return res; +} + +Bitmap *Bitmap::reverseImageCB() { +	warning("STUB: Bitmap::reverseImageCB()"); + +	return this; +} + +Bitmap *Bitmap::reverseImageCB05() { +	warning("STUB: Bitmap::reverseImageCB05()"); + +	return this; +} + +Bitmap *Bitmap::flipVertical() { +	warning("STUB: Bitmap::flipVertical()"); + +	return this; +} + +void Bitmap::drawShaded(int type, int x, int y, byte *palette) { +	warning("STUB: Bitmap::drawShaded(%d, %d, %d)", type, x, y); + +	putDib(x, y, (int32 *)palette); +} + +	void Bitmap::drawRotated(int x, int y, int angle, byte *palette) { +	warning("STUB: Bitmap::drawShaded(%d, %d, %d)", x, y, angle); + +	putDib(x, y, (int32 *)palette); +} + +bool BigPicture::load(MfcArchive &file) { +	debug(5, "BigPicture::load()"); +	Picture::load(file); + +	return true; +} + +Shadows::Shadows() { +	_staticAniObjectId = 0; +	_movementId = 0; +	_sceneId = 0; +} + +bool Shadows::load(MfcArchive &file) { +	debug(5, "Shadows::load()"); +	_sceneId = file.readUint32LE(); +	_staticAniObjectId = file.readUint32LE(); +	_movementId = file.readUint32LE(); + +	return true; +} + +void Shadows::init() { +	Scene *scene = g_fullpipe->accessScene(_sceneId); + +	StaticANIObject *st; +	Movement *mov; + +	if (scene && (st = scene->getStaticANIObject1ById(_staticAniObjectId, -1)) != 0 +		&& ((mov = st->getMovementById(_movementId)) != 0)) +		initMovement(mov); +} + +void Shadows::initMovement(Movement *mov) { +	uint num; + +	if (mov->_currMovement) +		num = mov->_currMovement->_dynamicPhases.size(); +	else +		num = mov->_dynamicPhases.size(); + +	_items.clear(); +	_items.resize(num); + +	Common::Point point; + +	_items[0].dynPhase = (DynamicPhase *)mov->_staticsObj1; +	_items[0].dynPhase->getDimensions(&point); +	_items[0].width = point.x; +	_items[0].height = point.y; + +	for (uint i = 1; i < num; i++) { +		_items[i].dynPhase = mov->getDynamicPhaseByIndex(i - 1); +		_items[i].dynPhase->getDimensions(&point); +		_items[i].width = point.x; +		_items[i].height = point.y; +	} +} + +DynamicPhase *Shadows::findSize(int width, int height) { +	int idx = 0; +	int min = 1000; + +	if (!_items.size()) +		return 0; + +	for (uint i = 0; i < _items.size(); i++) { +		int w = abs(width - _items[i].width); +		if (w < min) { +			min = w; +			idx = i; +		} +	} +	return _items[idx].dynPhase; +} + +} // End of namespace Fullpipe diff --git a/engines/fullpipe/gfx.h b/engines/fullpipe/gfx.h new file mode 100644 index 0000000000..10b82efede --- /dev/null +++ b/engines/fullpipe/gfx.h @@ -0,0 +1,217 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef FULLPIPE_GFX_H +#define FULLPIPE_GFX_H + +namespace Fullpipe { + +class DynamicPhase; +class Movement; +struct PicAniInfo; + +struct Bitmap { +	int _x; +	int _y; +	int _width; +	int _height; +	byte *_pixels; +	int _type; +	int _dataSize; +	int _flags; + +	Bitmap(); +	Bitmap(Bitmap *src); +	~Bitmap(); + +	void load(Common::ReadStream *s); +	void putDib(int x, int y, int32 *palette); +	bool putDibRB(int32 *palette, int x = -1, int y = -1); +	void putDibCB(int32 *palette); + +	void colorFill(uint16 *dest, int len, int color); +	void paletteFill(uint16 *dest, byte *src, int len, int32 *palette); +	void copierKeyColor(uint16 *dest, byte *src, int len, int keyColor, int32 *palette, bool cb05_format); +	void copier(uint16 *dest, byte *src, int len, int32 *palette, bool cb05_format); + +	Bitmap *reverseImage(); +	Bitmap *reverseImageRB(); +	Bitmap *reverseImageCB(); +	Bitmap *reverseImageCB05(); +	Bitmap *flipVertical(); + +	void drawShaded(int type, int x, int y, byte *palette); +	void drawRotated(int x, int y, int angle, byte *palette); + +	bool isPixelHitAtPos(int x, int y); +	bool isPixelAtHitPosRB(int x, int y); +}; + +class Picture : public MemoryObject { + public: +	Common::Rect _rect; +	Bitmap *_convertedBitmap; +	int _x; +	int _y; +	int _field_44; +	int _width; +	int _height; +	Bitmap *_bitmap; +	int _field_54; +	MemoryObject2 *_memoryObject2; +	int _alpha; +	byte *_paletteData; + +	void displayPicture(); + +  public: +	Picture(); +	virtual ~Picture(); + +	void freePicture(); + +	virtual bool load(MfcArchive &file); +	void setAOIDs(); +	void init(); +	void getDibInfo(); +	Bitmap *getPixelData(); +	void draw(int x, int y, int style, int angle); +	void drawRotated(int x, int y, int angle); + +	byte getAlpha() { return (byte)_alpha; } +	void setAlpha(byte alpha) { _alpha = alpha; } + +	Common::Point *getDimensions(Common::Point *p); +	bool isPointInside(int x, int y); +	bool isPixelHitAtPos(int x, int y); +	int getPixelAtPos(int x, int y); +	int getPixelAtPosEx(int x, int y); + +	byte *getPaletteData() { return _paletteData; } +	void setPaletteData(byte *pal); + +	void copyMemoryObject2(Picture *src); +}; + +class BigPicture : public Picture { +  public: +	BigPicture() {} +	virtual bool load(MfcArchive &file); +}; + +class GameObject : public CObject { +  public: +	int16 _okeyCode; +	int _field_8; +	int16 _flags; +	int16 _id; +	char *_objectName; +	int _ox; +	int _oy; +	int _priority; +	int _field_20; + +  public: +	GameObject(); +	GameObject(GameObject *src); +	~GameObject(); + +	virtual bool load(MfcArchive &file); +	void setOXY(int x, int y); +	void renumPictures(CPtrList *lst); +	void setFlags(int16 flags) { _flags = flags; } +	void clearFlags() { _flags = 0; } +	const char *getName() { return _objectName; } + +	bool canInteractAny(GameObject *obj2, int invId); +	bool getPicAniInfo(PicAniInfo *info); +	bool setPicAniInfo(PicAniInfo *info); +}; + +class PictureObject : public GameObject { +  public: +	Picture *_picture; +	CPtrList *_pictureObject2List; +	int _ox2; +	int _oy2; + +  public: +	PictureObject(); +	PictureObject(PictureObject *src); + +	bool load(MfcArchive &file, bool bigPicture); +	Common::Point *getDimensions(Common::Point *p); +	void draw(); +	void drawAt(int x, int y); + +	bool setPicAniInfo(PicAniInfo *picAniInfo); +	bool isPointInside(int x, int y); +	bool isPixelHitAtPos(int x, int y); +}; + +class Background : public CObject { +  public: +	CPtrList _picObjList; + +	char *_bgname; +	int _x; +	int _y; +	int16 _messageQueueId; +	MemoryObject *_palette; +	int _bigPictureArray1Count; +	int _bigPictureArray2Count; +	BigPicture ***_bigPictureArray; + +  public: +	Background(); +	virtual bool load(MfcArchive &file); +	void addPictureObject(PictureObject *pct); + +	BigPicture *getBigPicture(int x, int y) { return _bigPictureArray[x][y]; } +}; + +struct ShadowsItem { +	int width; +	int height; +	DynamicPhase *dynPhase; +}; + +typedef Common::Array<ShadowsItem> ShadowsItemArray; + +class Shadows : public CObject { +	int _sceneId; +	int _staticAniObjectId; +	int _movementId; +	ShadowsItemArray _items; + +  public: +	Shadows(); +	virtual bool load(MfcArchive &file); +	void init(); + +	void initMovement(Movement *mov); +	DynamicPhase *findSize(int width, int height); +}; + +} // End of namespace Fullpipe + +#endif /* FULLPIPE_GFX_H */ diff --git a/engines/fullpipe/init.cpp b/engines/fullpipe/init.cpp new file mode 100644 index 0000000000..c334542247 --- /dev/null +++ b/engines/fullpipe/init.cpp @@ -0,0 +1,247 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "fullpipe/fullpipe.h" + +#include "fullpipe/objects.h" +#include "fullpipe/gameloader.h" +#include "fullpipe/objectnames.h" +#include "fullpipe/input.h" + +#include "fullpipe/constants.h" + +namespace Fullpipe { + +void FullpipeEngine::initObjectStates() { +	setLevelStates(); + +	setObjectState(sO_Dude, getObjectEnumState(sO_Dude, sO_NotCarryingEgg)); +	setObjectState(sO_EggCracker, getObjectEnumState(sO_EggCracker, sO_DidNotCrackEgg)); +	setObjectState(sO_GuvTheDrawer, getObjectEnumState(sO_GuvTheDrawer, sO_Awaken)); +	setObjectState(sO_EggGulper, getObjectEnumState(sO_EggGulper, sO_First)); +	setObjectState(sO_EggGulperGaveCoin, getObjectEnumState(sO_EggGulperGaveCoin, sO_No)); +	setObjectState(sO_Jar_4, getObjectEnumState(sO_Jar_4, sO_OnTheSpring)); +	setObjectState(sO_GulpedEggs, getObjectEnumState(sO_GulpedEgg, sO_NotPresent)); + +	setSwallowedEggsState(); + +	setObjectState(sO_WeirdWacko, getObjectEnumState(sO_WeirdWacko, sO_InGlasses)); +	setObjectState(sO_TumyTrampie, getObjectEnumState(sO_TumyTrampie, sO_Drinking)); +	setObjectState(sO_StairsUp_8, getObjectEnumState(sO_StairsUp_8, sO_NotBroken)); +	setObjectState(sO_HareTheNooksiter, getObjectEnumState(sO_HareTheNooksiter, sO_WithHandle)); +	setObjectState(sO_Elephantine, getObjectEnumState(sO_Elephantine, sO_WithBoot)); +	setObjectState(sO_Fly_12, 0); +	setObjectState(sO_ClockAxis, getObjectEnumState(sO_ClockAxis, sO_NotAvailable)); +	setObjectState(sO_ClockHandle, getObjectEnumState(sO_ClockHandle, sO_In_7)); +	setObjectState(sO_BigMumsy, getObjectEnumState(sO_BigMumsy, sO_Sleeping)); +	setObjectState(sO_CoinSlot_1, getObjectEnumState(sO_CoinSlot_1, sO_Empty)); +	setObjectState(sO_FriesPit, getObjectEnumState(sO_FriesPit, sO_WithApple)); +	setObjectState(sO_Jug, getObjectEnumState(sO_Jug, sO_Blocked)); +	setObjectState(sO_RightStairs_9, getObjectEnumState(sO_RightStairs_9, sO_ClosedShe)); +	setObjectState(sO_Pipe_9, getObjectEnumState(sO_Pipe_9, sO_WithJug)); +	setObjectState(sO_Inflater, getObjectEnumState(sO_Inflater, sO_WithGum)); +	setObjectState(sO_Swingie, getObjectEnumState(sO_Swingie, sO_Swinging)); +	setObjectState(sO_DudeJumped, getObjectEnumState(sO_DudeJumped, sO_No)); +	setObjectState(sO_Bridge, getObjectEnumState(sO_Bridge, sO_Convoluted)); +	setObjectState(sO_Guardian, getObjectEnumState(sO_Guardian, sO_OnRight)); +	setObjectState(sO_Grandma, getObjectEnumState(sO_Grandma, sO_In_14)); +	setObjectState(sO_Boot_15, getObjectEnumState(sO_Boot_15, sO_NotPresent)); +	setObjectState(sO_LeftPipe_15, getObjectEnumState(sO_LeftPipe_15, sO_OpenedShe)); +	setObjectState(sO_Pedestal_16, getObjectEnumState(sO_Pedestal_16, sO_IsFree)); +	setObjectState(sO_Cup, getObjectEnumState(sO_Cup, sO_InSmokeRoom)); +	setObjectState(sO_Pedestal_17, getObjectEnumState(sO_Pedestal_17, sO_IsFree)); +	setObjectState(sO_UsherHand, getObjectEnumState(sO_UsherHand, sO_WithoutCoin)); +	setObjectState(sO_RightPipe_17, getObjectEnumState(sO_RightPipe_17, sO_ClosedShe)); +	setObjectState(sO_Fly_17, 1); +	setObjectState(sO_DudeSwinged, 0); +	setObjectState(sO_Girl, getObjectEnumState(sO_Girl, sO_Swinging)); +	setObjectState(sO_Sugar, getObjectEnumState(sO_Sugar, sO_Present)); +	setObjectState(sO_Janitors, getObjectEnumState(sO_Janitors, sO_Together)); +	setObjectState(sO_Bag_22, getObjectEnumState(sO_Bag_22, sO_NotFallen)); +	setObjectState(sO_Grandpa, getObjectEnumState(sO_Grandpa, sO_InSock)); +	setObjectState(sO_CoinSlot_22, getObjectEnumState(sO_CoinSlot_22, sO_Empty)); +	setObjectState(sO_UpperHatch_23, getObjectEnumState(sO_UpperHatch_23, sO_Closed)); +	setObjectState(sO_LowerHatch_23, getObjectEnumState(sO_LowerHatch_23, sO_Closed)); +	setObjectState(sO_Lever_23, getObjectEnumState(sO_Lever_23, sO_NotTaken)); +	setObjectState(sO_LeverHandle_23, getObjectEnumState(sO_LeverHandle_23, sO_WithoutStool)); +	setObjectState(sO_LowerPipe_21, getObjectEnumState(sO_LowerPipe_21, sO_ClosedShe)); +	setObjectState(sO_StarsDown_24, getObjectEnumState(sO_StarsDown_24, sO_OpenedShe)); +	setObjectState(sO_Hatch_26, getObjectEnumState(sO_Hatch_26, sO_Closed)); +	setObjectState(sO_Sock_26, getObjectEnumState(sO_Sock_26, sO_NotHanging)); +	setObjectState(sO_LeftPipe_26, getObjectEnumState(sO_LeftPipe_26, sO_ClosedShe)); +	setObjectState(sO_Valve1_26, getObjectEnumState(sO_Valve1_26, sO_Opened)); +	setObjectState(sO_Valve2_26, getObjectEnumState(sO_Valve2_26, sO_Closed)); +	setObjectState(sO_Valve3_26, getObjectEnumState(sO_Valve3_26, sO_Closed)); +	setObjectState(sO_Valve4_26, getObjectEnumState(sO_Valve4_26, sO_Closed)); +	setObjectState(sO_Valve5_26, getObjectEnumState(sO_Valve5_26, sO_Opened)); +	setObjectState(sO_Pool, getObjectEnumState(sO_Pool, sO_Overfull)); +	setObjectState(sO_Plank_25, getObjectEnumState(sO_Plank_25, sO_NearDudesStairs)); +	setObjectState(sO_Driver, getObjectEnumState(sO_Driver, sO_WithSteering)); +	setObjectState(sO_Janitress, getObjectEnumState(sO_Janitress, sO_WithMop)); +	setObjectState(sO_LeftPipe_29, getObjectEnumState(sO_LeftPipe_29, sO_ClosedShe)); +	setObjectState(sO_LeftPipe_30, getObjectEnumState(sO_LeftPipe_30, sO_ClosedShe)); +	setObjectState(sO_Leg, getObjectEnumState(sO_Leg, sO_ShowingHeel)); +	setObjectState(sO_Tub, getObjectEnumState(sO_Tub, sO_EmptyShe)); +	setObjectState(sO_Cactus, getObjectEnumState(sO_Cactus, sO_NotGrown)); +	setObjectState(sO_Fireman, getObjectEnumState(sO_Fireman, sO_WithHose)); +	setObjectState(sO_Cube, getObjectEnumState(sO_Cube, sO_In_33)); +	setObjectState(sO_MommyOfHandle_32, getObjectEnumState(sO_MommyOfHandle_32, sO_WithoutHandle)); +	setObjectState(sO_Pedestal_33, getObjectEnumState(sO_Pedestal_33, sO_IsFree)); +	setObjectState(sO_Valve_34, getObjectEnumState(sO_Valve_34, sO_WithNothing)); +	setObjectState(sO_Stool_34, getObjectEnumState(sO_Stool_34, sO_WithoutDrawer)); +	setObjectState(sO_Plank_34, getObjectEnumState(sO_Plank_34, sO_Passive)); +	setObjectState(sO_Hatch_34, getObjectEnumState(sO_Hatch_34, sO_Closed)); +	setObjectState(sO_Valve_35, getObjectEnumState(sO_Valve_35, sO_TurnedOff)); +	setObjectState(sO_Carpet_35, getObjectEnumState(sO_Carpet_35, sO_CannotTake)); +	setObjectState(sO_CoinSlot_35, getObjectEnumState(sO_CoinSlot_35, sO_WithCoin)); +	setObjectState(sO_BellyInflater, getObjectEnumState(sO_BellyInflater, sO_WithCork)); +	setObjectState(sO_Jawcrucnher, getObjectEnumState(sO_Jawcrucnher, sO_WithoutCarpet)); +	setObjectState(sO_Guard_1, getObjectEnumState(sO_Guard_1, sO_On)); +	setObjectState(sO_Gurad_2, getObjectEnumState(sO_Gurad_2, sO_On)); +	setObjectState(sO_Guard_3, getObjectEnumState(sO_Guard_3, sO_On)); +	setObjectState(sO_Bottle_38, getObjectEnumState(sO_Bottle_38, sO_OnTheTable)); +	setObjectState(sO_Boss, getObjectEnumState(sO_Boss, sO_WithHammer)); +} + +void FullpipeEngine::setLevelStates() { +	CGameVar *v = _gameLoader->_gameVar->getSubVarByName("OBJSTATES")->getSubVarByName(sO_LiftButtons); + +	if (v) { +		v->setSubVarAsInt(sO_Level0, 2833); +		v->setSubVarAsInt(sO_Level1, 2754); +		v->setSubVarAsInt(sO_Level2, 2757); +		v->setSubVarAsInt(sO_Level3, 2760); +		v->setSubVarAsInt(sO_Level4, 2763); +		v->setSubVarAsInt(sO_Level5, 2766); +		v->setSubVarAsInt(sO_Level6, 2769); +		v->setSubVarAsInt(sO_Level7, 2772); +		v->setSubVarAsInt(sO_Level8, 2775); +		v->setSubVarAsInt(sO_Level9, 2778); +	} +} + +void FullpipeEngine::addCursor(CursorInfo *cursorInfo, Scene *inv, int pictureId, int hotspotX, int hotspotY, int itemPictureOffsX, int itemPictureOffsY) { +	cursorInfo->pictureId = pictureId; +	cursorInfo->picture = inv->getPictureObjectById(pictureId, 0)->_picture; +	cursorInfo->hotspotX = hotspotX; +	cursorInfo->hotspotY = hotspotY; +	cursorInfo->itemPictureOffsX = itemPictureOffsX; +	cursorInfo->itemPictureOffsY = itemPictureOffsY; + +	getGameLoaderInputController()->addCursor(cursorInfo); +} + +void FullpipeEngine::initCursors() { +	CursorInfo crs; +	Scene *inv = accessScene(SC_INV); + +	addCursor(&crs, inv, PIC_CSR_DEFAULT,     15,  1, 10, 10); +	addCursor(&crs, inv, PIC_CSR_DEFAULT_INV, 18, 18, 23, 23); +	addCursor(&crs, inv, PIC_CSR_ITN,         11, 11, 10, 10); +	addCursor(&crs, inv, PIC_CSR_ITN_RED,     11, 11, 10, 10); +	addCursor(&crs, inv, PIC_CSR_ITN_GREEN,   11, 11, 10, 10); +	addCursor(&crs, inv, PIC_CSR_ITN_INV,     23, 17, 23, 17); +	addCursor(&crs, inv, PIC_CSR_GOU,         15, 17, 10, 10); +	addCursor(&crs, inv, PIC_CSR_GOD,         15,  1, 10, 10); +	addCursor(&crs, inv, PIC_CSR_GOL,         26,  1, 10, 10); +	addCursor(&crs, inv, PIC_CSR_GOR,         15,  1, 10, 10); +	addCursor(&crs, inv, PIC_CSR_GOFAR_L,      1,  1, 10, 10); +	addCursor(&crs, inv, PIC_CSR_GOFAR_R,     39,  1, 10, 10); +	addCursor(&crs, inv, PIC_CSR_ARCADE1,     12, 24, 10, 10); +	addCursor(&crs, inv, PIC_CSR_ARCADE2,     11, 11, 10, 10); +	addCursor(&crs, inv, PIC_CSR_ARCADE2_D,   22, 15, 10, 10); +	addCursor(&crs, inv, PIC_CSR_ARCADE3,     11, 11, 10, 10); +	addCursor(&crs, inv, PIC_CSR_ARCADE4,     18, 11, 10, 10); +	addCursor(&crs, inv, PIC_CSR_ARCADE5,     23, 11, 10, 10); +	addCursor(&crs, inv, PIC_CSR_ARCADE6,     11, 11, 10, 10); +	addCursor(&crs, inv, PIC_CSR_ARCADE6_D,    0,  0, 10, 10); +	addCursor(&crs, inv, PIC_CSR_ARCADE7,     21, 11, 10, 10); +	addCursor(&crs, inv, PIC_CSR_ARCADE7_D,    7, 20, 10, 10); +	addCursor(&crs, inv, PIC_CSR_ARCADE8,     23, 11, 10, 10); +	addCursor(&crs, inv, PIC_CSR_LIFT,         6, 13, 10, 10); + +	getGameLoaderInputController()->setCursorMode(0); +} + +void FullpipeEngine::initMap() { +	memset(_mapTable, 0, sizeof(_mapTable)); + +	updateMapPiece(PIC_MAP_S01, 1); +	updateMapPiece(PIC_MAP_A13, 1u); +} + +void FullpipeEngine::loadAllScenes() { +	accessScene(301); +	accessScene(302); +	accessScene(303); +	accessScene(304); +	accessScene(305); +	accessScene(321); +	accessScene(635); +	accessScene(649); +	accessScene(650); +	accessScene(651); +	accessScene(652); +	accessScene(653); +	accessScene(654); +	accessScene(655); +	accessScene(726); +	accessScene(858); +	accessScene(903); +	accessScene(1137); +	accessScene(1138); +	accessScene(1139); +	accessScene(1140); +	accessScene(1141); +	accessScene(1142); +	accessScene(1143); +	accessScene(1144); +	accessScene(1546); +	accessScene(1547); +	accessScene(1548); +	accessScene(1549); +	accessScene(1550); +	accessScene(1551); +	accessScene(1552); +	accessScene(2062); +	accessScene(2063); +	accessScene(2064); +	accessScene(2065); +	accessScene(2066); +	accessScene(2067); +	accessScene(2068); +	accessScene(2069); +	accessScene(2070); +	accessScene(2071); +	accessScene(2072); +	accessScene(2460); +	accessScene(3896); +	accessScene(3907); +	accessScene(4620); +	accessScene(4999); +	accessScene(5000); +	accessScene(5001); +	accessScene(5166); +	accessScene(5222); +} + +} // End of namespace Fullpipe diff --git a/engines/fullpipe/input.cpp b/engines/fullpipe/input.cpp new file mode 100644 index 0000000000..f71a524c48 --- /dev/null +++ b/engines/fullpipe/input.cpp @@ -0,0 +1,214 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "fullpipe/fullpipe.h" + +#include "fullpipe/objects.h" +#include "fullpipe/input.h" +#include "fullpipe/gfx.h" +#include "fullpipe/scene.h" +#include "fullpipe/gameloader.h" +#include "fullpipe/statics.h" +#include "fullpipe/constants.h" + +namespace Fullpipe { + +CInputController::CInputController() { +	g_fullpipe->_inputController = this; + +	_flag = 0; +	_cursorHandle = 0; +	_hCursor = 0; +	_field_14 = 0; +	_cursorId = 0; +	_cursorIndex = -1; +	_inputFlags = 1; + +	_cursorBounds.left = 0; +	_cursorBounds.top = 0; +	_cursorBounds.right = 0; +	_cursorBounds.bottom = 0; + +	_cursorItemPicture = 0; +} + +CInputController::~CInputController() { +	removeMessageHandler(126, -1); + +	g_fullpipe->_inputController = 0; +} + +void CInputController::setInputDisabled(bool state) { +	_flag = state; +	g_fullpipe->_inputDisabled = state; +} + +void setInputDisabled(bool state) { +	g_fullpipe->_inputController->setInputDisabled(state); +} + +void CInputController::addCursor(CursorInfo *cursor) { +	CursorInfo *newc = new CursorInfo(cursor); +	Common::Point p; +	 +	cursor->picture->getDimensions(&p); + +	newc->width = p.x; +	newc->height = p.y; + +	newc->picture->_x = -1; +	newc->picture->_y = -1; + +	_cursorsArray.push_back(newc); +} + +void CInputController::setCursorMode(bool enabled) { +	if (enabled) +		_inputFlags |= 1; +	else +		_inputFlags &= ~1; +} + +void CInputController::drawCursor(int x, int y) { +	if (_cursorIndex == -1) +		return; + +	_cursorBounds.left = g_fullpipe->_sceneRect.left + x - _cursorsArray[_cursorIndex]->hotspotX; +	_cursorBounds.top = g_fullpipe->_sceneRect.top + y - _cursorsArray[_cursorIndex]->hotspotY; +	_cursorBounds.right = _cursorBounds.left + _cursorsArray[_cursorIndex]->width; +	_cursorBounds.bottom = _cursorBounds.top + _cursorsArray[_cursorIndex]->height; + +	_cursorsArray[_cursorIndex]->picture->draw(_cursorBounds.left, _cursorBounds.top, 0, 0); + +	if (_cursorItemPicture) +		_cursorItemPicture->draw(_cursorBounds.left + _cursorsArray[_cursorIndex]->itemPictureOffsX, +								 _cursorBounds.top + _cursorsArray[_cursorIndex]->itemPictureOffsY, 0, 0); +} + +void CInputController::setCursor(int cursorId) { +	if (_cursorIndex == -1 || _cursorsArray[_cursorIndex]->pictureId != cursorId) { +		_cursorIndex = -1; + +		for (uint i = 0; i < _cursorsArray.size(); i++) { +			if (_cursorsArray[i]->pictureId == cursorId) { +				_cursorIndex = i; +				break; +			} +		} +	} +} + +CursorInfo::CursorInfo() { +	pictureId = 0; +	picture = 0; +	hotspotX = 0; +	hotspotY = 0; +	itemPictureOffsX = 0; +	itemPictureOffsY = 0; +	width = 0; +	height = 0; +} + +CursorInfo::CursorInfo(CursorInfo *src) { +	pictureId = src->pictureId; +	picture = src->picture; +	hotspotX = src->hotspotX; +	hotspotY = src->hotspotY; +	itemPictureOffsX = src->itemPictureOffsX; +	itemPictureOffsY = src->itemPictureOffsY; +	width = src->width; +	height = src->height; +} + +void FullpipeEngine::setCursor(int id) { +	if (_inputController) +		_inputController->setCursor(id); +} + +void FullpipeEngine::defHandleKeyDown(int key) { +	warning("STUB: FullpipeEngine::defHandleKeyDown(%d)", key); +} + +void FullpipeEngine::updateCursorsCommon() { +	GameObject *ani = _currentScene->getStaticANIObjectAtPos(_mouseVirtX, _mouseVirtY); + +	GameObject *pic = _currentScene->getPictureObjectAtPos(_mouseVirtX, _mouseVirtY); +	if (!ani || (pic && pic->_priority < ani->_priority)) +		ani = pic; + +	int selId = getGameLoaderInventory()->getSelectedItemId(); + +	_objectAtCursor = ani; + +	if (ani) { +		_objectIdAtCursor = ani->_id; + +		if (!selId && ani->_id >= _minCursorId && ani->_id <= _maxCursorId) { +			selId = _objectIdCursors[ani->_id - _minCursorId]; +			if (selId) { +				_cursorId = selId; +				return; +			} +		} +		if (_aniMan->canInteractAny(ani, selId)) { +			_cursorId = selId > 0 ? PIC_CSR_ITN_INV : PIC_CSR_ITN; +			return; +		} +		if (selId) { +			_cursorId = PIC_CSR_DEFAULT_INV; +			return; +		} +		if (_objectIdAtCursor == ANI_LIFTBUTTON && lift_getButtonIdP(((StaticANIObject *)ani)->_statics->_staticsId)) { +			_cursorId = PIC_CSR_LIFT; +			return; +		} +		if (_sceneRect.right - _mouseVirtX < 47 && _sceneRect.right < _sceneWidth - 1) { +			_cursorId = PIC_CSR_GOFAR_R; +			return; +		} +		if (_mouseVirtX - _sceneRect.left < 47 && _sceneRect.left > 0) { +			_cursorId = PIC_CSR_GOFAR_L; +			return; +		} +		_cursorId = PIC_CSR_DEFAULT; +		return; +	} else { +		_objectIdAtCursor = 0; + +		if (selId) { +			_cursorId = PIC_CSR_DEFAULT_INV; +			return; +		} +		if (_sceneRect.right - _mouseVirtX < 47 && _sceneRect.right < _sceneWidth - 1) { +			_cursorId = PIC_CSR_GOFAR_R; +			return; +		} +		if (_mouseVirtX - _sceneRect.left < 47 && _sceneRect.left > 0) { +			_cursorId = PIC_CSR_GOFAR_L; +			return; +		} +	} + +	_cursorId = PIC_CSR_DEFAULT; +} + +} // End of namespace Fullpipe diff --git a/engines/fullpipe/input.h b/engines/fullpipe/input.h new file mode 100644 index 0000000000..4b32e510e3 --- /dev/null +++ b/engines/fullpipe/input.h @@ -0,0 +1,77 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef FULLPIPE_INPUT_H +#define FULLPIPE_INPUT_H + +namespace Fullpipe { + +class Picture; + +void setInputDisabled(bool state); + +struct CursorInfo { +	int pictureId; +	Picture *picture; +	int hotspotX; +	int hotspotY; +	int itemPictureOffsX; +	int itemPictureOffsY; +	int width; +	int height; + +	CursorInfo(); +	CursorInfo(CursorInfo *src); +}; + +typedef Common::Array<CursorInfo *> CursorsArray; + +class CInputController { +	//CObject obj; +	int _flag; +	int _inputFlags; +	int _cursorHandle; +	int _hCursor; +	int _field_14; +	int _cursorId; +	int _cursorIndex; +	CursorsArray _cursorsArray; +	Common::Rect _cursorBounds; +	Picture *_cursorItemPicture; + + public: +	CInputController(); +	~CInputController(); + +	void setInputDisabled(bool state); +	void addCursor(CursorInfo *cursor); +	void setCursorMode(bool mode); + +	void drawCursor(int x, int y); +	void setCursor(int id); + +	void setCursorItemPicture(Picture *pic) { _cursorItemPicture = pic; } +}; + +} // End of namespace Fullpipe + +#endif /* FULLPIPE_INPUT_H */ diff --git a/engines/fullpipe/interaction.cpp b/engines/fullpipe/interaction.cpp new file mode 100644 index 0000000000..4153724b63 --- /dev/null +++ b/engines/fullpipe/interaction.cpp @@ -0,0 +1,495 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "fullpipe/fullpipe.h" + +#include "fullpipe/interaction.h" +#include "fullpipe/gameloader.h" +#include "fullpipe/statics.h" +#include "fullpipe/motion.h" + +namespace Fullpipe { + +int handleObjectInteraction(StaticANIObject *subject, GameObject *object, int invId) { +	return getGameLoaderInteractionController()->handleInteraction(subject, object, invId); +} + +bool CInteractionController::load(MfcArchive &file) { +	debug(5, "CInteractionController::load()"); + +	return _interactions.load(file); +} + +int static_compSceneId = 0; + +bool CInteractionController::compareInteractions(const void *p1, const void *p2) { +	const CInteraction *i1 = (const CInteraction *)p1; +	const CInteraction *i2 = (const CInteraction *)p2; + +	if (i2->_sceneId < i1->_sceneId) { +		if (i1->_sceneId != static_compSceneId) +			return false; +	} +	if (i2->_sceneId != i1->_sceneId) { +		if (i1->_sceneId > 0 && i2->_sceneId == static_compSceneId) +			return false; +		if (i2->_sceneId != i1->_sceneId) +			return true; +	} +	if (i2->_objectId3 == -1) +		return true; + +	if (i1->_objectId3 == i2->_objectId3) +		return true; + +	if (i1->_objectId3 == -1 || i1->_objectId3 == -2) +		return false; + +	return true; +} + +void CInteractionController::sortInteractions(int sceneId) { +	static_compSceneId = sceneId; + +	Common::sort(_interactions.begin(), _interactions.end(), CInteractionController::compareInteractions); +} + +bool CInteractionController::handleInteraction(StaticANIObject *subj, GameObject *obj, int invId) { +	if (subj) { +		if (!subj->isIdle() || (subj->_flags & 0x100)) +			return false; +	} + +	if (!_interactions.size()) +		return false; + +	CInteraction *inter = 0; +	CInteraction *previnter = 0; +	int dur = 0; +	int mindur = 0xFFFF; + +	MessageQueue *mq; +	ExCommand *ex; + +	for (CObList::iterator i = _interactions.begin(); i != _interactions.end(); ++i) { +		CInteraction *cinter = (CInteraction *)*i; + +		if (!cinter->canInteract(subj, obj, invId)) +			continue; + +		if ((inter || cinter->_objectId2) && (!obj || cinter->_objectId3 != obj->_id)) { +			if (cinter->_messageQueue) +				cinter->_messageQueue->calcDuration(subj); + +			PicAniInfo aniInfo; + +			obj->getPicAniInfo(&aniInfo); + +			if (cinter->_staticsId1) { +				StaticANIObject *ani = (StaticANIObject *)obj; +				ani->_messageQueueId = 0; +				ani->changeStatics2(cinter->_staticsId1); +			} +			int xpos = cinter->_xOffs + obj->_ox; +			int ypos = cinter->_yOffs + obj->_oy; + +			obj->setPicAniInfo(&aniInfo); + +			if (abs(xpos - subj->_ox) > 1 || abs(ypos - subj->_oy) > 1) { +				mq = getSc2MctlCompoundBySceneId(g_fullpipe->_currentScene->_sceneId)->method4C(subj, xpos, ypos, 1, cinter->_staticsId2); +				if (mq) { +					dur = mq->calcDuration(subj); +					delete mq; +				} else { +					dur = 0x10000; +				} +				inter = previnter; +			} else { +				dur = 0; +			} +			if (dur < mindur) { +				inter = cinter; +				mindur = dur; +				previnter = cinter; +			} +		} else { +			inter = cinter; +			break; +		} +	} + +	if (!inter) +		return false; + +	if (!inter->_objectId2) { +		StaticANIObject *ani = (StaticANIObject *)obj; + +		if (!ani->isIdle()) +			return false; + +		if (ani->_flags & 0x100) +			return false; + +		if (!inter->_staticsId1 || !(inter->_flags & 1)) +			goto LABEL_38; + +		if (ani->_movement || ani->_statics == 0 || ani->_statics->_staticsId != inter->_staticsId1) { +			mq = ani->changeStatics1(inter->_staticsId1); +			if (!mq) +				return false; + +			ex = new ExCommand((subj ? subj->_id : 0), 55, 0, 0, 0, 0, 1, 0, 0, 0); +			ex->_x = obj->_id; +			ex->_y = obj->_okeyCode; +			ex->_keyCode = subj ? subj->_okeyCode : 0; +			ex->_excFlags = 3; +			ex->_field_14 = (obj->_objtype != kObjTypePictureObject); +			ex->_field_20 = invId; +			mq->_exCommands.push_back(ex); + +			if (mq->_isFinished) { +				mq->_isFinished = 0; +				ani->queueMessageQueue(mq); +			} +		} else { +			if (ani->getMessageQueue()) +				ani->queueMessageQueue(0); +LABEL_38: +			if (inter->_messageQueue) { +				mq = new MessageQueue(inter->_messageQueue, 0, 1); +				mq->changeParam28ForObjectId(ani->_id, -1, ani->_okeyCode); + +				if (!mq->chain(0)) +					return false; +			} +		} +		return true; +	} + +	if (obj && !subj) +		return true; + +	if (!obj || inter->_objectId3 == obj->_id) { +		if (subj) { +			if (inter->_messageQueue) { +				if (subj->isIdle()) { +					mq = new MessageQueue(inter->_messageQueue, 0, 1); + +					if (!mq->chain(subj)) { +						if (mq) +							delete mq; + +						return false; +					} +				} +			} +		} +		return true; +	} + +	if (inter->isOverlapping(subj, obj)) { +		if (obj->_objtype == kObjTypeStaticANIObject) { +			StaticANIObject *ani = (StaticANIObject *)obj; + +			ani->queueMessageQueue(0); + +			if (inter->_staticsId1) +				ani->changeStatics2(inter->_staticsId1); + +			if (!(inter->_flags & 0x10000)) +				obj->_flags |= 0x80; +		} + +		if (!inter->_messageQueue) +			return false; + +		subj->setOXY(inter->_xOffs + obj->_ox, inter->_yOffs + obj->_oy); + +		mq = new MessageQueue(inter->_messageQueue, 0, 1); +		mq->changeParam28ForObjectId(obj->_id, -1, obj->_okeyCode); +		mq->_flags |= 1; + +		if (!(inter->_flags & 0x10000)) { +			ex = new ExCommand(obj->_id, 34, 0x80, 0, 0, 0, 1, 0, 0, 0); +			ex->_keyCode = obj->_okeyCode; +			ex->_field_14 = 0x100; +			ex->_messageNum = 0; +			ex->_excFlags = 3; +			mq->_exCommands.push_back(ex); +		} + +		ex = new ExCommand(obj->_id, 34, 0x100, 0, 0, 0, 1, 0, 0, 0); +		ex->_keyCode = obj->_okeyCode; +		ex->_field_14 = 0x100; +		ex->_messageNum = 0; +		ex->_excFlags = 3; +		mq->_exCommands.push_back(ex); + +		ex = new ExCommand(subj->_id, 34, 0x100, 0, 0, 0, 1, 0, 0, 0); +		ex->_keyCode = subj->_okeyCode; +		ex->_field_14 = 0x100; +		ex->_messageNum = 0; +		ex->_excFlags = 3; +		mq->_exCommands.push_back(ex); + +		ex = new ExCommand(subj->_id, 17, 0x40, 0, 0, 0, 1, 0, 0, 0); +		ex->_excFlags |= 3; +		ex->_keyCode = 0; +		mq->_exCommands.push_back(ex); + +		if (!mq->chain(subj)) { +			delete mq; + +			return false; +		} + +		subj->_flags |= 1; +		obj->_flags |= 1; +	} else { +		bool someFlag = false; +		PicAniInfo aniInfo; + +		obj->getPicAniInfo(&aniInfo); + +		if (obj->_objtype == kObjTypeStaticANIObject && inter->_staticsId1) { +			StaticANIObject *ani = (StaticANIObject *)obj; + +			ani->_messageQueueId = 0; +			ani->changeStatics2(inter->_staticsId1); +		} + +		int xpos = inter->_yOffs + obj->_ox; +		int ypos = inter->_yOffs + obj->_oy; + +		obj->setPicAniInfo(&aniInfo); + +		if (abs(xpos - subj->_ox) > 1 || abs(ypos - subj->_oy) > 1 +				|| (inter->_staticsId2 != 0 && (subj->_statics == 0 || subj->_statics->_staticsId != inter->_staticsId2))) { +			mq = getSc2MctlCompoundBySceneId(g_fullpipe->_currentScene->_sceneId)->method34(subj, xpos, ypos, 1, inter->_staticsId2); + +			if (!mq) +				return false; + +			ex = new ExCommand(subj->_id, 55, 0, 0, 0, 0, 1, 0, 0, 0); +			ex->_x = obj->_id; +			ex->_y = obj->_okeyCode; +			ex->_keyCode = subj->_okeyCode; +			ex->_excFlags = 3; +			ex->_field_20 = invId; +			ex->_field_14 = (obj->_objtype != kObjTypePictureObject); +			mq->_exCommands.push_back(ex); + +			someFlag = true; + +			ex = new ExCommand(subj->_id, 17, 0x40, 0, 0, 0, 1, 0, 0, 0); +			ex->_x = xpos; +			ex->_y = ypos; +			ex->_excFlags |= 3; +			ex->_keyCode = 6; +			ex->_field_14 = obj->_id; +			ex->_field_20 = obj->_okeyCode; +			ex->postMessage(); +		} + +		if (!inter->_staticsId1 || !(inter->_flags & 1)) +			return true; + +		StaticANIObject *ani = (StaticANIObject *)obj; + +		if (!ani->isIdle()) +			return false; + +		if (ani->getMessageQueue()) +			ani->queueMessageQueue(0); + +		if (!ani->_statics || ani->_statics->_staticsId != inter->_staticsId1 || ani->_movement) { +			mq = ani->changeStatics1(inter->_staticsId1); + +			if (!mq) +				return false; + +			if (someFlag) { +				if (!(inter->_flags & 0x10000)) { +					if (mq->_isFinished) { +						ani->_flags |= 0x80u; +					} else { +						ex = new ExCommand(ani->_id, 34, 0x80, 0, 0, 0, 1, 0, 0, 0); +						ex->_field_14 = 0x80; +						ex->_keyCode = ani->_okeyCode; +						ex->_excFlags = 3; +						mq->_exCommands.push_back(ex); +					} +				} +				ex = new ExCommand(ani->_id, 34, 0x100, 0, 0, 0, 1, 0, 0, 0); +				ex->_keyCode = ani->_okeyCode; +				ex->_field_14 = 0x100; +				ex->_excFlags = 3; +				mq->_exCommands.push_back(ex); +			} else { +				ex = new ExCommand(subj->_id, 55, 0, 0, 0, 0, 1, 0, 0, 0); +				ex->_x = ani->_id; +				ex->_y = ani->_okeyCode; +				ex->_keyCode = subj->_okeyCode; +				ex->_excFlags = 2; +				ex->_field_14 = (obj->_objtype != kObjTypePictureObject); +				ex->_field_20 = invId; +				mq->_exCommands.push_back(ex); + +				if (!mq->_isFinished) +					return true; + +				mq->_isFinished = 0; +				ani->queueMessageQueue(mq); +			} +		} else { +			obj->_flags |= 1; + +			if (inter->_flags & 0x10000) +				return true; + +			obj->_flags |= 0x80; +		} +	} + +	return true; +} + +CInteraction::CInteraction() { +	_objectId1 = 0; +	_objectId2 = 0; +	_staticsId1 = 0; +	_objectId3 = 0; +	_objectState2 = 0; +	_objectState1 = 0; +	_messageQueue = 0; +	_flags = 0; +	_yOffs = 0; +	_xOffs = 0; +	_staticsId2 = 0; +	_field_28 = 0; +	_sceneId = -1; +	_actionName = 0; +} + +bool CInteraction::load(MfcArchive &file) { +	debug(5, "CInteraction::load()"); + +	_objectId1 = file.readUint16LE(); +	_objectId2 = file.readUint16LE(); +	_staticsId1 = file.readUint16LE(); +	_staticsId2 = file.readUint16LE(); +	_objectId3 = file.readUint16LE(); +	_objectState2 = file.readUint32LE(); +	_objectState1 = file.readUint32LE(); +	_xOffs = file.readUint32LE(); +	_yOffs = file.readUint32LE(); +	_sceneId = file.readUint32LE(); +	_flags = file.readUint32LE(); +	_actionName = file.readPascalString(); + +	_messageQueue = (MessageQueue *)file.readClass(); + +	return true; +} + +bool CInteraction::canInteract(GameObject *obj1, GameObject *obj2, int invId) { +	if (_sceneId > 0 && g_fullpipe->_currentScene && g_fullpipe->_currentScene->_sceneId != _sceneId) +		return false; + +	if (_flags & 0x20000) +		return false; + +	if (!obj2) +		return false; +	if (obj2->_id != _objectId1) +		return false; + +	if ((_flags & 8) && (_flags & 1)) { +		if (!obj2->_objtype != kObjTypeStaticANIObject) +			return false; + +		StaticANIObject *st = (StaticANIObject *)obj2; + +		if (!st->_statics) +			return false; + +		if (st->_statics->_staticsId != _staticsId1) { +			if (_staticsId1) +				return false; +		} +	} + +	if ((_objectId3 != invId && _objectId3 != -1 && _objectId3 != -2) || (!invId && _objectId3 == -2)) +		return false; + +	if (_objectState1) { +		if (_flags & 0x10) { +			if ((g_fullpipe->getObjectState(obj1->getName()) & _objectState1) == 0) +				return false; +		} else { +			if (g_fullpipe->getObjectState(obj1->getName()) != _objectState1) +				return false; +		} +	} + +	if (_objectState2) { +		if (_flags & 0x10) { +			if ((g_fullpipe->getObjectState(obj2->getName()) & _objectState2) == 0) +				return false; +		} else { +			if (g_fullpipe->getObjectState(obj2->getName()) != _objectState2) +				return false; +		} +	} + +	if (_objectId2 && (!obj1 || _objectId2 != obj1->_id)) +		return false; + +	return true; +} + +bool CInteraction::isOverlapping(StaticANIObject *subj, GameObject *obj) { +	StaticANIObject *ani = (StaticANIObject *)obj; + +	if (abs(_xOffs + obj->_ox - subj->_ox) <= 1 +		&& abs(obj->_oy + _yOffs - subj->_oy) <= 1) { +		if (!_staticsId2 || subj->_statics != 0 && subj->_statics->_staticsId == _staticsId2) { +			if (!_staticsId1 || !(_flags & 1) || ani->_statics != 0 && ani->_statics->_staticsId == _staticsId1) +				return true; +		} +	} +	return false; +} + +bool EntranceInfo::load(MfcArchive &file) { +	debug(5, "EntranceInfo::load()"); + +	_sceneId = file.readUint32LE(); +	_field_4 = file.readUint32LE(); +	_messageQueueId = file.readUint32LE(); +	file.read(_gap_C, 292); // FIXME, Ugh +	_field_130 = file.readUint32LE(); + +	return true; +} + +} // End of namespace Fullpipe diff --git a/engines/fullpipe/interaction.h b/engines/fullpipe/interaction.h new file mode 100644 index 0000000000..e3090334fe --- /dev/null +++ b/engines/fullpipe/interaction.h @@ -0,0 +1,94 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef FULLPIPE_INTERACTION_H +#define FULLPIPE_INTERACTION_H + +#include "fullpipe/utils.h" + +namespace Fullpipe { + +class GameObject; +class MessageQueue; +class StaticANIObject; + +int handleObjectInteraction(StaticANIObject *subject, GameObject *object, int invId); + +class CInteraction : public CObject { + public: +	int16 _objectId1; +	int16 _objectId2; +	int16 _objectId3; +	int16 _staticsId1; +	int16 _staticsId2; +	int _objectState1; +	int _objectState2; +	int _xOffs; +	int _yOffs; +	MessageQueue *_messageQueue; +	int _sceneId; +	int _field_28; +	int _flags; +	char *_actionName; + + public: +	CInteraction(); +	virtual bool load(MfcArchive &file); +	bool canInteract(GameObject *obj1, GameObject *obj2, int invId); +	bool isOverlapping(StaticANIObject *subj, GameObject *obj); +}; + +class CInteractionController : public CObject { + public: +	CObList _interactions; +	int16 _field_20; +	bool _flag24; + + private: +	static bool compareInteractions(const void *p1, const void *p2); + + public: +	CInteractionController() : _field_20(0), _flag24(true) {} + +	virtual bool load(MfcArchive &file); + +	void enableFlag24() { _flag24 = true; } +	void disableFlag24() { _flag24 = false; } + +	void sortInteractions(int sceneId); + +	bool handleInteraction(StaticANIObject *subj, GameObject *obj, int invId); +}; + +struct EntranceInfo { +	int32 _sceneId; +	int32 _field_4; +	int32 _messageQueueId; +	byte _gap_C[292]; // FIXME +	int32 _field_130; + +	bool load(MfcArchive &file); +}; + +} // End of namespace Fullpipe + +#endif /* FULLPIPE_INTERACTION_H */ diff --git a/engines/fullpipe/inventory.cpp b/engines/fullpipe/inventory.cpp new file mode 100644 index 0000000000..1abd369e7b --- /dev/null +++ b/engines/fullpipe/inventory.cpp @@ -0,0 +1,420 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "fullpipe/fullpipe.h" + +#include "fullpipe/utils.h" +#include "fullpipe/inventory.h" +#include "fullpipe/gameloader.h" +#include "fullpipe/statics.h" +#include "fullpipe/input.h" + +namespace Fullpipe { + +bool CInventory::load(MfcArchive &file) { +	debug(5, "CInventory::load()"); + +	_sceneId = file.readUint16LE(); +	int numInvs = file.readUint32LE(); + +	for (int i = 0; i < numInvs; i++) { +		InventoryPoolItem *t = new InventoryPoolItem(); +		t->id = file.readUint16LE(); +		t->pictureObjectNormal = file.readUint16LE(); +		t->pictureObjectId1 = file.readUint16LE(); +		t->pictureObjectHover = file.readUint16LE(); +		t->pictureObjectSelected = file.readUint16LE(); +		t->flags = file.readUint32LE(); +		t->field_C = 0; +		t->field_A = -536; +		_itemsPool.push_back(t); +	} + +	return true; +} + +int CInventory::getInventoryPoolItemIndexById(int itemId) { +	if (_itemsPool.size() <= 0) +		return -1; + +	for (uint i = 0; i < _itemsPool.size(); i++) { +		if (_itemsPool[i]->id == itemId) +			return i; +	} + +	return 0; +} + +bool CInventory::setItemFlags(int itemId, int flags) { +	int idx = getInventoryPoolItemIndexById(itemId); + +	if (idx < 0) +		return false; +	else +		_itemsPool[idx]->flags = flags; + +	return true; +} + +CInventory2::CInventory2() { +	_selectedId = -1; +	_field_48 = -1; +	_scene = 0; +	_picture = 0; +	_isInventoryOut = false; +	_isLocked = 0; +	_topOffset = -65; +} + +bool CInventory2::loadPartial(MfcArchive &file) { // CInventory2_SerializePartially +	int numInvs = file.readUint32LE(); + +	for (int i = 0; i < numInvs; i++) { +		InventoryItem *t = new InventoryItem(); +		t->itemId = file.readUint16LE(); +		t->count = file.readUint16LE(); +		_inventoryItems.push_back(t); +	} + +	return true; +} + +void CInventory2::addItem(int itemId, int count) { +	if (getInventoryPoolItemIndexById(itemId) >= 0) +		_inventoryItems.push_back(new InventoryItem(itemId, count)); +} + +void CInventory2::addItem2(StaticANIObject *obj) { +	if (getInventoryPoolItemIndexById(obj->_id) >= 0 && getInventoryPoolItemFieldCById(obj->_id) != 2) { +		addItem(obj->_id, 1); +		obj->hide(); +	} +} + +void CInventory2::removeItem(int itemId, int count) { +	warning("STUB: CInventory2::removeItem(%d, %d)", itemId, count); +} + +void CInventory2::removeItem2(Scene *sceneObj, int itemId, int x, int y, int priority) { +	warning("STUB: void removeItem2(sc, %d, %d, %d, %d)", itemId, x, y, priority); +} + +int CInventory2::getCountItemsWithId(int itemId) { +	int res = 0; + +	for (uint i = 0; i < _inventoryItems.size(); i++) { +		if (_inventoryItems[i]->itemId == itemId) +			res += _inventoryItems[i]->count; +	} + +	return res; +} + +int CInventory2::getInventoryItemIndexById(int itemId) { +	for (uint i = 0; i < _inventoryItems.size(); i++) { +		if (_inventoryItems[i]->itemId == itemId) +			return i; +	} + +	return -1; +} + +int CInventory2::getInventoryPoolItemFieldCById(int itemId) { +	for (uint i = 0; i < _itemsPool.size(); i++) { +		if (_itemsPool[i]->id == itemId) +			return _itemsPool[i]->field_C; +	} + +	return 0; +} + +int CInventory2::getItemFlags(int itemId) { +	int idx = getInventoryPoolItemIndexById(itemId); + +	if (idx < 0) +		return 0; + +	return _itemsPool[idx]->flags; +} + +void CInventory2::rebuildItemRects() { +	_scene = g_fullpipe->accessScene(_sceneId); + +	if (!_scene) +		return; + +	_picture = _scene->getBigPicture(0, 0); +	_picture->setAlpha(50); + +	int itemX = 9; +	int itemY = 0; + +	for (uint i = 0; i < _scene->_picObjList.size(); i++) { +		PictureObject *pic = (PictureObject *)_scene->_picObjList[i]; + +		for (uint j = 0; j < _itemsPool.size(); j++) { +			if (_itemsPool[j]->pictureObjectNormal == pic->_id) { +				if (pic->_okeyCode) +					_scene->deletePictureObject(pic); +				else +					pic->_flags &= 0xFFFB; +			} +		} +	} + +	for (uint i = 0; i < _inventoryItems.size(); i++) { +		Common::Point point; + +		int idx = getInventoryPoolItemIndexById(_inventoryItems[i]->itemId); + +		InventoryIcon *icn = new InventoryIcon(); + +		icn->inventoryItemId = _itemsPool[idx]->id; +		 +		icn->pictureObjectNormal = _scene->getPictureObjectById(_itemsPool[idx]->pictureObjectNormal, 0); +		icn->pictureObjectHover = _scene->getPictureObjectById(_itemsPool[idx]->pictureObjectHover, 0); +		icn->pictureObjectSelected = _scene->getPictureObjectById(_itemsPool[idx]->pictureObjectSelected, 0); + +		icn->pictureObjectNormal->getDimensions(&point); + +		if (_itemsPool[idx]->flags & 0x10000) { +			icn->x1 = 730; +			icn->y1 = itemY; +			icn->x2 = point.x + 730; +			icn->y2 = point.y + itemY + 10; +		} else { +			icn->x1 = itemX; +			icn->y1 = itemY; +			icn->x2 = itemX + point.x; +			itemX = icn->x2 + 1; +			icn->y2 = point.y + itemY + 10; +		} + +		_inventoryIcons.push_back(icn); + +		if (itemX >= 2 * (icn->x1 - icn->x2) + 800) { +			itemX = 9; +			itemY = icn->y2 + 1; +		} +	} +} + +void CInventory2::draw() { +	if (!_scene) +		return; + +	int oldScLeft = g_fullpipe->_sceneRect.left; +	int oldScTop = g_fullpipe->_sceneRect.top; + +	g_fullpipe->_sceneRect.top = -_topOffset; +	g_fullpipe->_sceneRect.left = 0; + +	_picture->draw(-1, -1, 0, 0); + +	for (uint i = 0; i < _inventoryIcons.size(); i++) { +		InventoryIcon *icn = _inventoryIcons[i]; + +		if (icn->isSelected) { +			icn->pictureObjectSelected->drawAt(icn->x1, icn->y1 + 10); +		} else { +			if (icn->isMouseHover) +				icn->pictureObjectHover->drawAt(icn->x1, icn->y1 + 10); +			else +				icn->pictureObjectNormal->drawAt(icn->x1, icn->y1 + 10); +		} +    } + +	if (!_isInventoryOut) +		goto LABEL_30; + +	int v10, v11, v12; + +	if (_topOffset != -10) { +		if (_topOffset < -10) { +			v10 = -10; +			goto LABEL_13; +		} +		if (_topOffset + 10 >= 20) { +			v11 = -20; +cont: +			_topOffset += v11; +			goto reset; +		} +		v12 = -10; +		goto LABEL_25; +	} +	if (!_isInventoryOut) { +LABEL_30: +		if (_topOffset != -65) { +			if (_topOffset < -65) { +				v10 = -65; +LABEL_13: +				v11 = v10 - _topOffset; +				if (v11 >= 20) +					v11 = 20; +				goto cont; +			} +			if (_topOffset + 65 >= 20) { +				v11 = -20; +				goto cont; +			} +			v12 = -65; +LABEL_25: +			v11 = v12 - _topOffset; +			goto cont; +		} +	} + +reset: + +	g_fullpipe->_sceneRect.top = oldScTop; +	g_fullpipe->_sceneRect.left = oldScLeft; + +} + +void CInventory2::slideIn() { +	_isInventoryOut = false; + +	ExCommand *ex = new ExCommand(0, 17, 65, 0, 0, 0, 1, 0, 0, 0); + +	ex->_field_2C = 10; +	ex->_field_14 = _isInventoryOut; +	ex->_field_20 = !_isInventoryOut; +	ex->_excFlags |= 3; +	ex->postMessage(); +} + +void CInventory2::slideOut() { +	_isInventoryOut = true; + +	ExCommand *ex = new ExCommand(0, 17, 65, 0, 0, 0, 1, 0, 0, 0); + +	ex->_field_2C = 10; +	ex->_field_14 = _isInventoryOut; +	ex->_field_20 = !_isInventoryOut; +	ex->_excFlags |= 3; +	ex->postMessage(); +} + +bool CInventory2::handleLeftClick(ExCommand *cmd) { +	if (!_isInventoryOut) +		return false; + +    bool res = false; + +	for (uint i = 0; i < _inventoryIcons.size(); i++) { +		if (cmd->_x >= _inventoryIcons[i]->x1 && cmd->_x <= _inventoryIcons[i]->x2 &&  +			cmd->_y >= _inventoryIcons[i]->y1 && cmd->_y <= _inventoryIcons[i]->y2) { +			if (getSelectedItemId()) { +				if (getSelectedItemId() != _inventoryIcons[i]->inventoryItemId) +					unselectItem(0); +			} +			if (getItemFlags(_inventoryIcons[i]->inventoryItemId) & 1) { +				ExCommand *ex = new ExCommand(0, 17, 65, 0, 0, 0, 1, 0, 0, 0); +				ex->_field_2C = 11; +				ex->_field_14 = _inventoryIcons[i]->inventoryItemId; +				ex->_excFlags |= 3; +				ex->postMessage(); +			} +			if (!(getItemFlags(_inventoryIcons[i]->inventoryItemId) & 2)) { +				selectItem(_inventoryIcons[i]->inventoryItemId); +				_inventoryIcons[i]->isSelected = true; +			} +			res = true; +		} +	} + +    if (!res) +		unselectItem(this); + +	return res; +} + +int CInventory2::selectItem(int itemId) { +	if (getInventoryItemIndexById(itemId) < 0) +		return -1; + +	unselectItem(0); + +	_selectedId = itemId; + +	if (_scene) { +		int idx = getInventoryPoolItemIndexById(itemId); + +		Picture *pic = _scene->getPictureObjectById(_itemsPool[idx]->pictureObjectId1, 0)->_picture; +		g_fullpipe->getGameLoaderInputController()->setCursorItemPicture(pic); +	} + +	return _selectedId; +} + +bool CInventory2::unselectItem(bool flag) { +	if (_selectedId < 0) +		return false; + +	_selectedId = -1; + +	for (uint i = 0; i < _inventoryIcons.size(); i++) { +		if (_inventoryIcons[i]->isSelected) +			_inventoryIcons[i]->isSelected = false; +   } + +	g_fullpipe->getGameLoaderInputController()->setCursorItemPicture(0); + +	return true; +} + +int CInventory2::getHoveredItem(Common::Point *point) { +	int selId = getSelectedItemId(); + +	if (point->y <= 20 && !_isInventoryOut && !_isLocked) +		slideOut(); + +	if (!selId && point->y >= 55) { +		if (!_isInventoryOut) +			return 0; + +		if (!_isLocked) +			slideIn(); +	} + +	if (!_isInventoryOut) +		return 0; + +	for (uint i = 0; i < _inventoryIcons.size(); i++) { +		InventoryIcon *icn = _inventoryIcons[i]; +		if (selId || +			point->x < icn->x1 || +			point->x > icn->x2 || +			point->y < _topOffset + icn->y1 || +			point->y > _topOffset + icn->y2) { +			icn->isMouseHover = false; +		} else { +			icn->isMouseHover = true; +			return icn->inventoryItemId; +		} +    } + +	return 0; +} + +} // End of namespace Fullpipe diff --git a/engines/fullpipe/inventory.h b/engines/fullpipe/inventory.h new file mode 100644 index 0000000000..f84d27dde5 --- /dev/null +++ b/engines/fullpipe/inventory.h @@ -0,0 +1,130 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef FULLPIPE_INVENTORY_H +#define FULLPIPE_INVENTORY_H + +namespace Fullpipe { + +class Scene; +class BigPicture; + +struct InventoryPoolItem { +	int16 id; +	int16 pictureObjectNormal; +	int16 pictureObjectId1; +	int16 pictureObjectHover; +	int16 pictureObjectSelected; +	int16 field_A; +	int field_C; +	int obj; +	int flags; +}; + +typedef Common::Array<InventoryPoolItem *> InventoryPoolItems; + +class CInventory : public CObject { + protected: +	int16 _sceneId; +	InventoryPoolItems _itemsPool; + + public: +	CInventory() { _sceneId = 0; } +	virtual bool load(MfcArchive &file); + +	int getInventoryPoolItemIndexById(int itemId); +	bool setItemFlags(int itemId, int flags); +}; + +struct InventoryItem { +	int16 itemId; +	int16 count; + +	InventoryItem() { itemId = count = 0; } +	InventoryItem(int id, int cnt) : itemId(id), count(cnt) {} +}; + +typedef Common::Array<InventoryItem *> InventoryItems; + +class PictureObject; + +struct InventoryIcon { +	PictureObject *pictureObjectNormal; +	PictureObject *pictureObjectHover; +	PictureObject *pictureObjectSelected; +	int x1; +	int y1; +	int x2; +	int y2; +	int16 inventoryItemId; +	bool isSelected; +	bool isMouseHover; +}; + +typedef Common::Array<InventoryIcon *> InventoryIcons; + +class CInventory2 : public CInventory { +	InventoryItems _inventoryItems; +	InventoryIcons _inventoryIcons; +	int _selectedId; +	int _field_48; +	bool _isInventoryOut; +	bool _isLocked; +	int _topOffset; +	Scene *_scene; +	BigPicture *_picture; + + public: +	CInventory2(); +	bool loadPartial(MfcArchive &file); +	void addItem(int itemId, int count); +	void addItem2(StaticANIObject *obj); +	void removeItem(int itemId, int count); +	void removeItem2(Scene *sceneObj, int itemId, int x, int y, int priority); + +	int getInventoryItemIndexById(int itemId); +	int getInventoryPoolItemFieldCById(int itemId); +	int getCountItemsWithId(int itemId); +	int getItemFlags(int itemId); + +	void rebuildItemRects(); + +	Scene *getScene() { return _scene; } +	bool getIsLocked() { return _isLocked; } +	void setIsLocked(bool val) { _isLocked = val; } +	bool getIsInventoryOut() { return _isInventoryOut; } + +	int getSelectedItemId() { return _selectedId < 0 ? 0 : _selectedId; } +	int getHoveredItem(Common::Point *point); +	void slideIn(); +	void slideOut(); + +	bool handleLeftClick(ExCommand *cmd); +	int selectItem(int itemId); +	bool unselectItem(bool flag); + +	void draw(); +}; + +} // End of namespace Fullpipe + +#endif /* FULLPIPE_INVENTORY_H */ diff --git a/engines/fullpipe/lift.cpp b/engines/fullpipe/lift.cpp new file mode 100644 index 0000000000..25dd2613fe --- /dev/null +++ b/engines/fullpipe/lift.cpp @@ -0,0 +1,67 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "fullpipe/fullpipe.h" + +#include "fullpipe/constants.h" + +namespace Fullpipe { + +int FullpipeEngine::lift_getButtonIdP(int objid) { +	switch (objid) { +	case ST_LBN_0N: +		return ST_LBN_0P; +		break; +	case ST_LBN_1N: +		return ST_LBN_1P; +		break; +	case ST_LBN_2N: +		return ST_LBN_2P; +		break; +	case ST_LBN_3N: +		return ST_LBN_3P; +		break; +	case ST_LBN_4N: +		return ST_LBN_4P; +		break; +	case ST_LBN_5N: +		return ST_LBN_5P; +		break; +	case ST_LBN_6N: +		return ST_LBN_6P; +		break; +	case ST_LBN_7N: +		return ST_LBN_7P; +		break; +	case ST_LBN_8N: +		return ST_LBN_8P; +		break; +	case ST_LBN_9N: +		return ST_LBN_9P; +		break; +	default: +		return 0; +		break; +	} +} + +} // End of namespace Fullpipe diff --git a/engines/fullpipe/messages.cpp b/engines/fullpipe/messages.cpp new file mode 100644 index 0000000000..acf44f5729 --- /dev/null +++ b/engines/fullpipe/messages.cpp @@ -0,0 +1,723 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "fullpipe/fullpipe.h" + +#include "fullpipe/objects.h" +#include "fullpipe/messages.h" +#include "fullpipe/modal.h" +#include "fullpipe/statics.h" + +namespace Fullpipe { + +ExCommand::ExCommand() { +	_field_3C = 1; +	_messageNum = 0; +	_excFlags = 0; +	_parId = 0; +} + +ExCommand::ExCommand(ExCommand *src) : Message(src) { +	_field_3C = 1; +	_messageNum = src->_messageNum; +	_excFlags = src->_excFlags; +	_parId = src->_parId; + +} + +ExCommand::ExCommand(int16 parentId, int messageKind, int messageNum, int x, int y, int a7, int a8, int sceneClickX, int sceneClickY, int a11) :  +	Message(parentId, messageKind, x, y, a7, a8, sceneClickX, sceneClickY, a11) { +	_field_3C = 1; +	_messageNum = messageNum; +	_excFlags = 0; +	_parId = 0; +} + +bool ExCommand::load(MfcArchive &file) { +	debug(5, "ExCommand::load()"); + +	_parentId = file.readUint16LE(); +	_messageKind = file.readUint32LE(); +	_x = file.readUint32LE(); +	_y = file.readUint32LE(); +	_field_14 = file.readUint32LE(); +	_sceneClickX = file.readUint32LE(); +	_sceneClickY = file.readUint32LE(); +	_field_20 = file.readUint32LE(); +	_field_24 = file.readUint32LE(); +	_keyCode = file.readUint32LE(); +	_field_2C = file.readUint32LE(); +	_field_30 = file.readUint32LE(); +	_field_34 = file.readUint32LE(); + +	_messageNum = file.readUint32LE(); + +	_field_3C = 0; + +	if (g_fullpipe->_gameProjectVersion >= 12) { +		_excFlags = file.readUint32LE(); +		_parId = file.readUint32LE(); +	} + +	return true; +} + +bool ExCommand::handleMessage() { +	int cnt = 0; +	for (MessageHandler *m = g_fullpipe->_messageHandlers; m; m = m->nextItem) +		cnt += m->callback(this); + +	if (_messageKind == 17 || (_excFlags & 1)) { +		if (_parId) { +			MessageQueue *mq = g_fullpipe->_globalMessageQueueList->getMessageQueueById(_parId); +			if (mq) +				mq->update(); +		} +	} + +	if (_excFlags & 2) +		delete this; + +	return (cnt > 0); +} + +void ExCommand::sendMessage() { +	g_fullpipe->_exCommandList.push_back(this); + +	processMessages(); +} + +void ExCommand::postMessage() { +	g_fullpipe->_exCommandList.push_back(this); +} + +void ExCommand::handle() { +	if (g_fullpipe->_modalObject) { +		g_fullpipe->_modalObject->handleMessage(this); + +		delete this; +	} else { +		postMessage(); +	} +} + +Message::Message() { +	_messageKind = 0; +	_parentId = 0;		 + +	_x = 0; +	_y = 0; +	_field_14 = 0; +	_sceneClickX = 0; +	_sceneClickY = 0; +	_field_20 = 0; +	_field_24 = 0; +	_keyCode = 0; +	_field_2C = 0; +	_field_30 = 0; +	_field_34 = 0; +} + +Message::Message(Message *src) { +	_parentId = src->_parentId; +	_messageKind = src->_messageKind; +	_x = src->_x; +	_y = src->_y; +	_field_14 = src->_field_14; +	_sceneClickX = src->_sceneClickX; +	_sceneClickY = src->_sceneClickY; +	_field_20 = src->_field_20; +	_field_24 = src->_field_24; +	_keyCode = src->_keyCode; +	_field_2C = src->_field_2C; +	_field_30 = src->_field_30; +	_field_34 = src->_field_34; +} + +Message::Message(int16 parentId, int messageKind, int x, int y, int a6, int a7, int sceneClickX, int sceneClickY, int a10) { +	_messageKind = messageKind; +	_parentId = parentId; +	_x = x; +	_y = y; +	_field_14 = a6; +	_sceneClickX = sceneClickX; +	_sceneClickY = sceneClickY; +	_field_24 = a7; +	_field_20 = a10; +	_keyCode = 0; +	_field_2C = 0; +	_field_30 = 0; +	_field_34 = 0; +} + +CObjstateCommand::CObjstateCommand() { +	_value = 0; +	_objCommandName = 0; +} + +bool CObjstateCommand::load(MfcArchive &file) { +	debug(5, "CObjStateCommand::load()"); + +	_objtype = kObjTypeObjstateCommand; + +	_cmd.load(file); + +	_value = file.readUint32LE(); + +	_objCommandName = file.readPascalString(); + +	return true; +} + +MessageQueue::MessageQueue() { +	_field_14 = 0; +	_parId = 0; +	_dataId = 0; +	_id = 0; +	_isFinished = 0; +	_flags = 0; +	_queueName = 0; +} + +MessageQueue::MessageQueue(MessageQueue *src, int parId, int field_38) { +	_counter = 0; +	_field_38 = (field_38 == 0); + +	for (Common::List<ExCommand *>::iterator it = src->_exCommands.begin(); it != src->_exCommands.end(); ++it) { +		ExCommand *ex = new ExCommand(*it); +		ex->_excFlags |= 2; + +		_exCommands.push_back(ex); +	} +	_field_14 = src->_field_14; + +	if (parId) +		_parId = parId; +	else +		_parId = src->_parId; + +	_id = g_fullpipe->_globalMessageQueueList->compact(); +	_dataId = src->_dataId; +	_flags = src->_flags; + +	g_fullpipe->_globalMessageQueueList->addMessageQueue(this); + +	_isFinished = 0; +} + +MessageQueue::~MessageQueue() { +	for (Common::List<ExCommand *>::iterator it = _exCommands.begin(); it != _exCommands.end(); ++it) { +		ExCommand *ex = (ExCommand *)*it; + +		if (ex && ex->_excFlags & 2) +			delete ex; +	} + +	_exCommands.clear(); + +	if (_field_14) +		delete _field_14; + +	if (_flags & 2) { +		g_fullpipe->_globalMessageQueueList->removeQueueById(_id); +	} + +	finish(); + +	free(_queueName); +} + +bool MessageQueue::load(MfcArchive &file) { +	debug(5, "MessageQueue::load()"); + +	_dataId = file.readUint16LE(); + +	int count = file.readUint16LE(); + +	assert(g_fullpipe->_gameProjectVersion >= 12); + +	_queueName = file.readPascalString(); + +	for (int i = 0; i < count; i++) { +		ExCommand *tmp = (ExCommand *)file.readClass(); + +		_exCommands.push_back(tmp); +	} + +	_id = -1; +	_field_14 = 0; +	_parId = 0; +	_isFinished = 0; + +	return true; +} + +bool MessageQueue::chain(StaticANIObject *ani) { +	if (ani) +		ani->isIdle(); + +	if (checkGlobalExCommandList1() && checkGlobalExCommandList2()) { +		if (!(getFlags() & 2)) { +			g_fullpipe->_globalMessageQueueList->addMessageQueue(this); +			_flags |= 2; +		} +		if (ani) { +			ani->queueMessageQueue(this); +			return true; +		} else { +			sendNextCommand(); +			return true; +		} +	} +	return false; +} + +void MessageQueue::update() { +	if (_counter > 0) +		_counter--; + +	if (_exCommands.size()) { +		sendNextCommand(); +	} else if (_counter == 0) { +		_isFinished = 1; +		finish(); +	} +} + +void MessageQueue::messageQueueCallback1(int par) { +	// Autosave +	debug(3, "STUB: MessageQueue::messageQueueCallback1()"); +} + +ExCommand *MessageQueue::getExCommandByIndex(uint idx) { +	if (idx > _exCommands.size()) +		return 0; + +	Common::List<ExCommand *>::iterator it = _exCommands.begin(); + +	while (idx) { +		++it; +		idx--; +	} + +	return *it; +} + +void MessageQueue::sendNextCommand() { +	if (_exCommands.size()) { +		if (!(_flags & 4) && (_flags & 1)) { +			messageQueueCallback1(16); +		} +		ExCommand *ex = _exCommands.front(); + +		_exCommands.pop_front(); + +		_counter++; +		ex->_parId = _id; +		ex->_excFlags |= (ex->_field_24 == 0 ? 1 : 0) | (ex->_field_3C != 0 ? 2 : 0); + +		_flags |= 4; +		ex->sendMessage(); +	} else if (_counter <= 0) { +		_isFinished = 1; +		finish(); +	} +} + +bool MessageQueue::checkGlobalExCommandList1() { +	ExCommand *ex, *ex1; + +	for (uint i = 0; i < getCount(); i++) { +		ex = getExCommandByIndex(i); + +		if (ex->_messageKind != 1 && ex->_messageKind != 20 && ex->_messageKind != 5 && ex->_messageKind != 27) +			continue; + +		for (Common::List<ExCommand *>::iterator it = g_fullpipe->_exCommandList.begin(); it != g_fullpipe->_exCommandList.end(); it++) { +			ex1 = *it; + +			if (ex1->_messageKind != 1 && ex1->_messageKind != 20 && ex1->_messageKind != 5 && ex1->_messageKind != 27) +				continue; + +			if (ex1->_keyCode != ex->_keyCode && ex1->_keyCode != -1 && ex->_keyCode != -1) +				continue; + +			MessageQueue *mq = g_fullpipe->_globalMessageQueueList->getMessageQueueById(ex1->_parId); + +			if (mq) { +				if (mq->getFlags() & 1) +					return false; +			} +		} +	} +	return true; +} + +bool MessageQueue::checkGlobalExCommandList2() { +	ExCommand *ex, *ex1; + +	for (uint i = 0; i < getCount(); i++) { +		ex = getExCommandByIndex(i); + +		if (ex->_messageKind != 1 && ex->_messageKind != 20 && ex->_messageKind != 5 && ex->_messageKind != 27) +			continue; + +		for (Common::List<ExCommand *>::iterator it = g_fullpipe->_exCommandList.begin(); it != g_fullpipe->_exCommandList.end();) { +			ex1 = *it; + +			if (ex1->_messageKind != 1 && ex1->_messageKind != 20 && ex1->_messageKind != 5 && ex1->_messageKind != 27) { +				it++; +				continue; +			} + +			if (ex1->_keyCode != ex->_keyCode && ex1->_keyCode != -1 && ex->_keyCode != -1) { +				it++; +				continue; +			} + +			MessageQueue *mq = g_fullpipe->_globalMessageQueueList->getMessageQueueById(ex1->_parId); + +			if (mq) { +				if (mq->getFlags() & 1) +					return false; + +				delete mq; +			} + +			it = g_fullpipe->_exCommandList.erase(it); + +			if (ex1->_excFlags & 2) { +				delete ex1; +			} +		} +	} +	return true; +} + +void MessageQueue::finish() { +	if (!_parId) +		return; + +	MessageQueue *mq = g_fullpipe->_globalMessageQueueList->getMessageQueueById(_parId); + +	_parId = 0; + +	if (!mq) +		return; + +	if (!_flag1) { +		mq->update(); +		return; +	} + +	mq->_counter--; + +	if (!mq->_counter && !mq->_exCommands.size()) +		mq->update(); +} + +void MessageQueue::replaceKeyCode(int key1, int key2) { +	for (uint i = 0; i < getCount(); i++) { +		ExCommand *ex = getExCommandByIndex(i); +		int k = ex->_messageKind; +		if ((k == 1 || k == 20 || k == 5 || k == 6 || k == 2 || k == 18 || k == 19 || k == 22 || k == 55) +					&& ex->_keyCode == key1) +			ex->_keyCode = key2; +    } +} + +int MessageQueue::calcDuration(StaticANIObject *obj) { +	int res; +	ExCommand *ex; +	Movement *mov; + +	for (uint i = 0; (ex = getExCommandByIndex(i)); i++) +		if (ex->_parentId == obj->_id) { +			if (ex->_messageKind == 1 || ex->_messageKind == 20) { +				if ((mov = obj->getMovementById(ex->_messageNum)) != 0) { +					if (ex->_field_14 >= 1) +						res += ex->_field_14; +					else +						res += mov->calcDuration(); +				} +			} +		} + +	return res; +} + +void MessageQueue::changeParam28ForObjectId(int objId, int oldParam28, int newParam28) { +	for (uint i = 0; i < _exCommands.size(); i++) { +		ExCommand *ex = getExCommandByIndex(i); +		int k = ex->_messageKind; + +		if ((k == 1 || k == 20 || k == 5 || k == 6 || k == 2 || k == 18 || k == 19 || k == 22 || k == 55) +			 && ex->_keyCode == oldParam28 +			 && ex->_parentId == objId) +			ex->_keyCode = newParam28; +    } +} + +MessageQueue *GlobalMessageQueueList::getMessageQueueById(int id) { +	for (Common::Array<MessageQueue *>::iterator s = begin(); s != end(); ++s) { +		if ((*s)->_id == id) +			return *s; +	} + +	return 0; +} + +void GlobalMessageQueueList::deleteQueueById(int id) { +	for (uint i = 0; i < size(); i++) +		if (_storage[i]->_id == id) { +			remove_at(i); + +			disableQueueById(id); +			return; +		} +} + +void GlobalMessageQueueList::removeQueueById(int id) { +	for (uint i = 0; i < size(); i++) +		if (_storage[i]->_id == id) { +			_storage[i]->_flags &= 0xFD; // It is quite pointless +			remove_at(i); + +			disableQueueById(id); +			return; +		} +} + +void GlobalMessageQueueList::disableQueueById(int id) { +	for (Common::Array<MessageQueue *>::iterator s = begin(); s != end(); ++s) { +		if ((*s)->_parId == id) +			(*s)->_parId = 0; +	} +} + +int GlobalMessageQueueList::compact() { +	for (uint i = 0; i < size();) { +		if (((MessageQueue *)_storage[i])->_isFinished) { +			disableQueueById(_storage[i]->_id); +			remove_at(i); +		} else { +			i++; +		} +	} + +	return size() + 1; +} + +void GlobalMessageQueueList::addMessageQueue(MessageQueue *msg) { +	msg->setFlags(msg->getFlags() | 2); + +	push_back(msg); +} + +bool removeMessageHandler(int16 id, int pos) { +	if (g_fullpipe->_messageHandlers) { +		MessageHandler *curItem = g_fullpipe->_messageHandlers; +		MessageHandler *prevItem = 0; +		int curPos = 0; + +		while (id != curItem->id) { +			prevItem = curItem; +			curItem = curItem->nextItem; +			curPos++; + +			if (!curItem) +				return false; +		} + +		if (pos == -1 || curPos == pos) { +			prevItem->nextItem = curItem->nextItem; +			delete curItem; +			updateMessageHandlerIndex(prevItem->nextItem, -1); + +			return true; +		} +	} + +	return false; +} + +void updateMessageHandlerIndex(MessageHandler *msg, int offset) { +	for (; msg; msg = msg->nextItem) +		msg->index += offset; +} + +void addMessageHandler(int (*callback)(ExCommand *), int16 id) { +	if (getMessageHandlerById(id)) +		return; + +	MessageHandler *curItem = g_fullpipe->_messageHandlers; + +	if (!curItem) +		return; + +	int index = 0; +	for (MessageHandler *i = g_fullpipe->_messageHandlers->nextItem; i; i = i->nextItem) { +		curItem = i; +		index++; +	} + +	allocMessageHandler(curItem, id, callback, index); + +	if (curItem) +		updateMessageHandlerIndex(curItem->nextItem->nextItem, 1); +} + +MessageHandler *getMessageHandlerById(int16 id) { +	MessageHandler *curItem = g_fullpipe->_messageHandlers; + +	if (!curItem) +		return 0; + +	while (id != curItem->id) { +		curItem = curItem->nextItem; + +		if (!curItem) +			return 0; +	} + +	return curItem; +} + +bool allocMessageHandler(MessageHandler *where, int16 id, int (*callback)(ExCommand *), int index) { +	MessageHandler *msg = new MessageHandler; + +	if (where) { +		msg->nextItem = where->nextItem; +		where->nextItem = msg; +		msg->id = id; +		msg->callback = callback; +		msg->index = index; +	} else { +		msg->nextItem = 0; +		msg->id = id; +		msg->callback = callback; +		msg->index = 0; + +		g_fullpipe->_messageHandlers = msg; +	} + +	return true; +} + +int getMessageHandlersCount() { +	int result; +	MessageHandler *curItem = g_fullpipe->_messageHandlers; + +	for (result = 0; curItem; result++) +		curItem = curItem->nextItem; + +	return result; +} + +bool addMessageHandlerByIndex(int (*callback)(ExCommand *), int index, int16 id) { +	if (getMessageHandlerById(id)) +		return false; + +	if (index) { +		MessageHandler *curItem = g_fullpipe->_messageHandlers; + +		for (int i = index - 1; i > 0; i--) +			if (curItem) +				curItem = curItem->nextItem; + +		bool res = allocMessageHandler(curItem, id, callback, index); + +		if (res) +			updateMessageHandlerIndex(curItem->nextItem->nextItem, 1); + +		return res; +	} else { +		MessageHandler *newItem = new MessageHandler; + +		newItem->nextItem = g_fullpipe->_messageHandlers; +		newItem->id = id; +		newItem->callback = callback; +		newItem->index = 0; + +		updateMessageHandlerIndex(g_fullpipe->_messageHandlers, 1); +		g_fullpipe->_messageHandlers = newItem; + +		return true; +	} +} + +bool insertMessageHandler(int (*callback)(ExCommand *), int index, int16 id) { +	if (getMessageHandlerById(id)) +		return false; + +	MessageHandler *curItem = g_fullpipe->_messageHandlers; + +	for (int i = index; i > 0; i--) +		if (curItem) +			curItem = curItem->nextItem; + +	bool res = allocMessageHandler(curItem, id, callback, index + 1); +	if (curItem) +		updateMessageHandlerIndex(curItem->nextItem->nextItem, 1); + +	return res; +} + +void clearMessageHandlers() { +	MessageHandler *curItem; +	MessageHandler *nextItem; + +	curItem = g_fullpipe->_messageHandlers; +	if (curItem) { +		do { +			nextItem = curItem->nextItem; + +			delete curItem; + +			curItem = nextItem; +		} while (nextItem); + +		g_fullpipe->_messageHandlers = 0; +	} +} + +void processMessages() { +	if (!g_fullpipe->_isProcessingMessages) { +		g_fullpipe->_isProcessingMessages = true; + +		while (g_fullpipe->_exCommandList.size()) { +			ExCommand *ex = g_fullpipe->_exCommandList.front(); +			g_fullpipe->_exCommandList.pop_front(); +			ex->handleMessage(); +		} +		g_fullpipe->_isProcessingMessages = false; +	} +} + +void updateGlobalMessageQueue(int id, int objid) { +	MessageQueue *m = g_fullpipe->_globalMessageQueueList->getMessageQueueById(id);   +	if (m) { +		m->update(); +	} +} + +} // End of namespace Fullpipe diff --git a/engines/fullpipe/messages.h b/engines/fullpipe/messages.h new file mode 100644 index 0000000000..960e184a88 --- /dev/null +++ b/engines/fullpipe/messages.h @@ -0,0 +1,174 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef FULLPIPE_MESSAGEQUEUE_H +#define FULLPIPE_MESSAGEQUEUE_H + +#include "fullpipe/utils.h" +#include "fullpipe/inventory.h" +#include "fullpipe/gfx.h" +#include "fullpipe/sound.h" +#include "fullpipe/scene.h" + +namespace Fullpipe { + +class Message : public CObject { + public: +	int _messageKind; +	int16 _parentId; +	int _x; +	int _y; +	int _field_14; +	int _sceneClickX; +	int _sceneClickY; +	int _field_20; +	int _field_24; +	int _keyCode; +	int _field_2C; +	int _field_30; +	int _field_34; + + public: +	Message(); +	Message(Message *src); +	virtual ~Message() {} + +	Message(int16 parentId, int messageKind, int x, int y, int a6, int a7, int sceneClickX, int sceneClickY, int a10); +}; + +class ExCommand : public Message { + public: + +	int _messageNum; +	int _field_3C; +	int _excFlags; +	int _parId; + +	ExCommand(); +	ExCommand(ExCommand *src); +	ExCommand(int16 parentId, int messageKind, int messageNum, int x, int y, int a7, int a8, int sceneClickX, int sceneClickY, int a11); +	virtual ~ExCommand() {} + +	virtual bool load(MfcArchive &file); + +	bool handleMessage(); +	void sendMessage(); +	void postMessage(); +	void handle(); +}; + +class ExCommand2 : public ExCommand { + public: +	Common::Point **_points; +	int _pointsSize; +}; + +class CObjstateCommand : public CObject { + public: +	ExCommand _cmd; +	char *_objCommandName; +	int _value; + + public: +	CObjstateCommand(); +	virtual bool load(MfcArchive &file); +}; + +class MessageQueue : public CObject { +  public: +	int _id; +	int _flags; +	char *_queueName; +	int16 _dataId; +	int16 _field_12; +	CObject *_field_14; +	Common::List<ExCommand *> _exCommands; +	int _counter; +	int _field_38; +	int _isFinished; +	int _parId; +	int _flag1; + + public: +	MessageQueue(); +	MessageQueue(MessageQueue *src, int parId, int field_38); +	virtual ~MessageQueue(); + +	virtual bool load(MfcArchive &file); + +	int getFlags() { return _flags; } +	void setFlags(int flags) { _flags = flags; } + +	uint getCount() { return _exCommands.size(); } + +	ExCommand *getExCommandByIndex(uint idx); + +	void replaceKeyCode(int key1, int key2); + +	bool chain(StaticANIObject *ani); +	void update(); +	void sendNextCommand(); +	void finish(); + +	void messageQueueCallback1(int par); + +	bool checkGlobalExCommandList1(); +	bool checkGlobalExCommandList2(); + +	int calcDuration(StaticANIObject *obj); +	void changeParam28ForObjectId(int objId, int oldParam28, int newParam28); +}; + +class GlobalMessageQueueList : public Common::Array<MessageQueue *> { +  public: +	MessageQueue *getMessageQueueById(int id); +	void deleteQueueById(int id); +	void removeQueueById(int id); +	void disableQueueById(int id); +	void addMessageQueue(MessageQueue *msg); + +	int compact(); +}; + +struct MessageHandler { +	int (*callback)(ExCommand *cmd); +	int16 id; +	int16 field_6; +	int index; +	MessageHandler *nextItem; +}; + +bool removeMessageHandler(int16 id, int pos); +void updateMessageHandlerIndex(MessageHandler *msg, int offset); +void addMessageHandler(int (*callback)(ExCommand *), int16 id); +MessageHandler *getMessageHandlerById(int16 id); +bool allocMessageHandler(MessageHandler *where, int16 id, int (*callback)(ExCommand *), int index); +int getMessageHandlersCount(); +bool addMessageHandlerByIndex(int (*callback)(ExCommand *), int index, int16 id); +bool insertMessageHandler(int (*callback)(ExCommand *), int index, int16 id); +void clearMessageHandlers(); +void processMessages(); +void updateGlobalMessageQueue(int id, int objid); + +} // End of namespace Fullpipe + +#endif /* FULLPIPE_MESSAGEQUEUE_H */ diff --git a/engines/fullpipe/modal.cpp b/engines/fullpipe/modal.cpp new file mode 100644 index 0000000000..6f1bc0cc1f --- /dev/null +++ b/engines/fullpipe/modal.cpp @@ -0,0 +1,106 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "fullpipe/fullpipe.h" +#include "fullpipe/modal.h" +#include "fullpipe/messages.h" +#include "fullpipe/constants.h" +#include "fullpipe/scenes.h" + +namespace Fullpipe { + +bool CBaseModalObject::handleMessage(ExCommand *message) { +	warning("STUB: CBaseModalObject::handleMessage()"); + +	return true; +} + +bool CBaseModalObject::init(int counterdiff) { +	warning("STUB: CBaseModalObject::init(%d)", counterdiff); + +	return true; +} + +bool CBaseModalObject::update() { +	warning("STUB: CBaseModalObject::update()"); + +	return true; +} + +void CBaseModalObject::saveload() { +	warning("STUB: CBaseModalObject::saveload()"); +} + + +CModalIntro::CModalIntro() { +	_field_8 = 0; +	_countDown = 0; +	_needRedraw = 0; +	if (g_vars->sceneIntro_skipIntro) { +		_introFlags = 4; +	} else { +		_introFlags = 33; +		_countDown = 150; + +		PictureObject *pict = g_fullpipe->accessScene(SC_INTRO1)->getPictureObjectById(PIC_IN1_PIPETITLE, 0); +		pict->setFlags(pict->_flags & 0xFFFB); +	} +	g_vars->sceneIntro_skipIntro = false; +	_sfxVolume = g_fullpipe->_sfxVolume; +} + +bool CModalIntro::handleMessage(ExCommand *message) { +	if (message->_messageKind != 17) +		return false; + +	if (message->_messageNum != 36) +		return false; + +	if (message->_keyCode != 13 && message->_keyCode != 27 && message->_keyCode != 32) +		return false; + +	if (_needRedraw) { +		if (!(_introFlags & 0x10)) { +			_countDown = 0; +			g_vars->sceneIntro_needBlackout = true; +			return true; +		} +		g_vars->sceneIntro_playing = false; +		g_vars->sceneIntro_needBlackout = true; +	} + +	return true; +} + +void FullpipeEngine::openMap() { +	warning("STUB: FullpipeEngine::openMap()"); +} + +void FullpipeEngine::openHelp() { +	warning("STUB: FullpipeEngine::openHelp()"); +} + +void FullpipeEngine::openMainMenu() { +	warning("STUB: FullpipeEngine::openMainMenu()"); +} + +} // End of namespace Fullpipe diff --git a/engines/fullpipe/modal.h b/engines/fullpipe/modal.h new file mode 100644 index 0000000000..73236e8e5b --- /dev/null +++ b/engines/fullpipe/modal.h @@ -0,0 +1,59 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef FULLPIPE_MODAL_H +#define FULLPIPE_MODAL_H + +namespace Fullpipe { + +class CBaseModalObject { + public: + +	CBaseModalObject *_parentObj; + + public: + 	CBaseModalObject() : _parentObj(0) {} +	virtual ~CBaseModalObject() {} + +	virtual bool handleMessage(ExCommand *message); +	virtual bool init(int counterdiff); +	virtual bool update(); + +	void saveload(); +}; + +class CModalIntro : public CBaseModalObject { +	int _field_8; +	int _introFlags; +	int _countDown; +	int _needRedraw; +	int _sfxVolume; + + public: +	CModalIntro(); + +	virtual bool handleMessage(ExCommand *message); +}; + +} // End of namespace Fullpipe + +#endif /* FULLPIPE_MODAL_H */ diff --git a/engines/fullpipe/module.mk b/engines/fullpipe/module.mk new file mode 100644 index 0000000000..380f582c08 --- /dev/null +++ b/engines/fullpipe/module.mk @@ -0,0 +1,31 @@ +MODULE := engines/fullpipe + +MODULE_OBJS = \ +	behavior.o \ +	detection.o \ +	fullpipe.o \ +	gameloader.o \ +	gfx.o \ +	init.o \ +	input.o \ +	interaction.o \ +	inventory.o \ +	lift.o \ +	messages.o \ +	modal.o \ +	motion.o \ +	ngiarchive.o \ +	scene.o \ +	scenes.o \ +	sound.o \ +	stateloader.o \ +	statics.o \ +	utils.o + +# This module can be built as a plugin +ifeq ($(ENABLE_FULLPIPE), DYNAMIC_PLUGIN) +PLUGIN := 1 +endif + +# Include common rules +include $(srcdir)/rules.mk diff --git a/engines/fullpipe/motion.cpp b/engines/fullpipe/motion.cpp new file mode 100644 index 0000000000..4ba03f123f --- /dev/null +++ b/engines/fullpipe/motion.cpp @@ -0,0 +1,279 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "fullpipe/fullpipe.h" + +#include "common/file.h" +#include "common/array.h" +#include "common/list.h" + +#include "fullpipe/objects.h" +#include "fullpipe/motion.h" + +namespace Fullpipe { + +bool CMotionController::load(MfcArchive &file) { +	// Is originally empty	file.readClass(); + +	debug(5, "CMotionController::load()"); + +	return true; +} + +bool CMctlCompound::load(MfcArchive &file) { +	debug(5, "CMctlCompound::load()"); + +	int count = file.readUint32LE(); + +	debug(6, "CMctlCompound::count = %d", count); + +	for (int i = 0; i < count; i++) { +		debug(6, "CompoundArray[%d]", i); +		CMctlCompoundArrayItem *obj = (CMctlCompoundArrayItem *)file.readClass(); + +		int count1 = file.readUint32LE(); + +		debug(6, "ConnectionPoint::count: %d", count1); +		for (int j = 0; j < count1; j++) { +			debug(6, "ConnectionPoint[%d]", j); +			CMctlConnectionPoint *obj1 = (CMctlConnectionPoint *)file.readClass(); + +			obj->_connectionPoints.push_back(*obj1); +		} + +		obj->_field_20 = file.readUint32LE(); +		obj->_field_24 = file.readUint32LE(); + +		debug(6, "graphReact"); +		obj->_movGraphReactObj = (CMovGraphReact *)file.readClass(); + +		_motionControllers.push_back(*obj); +	} + +	return true; +} + +void CMctlCompound::addObject(StaticANIObject *obj) { +	warning("STUB: CMctlCompound::addObject()"); +} + +void CMctlCompound::initMovGraph2() { +	warning("STUB: CMctlCompound::initMovGraph2()"); +} + +MessageQueue *CMctlCompound::method34(StaticANIObject *subj, int xpos, int ypos, int flag, int staticsId) { +	warning("STUB: CMctlCompound::method34()"); + +	return 0; +} + +MessageQueue *CMctlCompound::method4C(StaticANIObject *subj, int xpos, int ypos, int flag, int staticsId) { +	warning("STUB: CMctlCompound::method4C()"); + +	return 0; +} + +bool CMctlCompoundArray::load(MfcArchive &file) { +	debug(5, "CMctlCompoundArray::load()"); + +	int count = file.readUint32LE(); + +	debug(0, "CMctlCompoundArray::count = %d", count); + +	assert(0); + +	return true; +} + +CMovGraph::CMovGraph() { +	_itemsCount = 0; +	_items = 0; +	//_callback1 = CMovGraphCallback1;  // TODO +	_field_44 = 0; +	// insertMessageHandler(CMovGraph_messageHandler, getMessageHandlersCount() - 1, 129); +} + +bool CMovGraph::load(MfcArchive &file) { +	debug(5, "CMovGraph::load()"); + +	_links.load(file); +	_nodes.load(file); + +	return true; +} + +void CMovGraph::addObject(StaticANIObject *obj) { +	warning("STUB: CMovGraph::addObject()"); +} + +CMovGraphLink::CMovGraphLink() { +	_distance = 0; +	_angle = 0; +	_flags = 0x10000000; +	_movGraphNode2 = 0; +	_movGraphNode1 = 0; +	_field_3C = 0; +	_field_38 = 0; +	_movGraphReact = 0; +	_name = 0; +} + +bool CMovGraphLink::load(MfcArchive &file) { +	debug(5, "CMovGraphLink::load()"); + +	_dwordArray1.load(file); +	_dwordArray2.load(file); + +	_flags = file.readUint32LE(); + +	debug(8, "GraphNode1"); +	_movGraphNode1 = (CMovGraphNode *)file.readClass(); +	debug(8, "GraphNode2"); +	_movGraphNode2 = (CMovGraphNode *)file.readClass(); + +	_distance = file.readDouble(); +	_angle = file.readDouble(); + +	debug(8, "distance: %g, angle: %g", _distance, _angle); + +	_movGraphReact = (CMovGraphReact *)file.readClass(); +	_name = file.readPascalString(); + +	return true; +} + +bool CMovGraphNode::load(MfcArchive &file) { +	debug(5, "CMovGraphNode::load()"); + +	_field_14 = file.readUint32LE(); +	_x = file.readUint32LE(); +	_y = file.readUint32LE(); +	_distance = file.readUint32LE(); + +	return true; +} + +CReactParallel::CReactParallel() { +	_x1 = 0; +	_x2 = 0; +	_dy = 0; +	_dx = 0; +	_points = 0; +	_y1 = 0; +	_y2 = 0; +} + +bool CReactParallel::load(MfcArchive &file) { +	debug(5, "CReactParallel::load()"); + +	_x1 = file.readUint32LE(); +	_y1 = file.readUint32LE(); +	_x2 = file.readUint32LE(); +	_y2 = file.readUint32LE(); +	_dx = file.readUint32LE(); +	_dy = file.readUint32LE(); + +	createRegion(); + +	return true; +} + +void CReactParallel::createRegion() { +	_points = (Common::Point **)malloc(sizeof(Common::Point *) * 4); + +	for (int i = 0; i < 4; i++) +		_points[i] = new Common::Point; + +	double at = atan2(_x1 - _x2, _y1 - _y2) + 1.570796; +	double sn = sin(at); +	double cs = cos(at); + +	_points[0]->x = (int16)(_x1 - _dx * cs); +	_points[0]->y = (int16)(_y1 - _dx * sn); + +	_points[1]->x = (int16)(_x2 - _dx * cs); +	_points[1]->y = (int16)(_y2 - _dx * sn); + +	_points[2]->x = (int16)(_x1 + _dy * cs); +	_points[2]->y = (int16)(_y2 + _dy * sn); + +	_points[3]->x = (int16)(_x1 + _dy * cs); +	_points[3]->y = (int16)(_y1 + _dy * sn); + +	// GdiObject::Attach(_rgn, CreatePolygonRgn(_points, 4, 2); +} + +CReactPolygonal::CReactPolygonal() { +	_field_C = 0; +	_points = 0; +	_pointCount = 0; +	_field_10 = 0; +} + +bool CReactPolygonal::load(MfcArchive &file) { +	debug(5, "CReactPolygonal::load()"); + +	_field_C = file.readUint32LE(); +	_field_10 = file.readUint32LE(); +	_pointCount = file.readUint32LE(); + +	if (_pointCount > 0) { +		_points = (Common::Point **)malloc(sizeof(Common::Point *) * _pointCount); + +		for (int i = 0; i < _pointCount; i++) { +			_points[i] = new Common::Point; + +			_points[i]->x = file.readUint32LE(); +			_points[i]->y = file.readUint32LE(); +		} + +	} + +	createRegion(); + +	return true; +} + +void CReactPolygonal::createRegion() { +	if (_points) { + +		// GdiObject::Attach(_rgn, CreatePolygonRgn(_points, _pointCount, 2); +	} +} + +int startWalkTo(int objId, int objKey, int x, int y, int a5) { +	warning("STUB: startWalkTo(%d, %d, %d, %d, %d)", objId, objKey, x, y, a5); + +	return 0; +} + +int doSomeAnimation(int objId, int objKey, int a3) { +	warning("STUB: doSomeAnimation(%d, %d, %d)", objId, objKey, a3); + +	return 0; +} + +int doSomeAnimation2(int objId, int objKey) { +	return doSomeAnimation(objId, objKey, 0); +} + +} // End of namespace Fullpipe diff --git a/engines/fullpipe/motion.h b/engines/fullpipe/motion.h new file mode 100644 index 0000000000..f110ac30df --- /dev/null +++ b/engines/fullpipe/motion.h @@ -0,0 +1,186 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef FULLPIPE_MOTION_H +#define FULLPIPE_MOTION_H + +namespace Fullpipe { + +int startWalkTo(int objId, int objKey, int x, int y, int a5); +int doSomeAnimation(int objId, int objKey, int a3); +int doSomeAnimation2(int objId, int objKey); + +class CMotionController : public CObject { + public: +	int _field_4; +	bool _isEnabled; + + public: +	CMotionController() : _isEnabled(true) {} +	virtual bool load(MfcArchive &file); + +	void setEnabled() { _isEnabled = true; } +	void clearEnabled() { _isEnabled = false; } + +	virtual void addObject(StaticANIObject *obj) {} +}; + +class CMctlCompoundArray : public Common::Array<CObject>, public CObject { + public: +	virtual bool load(MfcArchive &file); +}; + +class CMctlConnectionPointsArray : public Common::Array<CObject>, public CObject { + public: +	virtual bool load(MfcArchive &file); +}; + +class CMctlCompound : public CMotionController { +	CMctlCompoundArray _motionControllers; + + public: +	virtual bool load(MfcArchive &file); + +	virtual void addObject(StaticANIObject *obj); +	void initMovGraph2(); + +	MessageQueue *method34(StaticANIObject *subj, int xpos, int ypos, int flag, int staticsId); +	MessageQueue *method4C(StaticANIObject *subj, int xpos, int ypos, int flag, int staticsId); +}; + +class Unk2 : public CObject { +	int _items; +	int _count; + + public: +	Unk2() : _items(0), _count(0) {} +}; + +class CMovGraphNode : public CObject { +	int _x; +	int _y; +	int _distance; +	int16 _field_10; +	int16 _field_12; +	int _field_14; + +  public: +	CMovGraphNode() : _x(0), _y(0), _distance(0), _field_10(0), _field_14(0) {} +	virtual bool load(MfcArchive &file); +}; + +class CMovGraphReact : public CObject { +	// Empty +}; + +class CMctlCompoundArrayItem : public CObject { +	friend class CMctlCompound; + +  protected: +	CMotionController *_motionControllerObj; +	CMovGraphReact *_movGraphReactObj; +	CMctlConnectionPointsArray _connectionPoints; +	int _field_20; +	int _field_24; +	int _field_28; + + public: +	CMctlCompoundArrayItem() : _movGraphReactObj(0) {} +}; + +class CReactParallel : public CMovGraphReact { +	//CRgn _rgn; +	int _x1; +	int _y1; +	int _x2; +	int _y2; +	int _dx; +	int _dy; +	Common::Point **_points; + +  public: +	CReactParallel(); +	virtual bool load(MfcArchive &file); +	void createRegion(); +}; + +class CReactPolygonal : public CMovGraphReact { +	//CRgn _rgn; +	int _field_C; +	int _field_10; +	int _pointCount; +	Common::Point **_points; + +  public: +	CReactPolygonal(); +	virtual bool load(MfcArchive &file); +	void createRegion(); +}; + +class CMovGraphLink : public CObject { +	CMovGraphNode *_movGraphNode1; +	CMovGraphNode *_movGraphNode2; +	CDWordArray _dwordArray1; +	CDWordArray _dwordArray2; +	int _flags; +	int _field_38; +	int _field_3C; +	double _distance; +	double _angle; +	CMovGraphReact *_movGraphReact; +	char *_name; + +  public: +	CMovGraphLink(); +	virtual bool load(MfcArchive &file); +}; + +class CMovGraph : public CMotionController { +	CObList _nodes; +	CObList _links; +	int _field_44; +	int _items; +	int _itemsCount; +	int (*_callback1)(int, int, int); +	Unk2 _unk2; + + public: +	CMovGraph(); +	virtual bool load(MfcArchive &file); + +	virtual void addObject(StaticANIObject *obj); +}; + +class CMctlConnectionPoint : public CObject { +	int _connectionX; +	int _connectionY; +	int _field_C; +	int _field_10; +	int16 _field_14; +	int16 _field_16; +	int _messageQueueObj; +	int _motionControllerObj; +}; + +} // End of namespace Fullpipe + +#endif /* FULLPIPE_MOTION_H */ diff --git a/engines/fullpipe/ngiarchive.cpp b/engines/fullpipe/ngiarchive.cpp new file mode 100644 index 0000000000..5d895c17a0 --- /dev/null +++ b/engines/fullpipe/ngiarchive.cpp @@ -0,0 +1,156 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "fullpipe/fullpipe.h" +#include "common/archive.h" + +#include "common/file.h" +#include "common/hash-str.h" +#include "common/memstream.h" +#include "common/bufferedstream.h" +#include "common/textconsole.h" + +#include "fullpipe/ngiarchive.h" + +namespace Fullpipe { + +NGIArchive::NGIArchive(const Common::String &filename) : _ngiFilename(filename) { +	Common::File ngiFile; + +	if (!ngiFile.open(_ngiFilename)) { +		warning("NGIArchive::NGIArchive(): Could not find the archive file"); +		return; +	} + +	ngiFile.seek(4, SEEK_SET); + +	unsigned int count = ngiFile.readUint16LE(); // How many entries? + +	ngiFile.seek(20, SEEK_SET); + +	unsigned int key = ngiFile.readUint16LE(); + +	byte key1, key2; + +	key1 = key & 0xff; +	key2 = (key >> 8) & 0xff; + +	int fatSize = count * 32; + +	ngiFile.seek(32, SEEK_SET); + +	byte *fat = (byte *)calloc(fatSize, 1); + +	ngiFile.read(fat, fatSize); + +	for (int i = 0; i < fatSize; i++) { +		key1 = (key1 << 1) ^ key2; +		key2 = (key2 >> 1) ^ key1; + +		fat[i] ^= key1; +	} + +	NgiHeader header; +	NgiHeader *head; + +	for (uint i = 0; i < count; i++) { +		memcpy(header.filename, &fat[i * 32], 12); +		header.filename[12] = 0; +		header.flags = READ_LE_UINT32(&fat[i * 32 + 16]); +		header.extVal = READ_LE_UINT32(&fat[i * 32 + 20]); +		header.pos = READ_LE_UINT32(&fat[i * 32 + 24]); +		header.size = READ_LE_UINT32(&fat[i * 32 + 28]); + +		if (header.flags & 0x1e0) { +			warning("File has flags: %.8x\n", header.flags & 0x1e0); +		} + +		head = new NgiHeader(header); + +		_headers[header.filename] = head; +	} + +	free(fat); + +	g_fullpipe->_currArchive = this; + +	debug(0, "NGIArchive::NGIArchive(%s): Located %d files", filename.c_str(), _headers.size()); +} + +NGIArchive::~NGIArchive() { +	debug(0, "NGIArchive Destructor Called"); +	NgiHeadersMap::iterator it = _headers.begin(); +	for ( ; it != _headers.end(); ++it) { +		delete it->_value; +	} + +	g_fullpipe->_currArchive = 0; +} + +bool NGIArchive::hasFile(const Common::String &name) const { +	return _headers.contains(name); +} + +	int NGIArchive::listMembers(Common::ArchiveMemberList &list) const { +	int matches = 0; + +	NgiHeadersMap::const_iterator it = _headers.begin(); +	for ( ; it != _headers.end(); ++it) { +		list.push_back(Common::ArchiveMemberList::value_type(new Common::GenericArchiveMember(it->_value->filename, this))); +		matches++; +	} + +	return matches; +} + +const Common::ArchiveMemberPtr NGIArchive::getMember(const Common::String &name) const { +	if (!hasFile(name)) +		return Common::ArchiveMemberPtr(); + +	return Common::ArchiveMemberPtr(new Common::GenericArchiveMember(name, this)); +} + +Common::SeekableReadStream *NGIArchive::createReadStreamForMember(const Common::String &name) const { +	if (!_headers.contains(name)) { +		return 0; +	} + +	NgiHeader *hdr = _headers[name]; + +	Common::File archiveFile; +	archiveFile.open(_ngiFilename); +	archiveFile.seek(hdr->pos, SEEK_SET); + +	byte *data = (byte *)malloc(hdr->size); +	assert(data); + +	int32 len = archiveFile.read(data, hdr->size); +	assert(len == hdr->size); + +	return new Common::MemoryReadStream(data, hdr->size, DisposeAfterUse::YES); +} + +Common::Archive *makeNGIArchive(const Common::String &name) { +	return new NGIArchive(name); +} + +} // End of namespace Fullpipe diff --git a/engines/fullpipe/ngiarchive.h b/engines/fullpipe/ngiarchive.h new file mode 100644 index 0000000000..a5b05a2e50 --- /dev/null +++ b/engines/fullpipe/ngiarchive.h @@ -0,0 +1,69 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef FULLPIPE_NGIARCHIVE_H +#define FULLPIPE_NGIARCHIVE_H + +#include "common/str.h" + +namespace Fullpipe { + +class Archive; + +#define NGI_FILENAME_MAX 13 + +struct NgiHeader { +	int32 pos; +	int32 extVal; +	int32 flags; +	int32 size; +	char  filename[NGI_FILENAME_MAX]; +}; + +typedef Common::HashMap<Common::String, NgiHeader*, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo> NgiHeadersMap; + +class NGIArchive : public Common::Archive { +	NgiHeadersMap _headers; +	Common::String _ngiFilename; + +public: +	NGIArchive(const Common::String &name); +	virtual ~NGIArchive(); + +	// Archive implementation +	virtual bool hasFile(const Common::String &name) const; +	virtual int listMembers(Common::ArchiveMemberList &list) const; +	virtual const Common::ArchiveMemberPtr getMember(const Common::String &name) const; +	virtual Common::SeekableReadStream *createReadStreamForMember(const Common::String &name) const; +}; + +/** + * This factory method creates an Archive instance corresponding to the content + * of the NGI compressed file with the given name. + * + * May return 0 in case of a failure. + */ +Common::Archive *makeNGIArchive(const Common::String &name); + +} // End of namespace Fullpipe + +#endif diff --git a/engines/fullpipe/objectnames.h b/engines/fullpipe/objectnames.h new file mode 100644 index 0000000000..015df727e9 --- /dev/null +++ b/engines/fullpipe/objectnames.h @@ -0,0 +1,250 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +// This file is used in order to avoid usage of constants in Russian accross the code + +#ifndef FULLPIPE_OBJECTNAMES_H +#define FULLPIPE_OBJECTNAMES_H + +namespace Fullpipe { + +#define sO_Grandma "\xc1\xe0\xe1\xf3\xeb\xff"	// "Бабуля" +#define sO_Jar_4 "\xc1\xe0\xed\xea\xe0_4"	// "Банка_4" +#define sO_Pool "\xc1\xe0\xf1\xf1\xe5\xe9\xed"	// "Бассейн" +#define sO_TumyTrampie "\xc1\xe0\xf2\xf3\xf2\xe0"	// "Батута" +#define sO_WithoutBoot "\xc1\xe5\xe7 \xe1\xee\xf2\xe8\xed\xea\xe0"	// "Без ботинка" +#define sO_WithoutJug "\xc1\xe5\xe7 \xe3\xee\xf0\xf8\xea\xee\xe2"	// "Без горшков" +#define sO_WithoutCarpet "\xc1\xe5\xe7 \xea\xee\xe2\xf0\xe8\xea\xe0"	// "Без коврика" +#define sO_WithoutCoin "\xc1\xe5\xe7 \xec\xee\xed\xe5\xf2\xfb"	// "Без монеты" +#define sO_WithNothing "\xc1\xe5\xe7 \xed\xe8\xf7\xe5\xe3\xee"	// "Без ничего" +#define sO_WithoutHandle "\xc1\xe5\xe7 \xf0\xf3\xf7\xea\xe8"	// "Без ручки" +#define sO_WithoutStool "\xc1\xe5\xe7 \xf2\xe0\xe1\xf3\xf0\xe5\xf2\xea\xe8"	// "Без табуретки" +#define sO_WithoutDrawer "\xc1\xe5\xe7 \xff\xf9\xe8\xea\xe0"	// "Без ящика" +#define sO_Blocked "\xc1\xeb\xee\xea\xe8\xf0\xee\xe2\xe0\xed"	// "Блокирован" +#define sO_BlockedShe "\xc1\xeb\xee\xea\xe8\xf0\xee\xe2\xe0\xed\xe0"	// "Блокирована" +#define sO_Awaken "\xc1\xee\xe4\xf0\xf1\xf2\xe2\xf3\xe5\xf2"	// "Бодрствует" +#define sO_Boot_15 "\xc1\xee\xf2\xe8\xed\xee\xea_15"	// "Ботинок_15" +#define sO_Bottle_38 "\xc1\xf3\xf2\xfb\xeb\xea\xe0_38"	// "Бутылка_38" +#define sO_InSmokeRoom "\xc2 \xea\xf3\xf0\xe8\xeb\xea\xe5"	// "В курилке" +#define sO_InSock "\xc2 \xed\xee\xf1\xea\xe5"	// "В носке" +#define sO_InGlasses "\xc2 \xee\xf7\xea\xe0\xf5"	// "В очках" +#define sO_In_14 "\xc2_14"	// "В_14" +#define sO_In_32_Lies "\xc2_32 \xeb\xe5\xe6\xe8\xf2"	// "В_32 лежит" +#define sO_In_32_Stands "\xc2_32 \xf2\xee\xf0\xf7\xe8\xf2"	// "В_32 торчит" +#define sO_In_33 "\xc2_33"	// "В_33" +#define sO_In_7 "\xc2_7"	// "В_7" +#define sO_Together "\xc2\xe4\xe2\xee\xe5\xec"	// "Вдвоем" +#define sO_Valve1_26 "\xc2\xe5\xed\xf2\xe8\xeb\xfc\x31_26"	// "Вентиль1_26" +#define sO_Valve2_26 "\xc2\xe5\xed\xf2\xe8\xeb\xfc\x32_26"	// "Вентиль2_26" +#define sO_Valve3_26 "\xc2\xe5\xed\xf2\xe8\xeb\xfc\x33_26"	// "Вентиль3_26" +#define sO_Valve4_26 "\xc2\xe5\xed\xf2\xe8\xeb\xfc\x34_26"	// "Вентиль4_26" +#define sO_Valve5_26 "\xc2\xe5\xed\xf2\xe8\xeb\xfc\x35_26"	// "Вентиль5_26" +#define sO_Valve_34 "\xc2\xe5\xed\xf2\xe8\xeb\xfc_34"	// "Вентиль_34" +#define sO_UpperHatch_23 "\xc2\xe5\xf0\xf5\xed\xe8\xe9 \xeb\xfe\xea_23"	// "Верхний люк_23" +#define sO_Taken "\xc2\xe7\xff\xf2"	// "Взят" +#define sO_HangsOnPipe "\xc2\xe8\xf1\xe8\xf2 \xed\xe0 \xf2\xf0\xf3\xe1\xe5"	// "Висит на трубе" +#define sO_On "\xc2\xea\xeb"	// "Вкл" +#define sO_TurnedOn "\xc2\xea\xeb\xfe\xf7\xe5\xed"	// "Включен" +#define sO_Driver "\xc2\xee\xe4\xe8\xeb\xe0"	// "Водила" +#define sO_HareTheNooksiter "\xc2\xf3\xe3\xeb\xf3\xf1\xe5\xe4"	// "Вуглусед" +#define sO_Off "\xc2\xfb\xea\xeb"	// "Выкл" +#define sO_TurnedOff "\xc2\xfb\xea\xeb\xfe\xf7\xe5\xed"	// "Выключен" +#define sO_HasGrown "\xc2\xfb\xf0\xee\xf1"	// "Вырос" +#define sO_Boss "\xc3\xeb\xe0\xe2\xe0\xf0\xfc"	// "Главарь" +#define sO_Jug "\xc3\xee\xf0\xf8\xee\xea"	// "Горшок" +#define sO_Strolling "\xc3\xf3\xeb\xff\xe5\xf2"	// "Гуляет" +#define sO_Yes "\xc4\xe0"	// "Да" +#define sO_Girl "\xc4\xe5\xe2\xee\xf7\xea\xe0"	// "Девочка" +#define sO_Elephantine "\xc4\xe5\xe2\xee\xf7\xea\xe0-\xf1\xeb\xee\xed\xe8\xea"	// "Девочка-слоник" +#define sO_Grandpa "\xc4\xe5\xe4\xf3\xf8\xea\xe0"	// "Дедушка" +#define sO_Plank_25 "\xc4\xee\xf1\xea\xe0_25"	// "Доска_25" +#define sO_Plank_34 "\xc4\xee\xf1\xea\xe0_34"	// "Доска_34" +#define sO_DudeJumped "\xc4\xff\xe4\xff \xef\xf0\xfb\xe3\xe0\xeb"	// "Дядя прыгал" +#define sO_Dude "\xc4\xff\xe4\xff"	// "Дядя" +#define sO_GuvTheDrawer "\xc4\xff\xe4\xff-\xff\xf9\xe8\xea"	// "Дядя-ящик" +#define sO_DudeSwinged "\xc4\xff\xe4\xff_\xea\xe0\xf2\xe0\xeb\xf1\xff"	// "Дядя_катался" +#define sO_Eats "\xc5\xf1\xf2"	// "Ест" +#define sO_Present "\xc5\xf1\xf2\xfc"	// "Есть" +#define sO_CloseThing1 "\xc7\xe0\xea\xf0\xfb\xe2\xe0\xe5\xec\xee\xe5 1"	// "Закрываемое 1" +#define sO_CloseThing2 "\xc7\xe0\xea\xf0\xfb\xe2\xe0\xe5\xec\xee\xe5 2"	// "Закрываемое 2" +#define sO_CloseThing3 "\xc7\xe0\xea\xf0\xfb\xe2\xe0\xe5\xec\xee\xe5 3"	// "Закрываемое 3" +#define sO_CloseThing "\xc7\xe0\xea\xf0\xfb\xe2\xe0\xe5\xec\xee\xe5"	// "Закрываемое" +#define sO_Closed "\xc7\xe0\xea\xf0\xfb\xf2"	// "Закрыт" +#define sO_ClosedWithBoot "\xc7\xe0\xea\xf0\xfb\xf2\xe0 \xf1 \xe1\xee\xf2\xe8\xed\xea\xee\xec"	// "Закрыта с ботинком" +#define sO_ClosedShe "\xc7\xe0\xea\xf0\xfb\xf2\xe0"	// "Закрыта" +#define sO_HalfFull "\xc7\xe0\xef\xee\xeb\xed\xe5\xed \xed\xe0\xef\xee\xeb\xee\xe2\xe8\xed\xf3"	// "Заполнен наполовину" +#define sO_Full "\xc7\xe0\xef\xee\xeb\xed\xe5\xed \xf6\xe5\xeb\xe8\xea\xee\xec"	// "Заполнен целиком" +#define sO_MirroredTo "\xc7\xe5\xf0\xea\xe0\xeb\xfc\xed\xe0\xff \xea"	// "Зеркальная к" +#define sO_Playing "\xc8\xe3\xf0\xe0\xe5\xf2"	// "Играет" +#define sO_Tub "\xca\xe0\xe4\xea\xe0"	// "Кадка" +#define sO_Cactus "\xca\xe0\xea\xf2\xf3\xf1"	// "Кактус" +#define sO_SwingingWithBoot "\xca\xe0\xf2\xe0\xe5\xf2\xf1\xff \xf1 \xe1\xee\xf2\xe8\xed\xea\xee\xec"	// "Катается с ботинком" +#define sO_Swinging "\xca\xe0\xf2\xe0\xe5\xf2\xf1\xff"	// "Катается" +#define sO_Swingie "\xca\xe0\xf7\xe5\xeb\xe5\xed\xff"	// "Качеленя" +#define sO_LiftButtons "\xca\xed\xee\xef\xea\xe8 \xeb\xe8\xf4\xf2\xe0"	// "Кнопки лифта" +#define sO_Carpet_35 "\xca\xee\xe2\xf0\xe8\xea_35"	// "Коврик_35" +#define sO_Valve_35 "\xca\xf0\xe0\xed_35"	// "Кран_35" +#define sO_Cup "\xca\xf0\xf3\xe6\xea\xe0"	// "Кружка" +#define sO_Cube "\xca\xf3\xe1\xe8\xea"	// "Кубик" +#define sO_LeftPipe_15 "\xcb\xe5\xe2\xe0\xff \xf2\xf0\xf3\xe1\xe0_15"	// "Левая труба_15" +#define sO_LeftPipe_26 "\xcb\xe5\xe2\xe0\xff \xf2\xf0\xf3\xe1\xe0_26"	// "Левая труба_26" +#define sO_LeftPipe_29 "\xcb\xe5\xe2\xe0\xff \xf2\xf0\xf3\xe1\xe0_29"	// "Левая труба_29" +#define sO_LeftPipe_30 "\xcb\xe5\xe2\xe0\xff \xf2\xf0\xf3\xe1\xe0_30"	// "Левая труба_30" +#define sO_LeftPipe_37 "\xcb\xe5\xe2\xe0\xff \xf2\xf0\xf3\xe1\xe0_37"	// "Левая труба_37" +#define sO_StarsDown_24 "\xcb\xe5\xf1\xf2\xed\xe8\xf6\xe0 \xe2\xed\xe8\xe7_24"	// "Лестница вниз_24" +#define sO_StairsUp_8 "\xcb\xe5\xf1\xf2\xed\xe8\xf6\xe0 \xf1\xe2\xe5\xf0\xf5\xf3_8"	// "Лестница сверху_8" +#define sO_Stairway "\xcb\xe5\xf1\xf2\xed\xe8\xf6\xe0"	// "Лестница" +#define sO_Fliers "\xcb\xe5\xf2\xf3\xed\xfb"	// "Летуны" +#define sO_Hatch_26 "\xcb\xfe\xea_26"	// "Люк_26" +#define sO_Hatch_34 "\xcb\xfe\xea_34"	// "Люк_34" +#define sO_MommyOfHandle_32 "\xcc\xe0\xec\xe0 \xf0\xf3\xf7\xea\xe8_32"	// "Мама ручки_32" +#define sO_BigMumsy "\xcc\xe0\xec\xe0\xf8\xe0"	// "Мамаша" +#define sO_Bag_22 "\xcc\xe5\xf8\xee\xea_22"	// "Мешок_22" +#define sO_CoinSlot_1 "\xcc\xee\xed\xe5\xf2\xee\xef\xf0\xe8\xe5\xec\xed\xe8\xea 1"	// "Монетоприемник 1" +#define sO_CoinSlot_22 "\xcc\xee\xed\xe5\xf2\xee\xef\xf0\xe8\xe5\xec\xed\xe8\xea_22"	// "Монетоприемник_22" +#define sO_CoinSlot_35 "\xcc\xee\xed\xe5\xf2\xee\xef\xf0\xe8\xe5\xec\xed\xe8\xea_35"	// "Монетоприемник_35" +#define sO_Bridge "\xcc\xee\xf1\xf2"	// "Мост" +#define sO_Fly_12 "\xcc\xf3\xf5\xe0_12"	// "Муха_12" +#define sO_Fly_17 "\xcc\xf3\xf5\xe0_17"	// "Муха_17" +#define sO_OnTheFloor "\xcd\xe0 \xef\xee\xeb\xf3"	// "На полу" +#define sO_OnTheSpring "\xcd\xe0 \xef\xf0\xf3\xe6\xe8\xed\xe5"	// "На пружине" +#define sO_OnTheTable "\xcd\xe0 \xf1\xf2\xee\xeb\xe5"	// "На столе" +#define sO_OnStool "\xcd\xe0 \xf2\xe0\xe1\xf3\xf0\xe5\xf2\xea\xe5"	// "На табуретке" +#define sO_Inflater "\xcd\xe0\xe4\xf3\xe2\xe0\xf2\xe5\xeb\xfc"	// "Надуватель" +#define sO_NotTaken "\xcd\xe5 \xe2\xe7\xff\xf2"	// "Не взят" +#define sO_NotHanging "\xcd\xe5 \xe2\xe8\xf1\xe8\xf2"	// "Не висит" +#define sO_NotGrown "\xcd\xe5 \xe2\xfb\xf0\xee\xf1"	// "Не вырос" +#define sO_DidNotCrackEgg "\xcd\xe5 \xea\xee\xeb\xee\xeb \xff\xe9\xf6\xee"	// "Не колол яйцо" +#define sO_NotFallen "\xcd\xe5 \xef\xe0\xe4\xe0\xeb"	// "Не падал" +#define sO_NotAvailable "\xcd\xe5\xe4\xee\xf1\xf2\xf3\xef\xed\xe0"	// "Недоступна" +#define sO_CannotTake "\xcd\xe5\xeb\xfc\xe7\xff \xe2\xe7\xff\xf2\xfc"	// "Нельзя взять" +#define sO_No "\xcd\xe5\xf2"	// "Нет" +#define sO_LowerHatch_23 "\xcd\xe8\xe6\xed\xe8\xe9 \xeb\xfe\xea_23"	// "Нижний люк_23" +#define sO_LowerPipe "\xcd\xe8\xe6\xed\xff\xff \xf2\xf0\xf3\xe1\xe0"	// "Нижняя труба" +#define sO_LowerPipe_21 "\xcd\xe8\xe6\xed\xff\xff \xf2\xf0\xf3\xe1\xe0_21"	// "Нижняя труба_21" +#define sO_WantsNothing "\xcd\xe8\xf7\xe5\xe3\xee \xed\xe5 \xf5\xee\xf7\xe5\xf2"	// "Ничего не хочет" +#define sO_Leg "\xcd\xee\xe3\xe0"	// "Нога" +#define sO_FriesPit "\xcd\xee\xf0\xea\xe0 \xea\xee\xe7\xff\xe2\xea\xe8"	// "Норка козявки" +#define sO_Sock_26 "\xcd\xee\xf1\xee\xea_26"	// "Носок_26" +#define sO_ClockAxis "\xce\xf1\xfc \xf7\xe0\xf1\xee\xe2"	// "Ось часов" +#define sO_Opened "\xce\xf2\xea\xf0\xfb\xf2"	// "Открыт" +#define sO_OpenedWithBoot "\xce\xf2\xea\xf0\xfb\xf2\xe0 \xf1 \xe1\xee\xf2\xe8\xed\xea\xee\xec"	// "Открыта с ботинком" +#define sO_OpenedShe "\xce\xf2\xea\xf0\xfb\xf2\xe0"	// "Открыта" +#define sO_WeirdWacko "\xce\xf2\xec\xee\xf0\xee\xe6\xe5\xed\xed\xfb\xe9"	// "Отмороженный" +#define sO_NotPresent "\xce\xf2\xf1\xf3\xf2\xf1\xf2\xe2\xf3\xe5\xf2"	// "Отсутствует" +#define sO_Error "\xce\xf8\xe8\xe1\xea\xe0"	// "Ошибка" +#define sO_Passive "\xcf\xe0\xf1\xf1\xe8\xe2\xed\xe0"	// "Пассивна" +#define sO_First "\xcf\xe5\xf0\xe2\xfb\xe9"	// "Первый" +#define sO_UpsideDown "\xcf\xe5\xf0\xe5\xe2\xe5\xf0\xed\xf3\xf2\xe0"	// "Перевернута" +#define sO_Overfull "\xcf\xe5\xf0\xe5\xef\xee\xeb\xed\xe5\xed"	// "Переполнен" +#define sO_Fireman "\xcf\xee\xe6\xe0\xf0\xed\xe8\xea"	// "Пожарник" +#define sO_ShowingHeel "\xcf\xee\xea\xe0\xe7\xfb\xe2\xe0\xe5\xf2 \xef\xff\xf2\xea\xf3"	// "Показывает пятку" +#define sO_FullPipe "\xcf\xee\xeb\xed\xe0\xff \xd2\xf0\xf3\xe1\xe0"	// "Полная Труба" +#define sO_RightStairs_9 "\xcf\xf0\xe0\xe2\xe0\xff \xeb\xe5\xf1\xf2\xed\xe8\xf6\xe0_9"	// "Правая лестница_9" +#define sO_RightPipe_17 "\xcf\xf0\xe0\xe2\xe0\xff \xf2\xf0\xf3\xe1\xe0_17"	// "Правая труба_17" +#define sO_Available "\xcf\xf0\xe8\xf1\xf3\xf2\xf1\xf2\xe2\xf3\xe5\xf2"	// "Присутствует" +#define sO_GulpedEgg "\xcf\xf0\xee\xe3\xeb\xee\xf7\xe5\xed\xed\xee\xe5 \xff\xe9\xf6\xee"	// "Проглоченное яйцо" +#define sO_GulpedEggs "\xcf\xf0\xee\xe3\xeb\xee\xf7\xe5\xed\xed\xfb\xe5 \xff\xe9\xf6\xe0"	// "Проглоченные яйца" +#define sO_BellyInflater "\xcf\xf3\xe7\xee\xe4\xf3\xe2"	// "Пузодув" +#define sO_Empty "\xcf\xf3\xf1\xf2"	// "Пуст" +#define sO_EmptyShe "\xcf\xf3\xf1\xf2\xe0\xff"	// "Пустая" +#define sO_WayToPipe "\xcf\xf3\xf2\xfc \xea \xf2\xf0\xf3\xe1\xe5"	// "Путь к трубе" +#define sO_Drinking "\xcf\xfc\xe5\xf2"	// "Пьет" +#define sO_BrokenInPieces "\xd0\xe0\xe7\xe1\xe8\xf2\xe0"	// "Разбита" +#define sO_Unblocked "\xd0\xe0\xe7\xe1\xeb\xee\xea\xe8\xf0\xee\xe2\xe0\xed"	// "Разблокирован" +#define sO_Unfolded "\xd0\xe0\xe7\xe2\xe5\xf0\xed\xf3\xf2"	// "Развернут" +#define sO_Jawcrucnher "\xd0\xee\xf2\xee\xf5\xf0\xf3\xf1"	// "Ротохрус" +#define sO_UsherHand "\xd0\xf3\xea\xe0 \xc1\xe8\xeb\xe5\xf2\xe5\xf0\xf8\xe8"	// "Рука Билетерши" +#define sO_LeverHandle_23 "\xd0\xf3\xea\xee\xff\xf2\xea\xe0 \xf0\xfb\xf7\xe0\xe3\xe0_23"	// "Рукоятка рычага_23" +#define sO_ClockHandle "\xd0\xf3\xf7\xea\xe0 \xee\xf2 \xf7\xe0\xf1\xee\xe2"	// "Ручка от часов" +#define sO_Lever_23 "\xd0\xfb\xf7\xe0\xe3_23"	// "Рычаг_23" +#define sO_WithDudeOnLeft "\xd1 \xc4\xff\xe4\xe5\xe9 \xf1\xeb\xe5\xe2\xe0"	// "С Дядей слева" +#define sO_WithDudeOnRight "\xd1 \xc4\xff\xe4\xe5\xe9 \xf1\xef\xf0\xe0\xe2\xe0"	// "С Дядей справа" +#define sO_WithBoot "\xd1 \xe1\xe0\xf8\xec\xe0\xea\xee\xec"	// "С башмаком" +#define sO_WithBig "\xd1 \xe1\xee\xeb\xfc\xf8\xe8\xec"	// "С большим" +#define sO_WithPlunger "\xd1 \xe2\xe0\xed\xf2\xf3\xe7\xee\xec"	// "С вантузом" +#define sO_WithJug "\xd1 \xe3\xee\xf0\xf8\xea\xee\xec"	// "С горшком" +#define sO_WithGum "\xd1 \xe6\xe2\xe0\xf7\xea\xee\xe9"	// "С жвачкой" +#define sO_WithShovel "\xd1 \xeb\xee\xef\xe0\xf2\xee\xe9"	// "С лопатой" +#define sO_WithTiny "\xd1 \xec\xe0\xeb\xfb\xec"	// "С малым" +#define sO_WithHammer "\xd1 \xec\xee\xeb\xee\xf2\xea\xee\xec"	// "С молотком" +#define sO_WithCoin "\xd1 \xec\xee\xed\xe5\xf2\xee\xe9"	// "С монетой" +#define sO_WithSock "\xd1 \xed\xee\xf1\xea\xee\xec"	// "С носком" +#define sO_WithCork "\xd1 \xef\xf0\xee\xe1\xea\xee\xe9"	// "С пробкой" +#define sO_WithSteering "\xd1 \xf0\xf3\xeb\xe5\xec"	// "С рулем" +#define sO_WithHandle "\xd1 \xf0\xf3\xf7\xea\xee\xe9"	// "С ручкой" +#define sO_WithApple "\xd1 \xff\xe1\xeb\xee\xea\xee\xec"	// "С яблоком" +#define sO_WithDrawer "\xd1 \xff\xf9\xe8\xea\xee\xec"	// "С ящиком" +#define sO_Sugar "\xd1\xe0\xf5\xe0\xf0\xee\xea"	// "Сахарок" +#define sO_Convoluted "\xd1\xe2\xe5\xf0\xed\xf3\xf2"	// "Свернут" +#define sO_IsFree "\xd1\xe2\xee\xe1\xee\xe4\xed\xe0"	// "Свободна" +#define sO_Sitting "\xd1\xe8\xe4\xe8\xf2"	// "Сидит" +#define sO_Laughing "\xd1\xec\xe5\xe5\xf2\xf1\xff"	// "Смеется" +#define sO_WithEveryone "\xd1\xee \xe2\xf1\xe5\xec\xe8"	// "Со всеми" +#define sO_WithMop "\xd1\xee \xf8\xe2\xe0\xe1\xf0\xee\xe9"	// "Со шваброй" +#define sO_WithHose "\xd1\xee \xf8\xeb\xe0\xed\xe3\xee\xec"	// "Со шлангом" +#define sO_WithBrush "\xd1\xee \xf9\xe5\xf2\xea\xee\xe9"	// "Со щеткой" +#define sO_Sleeping "\xd1\xef\xe8\xf2"	// "Спит" +#define sO_OnRight "\xd1\xef\xf0\xe0\xe2\xe0"	// "Справа" +#define sO_StandsInBoots "\xd1\xf2\xee\xe8\xf2 \xe2 \xe1\xee\xf2\xe8\xed\xea\xe0\xf5"	// "Стоит в ботинках" +#define sO_StandsInCorner "\xd1\xf2\xee\xe8\xf2 \xe2 \xf3\xe3\xeb\xf3"	// "Стоит в углу" +#define sO_Guardian "\xd1\xf2\xee\xf0\xee\xe6"	// "Сторож" +#define sO_Guard_1 "\xd1\xf2\xf0\xe0\xe6 1"	// "Страж 1" +#define sO_Gurad_2 "\xd1\xf2\xf0\xe0\xe6 2"	// "Страж 2" +#define sO_Guard_3 "\xd1\xf2\xf0\xe0\xe6 3"	// "Страж 3" +#define sO_Stool_34 "\xd2\xe0\xe1\xf3\xf0\xe5\xf2_34"	// "Табурет_34" +#define sO_Pipe_9 "\xd2\xf0\xf3\xe1\xe0_9"	// "Труба_9" +#define sO_Pedestal_16 "\xd2\xf3\xec\xe1\xe0_16"	// "Тумба_16" +#define sO_Pedestal_17 "\xd2\xf3\xec\xe1\xe0_17"	// "Тумба_17" +#define sO_Pedestal_33 "\xd2\xf3\xec\xe1\xe0_33"	// "Тумба_33" +#define sO_NearDudesStairs "\xd3 \xc4\xff\xe4\xe8 \xed\xe0 \xeb\xe5\xf1\xf2\xed\xe8\xf6\xe5"	// "У Дяди на лестнице" +#define sO_NearDude "\xd3 \xc4\xff\xe4\xe8"	// "У Дяди" +#define sO_NearPipeWithStool "\xd3 \xf2\xf0\xf3\xe1\xfb \xf1 \xf2\xe0\xe1\xf3\xf0\xe5\xf2\xea\xee\xe9"	// "У трубы с табуреткой" +#define sO_NearPipe "\xd3 \xf2\xf0\xf3\xe1\xfb"	// "У трубы" +#define sO_Janitors "\xd3\xe1\xee\xf0\xf9\xe8\xea\xe8"	// "Уборщики" +#define sO_Janitress "\xd3\xe1\xee\xf0\xf9\xe8\xf6\xe0"	// "Уборщица" +#define sO_Gone "\xd3\xe5\xf5\xe0\xeb\xe0"	// "Уехала" +#define sO_FallenOnce "\xd3\xef\xe0\xeb \xf0\xe0\xe7"	// "Упал раз" +#define sO_FallenBrush "\xd3\xef\xe0\xeb\xe0 \xf9\xe5\xf2\xea\xe0"	// "Упала щетка" +#define sO_NotBroken "\xd6\xe5\xeb\xe0"	// "Цела" +#define sO_ScratchingBelly "\xd7\xe5\xf8\xe5\xf2 \xef\xf3\xe7\xee"	// "Чешет пузо" +#define sO_Level0 "\xdd\xf2\xe0\xe6 0"	// "Этаж 0" +#define sO_Level1 "\xdd\xf2\xe0\xe6 1"	// "Этаж 1" +#define sO_Level2 "\xdd\xf2\xe0\xe6 2"	// "Этаж 2" +#define sO_Level3 "\xdd\xf2\xe0\xe6 3"	// "Этаж 3" +#define sO_Level4 "\xdd\xf2\xe0\xe6 4"	// "Этаж 4" +#define sO_Level5 "\xdd\xf2\xe0\xe6 5"	// "Этаж 5" +#define sO_Level6 "\xdd\xf2\xe0\xe6 6"	// "Этаж 6" +#define sO_Level7 "\xdd\xf2\xe0\xe6 7"	// "Этаж 7" +#define sO_Level8 "\xdd\xf2\xe0\xe6 8"	// "Этаж 8" +#define sO_Level9 "\xdd\xf2\xe0\xe6 9"	// "Этаж 9" +#define sO_EggGulperGaveCoin "\xdf\xe9\xf6\xe5\xe3\xeb\xee\xf2 \xee\xf2\xe4\xe0\xeb \xec\xee\xed\xe5\xf2\xf3"	// "Яйцеглот отдал монету" +#define sO_EggGulper "\xdf\xe9\xf6\xe5\xe3\xeb\xee\xf2"	// "Яйцеглот" +#define sO_EggCracker "\xdf\xe9\xf6\xe5\xea\xee\xeb"	// "Яйцекол" +#define sO_NotCarryingEgg "\xdf\xe9\xf6\xee \xed\xe5 \xed\xe5\xf1\xe5\xf2"	// "Яйцо не несет" +#define sO_Egg1 "\xdf\xe9\xf6\xee\x31"	// "Яйцо1" +#define sO_Egg2 "\xdf\xe9\xf6\xee\x32"	// "Яйцо2" +#define sO_Egg3 "\xdf\xe9\xf6\xee\x33"	// "Яйцо3" + +} // End of namespace Fullpipe + +#endif /* FULLPIPE_OBJECTNAMES_H */ diff --git a/engines/fullpipe/objects.h b/engines/fullpipe/objects.h new file mode 100644 index 0000000000..55686acaec --- /dev/null +++ b/engines/fullpipe/objects.h @@ -0,0 +1,134 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef FULLPIPE_OBJECTS_H +#define FULLPIPE_OBJECTS_H + +#include "fullpipe/utils.h" + +namespace Fullpipe { + +class MessageQueue; +class SceneTagList; + +class GameProject : public CObject { + public: +	int _field_4; +	char *_headerFilename; +	SceneTagList *_sceneTagList; +	int _field_10; + + public: +	GameProject(); +	~GameProject(); +	virtual bool load(MfcArchive &file); +}; + +struct PicAniInfo { +	int32 type; +	int16 objectId; +	int16 field_6; +	int32 field_8; +	int16 sceneId; +	int16 field_E; +	int32 ox; +	int32 oy; +	int32 priority; +	int16 staticsId; +	int16 movementId; +	int16 dynamicPhaseIndex; +	int16 flags; +	int32 field_24; +	int32 someDynamicPhaseIndex; + +	bool load(MfcArchive &file); +}; + +class CMotionController; + +class Sc2 : public CObject { + public: +	int16 _sceneId; +	int16 _field_2; +	Scene *_scene; +	CMotionController *_motionController; +	int32 *_data1; // FIXME, could be a struct +	int _count1; +	PicAniInfo **_defPicAniInfos; +	int _defPicAniInfosCount; +	PicAniInfo **_picAniInfos; +	int _picAniInfosCount; +	int _isLoaded; +	EntranceInfo **_entranceData; +	int _entranceDataCount; + + public: +	Sc2(); +	virtual bool load(MfcArchive &file); +}; + +typedef Common::Array<Sc2> Sc2Array; + +union VarValue { +	float floatValue; +	int32 intValue; +	char *stringValue; +}; + +class CGameVar : public CObject { + public: +	CGameVar *_nextVarObj; +	CGameVar *_prevVarObj; +	CGameVar *_parentVarObj; +	CGameVar *_subVars; +	CGameVar *_field_14; +	char *_varName; +	VarValue _value; +	int _varType; + + public: +	CGameVar(); +	virtual bool load(MfcArchive &file); +	CGameVar *getSubVarByName(const char *name); +	bool setSubVarAsInt(const char *name, int value); +	int getSubVarAsInt(const char *name); +	CGameVar *addSubVarAsInt(const char *name, int value); +	bool addSubVar(CGameVar *subvar); +	int getSubVarsCount(); +	CGameVar *getSubVarByIndex(int idx); +}; + +struct PreloadItem { +	int preloadId1; +	int preloadId2; +	int sceneId; +	int field_C; +}; + +class PreloadItems : public Common::Array<PreloadItem>, public CObject { + public: +	virtual bool load(MfcArchive &file); +}; + +} // End of namespace Fullpipe + +#endif /* FULLPIPE_OBJECTS_H */ diff --git a/engines/fullpipe/scene.cpp b/engines/fullpipe/scene.cpp new file mode 100644 index 0000000000..18d6a888b7 --- /dev/null +++ b/engines/fullpipe/scene.cpp @@ -0,0 +1,690 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "fullpipe/fullpipe.h" + +#include "fullpipe/objects.h" +#include "fullpipe/ngiarchive.h" +#include "fullpipe/statics.h" +#include "fullpipe/messages.h" +#include "fullpipe/gameloader.h" + +#include "fullpipe/constants.h" + +#include "common/algorithm.h" + +namespace Fullpipe { + +Scene *FullpipeEngine::accessScene(int sceneId) { +	SceneTag *t = 0; + +	for (SceneTagList::iterator s = _gameProject->_sceneTagList->begin(); s != _gameProject->_sceneTagList->end(); ++s) { +		if (s->_sceneId == sceneId) { +			t = &(*s); +			break; +		} +	} + +	if (!t) +		return 0; + +	if (!t->_scene) { +		t->loadScene(); +	} + +	return t->_scene; +} + +bool SceneTagList::load(MfcArchive &file) { +	debug(5, "SceneTagList::load()"); + +	int numEntries = file.readUint16LE(); + +	for (int i = 0; i < numEntries; i++) { +		SceneTag *t = new SceneTag(); +		t->load(file); +		push_back(*t); +	} + +	return true; +} + +SceneTag::SceneTag() { +	_field_4 = 0; +	_scene = 0; +	_tag = 0; +} + +bool SceneTag::load(MfcArchive &file) { +	debug(5, "SceneTag::load()"); + +	_field_4 = 0; +	_scene = 0; + +	_sceneId = file.readUint16LE(); + +	_tag = file.readPascalString(); + +	debug(6, "sceneId: %d  tag: %s", _sceneId, _tag); + +	return true; +} + +SceneTag::~SceneTag() { +	free(_tag); +} + +void SceneTag::loadScene() { +	char *archname = genFileName(0, _sceneId, "nl"); + +	Common::Archive *arch = makeNGIArchive(archname); + +	char *fname = genFileName(0, _sceneId, "sc"); + +	Common::SeekableReadStream *file = arch->createReadStreamForMember(fname); + +	_scene = new Scene(); + +	MfcArchive archive(file); + +	_scene->load(archive); + +	if (_scene->_shadows) +		_scene->_shadows->init(); + +	delete file; + +	g_fullpipe->_currArchive = 0; + +	free(fname); +	free(archname); +} + +Scene::Scene() { +	_sceneId = 0; +	_field_BC = 0; +	_shadows = 0; +	_soundList = 0; +	_libHandle = 0; +	_sceneName = 0; +} + +bool Scene::load(MfcArchive &file) { +	debug(5, "Scene::load()"); + +	Background::load(file); + +	_sceneId = file.readUint16LE(); +	 +	_sceneName = file.readPascalString(); +	debug(0, "scene: <%s> %d", transCyrillic((byte *)_sceneName), _sceneId); + +	int count = file.readUint16LE(); +	debug(7, "scene.ani: %d", count); + +	for (int i = 0; i < count; i++) { +		int aniNum = file.readUint16LE(); +		char *aniname = genFileName(0, aniNum, "ani"); + +		Common::SeekableReadStream *f = g_fullpipe->_currArchive->createReadStreamForMember(aniname); + +		StaticANIObject *ani = new StaticANIObject(); + +		MfcArchive archive(f); + +		ani->load(archive); +		ani->_sceneId = _sceneId; + +		_staticANIObjectList1.push_back(ani); + +		delete f; +		free(aniname); +	} + +	count = file.readUint16LE(); +	debug(7, "scene.mq: %d", count); + +	for (int i = 0; i < count; i++) { +		int qNum = file.readUint16LE(); +		char *qname = genFileName(0, qNum, "qu"); + +		Common::SeekableReadStream *f = g_fullpipe->_currArchive->createReadStreamForMember(qname); +		MfcArchive archive(f); + +		archive.readUint16LE(); // Skip 2 bytes + +		MessageQueue *mq = new MessageQueue(); + +		mq->load(archive); + +		_messageQueueList.push_back(mq); + +		delete f; +		free(qname); +	} + +	count = file.readUint16LE(); +	debug(7, "scene.fa: %d", count); + +	for (int i = 0; i < count; i++) { +		// There are no .FA files +		assert(0); +	} + +	_libHandle = g_fullpipe->_currArchive; + +	if (_picObjList.size() > 0 && _bgname && strlen(_bgname) > 1) { +		char fname[260]; + +		strcpy(fname, _bgname); +		strcpy(strrchr(fname, '.') + 1, "col"); + +		MemoryObject *col = new MemoryObject(); +		col->loadFile(fname); + +		_palette = col; +	} + +	char *shdname = genFileName(0, _sceneId, "shd"); + +	Shadows *shd = new Shadows(); + +	if (shd->loadFile(shdname)) +		_shadows = shd; + +	free(shdname); + +	char *slsname = genFileName(0, _sceneId, "sls"); + +	if (g_fullpipe->_soundEnabled) { +		_soundList = new SoundList(); + +		if (g_fullpipe->_flgSoundList) { +			char *nlname = genFileName(17, _sceneId, "nl"); + +			_soundList->loadFile(slsname, nlname); + +			free(nlname); +		} else { +			_soundList->loadFile(slsname, 0); +		} +	} + +	free(slsname); + +	initStaticANIObjects(); + +	if (file.size() - file.pos() > 0) +		error("Scene::load  (%d bytes left)", file.size() - file.pos()); + +	return true; +} + +void Scene::initStaticANIObjects() { +	for (uint i = 0; i < _staticANIObjectList1.size(); i++) +		((StaticANIObject *)_staticANIObjectList1[i])->initMovements(); +} + +void Scene::init() { +	_x = 0; +	_y = 0; + +	g_fullpipe->_sceneRect.moveTo(0, 0); + +	for (uint i = 0; i < _picObjList.size(); i++) +		((PictureObject *)_picObjList[i])->clearFlags(); + +	for (uint i = 0; i < _staticANIObjectList1.size(); i++) +		((StaticANIObject *)_staticANIObjectList1[i])->clearFlags(); + +	if (_staticANIObjectList2.size() != _staticANIObjectList1.size()) { +		_staticANIObjectList2.clear(); + +		for (CPtrList::iterator s = _staticANIObjectList1.begin(); s != _staticANIObjectList1.end(); ++s) +			_staticANIObjectList2.push_back(*s); +	} +} + +StaticANIObject *Scene::getAniMan() { +	StaticANIObject *aniMan = getStaticANIObject1ById(ANI_MAN, -1); + +	deleteStaticANIObject(aniMan); + +	return aniMan; +} + +StaticANIObject *Scene::getStaticANIObject1ById(int obj, int a3) { +	for (CPtrList::iterator s = _staticANIObjectList1.begin(); s != _staticANIObjectList1.end(); ++s) { +		StaticANIObject *o = (StaticANIObject *)*s; +		if (o->_id == obj && (a3 == -1 || o->_okeyCode == a3)) +			return o; +	} + +	return 0; +} + +StaticANIObject *Scene::getStaticANIObject1ByName(char *name, int a3) { +	for (uint n = 0; n < _staticANIObjectList1.size(); n++) { +		StaticANIObject *o = (StaticANIObject *)_staticANIObjectList1[n]; +		if (!strcmp(o->_objectName, name) && (a3 == -1 || o->_okeyCode == a3)) +			return o; +	} + +	return 0; +} + +void Scene::deleteStaticANIObject(StaticANIObject *obj) { +	for (uint n = 0; n < _staticANIObjectList1.size(); n++) +		if ((StaticANIObject *)_staticANIObjectList1[n] == obj) { +			_staticANIObjectList1.remove_at(n); +			break; +		} + +	for (uint n = 0; n < _staticANIObjectList2.size(); n++) +		if ((StaticANIObject *)_staticANIObjectList2[n] == obj) { +			_staticANIObjectList2.remove_at(n); +			break; +		} +} + +void Scene::addStaticANIObject(StaticANIObject *obj, bool addList2) { +	if (obj->_okeyCode) +		obj->renumPictures(&_staticANIObjectList1); + +	_staticANIObjectList1.push_back(obj); + +	if (addList2) { +		if (!obj->_okeyCode) +			obj->clearFlags(); + +		_staticANIObjectList2.push_back(obj); +	} +} + +void Scene::setPictureObjectsFlag4() { +	for (uint i = 0; i < _picObjList.size(); i++) { +		((PictureObject *)_picObjList[i])->_flags |= 4; +	} +} + +PictureObject *Scene::getPictureObjectById(int objId, int flags) { +	for (uint i = 0; i < _picObjList.size(); i++) { +		if (((PictureObject *)_picObjList[i])->_id == objId && ((PictureObject *)_picObjList[i])->_okeyCode == flags) +			return (PictureObject *)_picObjList[i]; +	} + +	return 0; +} + +PictureObject *Scene::getPictureObjectByName(const char *objName, int flags) { +	for (uint i = 0; i < _picObjList.size(); i++) { +		if (!strcmp(((PictureObject *)_picObjList[i])->_objectName, objName) && (((PictureObject *)_picObjList[i])->_okeyCode == flags || flags == -1)) +			return (PictureObject *)_picObjList[i]; +	} + +	return 0; +} + +void Scene::deletePictureObject(PictureObject *obj) { +	for (uint i = 0; i < _picObjList.size(); i++) { +		if (((PictureObject *)_picObjList[i]) == obj) { +			_picObjList.remove_at(i); +			delete obj; + +			return; +		} +	} +} + +MessageQueue *Scene::getMessageQueueById(int messageId) { +	for (uint i = 0; i < _messageQueueList.size(); i++) +		if (((MessageQueue *)_messageQueueList[i])->_dataId == messageId) +			return (MessageQueue *)_messageQueueList[i]; + +	return 0; +} + +MessageQueue *Scene::getMessageQueueByName(char *name) { +	for (uint i = 0; i < _messageQueueList.size(); i++) +		if (!strcmp(((MessageQueue *)_messageQueueList[i])->_queueName, name)) +			return (MessageQueue *)_messageQueueList[i]; + +	return 0; +} + +void Scene::preloadMovements(CGameVar *var) { +	CGameVar *preload = var->getSubVarByName("PRELOAD"); +	if (!preload) +		return; + +	for (CGameVar *i = preload->_subVars; i; i = i->_nextVarObj) { +		StaticANIObject *ani = getStaticANIObject1ByName(i->_varName, -1); + +		if (ani) { +			CGameVar *subVars = i->_subVars; + +			if (subVars) { +				for (;subVars; subVars = subVars->_nextVarObj) { +					Movement *mov = ani->getMovementByName(subVars->_varName); + +					if (mov) +						mov->loadPixelData(); +				} +			} else { +				ani->loadMovementsPixelData(); +			} +		} +    } +} + +void Scene::initObjectCursors(const char *varname) { +	CGameVar *cursorsVar = g_fullpipe->getGameLoaderGameVar()->getSubVarByName(varname)->getSubVarByName("CURSORS"); + +	if (!cursorsVar || !cursorsVar->_subVars) +		return; + +	int maxId = 0; +	int minId = 0xffff; + +	for (CGameVar *sub = cursorsVar->_subVars; sub; sub = sub->_nextVarObj) { +		GameObject *obj = getPictureObjectByName(sub->_varName, -1); + +		if (obj || (obj = getStaticANIObject1ByName(sub->_varName, -1)) != 0) { +          if (obj->_id < minId) +            minId = obj->_id; +          if (obj->_id > maxId) +            maxId = obj->_id; +        } +    } + +	g_fullpipe->_minCursorId = minId; +	g_fullpipe->_maxCursorId = maxId; + +	g_fullpipe->_objectIdCursors.resize(maxId - minId + 1); + +	for (CGameVar *sub = cursorsVar->_subVars; sub; sub = sub->_nextVarObj) { +		GameObject *obj = getPictureObjectByName(sub->_varName, -1); + +		if (!obj) +			obj = getStaticANIObject1ByName(sub->_varName, -1); + +		PictureObject *pic = getGameLoaderInventory()->getScene()->getPictureObjectByName(sub->_value.stringValue, -1); + +		if (obj && pic) +			g_fullpipe->_objectIdCursors[obj->_id - minId] = pic->_id; +	} +} + +bool Scene::compareObjPriority(const void *p1, const void *p2) { +	if (((const StaticANIObject *)p1)->_priority > ((const StaticANIObject *)p2)->_priority) +		return true; + +	return false; +} + +void Scene::objectList_sortByPriority(CPtrList &list) { +	Common::sort(list.begin(), list.end(), Scene::compareObjPriority); +} + +void Scene::draw() { +	debug(0, ">>>>> Scene::draw()"); +	updateScrolling(); + +	drawContent(60000, 0, true); + +	objectList_sortByPriority(_staticANIObjectList2); + +	for (CPtrList::iterator s = _staticANIObjectList2.begin(); s != _staticANIObjectList2.end(); ++s) { +		((StaticANIObject *)*s)->draw2(); +	} + +	int priority = -1; +	for (CPtrList::iterator s = _staticANIObjectList2.begin(); s != _staticANIObjectList2.end(); ++s) { +		drawContent(((StaticANIObject *)*s)->_priority, priority, false); +		((StaticANIObject *)*s)->draw(); + +		priority = ((StaticANIObject *)*s)->_priority; +	} + +	drawContent(-1, priority, false); +} + +void Scene::updateScrolling() { +	debug(0, "STUB Scene::updateScrolling()"); +} + +void Scene::updateScrolling2() { +	warning("STUB Scene::updateScrolling2()"); +} + +StaticANIObject *Scene::getStaticANIObjectAtPos(int x, int y) { +	StaticANIObject *res = 0; + +	for (uint i = 0; i < _staticANIObjectList1.size(); i++) { +		StaticANIObject *p = (StaticANIObject *)_staticANIObjectList1[i]; +		int pixel; + +		if ((p->_field_8 & 0x100) && (p->_flags & 4) && +				p->getPixelAtPos(x, y, &pixel) && +				(!res || res->_priority >= p->_priority)) +			res = p; +	} + +	return res; +} + +PictureObject *Scene::getPictureObjectAtPos(int x, int y) { +	PictureObject *res = 0; + +	for (uint i = 0; i < _picObjList.size(); i++) { +		PictureObject *p = (PictureObject *)_picObjList[i]; +		if ((p->_field_8 & 0x100) && (p->_flags & 4) && +				p->isPixelHitAtPos(x, y) && +				(!res || res->_priority >= p->_priority)) +			res = p; +	} + +	return res; +} + +int Scene::getPictureObjectIdAtPos(int x, int y) { +	PictureObject *resp = 0; +	int res = 0; + +	for (uint i = 0; i < _picObjList.size(); i++) { +		PictureObject *p = (PictureObject *)_picObjList[i]; +		if ((p->_field_8 & 0x100) && (p->_flags & 4) && +				p->isPixelHitAtPos(x, y) && +				(!res || resp->_priority >= p->_priority)) { +			resp = p; +			res = p->_id; +		} +	} + +	return res; +} + +void Scene::update(int counterdiff) { +	debug(0, "Scene::update(%d)", counterdiff); + +	for (CPtrList::iterator s = _staticANIObjectList2.begin(); s != _staticANIObjectList2.end(); ++s) +		((StaticANIObject *)*s)->update(counterdiff); +} + +void Scene::drawContent(int minPri, int maxPri, bool drawBg) { +	if (!_picObjList.size() && !_bigPictureArray1Count) +		return; + +	if (_palette) { +		g_fullpipe->_globalPalette = _palette->_data; +	} + +	debug(8, "Scene::drawContent(>%d, <%d, %d)", minPri, maxPri, drawBg); + +	if (_picObjList.size() > 2) { // We need to z-sort them +		objectList_sortByPriority(_picObjList); +	} + +	if (minPri == -1 && _picObjList.size()) +		minPri = ((PictureObject *)_picObjList.back())->_priority - 1; + +	if (maxPri == -1) +		maxPri = 60000; + +	debug(8, "-> Scene::drawContent(>%d, <%d, %d)", minPri, maxPri, drawBg); + +	Common::Point point; + +	debug(8, "_bigPict: %d objlist: %d", _bigPictureArray1Count, _picObjList.size()); +	if (drawBg && _bigPictureArray1Count && _picObjList.size()) { + +		_bigPictureArray[0][0]->getDimensions(&point); + +		int width = point.x; +		int height = point.y; + +		debug(8, "w: %d h:%d", width, height); + +		((PictureObject *)_picObjList[0])->getDimensions(&point); + +		debug(8, "w2: %d h2:%d", point.x, point.y); + +		int bgStX = g_fullpipe->_sceneRect.left % point.x; + +		if (bgStX < 0) +			bgStX += point.x; + +		int bgNumX = bgStX / width; +		int bgOffsetX = bgStX % width; + +		int bgStY = g_fullpipe->_sceneRect.top % point.y; + +		if (bgStY < 0) +			bgStY += point.y; + +		int bgNumY = bgStY / height; +		int bgOffsetY = bgStY % height; + +		int bgPosX = g_fullpipe->_sceneRect.left - bgOffsetX; + +		if (bgPosX < g_fullpipe->_sceneRect.right - 1) { +			while (1) { +				int v25 = bgNumY; +				for (int y = g_fullpipe->_sceneRect.top - bgOffsetY; y < g_fullpipe->_sceneRect.bottom - 1;) { +					BigPicture *v27 = _bigPictureArray[bgNumX][v25]; +					v27->draw(bgPosX, y, 0, 0); +					y += v27->getDimensions(&point)->y; +					v25++; + +					if (v25 >= _bigPictureArray2Count) { +						if (!((PictureObject *)_picObjList[0])->_flags & 0x20) +							break; +						v25 = 0; +					} +				} +				_bigPictureArray[bgNumX][0]->getDimensions(&point); +				int v32 = point.x + bgPosX; +				bgPosX += point.x; +				bgNumX++; + +				if (bgNumX >= _bigPictureArray1Count) { +					if (!(((PictureObject *)_picObjList[0])->_flags & 0x2)) +						break; +					bgNumX = 0; +				} +				if (v32 >= g_fullpipe->_sceneRect.right - 1) +					break; +			} +		} +    } + + +	for (uint i = 1; i < _picObjList.size(); i++) { +		PictureObject *obj = (PictureObject *)_picObjList[i]; + +		debug(8, "pri: %d", obj->_priority); +		if (obj->_priority < minPri || obj->_priority >= maxPri) +			continue; + +		int objX = obj->_ox; +		int objY = obj->_oy; + +		debug(8, "obj: %d %d", objX, objY); + +		obj->getDimensions(&point); + +		int width = point.x; +		int height = point.y; + +		if (obj->_flags & 8) { +			while (objX > g_fullpipe->_sceneRect.right) { +				objX -= width; +				obj->setOXY(objX, objY); +			} +			for (int j = width + objX; width + objX < g_fullpipe->_sceneRect.left; j = width + objX) { +				objX = j; +				obj->setOXY(j, objY); +			} +		} + +		if (obj->_flags & 0x10) { +			while (objY > g_fullpipe->_sceneRect.bottom) { +				objY -= height; +				obj->setOXY(objX, objY); +			} +			for (int j = objY + height; objY + height < g_fullpipe->_sceneRect.top; j = objY + height) { +				objY = j; +				obj->setOXY(objX, j); +			} +		} +		if (obj->_flags & 4) +			obj->draw(); + +		if (obj->_flags & 2) { +			if (objX > g_fullpipe->_sceneRect.left) { +				obj->setOXY(objX - width, objY); +				obj->draw(); +				obj->setOXY(objX, objY); +			} +			if (width + objX < g_fullpipe->_sceneRect.right) { +				obj->setOXY(width + objX, objY); +				obj->draw(); +				obj->setOXY(objX, objY); +			} +		} + +		if (obj->_flags & 0x20) { +			if (objY > g_fullpipe->_sceneRect.top) { +				obj->setOXY(objX, objY - height); +				obj->draw(); +				obj->setOXY(objX, objY); +			} +			if (height + objY < g_fullpipe->_sceneRect.bottom) { +				obj->setOXY(objX, height + objY); +				obj->draw(); +				obj->setOXY(objX, objY); +			} +		} +	} +} + +} // End of namespace Fullpipe diff --git a/engines/fullpipe/scene.h b/engines/fullpipe/scene.h new file mode 100644 index 0000000000..c1c8d47ba8 --- /dev/null +++ b/engines/fullpipe/scene.h @@ -0,0 +1,108 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef FULLPIPE_SCENE_H +#define FULLPIPE_SCENE_H + +#include "fullpipe/gfx.h" + +namespace Fullpipe { + +class MessageQueue; + +class Scene : public Background { + public: +	CPtrList _staticANIObjectList1; +	CPtrList _staticANIObjectList2; +	CPtrList _messageQueueList; +	CPtrList _faObjectList; +	Shadows *_shadows; +	SoundList *_soundList; +	int16 _sceneId; +	char *_sceneName; +	int _field_BC; +	NGIArchive *_libHandle; + +  public: +	Scene(); + +	virtual bool load(MfcArchive &file); + +	void initStaticANIObjects(); +	void init(); +	void draw(); +	void drawContent(int minPri, int maxPri, bool drawBG); +	void updateScrolling(); +	void updateScrolling2(); + +	void update(int counterdiff); + +	StaticANIObject *getAniMan(); +	StaticANIObject *getStaticANIObject1ById(int obj, int a3); +	StaticANIObject *getStaticANIObject1ByName(char *name, int a3); +	MessageQueue *getMessageQueueById(int messageId); +	MessageQueue *getMessageQueueByName(char *name); + +	void deleteStaticANIObject(StaticANIObject *obj); +	void addStaticANIObject(StaticANIObject *obj, bool addList2); + +	void setPictureObjectsFlag4(); +	PictureObject *getPictureObjectById(int objId, int flags); +	PictureObject *getPictureObjectByName(const char *name, int keyCode); +	void deletePictureObject(PictureObject *obj); +	void preloadMovements(CGameVar *var); + +	StaticANIObject *getStaticANIObjectAtPos(int x, int y); +	PictureObject *getPictureObjectAtPos(int x, int y); +	int getPictureObjectIdAtPos(int x, int y); + +	void initObjectCursors(const char *name); + +  private: +	static bool compareObjPriority(const void *p1, const void *p2); +	void objectList_sortByPriority(CPtrList &list); +}; + +class SceneTag : public CObject { + public: +	int _field_4; +	char *_tag; +	Scene *_scene; +	int16 _sceneId; +	int16 _field_12; + + public: +	SceneTag(); +	~SceneTag(); + +	virtual bool load(MfcArchive &file); +	void loadScene(); +}; + +class SceneTagList : public Common::List<SceneTag>, public CObject { + public: +	virtual bool load(MfcArchive &file); +}; + +} // End of namespace Fullpipe + +#endif /* FULLPIPE_SCENE_H */ diff --git a/engines/fullpipe/scenes.cpp b/engines/fullpipe/scenes.cpp new file mode 100644 index 0000000000..0c06e03b75 --- /dev/null +++ b/engines/fullpipe/scenes.cpp @@ -0,0 +1,1433 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "fullpipe/fullpipe.h" + +#include "fullpipe/utils.h" +#include "fullpipe/gfx.h" +#include "fullpipe/objects.h" +#include "fullpipe/statics.h" +#include "fullpipe/scene.h" +#include "fullpipe/gameloader.h" +#include "fullpipe/sound.h" +#include "fullpipe/motion.h" +#include "fullpipe/input.h" +#include "fullpipe/messages.h" +#include "fullpipe/behavior.h" + +#include "fullpipe/constants.h" +#include "fullpipe/objectnames.h" +#include "fullpipe/scenes.h" +#include "fullpipe/modal.h" +#include "fullpipe/interaction.h" + +namespace Fullpipe { + +int defaultUpdateCursor(); +void setElevatorButton(const char *name, int state); + +int sceneIntro_updateCursor(); +void sceneIntro_initScene(Scene *sc); +int sceneHandlerIntro(ExCommand *cmd); + +void scene01_fixEntrance(); +void scene01_initScene(Scene *sc, int entrance); +int sceneHandler01(ExCommand *cmd); + +Vars::Vars() { +	sceneIntro_aniin1man = 0; +	sceneIntro_needSleep = true; +	sceneIntro_needGetup = false; +	sceneIntro_skipIntro = true; +	sceneIntro_playing = false; +	sceneIntro_needBlackout = false; + +	swallowedEgg1 = 0; +	swallowedEgg2 = 0; +	swallowedEgg3 = 0; + +	scene01_picSc01Osk = 0; +	scene01_picSc01Osk2 = 0; +} + +bool FullpipeEngine::sceneSwitcher(EntranceInfo *entrance) { +	CGameVar *sceneVar; +	Common::Point sceneDim; + +	Scene *scene = accessScene(entrance->_sceneId); + +	if (!scene) +		return 0; + +	((PictureObject *)scene->_picObjList.front())->getDimensions(&sceneDim); +	_sceneWidth = sceneDim.x; +	_sceneHeight = sceneDim.y; + +	_sceneRect.top = 0; +	_sceneRect.left = 0; +	_sceneRect.right = 799; +	_sceneRect.bottom = 599; + +	scene->_x = 0; +	scene->_y = 0; + +	_aniMan->setOXY(0, 0); +	_aniMan->clearFlags(); +	_aniMan->_callback1 = 0; +	_aniMan->_callback2 = 0; +	_aniMan->_shadowsOn = 1; + +	_scrollSpeed = 8; + +	_isSaveAllowed = true; +	_updateFlag = true; +	_flgCanOpenMap = true; + +	if (entrance->_sceneId == SC_DBGMENU) { +		_inventoryScene = 0; +	} else { +		_gameLoader->loadScene(SC_INV); +		getGameLoaderInventory()->rebuildItemRects(); +		_inventoryScene = getGameLoaderInventory()->getScene(); +	} +	if (_soundEnabled) { +		if (scene->_soundList) { +			_currSoundListCount = 2; +			_currSoundList1[0] = accessScene(SC_COMMON)->_soundList; +			_currSoundList1[1] = scene->_soundList; + +			for (int i = 0; i < scene->_soundList->getCount(); i++) { +				scene->_soundList->getSoundByIndex(i)->updateVolume(); +			} +		} else { +			_currSoundListCount = 1; +			_currSoundList1[0] = accessScene(SC_COMMON)->_soundList; +		} +	} + +	getGameLoaderInteractionController()->sortInteractions(scene->_sceneId); +	_currentScene = scene; +	scene->addStaticANIObject(_aniMan, 1); +	_scene2 = scene; +	_aniMan->_movement = 0; +	_aniMan->_statics = _aniMan->getStaticsById(ST_MAN_EMPTY); +	_aniMan->setOXY(0, 0); + +	if (_aniMan) { +		_aniMan2 = _aniMan; +		CMctlCompound *cmp = getSc2MctlCompoundBySceneId(entrance->_sceneId); +		cmp->initMovGraph2(); +		cmp->addObject(_aniMan); +		cmp->setEnabled(); +		getGameLoaderInteractionController()->enableFlag24(); +		setInputDisabled(0); +	} else { +		_aniMan2 = 0; +	} + +	scene->setPictureObjectsFlag4(); + +	for (CPtrList::iterator s = scene->_staticANIObjectList1.begin(); s != scene->_staticANIObjectList1.end(); ++s) { +		StaticANIObject *o = (StaticANIObject *)*s; +		o->setFlags(o->_flags & 0xFE7F); +	} + +	PictureObject *p = accessScene(SC_INV)->getPictureObjectById(PIC_INV_MENU, 0); +	p->setFlags(p->_flags & 0xFFFB); + +	removeMessageHandler(2, -1); +	_updateScreenCallback = 0; + +	switch (entrance->_sceneId) { +	case SC_INTRO1: +		sceneVar = _gameLoader->_gameVar->getSubVarByName("SC_INTRO1"); +		scene->preloadMovements(sceneVar); +		sceneIntro_initScene(scene); +		_behaviorManager->initBehavior(scene, sceneVar); +		scene->initObjectCursors("SC_INTRO1"); +		setSceneMusicParameters(sceneVar); +		addMessageHandler(sceneHandlerIntro, 2); +		_updateCursorCallback = sceneIntro_updateCursor; +		break; + +	case SC_1: +		scene01_fixEntrance(); +		sceneVar = _gameLoader->_gameVar->getSubVarByName("SC_1"); +		scene->preloadMovements(sceneVar); +		scene01_initScene(scene, entrance->_field_4); +		_behaviorManager->initBehavior(scene, sceneVar); +		scene->initObjectCursors("SC_1"); +		setSceneMusicParameters(sceneVar); +		addMessageHandler(sceneHandler01, 2); +		_updateCursorCallback = defaultUpdateCursor; +		break; + +#if 0 +	case SC_2: +		sceneVar = _gameLoader->_gameVar->getSubVarByName("SC_2"); +		scene->preloadMovements(sceneVar); +		scene02_initScene(scene); +		_behaviorManager->initBehavior(scene, sceneVar); +		scene->initObjectCursors("SC_2"); +		setSceneMusicParameters(sceneVar); +		addMessageHandler(sceneHandler02, 2); +		_updateCursorCallback = defaultUpdateCursor; +		break; + +	case SC_3: +		sceneVar = _gameLoader->_gameVar->getSubVarByName("SC_3"); +		scene->preloadMovements(sceneVar); +		scene03_initScene(scene); +		_behaviorManager->initBehavior(scene, sceneVar); +		scene->initObjectCursors("SC_3"); +		setSceneMusicParameters(sceneVar); +		addMessageHandler(sceneHandler03, 2); +		j_Scene_sc03_sub_40F160(scene); +		_updateCursorCallback = scene03_updateCursor; +		break; + +	case SC_4: +		sceneVar = _gameLoader->_gameVar->getSubVarByName("SC_4"); +		scene->preloadMovements(sceneVar); +		scene04_initScene(scene); +		_behaviorManager->initBehavior(scene, sceneVar); +		scene->initObjectCursors("SC_4"); +		setSceneMusicParameters(sceneVar); +		insertMessageHandler(sceneHandler04, 2, 2); +		_updateCursorCallback = scene04_updateCursor; +		break; + +	case SC_5: +		sceneVar = _gameLoader->_gameVar->getSubVarByName("SC_5"); +		scene->preloadMovements(sceneVar); +		scene05_initScene(scene); +		_behaviorManager->initBehavior(scene, sceneVar); +		scene->initObjectCursors("SC_5"); +		setSceneMusicParameters(sceneVar); +		insertMessageHandler(sceneHandler05, 2, 2); +		_updateCursorCallback = defaultUpdateCursor; +		break; + +	case SC_6: +		sceneVar = _gameLoader->_gameVar->getSubVarByName("SC_6"); +		scene->preloadMovements(sceneVar); +		scene06_initScene(scene); +		_behaviorManager->initBehavior(scene, sceneVar); +		scene->initObjectCursors("SC_6"); +		setSceneMusicParameters(sceneVar); +		sub_415300(); +		insertMessageHandler(sceneHandler06, 2, 2); +		_updateCursorCallback = scene06_updateCursor; +		break; + +	case SC_7: +		sceneVar = _gameLoader->_gameVar->getSubVarByName("SC_7"); +		scene->preloadMovements(sceneVar); +		scene07_initScene(scene); +		_behaviorManager->initBehavior(scene, sceneVar); +		scene->initObjectCursors("SC_7"); +		setSceneMusicParameters(sceneVar); +		addMessageHandler(sceneHandler07, 2); +		_updateCursorCallback = defaultUpdateCursor; +		break; + +	case SC_8: +		sceneVar = _gameLoader->_gameVar->getSubVarByName("SC_8"); +		scene->preloadMovements(sceneVar); +		scene08_initScene(scene); +		_behaviorManager->initBehavior(scene, sceneVar); +		scene->initObjectCursors("SC_8"); +		setSceneMusicParameters(sceneVar); +		sub_416890(); +		addMessageHandler(sceneHandler08, 2); +		_updateCursorCallback = scene08_updateCursor; +		break; + +	case SC_9: +		sceneVar = _gameLoader->_gameVar->getSubVarByName("SC_9"); +		scene->preloadMovements(sceneVar); +		scene09_initScene(scene); +		_behaviorManager->initBehavior(scene, sceneVar); +		scene->initObjectCursors("SC_9"); +		setSceneMusicParameters(sceneVar); +		insertMessageHandler(sceneHandler09, 2, 2); +		_updateCursorCallback = scene09_updateCursor; +		break; + +	case SC_10: +		sceneVar = _gameLoader->_gameVar->getSubVarByName("SC_10"); +		scene->preloadMovements(sceneVar); +		scene10_initScene(scene); +		_behaviorManager->initBehavior(scene, sceneVar); +		scene->initObjectCursors("SC_10"); +		setSceneMusicParameters(sceneVar); +		insertMessageHandler(sceneHandler10, 2, 2); +		_updateCursorCallback = scene10_updateCursor; +		break; + +	case SC_11: +		sceneVar = _gameLoader->_gameVar->getSubVarByName("SC_11"); +		scene->preloadMovements(sceneVar); +		scene11_initScene(scene); +		_behaviorManager->initBehavior(scene, sceneVar); +		scene->initObjectCursors("SC_11"); +		setSceneMusicParameters(sceneVar); +		insertMessageHandler(sceneHandler11, 2, 2); +		scene11_sub_41A980(); +		_updateCursorCallback = scene11_updateCursor; +		break; + +	case SC_12: +		sceneVar = _gameLoader->_gameVar->getSubVarByName("SC_12"); +		scene->preloadMovements(sceneVar); +		scene12_initScene(scene); +		_behaviorManager->initBehavior(scene, sceneVar); +		scene->initObjectCursors("SC_12"); +		setSceneMusicParameters(sceneVar); +		addMessageHandler(sceneHandler12, 2); +		_updateCursorCallback = defaultUpdateCursor; +		break; + +	case SC_13: +		sceneVar = _gameLoader->_gameVar->getSubVarByName("SC_13"); +		scene->preloadMovements(sceneVar); +		scene13_initScene(scene); +		_behaviorManager->initBehavior(scene, sceneVar); +		scene->initObjectCursors("SC_13"); +		setSceneMusicParameters(sceneVar); +		insertMessageHandler(sceneHandler13, 2, 2); +		_updateCursorCallback = defaultUpdateCursor; +		break; + +	case SC_14: +		sceneVar = _gameLoader->_gameVar->getSubVarByName("SC_14"); +		scene->preloadMovements(sceneVar); +		scene14_initScene(scene); +		_behaviorManager->initBehavior(scene, sceneVar); +		scene->initObjectCursors("SC_14"); +		setSceneMusicParameters(sceneVar); +		insertMessageHandler(sceneHandler14, 2, 2); +		scene14_sub_41D2B0(); +		_updateCursorCallback = scene14_updateCursor; +		break; + +	case SC_15: +		sceneVar = _gameLoader->_gameVar->getSubVarByName("SC_15"); +		scene->preloadMovements(sceneVar); +		scene15_initScene(scene); +		_behaviorManager->initBehavior(scene, sceneVar); +		scene->initObjectCursors("SC_15"); +		setSceneMusicParameters(sceneVar); +		insertMessageHandler(sceneHandler15, 2, 2); +		_updateCursorCallback = scene15_updateCursor; +		break; + +	case SC_16: +		sceneVar = _gameLoader->_gameVar->getSubVarByName("SC_16"); +		scene->preloadMovements(sceneVar); +		scene16_initScene(scene); +		_behaviorManager->initBehavior(scene, sceneVar); +		scene->initObjectCursors("SC_16"); +		setSceneMusicParameters(sceneVar); +		addMessageHandler(sceneHandler16, 2); +		_updateCursorCallback = scene16_updateCursor; +		break; + +	case SC_17: +		sceneVar = _gameLoader->_gameVar->getSubVarByName("SC_17"); +		scene->preloadMovements(sceneVar); +		scene17_initScene(scene); +		_behaviorManager->initBehavior(scene, sceneVar); +		scene->initObjectCursors("SC_17"); +		setSceneMusicParameters(sceneVar); +		addMessageHandler(sceneHandler17, 2); +		scene17_sub_41F060(); +		_updateCursorCallback = scene17_updateCursor; +		break; + +	case SC_18: +		sub_40E1B0(); +		sceneVar = _gameLoader->_gameVar->getSubVarByName("SC_18"); +		scene->preloadMovements(sceneVar); +		sub_4062D0(); +		if (dword_476C38) +			scene18_initScene1(scene); +		else +			scene18_initScene2(scene); +		_behaviorManager->initBehavior(scene, sceneVar); +		scene->initObjectCursors("SC_18"); +		setSceneMusicParameters(sceneVar); +		insertMessageHandler(sceneHandler18, 2, 2); +		_updateCursorCallback = scene18_updateCursor; +		break; + +	case SC_19: +		if (!g_scene3) { +			g_scene3 = accessScene(SC_18); +			getGameLoader()->loadScene(SC_18); +			scene18_initScene2(g_scene3); +			sub_40C5F0(); +			scene19_sub_420B10(g_scene3, entrance->field_4); +			dword_476C38 = 1; +		} +		sub_40C650(); +		sceneVar = _gameLoader->_gameVar->getSubVarByName("SC_19"); +		scene->preloadMovements(sceneVar); +		sub_4062D0(); +		if (dword_476C38) +			scene18_initScene1(scene); +		else +			scene19_initScene2(); +		_behaviorManager->initBehavior(scene, sceneVar); +		scene->initObjectCursors("SC_19"); +		setSceneMusicParameters(sceneVar); +		addMessageHandler(sceneHandler19, 2); +		scene19_sub_4211D0(scene); +		_updateCursorCallback = scene19_updateCursor; +		break; + +	case SC_20: +		sceneVar = _gameLoader->_gameVar->getSubVarByName("SC_20"); +		scene->preloadMovements(sceneVar); +		scene20_initScene(scene); +		_behaviorManager->initBehavior(scene, sceneVar); +		scene->initObjectCursors("SC_20"); +		setSceneMusicParameters(sceneVar); +		addMessageHandler(sceneHandler20, 2); +		_updateCursorCallback = defaultUpdateCursor; +		break; + +	case SC_21: +		sceneVar = _gameLoader->_gameVar->getSubVarByName("SC_21"); +		scene->preloadMovements(sceneVar); +		scene21_initScene(scene); +		_behaviorManager->initBehavior(scene, sceneVar); +		scene->initObjectCursors("SC_21"); +		setSceneMusicParameters(sceneVar); +		insertMessageHandler(sceneHandler21, 2, 2); +		_updateCursorCallback = scene21_updateCursor; +		break; + +	case SC_22: +		sceneVar = _gameLoader->_gameVar->getSubVarByName("SC_22"); +		scene->preloadMovements(sceneVar); +		scene22_initScene(scene); +		_behaviorManager->initBehavior(scene, sceneVar); +		scene->initObjectCursors("SC_22"); +		setSceneMusicParameters(sceneVar); +		scene22_sub_4228A0(); +		insertMessageHandler(sceneHandler22, 2, 2); +		_updateCursorCallback = scene22_updateCursor; +		break; + +	case SC_23: +		sceneVar = _gameLoader->_gameVar->getSubVarByName("SC_23"); +		scene->preloadMovements(sceneVar); +		scene23_initScene(scene); +		_behaviorManager->initBehavior(scene, sceneVar); +		scene->initObjectCursors("SC_23"); +		setSceneMusicParameters(sceneVar); +		insertMessageHandler(sceneHandler23, 2, 2); +		scene23_sub_423B00(); +		_updateCursorCallback = scene23_updateCursor; +		break; + +	case SC_24: +		sceneVar = _gameLoader->_gameVar->getSubVarByName("SC_24"); +		scene->preloadMovements(sceneVar); +		scene24_initScene(scene); +		_behaviorManager->initBehavior(scene, sceneVar); +		scene->initObjectCursors("SC_24"); +		setSceneMusicParameters(sceneVar); +		addMessageHandler(sceneHandler24, 2); +		scene24_sub_423DD0(); +		_updateCursorCallback = defaultUpdateCursor; +		break; + +	case SC_25: +		sceneVar = _gameLoader->_gameVar->getSubVarByName("SC_25"); +		scene->preloadMovements(sceneVar); +		scene25_initScene(scene, entrance->field_4); +		_behaviorManager->initBehavior(scene, sceneVar); +		scene->initObjectCursors("SC_25"); +		setSceneMusicParameters(sceneVar); +		addMessageHandler(sceneHandler25, 2); +		scene25_sub_4253B0(scene, entrance->field_4); +		_updateCursorCallback = scene25_updateCursor; +		break; + +	case SC_26: +		sceneVar = _gameLoader->_gameVar->getSubVarByName("SC_26"); +		scene->preloadMovements(sceneVar); +		scene26_initScene(scene); +		_behaviorManager->initBehavior(scene, sceneVar); +		scene->initObjectCursors("SC_26"); +		setSceneMusicParameters(sceneVar); +		insertMessageHandler(sceneHandler26, 2, 2); +		scene26_sub_426140(scene); +		_updateCursorCallback = scene26_updateCursor; +		break; + +	case SC_27: +		sceneVar = _gameLoader->_gameVar->getSubVarByName("SC_27"); +		scene->preloadMovements(sceneVar); +		scene27_initScene(scene); +		_behaviorManager->initBehavior(scene, sceneVar); +		scene->initObjectCursors("SC_27"); +		setSceneMusicParameters(sceneVar); +		addMessageHandler(sceneHandler27, 2); +		_updateCursorCallback = scene27_updateCursor; +		break; + +	case SC_28: +		sceneVar = _gameLoader->_gameVar->getSubVarByName("SC_28"); +		scene->preloadMovements(sceneVar); +		scene28_initScene(scene); +		_behaviorManager->initBehavior(scene, sceneVar); +		scene->initObjectCursors("SC_28"); +		setSceneMusicParameters(sceneVar); +		insertMessageHandler(sceneHandler28, 2, 2); +		_updateCursorCallback = scene28_updateCursor; +		break; + +	case SC_29: +		sceneVar = _gameLoader->_gameVar->getSubVarByName("SC_29"); +		scene->preloadMovements(sceneVar); +		scene29_initScene(scene); +		_behaviorManager->initBehavior(scene, sceneVar); +		scene->initObjectCursors("SC_29"); +		setSceneMusicParameters(sceneVar); +		addMessageHandler(sceneHandler29, 2); +		_updateCursorCallback = scene29_updateCursor; +		break; + +	case SC_30: +		sceneVar = _gameLoader->_gameVar->getSubVarByName("SC_30"); +		scene->preloadMovements(sceneVar); +		scene30_initScene(scene, entrance->field_4); +		_behaviorManager->initBehavior(scene, sceneVar); +		scene->initObjectCursors("SC_30"); +		setSceneMusicParameters(sceneVar); +		addMessageHandler(sceneHandler30, 2); +		_updateCursorCallback = scene30_updateCursor; +		break; + +	case SC_31: +		sceneVar = _gameLoader->_gameVar->getSubVarByName("SC_31"); +		scene->preloadMovements(sceneVar); +		scene31_initScene(scene); +		_behaviorManager->initBehavior(scene, sceneVar); +		scene->initObjectCursors("SC_31"); +		setSceneMusicParameters(sceneVar); +		addMessageHandler(sceneHandler31, 2); +		_updateCursorCallback = defaultUpdateCursor; +		break; + +	case SC_32: +		sceneVar = _gameLoader->_gameVar->getSubVarByName("SC_32"); +		scene->preloadMovements(sceneVar); +		scene32_initScene(scene); +		_behaviorManager->initBehavior(scene, sceneVar); +		scene->initObjectCursors("SC_32"); +		setSceneMusicParameters(sceneVar); +		insertMessageHandler(sceneHandler32, 2, 2); +		scene32_sub_42C5C0(); +		_updateCursorCallback = scene32_updateCursor; +		break; + +	case SC_33: +		sceneVar = _gameLoader->_gameVar->getSubVarByName("SC_33"); +		scene->preloadMovements(sceneVar); +		scene33_initScene(scene); +		_behaviorManager->initBehavior(scene, sceneVar); +		scene->initObjectCursors("SC_33"); +		setSceneMusicParameters(sceneVar); +		insertMessageHandler(sceneHandler33, 2, 2); +		scene33_sub_42CEF0(); +		_updateCursorCallback = scene33_updateCursor; +		break; + +	case SC_34: +		sceneVar = _gameLoader->_gameVar->getSubVarByName("SC_34"); +		scene->preloadMovements(sceneVar); +		scene34_initScene(scene); +		_behaviorManager->initBehavior(scene, sceneVar); +		scene->initObjectCursors("SC_34"); +		setSceneMusicParameters(sceneVar); +		insertMessageHandler(sceneHandler34, 2, 2); +		scene34_sub_42DEE0(); +		_updateCursorCallback = scene34_updateCursor; +		break; + +	case SC_35: +		sceneVar = _gameLoader->_gameVar->getSubVarByName("SC_35"); +		scene->preloadMovements(sceneVar); +		scene35_initScene(scene); +		_behaviorManager->initBehavior(scene, sceneVar); +		scene->initObjectCursors("SC_35"); +		setSceneMusicParameters(sceneVar); +		insertMessageHandler(sceneHandler35, 2, 2); +		_updateCursorCallback = defaultUpdateCursor; +		break; + +	case SC_36: +		sceneVar = _gameLoader->_gameVar->getSubVarByName("SC_36"); +		scene->preloadMovements(sceneVar); +		scene36_initScene(scene); +		_behaviorManager->initBehavior(scene, sceneVar); +		scene->initObjectCursors("SC_36"); +		setSceneMusicParameters(sceneVar); +		addMessageHandler(sceneHandler36, 2); +		_updateCursorCallback = scene36_updateCursor; +		break; + +	case SC_37: +		sceneVar = _gameLoader->_gameVar->getSubVarByName("SC_37"); +		scene->preloadMovements(sceneVar); +		scene37_initScene(scene); +		_behaviorManager->initBehavior(scene, sceneVar); +		scene->initObjectCursors("SC_37"); +		setSceneMusicParameters(sceneVar); +		insertMessageHandler(sceneHandler37, 2, 2); +		_updateCursorCallback = scene37_updateCursor; +		break; + +	case SC_38: +		sceneVar = _gameLoader->_gameVar->getSubVarByName("SC_38"); +		scene->preloadMovements(sceneVar); +		scene38_initScene(scene); +		_behaviorManager->initBehavior(scene, sceneVar); +		scene->initObjectCursors("SC_38"); +		setSceneMusicParameters(sceneVar); +		addMessageHandler(sceneHandler38, 2); +		_updateCursorCallback = defaultUpdateCursor; +		break; + +	case SC_FINAL1: +		sceneVar = _gameLoader->_gameVar->getSubVarByName("SC_FINAL1"); +		scene->preloadMovements(sceneVar); +		sceneFinal1_initScene(); +		_behaviorManager->initBehavior(scene, sceneVar); +		scene->initObjectCursors("SC_FINAL1"); +		setSceneMusicParameters(sceneVar); +		addMessageHandler(sceneHandlerFinal1, 2); +		_updateCursorCallback = sceneFinal1_updateCursor; +		break; + +	case SC_DBGMENU: +		sceneVar = _gameLoader->_gameVar->getSubVarByName("SC_DBGMENU"); +		scene->preloadMovements(sceneVar); +		sceneDbgMenu_initScene(scene); +		_behaviorManager->initBehavior(scene, sceneVar); +		scene->initObjectCursors("SC_DBGMENU"); +		addMessageHandler(sceneHandlerDbgMenu, 2); +		break; +#endif + +	default: +		_behaviorManager->initBehavior(0, 0); +		break; +	} + +	return true; +} + +void setElevatorButton(const char *name, int state) { +	CGameVar *var = g_fullpipe->getGameLoaderGameVar()->getSubVarByName("OBJSTATES")->getSubVarByName(sO_LiftButtons); + +	if (var) +		var->setSubVarAsInt(name, state); +} + +void global_messageHandler_KickStucco() { +	warning("STUB: global_messageHandler_KickStucco()"); +} + +void global_messageHandler_KickMetal() { +	warning("STUB: global_messageHandler_KickMetal()"); +} + +int global_messageHandler1(ExCommand *cmd) { +	debug(0, "global_messageHandler1: %d %d", cmd->_messageKind, cmd->_messageNum); + +	if (cmd->_excFlags & 0x10000) { +		if (cmd->_messageNum == MV_MAN_TOLADDER) +			cmd->_messageNum = MV_MAN_TOLADDER2; +		if (cmd->_messageNum == MV_MAN_STARTLADDER) +			cmd->_messageNum = MV_MAN_STARTLADDER2; +		if (cmd->_messageNum == MV_MAN_GOLADDER) +			cmd->_messageNum = MV_MAN_GOLADDER2; +		if (cmd->_messageNum == MV_MAN_STOPLADDER) +			cmd->_messageNum = MV_MAN_STOPLADDER2; +	} + +	if (g_fullpipe->_inputDisabled) { +		if (cmd->_messageKind == 17) { +			switch (cmd->_messageNum) { +			case 29: +			case 30: +			case 36: +			case 106: +				cmd->_messageKind = 0; +				break; +			default: +				break; +			} +		} +	} else if (cmd->_messageKind == 17) { +		switch (cmd->_messageNum) { +		case MSG_MANSHADOWSON: +			g_fullpipe->_aniMan->_shadowsOn = 1; +			break; +		case MSG_HMRKICK_STUCCO: +			global_messageHandler_KickStucco(); +			break; +		case MSG_MANSHADOWSOFF: +			g_fullpipe->_aniMan->_shadowsOn = 0; +			break; +		case MSG_DISABLESAVES: +			g_fullpipe->disableSaves(cmd); +			break; +		case MSG_ENABLESAVES: +			g_fullpipe->enableSaves(); +			break; +		case MSG_HMRKICK_METAL: +			global_messageHandler_KickMetal(); +			break; +		case 29: // left mouse +			if (g_fullpipe->_inventoryScene) { +				if (getGameLoaderInventory()->handleLeftClick(cmd)) +					cmd->_messageKind = 0; +			} +			break; +		case 107: // right mouse +			if (getGameLoaderInventory()->getSelectedItemId()) { +				getGameLoaderInventory()->unselectItem(0); +				cmd->_messageKind = 0; +			} +			break; +		case 36: // keydown +			switch (cmd->_keyCode) { +			case '\x1B': // ESC +				if (g_fullpipe->_currentScene) { +					getGameLoaderInventory()->unselectItem(0); +					g_fullpipe->openMainMenu(); +					cmd->_messageKind = 0; +				} +				break; +			case 't': +				g_fullpipe->stopAllSounds(); +				cmd->_messageKind = 0; +				break; +			case 'u': +				g_fullpipe->toggleMute(); +				cmd->_messageKind = 0; +				break; +			case ' ': +				if (getGameLoaderInventory()->getIsLocked()) { +					if (getGameLoaderInventory()->getIsInventoryOut()) { +						getGameLoaderInventory()->setIsLocked(0); +					} +				} else { +					getGameLoaderInventory()->slideOut(); +					getGameLoaderInventory()->setIsLocked(1); +				} +				break; +			case '\t': +				if (g_fullpipe->_flgCanOpenMap) +					g_fullpipe->openMap(); +				cmd->_messageKind = 0; +				break; +			case 'p': +				if (g_fullpipe->_flgCanOpenMap) +					g_fullpipe->openHelp(); +				cmd->_messageKind = 0; +				break; +			default: +				g_fullpipe->defHandleKeyDown(cmd->_keyCode); +				break; +			} +			break; +		case 33: +			if (!g_fullpipe->_inventoryScene) +				break; + +			int invItem; + +			if (g_fullpipe->_updateFlag && (invItem = g_fullpipe->_inventory->getHoveredItem(&g_fullpipe->_mouseScreenPos))) { +				g_fullpipe->_cursorId = PIC_CSR_ITN; +				if (!g_fullpipe->_currSelectedInventoryItemId && !g_fullpipe->_aniMan->_movement &&  +					!(g_fullpipe->_aniMan->_flags & 0x100) && g_fullpipe->_aniMan->isIdle()) { +					int st = g_fullpipe->_aniMan->_statics->_staticsId; +					ExCommand *newex = 0; + +					if (st == ST_MAN_RIGHT) { +						newex = new ExCommand(g_fullpipe->_aniMan->_id, 1, rMV_MAN_LOOKUP, 0, 0, 0, 1, 0, 0, 0); +					} else if (st == (0x4000 | ST_MAN_RIGHT)) { +						newex = new ExCommand(g_fullpipe->_aniMan->_id, 1, MV_MAN_LOOKUP, 0, 0, 0, 1, 0, 0, 0); +					} + +					if (newex) { +						newex->_keyCode = g_fullpipe->_aniMan->_okeyCode; +						newex->_excFlags |= 3; +						newex->postMessage(); +					} +				} + +				if (g_fullpipe->_currSelectedInventoryItemId != invItem) +					g_fullpipe->playSound(SND_CMN_070, 0); + +				g_fullpipe->_currSelectedInventoryItemId = invItem; +				g_fullpipe->setCursor(g_fullpipe->_cursorId); +				break; +			} +			if (g_fullpipe->_updateCursorCallback) +				g_fullpipe->_updateCursorCallback(); + +			g_fullpipe->_currSelectedInventoryItemId = 0; +			g_fullpipe->setCursor(g_fullpipe->_cursorId); +			break; +		case 65: // open map +			if (cmd->_field_2C == 11 && cmd->_field_14 == ANI_INV_MAP && g_fullpipe->_flgCanOpenMap) +				g_fullpipe->openMap(); +			break; +		default: +			break; +		} +	} + +	if (cmd->_messageKind == 56) { +		getGameLoaderInventory()->rebuildItemRects(); + +		ExCommand *newex = new ExCommand(0, 35, SND_CMN_031, 0, 0, 0, 1, 0, 0, 0); + +		newex->_field_14 = 1; +		newex->_excFlags |= 3; +		newex->postMessage(); + +		return 1; +	} else if (cmd->_messageKind == 57) { +		getGameLoaderInventory()->rebuildItemRects(); + +		return 1; +	} + +	return 0; +} + +void staticANIObjectCallback(int *arg) { +	(*arg)--; +} + +int global_messageHandler2(ExCommand *cmd) { +	if (cmd->_messageKind != 17) +		return 0; + +	int res = 0; +	StaticANIObject *ani; + +	switch (cmd->_messageNum) { +	case 0x44c8: +		// Unk3_sub_4477A0(&unk3, _parentId, _field_14 != 0); +		break; + +	case 28: +		ani = g_fullpipe->_currentScene->getStaticANIObject1ById(cmd->_parentId, cmd->_keyCode); +		if (ani) +			ani->_priority = cmd->_field_14; +		break; + +	case 25: +		ani = g_fullpipe->_currentScene->getStaticANIObject1ById(cmd->_parentId, cmd->_keyCode); +		if (ani) { +			if (cmd->_field_14) { +				ani->setFlags40(true); +				ani->_callback2 = staticANIObjectCallback; +			} else { +				ani->setFlags40(false); +				ani->_callback2 = 0; +			} +		} +		break; + +	case 26: +		ani = g_fullpipe->_currentScene->getStaticANIObject1ById(cmd->_parentId, cmd->_keyCode); +		if (ani) { +			Movement *mov = ani->_movement; +			if (mov) +				mov->_currDynamicPhase->_field_68 = 0; +		} +		break; + +	default: +#if 0 +		// We never put anything into _defMsgArray +		while (::iterator it = g_fullpipe->_defMsgArray.begin(); it != g_fullpipe->_defMsgArray.end(); ++it) +			if (((ExCommand *)*it)->_field_24 == _messageNum) { +				((ExCommand *)*it)->firef34(v13); +				res = 1; +			} +#endif + +		//debug_msg(_messageNum); + +		if (!g_fullpipe->_soundEnabled || cmd->_messageNum != 33 || g_fullpipe->_currSoundListCount <= 0) +			return res; + +		for (int snd = 0; snd < g_fullpipe->_currSoundListCount; snd++) { +			SoundList *s = g_fullpipe->_currSoundList1[snd]; +		    int ms = s->getCount(); +			for (int i = 0; i < ms; i++) { +				s->getSoundByIndex(i)->setPanAndVolumeByStaticAni(); +			} +		} +	} + +	return res; +} + +int global_messageHandler3(ExCommand *cmd) { +	int result = 0; + +	if (cmd->_messageKind == 17) { +		switch (cmd->_messageNum) { +		case 29: +		case 30: +		case 31: +		case 32: +		case 36: +			if (g_fullpipe->_inputDisabled) +				cmd->_messageKind = 0; +			break; +		default: +			break; +		} +	} + +	StaticANIObject *ani, *ani2; + +	switch (cmd->_messageKind) { +	case 17: +		switch (cmd->_messageNum) { +		case 61: +			return g_fullpipe->_gameLoader->preloadScene(cmd->_parentId, cmd->_keyCode); +		case 62: +			return g_fullpipe->_gameLoader->gotoScene(cmd->_parentId, cmd->_keyCode); +		case 64: +			if (g_fullpipe->_currentScene && g_fullpipe->_msgObjectId2 +					&& (!(cmd->_keyCode & 4) || g_fullpipe->_msgObjectId2 != cmd->_field_14 || g_fullpipe->_msgId != cmd->_field_20)) { +				ani = g_fullpipe->_currentScene->getStaticANIObject1ById(g_fullpipe->_msgObjectId2, g_fullpipe->_msgId); +				if (ani) { +					ani->_flags &= 0xFF7F; +					ani->_flags &= 0xFEFF; +					ani->deleteFromGlobalMessageQueue(); +				} +			} +			g_fullpipe->_msgX = 0; +			g_fullpipe->_msgY = 0; +			g_fullpipe->_msgObjectId2 = 0; +			g_fullpipe->_msgId = 0; +			if ((cmd->_keyCode & 1) || (cmd->_keyCode & 2)) { +				g_fullpipe->_msgX = cmd->_x; +				g_fullpipe->_msgY = cmd->_y; +			} +			if (cmd->_keyCode & 4) { +				g_fullpipe->_msgObjectId2 = cmd->_field_14; +				g_fullpipe->_msgId = cmd->_field_20; +			} +			return result; +		case 29: +			if (!g_fullpipe->_currentScene) +				return result; + +			if (g_fullpipe->_gameLoader->_interactionController->_flag24) { +				ani = g_fullpipe->_currentScene->getStaticANIObjectAtPos(cmd->_sceneClickX, cmd->_sceneClickY); +				ani2 = g_fullpipe->_currentScene->getStaticANIObject1ById(g_fullpipe->_gameLoader->_field_FA, -1); +				if (ani) { +					if (g_fullpipe->_msgObjectId2 == ani->_id && g_fullpipe->_msgId == ani->_okeyCode) { +						cmd->_messageKind = 0; +						return result; +					} +					if (ani2->canInteractAny(ani, cmd->_keyCode)) { +						handleObjectInteraction(ani2, ani, cmd->_keyCode); +						return 1; +					} +				} else { +					int id = g_fullpipe->_currentScene->getPictureObjectIdAtPos(cmd->_sceneClickX, cmd->_sceneClickY); +					PictureObject *pic = g_fullpipe->_currentScene->getPictureObjectById(id, 0); +					if (pic) { +						if (g_fullpipe->_msgObjectId2 == pic->_id && g_fullpipe->_msgId == pic->_okeyCode) { +							cmd->_messageKind = 0; +							return result; +						} +						if (ani2->canInteractAny(pic, cmd->_keyCode)) { +							if (!ani2 || (ani2->isIdle() && !(ani2->_flags & 0x80) && !(ani2->_flags & 0x100))) +								handleObjectInteraction(ani2, pic, cmd->_keyCode); +							return 1; +						} +					} +				} +			} +			if (getSc2MctlCompoundBySceneId(g_fullpipe->_currentScene->_sceneId)->_isEnabled && cmd->_keyCode <= 0) { +				if (g_fullpipe->_msgX != cmd->_sceneClickX || g_fullpipe->_msgY != cmd->_sceneClickY) { +					ani = g_fullpipe->_currentScene->getStaticANIObject1ById(g_fullpipe->_gameLoader->_field_FA, -1); +					if (!ani || (ani->isIdle() && !(ani->_flags & 0x80) && !(ani->_flags & 0x100))) { +						result = startWalkTo(g_fullpipe->_gameLoader->_field_FA, -1, cmd->_sceneClickX, cmd->_sceneClickY, 0); +						if (result) { +							ExCommand *ex = new ExCommand(g_fullpipe->_gameLoader->_field_FA, 17, 64, 0, 0, 0, 1, 0, 0, 0); + +							ex->_keyCode = 1; +							ex->_excFlags |= 3; +							ex->_x = cmd->_sceneClickX; +							ex->_y = cmd->_sceneClickY; +							ex->postMessage(); +						} +					} +				} else { +					cmd->_messageKind = 0; +				} +			} +			return result; +		default: +			return result; +		} +	case 58: +		g_fullpipe->setCursor(cmd->_keyCode); +		return result; +	case 59: +		setInputDisabled(1); +		return result; +	case 60: +		setInputDisabled(0); +		return result; +	case 56: +		if (cmd->_field_2C) { +			ani = g_fullpipe->_currentScene->getStaticANIObject1ById(cmd->_parentId, cmd->_keyCode); +			if (ani) { +				getGameLoaderInventory()->addItem2(ani); +				result = 1; +			} +		} else { +			result = 1; +			getGameLoaderInventory()->addItem(cmd->_parentId, 1); +		} +		getGameLoaderInventory()->rebuildItemRects(); +		return result; +	case 57: +		if (cmd->_field_2C) { +			if (!cmd->_field_20) { +				getGameLoaderInventory()->removeItem2(g_fullpipe->_currentScene, cmd->_parentId, cmd->_x, cmd->_y, cmd->_field_14); +				getGameLoaderInventory()->rebuildItemRects(); +				return 1; +			} +			ani = g_fullpipe->_currentScene->getStaticANIObject1ById(g_fullpipe->_gameLoader->_field_FA, -1); +			if (ani) { +				getGameLoaderInventory()->removeItem2(g_fullpipe->_currentScene, cmd->_parentId, ani->_ox + cmd->_x, ani->_oy + cmd->_y, ani->_priority + cmd->_field_14); +				getGameLoaderInventory()->rebuildItemRects(); +				return 1; +			} +		} else { +			getGameLoaderInventory()->removeItem(cmd->_parentId, 1); +		} +		getGameLoaderInventory()->rebuildItemRects(); +		return 1; +	case 55: +		if (g_fullpipe->_currentScene) { +			GameObject *obj; +			if (cmd->_field_14) +				obj = g_fullpipe->_currentScene->getStaticANIObject1ById(cmd->_x, cmd->_y); +			else +				obj = g_fullpipe->_currentScene->getPictureObjectById(cmd->_x, cmd->_y); +			handleObjectInteraction(g_fullpipe->_currentScene->getStaticANIObject1ById(cmd->_parentId, cmd->_keyCode), obj, cmd->_field_20); +			result = 1; +		} +		return result; +	case 51: +		return startWalkTo(cmd->_parentId, cmd->_keyCode, cmd->_x, cmd->_y, cmd->_field_20); +	case 52: +		return doSomeAnimation(cmd->_parentId, cmd->_keyCode, cmd->_field_20); +	case 53: +		return doSomeAnimation2(cmd->_parentId, cmd->_keyCode); +	case 63: +		if (cmd->_objtype == kObjTypeObjstateCommand) { +			CObjstateCommand *c = (CObjstateCommand *)cmd; +			result = 1; +			g_fullpipe->setObjectState(c->_objCommandName, c->_value); +		} +		return result; +	default: +		return result; +	} +} + +int global_messageHandler4(ExCommand *cmd) { +	StaticANIObject *ani = 0; + +	switch (cmd->_messageKind) { +	case 18: { +		MessageQueue *mq = new MessageQueue(g_fullpipe->_currentScene->getMessageQueueById(cmd->_messageNum), cmd->_parId, 0); + +		if (cmd->_excFlags & 1) +			mq->_flag1 = 1; +		else +			mq->_flag1 = 0; + +		mq->sendNextCommand(); +		break; +	} +	case 2: +		if (!g_fullpipe->_currentScene) +			break; + +		ani = g_fullpipe->_currentScene->getStaticANIObject1ById(cmd->_parentId, cmd->_keyCode); +		if (!ani) +			break; + +		ani->trySetMessageQueue(cmd->_messageNum, cmd->_parId); +		break; + +	case 1: { +		if (!g_fullpipe->_currentScene) +			break; + +		ani = g_fullpipe->_currentScene->getStaticANIObject1ById(cmd->_parentId, cmd->_keyCode); +		if (!ani) +			break; + +		int flags = cmd->_field_14; +		if (flags <= 0) +			flags = -1; + +		if (cmd->_excFlags & 1) +			ani->startAnim(cmd->_messageNum, 0, flags); +		else +			ani->startAnim(cmd->_messageNum, cmd->_parId, flags); + +		break; +	} +	case 8: +		if (!g_fullpipe->_currentScene) +			break; + +		ani = g_fullpipe->_currentScene->getStaticANIObject1ById(cmd->_parentId, cmd->_keyCode); +		if (!ani) +			break; + +		ani->startAnimEx(cmd->_messageNum, cmd->_parId, -1, -1); +		break; + +	case 20: { +		if (!g_fullpipe->_currentScene) +			break; + +		ani = g_fullpipe->_currentScene->getStaticANIObject1ById(cmd->_parentId, cmd->_keyCode); +		if (!ani) +			break; + +		int flags = cmd->_field_14; +		if (flags <= 0) +			flags = -1; + +		ExCommand2 *cmd2 = (ExCommand2 *)cmd; + +		if (cmd->_excFlags & 1) { +			ani->startAnimSteps(cmd->_messageNum, 0, cmd->_x, cmd->_y, cmd2->_points, cmd2->_pointsSize >> 3, flags); +		} else { +			ani->startAnimSteps(cmd->_messageNum, cmd->_parId, cmd->_x, cmd->_y, cmd2->_points, cmd2->_pointsSize >> 3, flags); +		} +		break; +	} +	case 21: +		if (!g_fullpipe->_currentScene) +			break; + +		ani = g_fullpipe->_currentScene->getStaticANIObject1ById(cmd->_parentId, cmd->_keyCode); +		if (!ani) +			break; + +		ani->queueMessageQueue(0); +		ani->playIdle(); +		break; +	case 9: +		// Nop in original +		break; +	case 3: +		g_fullpipe->_currentScene->_y = cmd->_messageNum - cmd->_messageNum % g_fullpipe->_scrollSpeed; +		break; + +	case 4: +		g_fullpipe->_currentScene->_x = cmd->_messageNum - cmd->_messageNum % g_fullpipe->_scrollSpeed; +		break; + +	case 19: { +		if (!g_fullpipe->_currentScene) +			break; +		ani = g_fullpipe->_currentScene->getStaticANIObject1ById(cmd->_parentId, cmd->_keyCode); +		if (!ani) +			break; + +		MessageQueue *mq = ani->getMessageQueue(); +		MessageQueue *mq2 = ani->changeStatics1(cmd->_messageNum); + +		if (!mq2 || !mq2->getExCommandByIndex(0) || !mq) +			break; + +		mq2->_parId = mq->_id; +		mq2->_flag1 = (cmd->_field_24 == 0); +		break; +	} +	case 22: +		if (!g_fullpipe->_currentScene) +			break; + +		ani = g_fullpipe->_currentScene->getStaticANIObject1ById(cmd->_parentId, cmd->_keyCode); +		if (!ani) +			break; + +		ani->_flags |= 4; +		ani->changeStatics2(cmd->_messageNum); +		break; + +	case 6: +		if (!g_fullpipe->_currentScene) +			break; + +		ani = g_fullpipe->_currentScene->getStaticANIObject1ById(cmd->_parentId, cmd->_keyCode); +		if (!ani) +			break; + +		ani->hide(); +		break; + +	case 27: +		if (!g_fullpipe->_currentScene || g_fullpipe->_currentScene->getStaticANIObject1ById(cmd->_parentId, cmd->_keyCode) == 0) { +			ani = g_fullpipe->accessScene(cmd->_field_20)->getStaticANIObject1ById(cmd->_parentId, -1); +			if (ani) { +				ani = new StaticANIObject(ani); +				g_fullpipe->_currentScene->addStaticANIObject(ani, 1); +			} +		} + +		// fall through +	case 5: +		if (g_fullpipe->_currentScene) +			ani = g_fullpipe->_currentScene->getStaticANIObject1ById(cmd->_parentId, cmd->_keyCode); + +		if (!ani) +			break; + +		if (cmd->_field_14 >= 0) +			ani->_priority = cmd->_field_14; + +		ani->show1(cmd->_x, cmd->_y, cmd->_messageNum, cmd->_parId); +		break; + +	case 10: +		if (!g_fullpipe->_currentScene) +			break; + +		ani = g_fullpipe->_currentScene->getStaticANIObject1ById(cmd->_parentId, cmd->_keyCode); +		if (!ani) +			break; + +		if (cmd->_field_14 >= 0) +			ani->_priority = cmd->_field_14; + +		ani->show2(cmd->_x, cmd->_y, cmd->_messageNum, cmd->_parId); +		break; + +	case 7: { +		if (!g_fullpipe->_currentScene->_picObjList.size()) +			break; + +		int offX = g_fullpipe->_scrollSpeed * (cmd->_x / g_fullpipe->_scrollSpeed); +		int offY = g_fullpipe->_scrollSpeed * (cmd->_y / g_fullpipe->_scrollSpeed); + +		if (cmd->_messageNum) { +			g_fullpipe->_currentScene->_x = offX - g_fullpipe->_sceneRect.left; +			g_fullpipe->_currentScene->_y = offY - g_fullpipe->_sceneRect.top; + +			if (cmd->_field_24) { +				g_fullpipe->_currentScene->_messageQueueId = cmd->_parId; +			} +		} else { +			g_fullpipe->_sceneRect.moveTo(offX, offY); + +			g_fullpipe->_currentScene->_x = 0; +			g_fullpipe->_currentScene->_y = 0; + +			g_fullpipe->_currentScene->updateScrolling2(); +		} +		break; +	} +	case 34: +		if (!g_fullpipe->_currentScene) +			break; + +		ani = g_fullpipe->_currentScene->getStaticANIObject1ById(cmd->_parentId, cmd->_keyCode); +		if (!ani) +			break; + +		ani->_flags = cmd->_messageNum | (ani->_flags & ~cmd->_field_14); + +		break; + +	case 35: +		global_messageHandler_handleSound(cmd); +		break; + +	case 11: +	case 12: +		break; +	default: +		return 0; +		break; +	} + +	return 1; +} + +int defaultUpdateCursor() { +	g_fullpipe->updateCursorsCommon(); + +	return g_fullpipe->_cursorId; +} + +int sceneIntro_updateCursor() { +	g_fullpipe->_cursorId = 0; + +	return 0; +} + +void FullpipeEngine::setSwallowedEggsState() { +	CGameVar *v = _gameLoader->_gameVar->getSubVarByName("OBJSTATES")->getSubVarByName(sO_GulpedEggs); + +	g_vars->swallowedEgg1 = v->getSubVarByName(sO_Egg1); +	g_vars->swallowedEgg2 = v->getSubVarByName(sO_Egg2); +	g_vars->swallowedEgg3 = v->getSubVarByName(sO_Egg3); + +	g_vars->swallowedEgg1->_value.intValue = 0; +	g_vars->swallowedEgg2->_value.intValue = 0; +	g_vars->swallowedEgg3->_value.intValue = 0; +} + +void sceneIntro_initScene(Scene *sc) { +	g_fullpipe->_gameLoader->loadScene(SC_INTRO2); + +	g_vars->sceneIntro_aniin1man = sc->getStaticANIObject1ById(ANI_IN1MAN, -1); +	g_vars->sceneIntro_needSleep = true; +	g_vars->sceneIntro_needGetup = false; +	g_vars->sceneIntro_playing = true; +	g_vars->sceneIntro_needBlackout = false; + +	if (g_fullpipe->_recordEvents || g_fullpipe->_inputArFlag) +		g_vars->sceneIntro_skipIntro = false; + +	g_fullpipe->_modalObject = new CModalIntro; +} + +int sceneHandlerIntro(ExCommand *cmd) { +	warning("STUB: sceneHandlerIntro()"); + +	return 0; +} + +void scene01_fixEntrance() { +	CGameVar *var = g_fullpipe->getGameLoaderGameVar()->getSubVarByName("OBJSTATES")->getSubVarByName("SAVEGAME"); +	if (var->getSubVarAsInt("Entrance") == TrubaLeft) +		var->setSubVarAsInt("Entrance", TrubaRight); +} + +void scene01_initScene(Scene *sc, int entrance) { +	g_vars->scene01_picSc01Osk = sc->getPictureObjectById(PIC_SC1_OSK, 0); +	g_vars->scene01_picSc01Osk->_flags &= 0xFFFB; + +	g_vars->scene01_picSc01Osk2 = sc->getPictureObjectById(PIC_SC1_OSK2, 0); +	g_vars->scene01_picSc01Osk2->_flags &= 0xFFFB; + +	if (g_fullpipe->getObjectState(sO_EggCracker) == g_fullpipe->getObjectEnumState(sO_EggCracker, sO_DidNotCrackEgg)) { +		PictureObject *pic = sc->getPictureObjectById(PIC_SC1_KUCHKA, 0); +		if (pic) +			pic->_flags &= 0xFFFB; +	} + +	if (entrance != TrubaLeft) { +		StaticANIObject *bootAnim = sc->getStaticANIObject1ById(ANI_BOOT_1, -1); +		if (bootAnim) +			bootAnim->_flags &= ~0x04; +	} + +	setElevatorButton(sO_Level2, ST_LBN_2N); +} + +int sceneHandler01(ExCommand *cmd) { +	int res = 0; + +	if (cmd->_messageKind != 17) +		return 0; + +	if (cmd->_messageNum > MSG_SC1_SHOWOSK) { +		if (cmd->_messageNum == MSG_SC1_UTRUBACLICK) +			handleObjectInteraction(g_fullpipe->_aniMan, g_fullpipe->_currentScene->getPictureObjectById(PIC_SC1_LADDER, 0), 0); + +		return 0; +	} + +	if (cmd->_messageNum == MSG_SC1_SHOWOSK) { +		g_vars->scene01_picSc01Osk->_flags |= 4; + +		g_vars->scene01_picSc01Osk->_priority = 20; +		g_vars->scene01_picSc01Osk2->_priority = 21; + +		return 0; +	} + +	if (cmd->_messageNum != 0x21) { +		if (cmd->_messageNum == MSG_SC1_SHOWOSK2) { +			g_vars->scene01_picSc01Osk2->_flags |= 4; +			g_vars->scene01_picSc01Osk2->_priority = 20; +			g_vars->scene01_picSc01Osk->_priority = 21; + +			return 0; +		} + +		return 0; +	} + +	if (g_fullpipe->_aniMan2) { +		if (g_fullpipe->_aniMan2->_ox < g_fullpipe->_sceneRect.left + 200) { +			g_fullpipe->_currentScene->_x = g_fullpipe->_aniMan2->_ox - g_fullpipe->_sceneRect.left - 300; +		} + +		if (g_fullpipe->_aniMan2->_ox > g_fullpipe->_sceneRect.right - 200) +			g_fullpipe->_currentScene->_x = g_fullpipe->_aniMan2->_ox - g_fullpipe->_sceneRect.right + 300; + +		res = 1; +	} +	g_fullpipe->_behaviorManager->updateBehaviors(); + +	g_fullpipe->startSceneTrack(); + +	return res; +} + +} // End of namespace Fullpipe diff --git a/engines/fullpipe/scenes.h b/engines/fullpipe/scenes.h new file mode 100644 index 0000000000..ae5f2dafb1 --- /dev/null +++ b/engines/fullpipe/scenes.h @@ -0,0 +1,51 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef FULLPIPE_SCENES_H +#define FULLPIPE_SCENES_H + +namespace Fullpipe { + +class StaticANIObject; + +class Vars { + public: +	Vars(); + +	CGameVar *swallowedEgg1; +	CGameVar *swallowedEgg2; +	CGameVar *swallowedEgg3; + +	StaticANIObject *sceneIntro_aniin1man; +	bool sceneIntro_needSleep; +	bool sceneIntro_needGetup; +	bool sceneIntro_skipIntro; +	bool sceneIntro_playing; +	bool sceneIntro_needBlackout; + +	PictureObject *scene01_picSc01Osk; +	PictureObject *scene01_picSc01Osk2; +}; + +} // End of namespace Fullpipe + +#endif /* FULLPIPE_SCENES_H */ diff --git a/engines/fullpipe/sound.cpp b/engines/fullpipe/sound.cpp new file mode 100644 index 0000000000..7f34412334 --- /dev/null +++ b/engines/fullpipe/sound.cpp @@ -0,0 +1,140 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "fullpipe/fullpipe.h" + +#include "fullpipe/objects.h" +#include "fullpipe/sound.h" +#include "fullpipe/ngiarchive.h" + +namespace Fullpipe { + +SoundList::SoundList() { +	_soundItems = 0; +	_soundItemsCount = 0; +	_libHandle = 0; +} + +bool SoundList::load(MfcArchive &file, char *fname) { +	debug(5, "SoundList::load()"); + +	_soundItemsCount = file.readUint32LE(); +	_soundItems = (Sound **)calloc(_soundItemsCount, sizeof(Sound *)); + +	if (fname) { +	  _libHandle = (NGIArchive *)makeNGIArchive(fname); +	} else { +		_libHandle = 0; +	} + +	for (int i = 0; i < _soundItemsCount; i++) { +		Sound *snd = new Sound(); + +		_soundItems[i] = 0; +		snd->load(file, _libHandle); +	} + +	return true; +	 +} + +bool SoundList::loadFile(const char *fname, char *libname) { +	Common::File file; + +	if (!file.open(fname)) +		return false; + +	MfcArchive archive(&file); + +	return load(archive, libname); +} + +Sound::Sound() { +	_id = 0; +	_directSoundBuffer = 0; +	_soundData = 0; +	_objectId = 0; +	memset(_directSoundBuffers, 0, sizeof(_directSoundBuffers)); +	_description = 0; +} + + +bool Sound::load(MfcArchive &file, NGIArchive *archive) { +	debug(5, "Sound::load()"); + +	MemoryObject::load(file); + +	_id = file.readUint32LE(); +	_description = file.readPascalString(); + +	assert(g_fullpipe->_gameProjectVersion >= 6); + +	_objectId = file.readUint16LE(); + +	if (archive && archive->hasFile(_memfilename)) { +		Common::SeekableReadStream *s = archive->createReadStreamForMember(_memfilename); + +		_soundData = (byte *)calloc(s->size(), 1); + +		s->read(_soundData, s->size()); + +		delete s; +	} + +	return true; +} + +void Sound::updateVolume() { +	debug(3, "STUB Sound::updateVolume()"); +} + +void Sound::setPanAndVolumeByStaticAni() { +	debug(3, "STUB Sound::setPanAndVolumeByStaticAni()"); +} + +void FullpipeEngine::setSceneMusicParameters(CGameVar *var) { +	warning("STUB: FullpipeEngine::setSceneMusicParameters()"); +} + +void FullpipeEngine::startSceneTrack() { +	debug(3, "STUB: FullpipeEngine::startSceneTrack()"); +} + +void FullpipeEngine::stopAllSounds() { +	warning("STUB: FullpipeEngine::stopAllSounds()"); +} + +void FullpipeEngine::toggleMute() { +	warning("STUB: FullpipeEngine::toggleMute()"); +} + +void FullpipeEngine::playSound(int id, int flag) { +	warning("STUB: FullpipeEngine::playSounds(%d, %d)", id, flag); +} + +void global_messageHandler_handleSound(ExCommand *cmd) { +	debug(0, "STUB: global_messageHandler_handleSound()"); +} + + + +} // End of namespace Fullpipe diff --git a/engines/fullpipe/sound.h b/engines/fullpipe/sound.h new file mode 100644 index 0000000000..4014cdd94e --- /dev/null +++ b/engines/fullpipe/sound.h @@ -0,0 +1,61 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef FULLPIPE_SOUND_H +#define FULLPIPE_SOUND_H + +namespace Fullpipe { + +class Sound : public MemoryObject { +	int _id; +	char *_description; +	int16 _objectId; +	int16 _field_32; +	int _directSoundBuffer; +	int _directSoundBuffers[7]; +	byte *_soundData; + +  public: +	Sound(); +	bool load(MfcArchive &file, NGIArchive *archive); +	void updateVolume(); + +	void setPanAndVolumeByStaticAni(); +}; + +class SoundList : public CObject { +	Sound **_soundItems; +	int _soundItemsCount; +	NGIArchive *_libHandle; + + public: +	SoundList(); +	bool load(MfcArchive &file, char *fname); +	bool loadFile(const char *fname, char *libname); + +	int getCount() { return _soundItemsCount; } +	Sound *getSoundByIndex(int idx) { return _soundItems[idx]; } +}; + +} // End of namespace Fullpipe + +#endif /* FULLPIPE_SOUND_H */ diff --git a/engines/fullpipe/stateloader.cpp b/engines/fullpipe/stateloader.cpp new file mode 100644 index 0000000000..40169ddf9f --- /dev/null +++ b/engines/fullpipe/stateloader.cpp @@ -0,0 +1,411 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "fullpipe/fullpipe.h" + +#include "common/file.h" +#include "common/array.h" +#include "common/list.h" + +#include "fullpipe/objects.h" +#include "fullpipe/gameloader.h" +#include "fullpipe/scene.h" +#include "fullpipe/statics.h" +#include "fullpipe/interaction.h" + +#include "fullpipe/constants.h" + +namespace Fullpipe { + +bool FullpipeEngine::loadGam(const char *fname, int scene) { +	_gameLoader = new CGameLoader(); + +	if (!_gameLoader->loadFile(fname)) +		return false; + +	_currSoundListCount = 0; +	initObjectStates(); +	// set_g_messageQueueCallback1(messageQueueCallback1); // substituted with direct call + +	addMessageHandlerByIndex(global_messageHandler1, 0, 4); + +	_inventory = getGameLoaderInventory(); +	_inventory->setItemFlags(ANI_INV_MAP, 0x10003); +	_inventory->addItem(ANI_INV_MAP, 1); + +	_inventory->rebuildItemRects(); + +	for (CPtrList::iterator p = _inventory->getScene()->_picObjList.begin(); p != _inventory->getScene()->_picObjList.end(); ++p) { +		((MemoryObject *)((PictureObject *)*p)->_picture)->load(); +	} + +	// _sceneSwitcher = sceneSwitcher; // substituted with direct call +	// _preloadCallback = gameLoaderPreloadCallback +	// _readSavegameCallback = gameLoaderReadSavegameCallback; + +	_aniMan = accessScene(SC_COMMON)->getAniMan(); +	_scene2 = 0; + +	_movTable = _aniMan->countMovements(); + +	_aniMan->setSpeed(1); + +	PictureObject *pic = accessScene(SC_INV)->getPictureObjectById(PIC_INV_MENU, 0); + +	pic->setFlags(pic->_flags & 0xFFFB); + +	// Not used in full game +	//_evalVersionPic = accessScene(SC_COMMON)->getPictureObjectById(PIC_CMN_EVAL, 0); + +	initMap(); +	initCursors(); + +	setMusicAllowed(_gameLoader->_gameVar->getSubVarAsInt("MUSIC_ALLOWED")); + +	if (scene) { +		_gameLoader->loadScene(scene); +		_gameLoader->gotoScene(scene, TrubaLeft); +	} else { +		if (_flgPlayIntro) { +			_gameLoader->loadScene(SC_INTRO1); +			_gameLoader->gotoScene(SC_INTRO1, TrubaUp); +		} else { +			_gameLoader->loadScene(SC_1); +			_gameLoader->gotoScene(SC_1, TrubaLeft); +		} +	} + +	if (!_currentScene) +		return false; + +	return true; +} + +GameProject::GameProject() { +	_field_4 = 0; +	_headerFilename = 0; +	_field_10 = 12; +} + +bool GameProject::load(MfcArchive &file) { +	debug(5, "GameProject::load()"); + +	_field_4 = 0; +	_headerFilename = 0; +	_field_10 = 12; + +	g_fullpipe->_gameProjectVersion = file.readUint32LE(); +	g_fullpipe->_pictureScale = file.readUint16LE(); +	g_fullpipe->_scrollSpeed = file.readUint32LE(); + +	_headerFilename = file.readPascalString(); + +	debug(1, "_gameProjectVersion = %d", g_fullpipe->_gameProjectVersion); +	debug(1, "_pictureScale = %d", g_fullpipe->_pictureScale); +	debug(1, "_scrollSpeed = %d", g_fullpipe->_scrollSpeed); +	debug(1, "_headerFilename = %s", _headerFilename); + +	_sceneTagList = new SceneTagList(); + +	_sceneTagList->load(file); + +	if (g_fullpipe->_gameProjectVersion >= 3) +		_field_4 = file.readUint32LE(); + +	if (g_fullpipe->_gameProjectVersion >= 5) { +		file.readUint32LE(); +		file.readUint32LE(); +	} + +	return true; +} + +GameProject::~GameProject() { +	free(_headerFilename); +} + +bool PreloadItems::load(MfcArchive &file) { +	debug(5, "PreloadItems::load()"); + +	int count = file.readCount(); + +	resize(count); + +	for (int i = 0; i < count; i++) { +		PreloadItem *t = new PreloadItem(); +		t->preloadId1 = file.readUint32LE(); +		t->preloadId2 = file.readUint32LE(); +		t->sceneId = file.readUint32LE(); +		t->field_C = file.readUint32LE(); + +		push_back(*t); +	} + +	return true; +} + +CGameVar::CGameVar() { +	_subVars = 0; +	_parentVarObj = 0; +	_nextVarObj = 0; +	_prevVarObj = 0; +	_field_14 = 0; +	_varType = 0; +	_value.floatValue = 0; +	_varName = 0; +} + +bool CGameVar::load(MfcArchive &file) { +	_varName = file.readPascalString(); +	_varType = file.readUint32LE(); + +	debugN(6, "[%03d] ", file.getLevel()); +	for (int i = 0; i < file.getLevel(); i++) +		debugN(6, " "); + +	debugN(6, "<%s>: ", transCyrillic((byte *)_varName)); + +	switch (_varType) { +	case 0: +		_value.intValue = file.readUint32LE(); +		debug(6, "d --> %d", _value.intValue); +		break; +	case 1: +		_value.intValue = file.readUint32LE(); // FIXME +		debug(6, "f --> %f", _value.floatValue); +		break; +	case 2: +		_value.stringValue = file.readPascalString(); +		debug(6, "s --> %s", _value.stringValue); +		break; +	default: +		error("Unknown var type: %d (0x%x)", _varType, _varType); +	} + +	file.incLevel(); +	_parentVarObj = (CGameVar *)file.readClass(); +	_prevVarObj = (CGameVar *)file.readClass(); +	_nextVarObj = (CGameVar *)file.readClass(); +	_field_14 = (CGameVar *)file.readClass(); +	_subVars = (CGameVar *)file.readClass(); +	file.decLevel(); + +	return true; +} + +CGameVar *CGameVar::getSubVarByName(const char *name) { +	CGameVar *sv = 0; + +	if (_subVars != 0) { +		sv = _subVars; +		for (;sv && scumm_stricmp(sv->_varName, name); sv = sv->_nextVarObj) +			; +	} +	return sv; +} + +bool CGameVar::setSubVarAsInt(const char *name, int value) { +	CGameVar *var = getSubVarByName(name); + +	if (var) { +		if (var->_varType == 0) { +			var->_value.intValue = value; + +			return true; +		} +		return false; +	} + +	var = new CGameVar(); +	var->_varType = 0; +	var->_value.intValue = value; +	var->_varName = (char *)calloc(strlen(name) + 1, 1); +	strcpy(var->_varName, name); + +	return addSubVar(var); +} + +int CGameVar::getSubVarAsInt(const char *name) { +	CGameVar *var = getSubVarByName(name); + +	if (var) +		return var->_value.intValue; +	else +		return 0; +} + +CGameVar *CGameVar::addSubVarAsInt(const char *name, int value) { +	if (getSubVarByName(name)) { +		return 0; +	} else { +		CGameVar *var = new CGameVar(); + +		var->_varType = 0; +		var->_value.intValue = value; + +		var->_varName = (char *)calloc(strlen(name) + 1, 1); +		strcpy(var->_varName, name); + +		return (addSubVar(var) != 0) ? var : 0; +	} +} + +bool CGameVar::addSubVar(CGameVar *subvar) { +	CGameVar *var = _subVars; + +	if (var) { +		for (CGameVar *i = var->_nextVarObj; i; i = i->_nextVarObj) +			var = i; + +		var->_nextVarObj = subvar; +		subvar->_prevVarObj = var; +		subvar->_parentVarObj = this; + +		return true; +	} else { +		_subVars = subvar; +		subvar->_parentVarObj = this; + +		return true; +	} + +	return false; +} + +int CGameVar::getSubVarsCount() { +	int res; +	CGameVar *sub = _subVars; + +	for (res = 0; sub; res++) +		sub = sub->_nextVarObj; + +	return res; +} + +CGameVar *CGameVar::getSubVarByIndex(int idx) { +	CGameVar *sub = _subVars; + +	while (idx--) { +		sub = sub->_nextVarObj; + +		if (!sub) +			return 0; +	} + +	return sub; +} + +Sc2::Sc2() { +	_sceneId = 0; +	_field_2 = 0; +	_scene = 0; +	_motionController = 0; +	_data1 = 0; +	_count1 = 0; +	_defPicAniInfos = 0; +	_defPicAniInfosCount = 0; +	_picAniInfos = 0; +	_picAniInfosCount = 0; +	_isLoaded = 0; +	_entranceData = 0; +	_entranceDataCount = 0; +} + +bool Sc2::load(MfcArchive &file) { +	debug(5, "Sc2::load()"); + +	_sceneId = file.readUint16LE(); + +	_motionController = (CMotionController *)file.readClass(); + +	_count1 = file.readUint32LE(); +	debug(4, "count1: %d", _count1); +	if (_count1 > 0) { +		_data1 = (int32 *)malloc(_count1 * sizeof(int32)); + +		for (int i = 0; i < _count1; i++) { +			_data1[i] = file.readUint32LE(); +		} +	} else { +		_data1 = 0; +	} + +	_defPicAniInfosCount = file.readUint32LE(); +	debug(4, "defPicAniInfos: %d", _defPicAniInfosCount); +	if (_defPicAniInfosCount > 0) { +		_defPicAniInfos = (PicAniInfo **)malloc(_defPicAniInfosCount * sizeof(PicAniInfo *)); + +		for (int i = 0; i < _defPicAniInfosCount; i++) { +			_defPicAniInfos[i] = new PicAniInfo(); + +			_defPicAniInfos[i]->load(file); +		} +	} else { +		_defPicAniInfos = 0; +	} + +	_picAniInfos = 0; +	_picAniInfosCount = 0; + +	_entranceDataCount = file.readUint32LE(); +	debug(4, "_entranceData: %d", _entranceDataCount); + +	if (_entranceDataCount > 0) { +		_entranceData = (EntranceInfo **)malloc(_entranceDataCount * sizeof(EntranceInfo *)); + +		for (int i = 0; i < _entranceDataCount; i++) { +			_entranceData[i] = new EntranceInfo(); +			_entranceData[i]->load(file); +		} +	} else { +		_entranceData = 0; +	} + +	if (file.size() - file.pos() > 0) +		error("Sc2::load(): (%d bytes left)", file.size() - file.pos()); + +	return true; +} + +bool PicAniInfo::load(MfcArchive &file) { +	debug(5, "PicAniInfo::load()"); + +	type = file.readUint32LE(); +	objectId = file.readUint16LE(); +	field_6 = file.readUint16LE(); +	field_8 = file.readUint32LE(); +	sceneId = file.readUint16LE(); +	field_E = file.readUint16LE(); +	ox = file.readUint32LE(); +	oy = file.readUint32LE(); +	priority = file.readUint32LE(); +	staticsId = file.readUint16LE(); +	movementId = file.readUint16LE(); +	dynamicPhaseIndex = file.readUint16LE(); +	flags = file.readUint16LE(); +	field_24 = file.readUint32LE(); +	someDynamicPhaseIndex = file.readUint32LE(); + +	return true; +} + +} // End of namespace Fullpipe diff --git a/engines/fullpipe/statics.cpp b/engines/fullpipe/statics.cpp new file mode 100644 index 0000000000..1fd02f8eb6 --- /dev/null +++ b/engines/fullpipe/statics.cpp @@ -0,0 +1,1720 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "fullpipe/fullpipe.h" + +#include "fullpipe/objects.h" +#include "fullpipe/ngiarchive.h" +#include "fullpipe/statics.h" +#include "fullpipe/messages.h" +#include "fullpipe/interaction.h" + +#include "fullpipe/constants.h" +#include "fullpipe/objectnames.h" + +namespace Fullpipe { + +CStepArray::CStepArray() { +	_points = 0; +	_maxPointIndex = 0; +	_currPointIndex = 0; +	_pointsCount = 0; +	_isEos = 0; +} + +CStepArray::~CStepArray() { +	if (_pointsCount) { +		for (int i = 0; i < _pointsCount; i++) +			delete _points[i]; + +		delete _points; + +		_points = 0; +	} +} + +void CStepArray::clear() { +	_currPointIndex = 0; +	_maxPointIndex = 0; +	_isEos = 0; + +	for (int i = 0; i < _pointsCount; i++) { +		_points[i]->x = 0; +		_points[i]->y = 0; +	} +} + +Common::Point *CStepArray::getCurrPoint(Common::Point *point) { +	if (_isEos || _points == 0) { +		point->x = 0; +		point->y = 0; +	} else { +		point = _points[_currPointIndex]; +	} +	return point; +} + +bool CStepArray::gotoNextPoint() { +	if (_currPointIndex < _maxPointIndex) { +		_currPointIndex++; +		return true; +	} else { +		_isEos = 1; +		return false; +	} +} + +StaticANIObject::StaticANIObject() { +	_shadowsOn = 1; +	_field_30 = 0; +	_field_34 = 1; +	_initialCounter = 0; +	_messageQueueId = 0; +	_animExFlag = 0; +	_counter = 0; +	_movement = 0; +	_statics = 0; +	_flags = 0; +	_callback1 = 0; +	_callback2 = 0; +	_sceneId = -1; +	_someDynamicPhaseIndex = -1; + +	_field_32 = 0; +	_field_96 = 0; +	_messageNum = 0; +	_objtype = kObjTypeStaticANIObject; +} + +StaticANIObject::StaticANIObject(StaticANIObject *src) : GameObject(src) { +	_shadowsOn = src->_shadowsOn; +	_field_30 = src->_field_30; +	_field_34 = 1; +	_initialCounter = 0; + +	_field_32 = 0; +	_field_96 = 0; +	_messageNum = 0; + +	_messageQueueId = 0; +	_animExFlag = 0; +	_counter = 0; +	_someDynamicPhaseIndex = -1; +	_sceneId = src->_sceneId; +	_callback1 = src->_callback1; +	_callback2 = src->_callback2; +	_objtype = kObjTypeStaticANIObject; + +	for (uint i = 0; i < src->_staticsList.size(); i++) +		_staticsList.push_back(new Statics((Statics *)src->_staticsList[i], 0)); + +	_movement = 0; +	_statics = 0; + +	for (uint i = 0; i < src->_movements.size(); i++) { +		Movement *mov; +		if (((Movement *)src->_movements[i])->_currMovement) { +			mov = new Movement(getMovementById(src->getMovementIdById(((Movement *)src->_movements[i])->_id)), this); +			mov->_id = ((Movement *)src->_movements[i])->_id; +		} else { +			mov = new Movement(((Movement *)src->_movements[i]), 0, -1, this); +		} + +		_movements.push_back(mov); +	} +} + +bool StaticANIObject::load(MfcArchive &file) { +	debug(5, "StaticANIObject::load()"); + +	GameObject::load(file); + +	int count = file.readUint16LE(); + +	for (int i = 0; i < count; i++) { +		Statics *st = new Statics(); + +		st->load(file); +		_staticsList.push_back(st); +	} + +	count = file.readUint16LE(); +	debug(7, "Movements: %d", count); + +	for (int i = 0; i < count; i++) { +		int movNum = file.readUint16LE(); + +		char *movname = genFileName(_id, movNum, "mov"); + +		Common::SeekableReadStream *f = g_fullpipe->_currArchive->createReadStreamForMember(movname); + +		Movement *mov = new Movement(); + +		MfcArchive archive(f); + +		mov->load(archive, this); + +		_movements.push_back(mov); + +		delete f; +		free(movname); +	} + +	Common::Point pt; +	if (count) { // We have movements +		((Movement *)_movements[0])->getCurrDynamicPhaseXY(pt); +	} else { +		pt.x = pt.y = 100; +	} + +	setOXY(pt.x, pt.y); + +	return true; +} + +void StaticANIObject::setOXY(int x, int y) { +	_ox = x; +	_oy = y; +	 +	if (_movement) +		_movement->setOXY(x, y); +} + +void StaticANIObject::clearFlags() { +	_flags = 0; + +	deleteFromGlobalMessageQueue(); +	_messageQueueId = 0; +	_movement = 0; +	_statics = 0; +	_animExFlag = 0; +	_counter = 0; +	_messageNum = 0; +	_stepArray.clear(); +} + +void StaticANIObject::setFlags40(bool state) { +	if (state) { +		_flags |= 0x40; +	} else { +		if (_flags & 0x40) +			_flags ^= 0x40; +	} +} + +void StaticANIObject::deleteFromGlobalMessageQueue() { +	while (_messageQueueId) { +		if (g_fullpipe->_globalMessageQueueList->getMessageQueueById(_messageQueueId)) { +			if (!isIdle()) +				return; + +			g_fullpipe->_globalMessageQueueList->deleteQueueById(_messageQueueId); +		} else { +			_messageQueueId = 0; +		} +	} +} + +void StaticANIObject::queueMessageQueue(MessageQueue *mq) { +	if (isIdle() && !(_flags & 0x80)) { +		deleteFromGlobalMessageQueue(); +		_messageQueueId = 0; +		_messageNum = 0; + +		if (_flags & 2) +			_flags ^= 2; + +		if (mq) { +			_animExFlag = 0; +			if (_movement) +				_messageQueueId = mq->_id; +			else +				mq->sendNextCommand(); +		} else { +			_messageQueueId = 0; +		} +	} +} + +MessageQueue *StaticANIObject::getMessageQueue() { +	if (this->_messageQueueId <= 0) +		return 0; + +	return g_fullpipe->_globalMessageQueueList->getMessageQueueById(_messageQueueId); +} + +bool StaticANIObject::trySetMessageQueue(int msgNum, int qId) { +	if (_messageQueueId || !msgNum) { +		updateGlobalMessageQueue(qId, _id); +		return false; +	} + +	_flags |= 2; + +	_messageNum = msgNum; +	_messageQueueId = qId; + +	return true; +} + +bool StaticANIObject::isIdle() { +	if (_messageQueueId) { +		MessageQueue *m = g_fullpipe->_globalMessageQueueList->getMessageQueueById(_messageQueueId); + +		if (m && m->getFlags() & 1) +			return false; +	} + +	return true; +} + +Statics *StaticANIObject::getStaticsById(int itemId) { +	for (uint i = 0; i < _staticsList.size(); i++) +		if (((Statics *)_staticsList[i])->_staticsId == itemId) +			return (Statics *)_staticsList[i]; + +	return 0; +} + +Statics *StaticANIObject::getStaticsByName(char *name) { +	for (uint i = 0; i < _staticsList.size(); i++) +		if (!strcmp(((Statics *)_staticsList[i])->_staticsName, name)) +			return (Statics *)_staticsList[i]; + +	return 0; +} + +Movement *StaticANIObject::getMovementById(int itemId) { +	for (uint i = 0; i < _movements.size(); i++) +		if (((Movement *)_movements[i])->_id == itemId) +			return (Movement *)_movements[i]; + +	return 0; +} + +int StaticANIObject::getMovementIdById(int itemId) { +	for (uint i = 0; i < _movements.size(); i++) { +		Movement *mov = (Movement *)_movements[i]; +		if (mov->_currMovement) { +			if (mov->_id == itemId) +				return mov->_id; +			if (mov->_currMovement->_id == itemId) +				return mov->_id; +		} +	} + +	return 0; +} + +Movement *StaticANIObject::getMovementByName(char *name) { +	for (uint i = 0; i < _movements.size(); i++) +		if (!strcmp(((Movement *)_movements[i])->_objectName, name)) +			return (Movement *)_movements[i]; + +	return 0; +} + +bool StaticANIObject::getPixelAtPos(int x, int y, int *pixel) { +	bool res = false; +	Picture *pic; + +	if (_movement) +		pic = _movement->_currDynamicPhase; +	else +		pic = _statics; + +	if (!pic) +		return false; + +	int ongoing; +	int xani, yani; +	int oxani, oyani; +	Common::Point point; + +	if (_movement) +		ongoing = _movement->_currMovement != 0; +	else +		ongoing = _statics->_staticsId & 0x4000; + +	if (_movement) { +		_movement->getCurrDynamicPhaseXY(point); +		xani = point.x; +		yani = point.y; +		oxani = _movement->_ox; +		oyani = _movement->_oy; +	} else { +		_statics->getSomeXY(point); +		xani = point.x; +		yani = point.y; +		oxani = _ox; +		oyani = _oy; +	} + +	int xtarget = x - (oxani - xani); +	int ytarget = y - (oyani - yani); + +	if (ongoing && _movement) +		xtarget = pic->getDimensions(&point)->x - xtarget; + +	x = pic->_x; +	y = pic->_y; +	pic->_x = 0; +	pic->_y = 0; +	if (pic->isPixelHitAtPos(xtarget, ytarget)) { +		*pixel = pic->getPixelAtPos(xtarget, ytarget); + +		res = true; +	} else { +		res = false; +	} +	pic->_x = x; +	pic->_y = y; + +	return res; +} + +void Movement::draw(bool flipFlag, int angle) { +	debug(3, "Movement::draw(%d, %d)", flipFlag, angle); + +	Common::Point point; + +	getCurrDynamicPhaseXY(point); + +	int x = _ox - point.x; +	int y = _oy - point.y; + +	if (_currDynamicPhase->getPaletteData()) +		g_fullpipe->_globalPalette = _currDynamicPhase->getPaletteData(); + +	if (_currDynamicPhase->getAlpha() < 0xFF) { +		warning("Movement::draw: alpha < 0xff: %d", _currDynamicPhase->getAlpha()); +		//vrtSetAlphaBlendMode(g_vrtDrawHandle, 1, _currDynamicPhase->getAlpha()); +	} + +	Bitmap *bmp; +	if (_currMovement) { +		bmp = _currDynamicPhase->getPixelData()->reverseImage(); +	} else { +		bmp = _currDynamicPhase->getPixelData(); +	} + +	if (flipFlag) { +		bmp->flipVertical()->drawShaded(1, x, y + 30 + _currDynamicPhase->_rect->bottom, _currDynamicPhase->_paletteData); +	} if (angle) { +		bmp->drawRotated(x, y, angle, _currDynamicPhase->_paletteData); +	} else { +		bmp->putDib(x, y, (int32 *)_currDynamicPhase->_paletteData); +	} + +	if (_currDynamicPhase->_rect->top) { +		if (!_currDynamicPhase->_convertedBitmap) { +			//v12 = Picture_getPixelData(v5); +			//v13 = Bitmap_convertTo16Bit565(v12, (unsigned int *)&_currDynamicPhase->rect); +			//_currDynamicPhase->convertedBitmap = v13; +		} + +		if (_currDynamicPhase->_convertedBitmap) { +			if (_currMovement) { +				//vrtSetAlphaBlendMode(g_vrtDrawHandle, 1, LOBYTE(_currDynamicPhase->rect.top)); +				_currDynamicPhase->_convertedBitmap->reverseImage()->putDib(x, y, (int32 *)_currDynamicPhase->_paletteData); +				//vrtSetAlphaBlendMode(g_vrtDrawHandle, 0, 255); +			} else { +				//vrtSetAlphaBlendMode(g_vrtDrawHandle, 1, LOBYTE(_currDynamicPhase->rect.top)); +				_currDynamicPhase->_convertedBitmap->putDib(x, y, (int32 *)_currDynamicPhase->_paletteData); +				//vrtSetAlphaBlendMode(g_vrtDrawHandle, 0, 255); +			} +		} +	} +} + + +void StaticANIObject::loadMovementsPixelData() { +	for (uint i = 0; i < _movements.size(); i++) +		((Movement *)_movements[i])->loadPixelData(); +} + +Statics *StaticANIObject::addReverseStatics(Statics *st) { +	Statics *res = getStaticsById(st->_staticsId ^ 0x4000); + +	if (!res) { +		res = new Statics(st, true); + +		_staticsList.push_back(res); +	} + +	return res; +} + +void StaticANIObject::draw() { +	if ((_flags & 4) == 0) +		return; + +	Common::Point point; +	Common::Rect rect; + +	debug(0, "StaticANIObject::draw() (%s) [%d] [%d, %d]", transCyrillic((byte *)_objectName), _id, _ox, _oy); + +	if (_shadowsOn && g_fullpipe->_currentScene && g_fullpipe->_currentScene->_shadows +		&& (getCurrDimensions(point)->x != 1 || getCurrDimensions(point)->y != 1)) { + +		DynamicPhase *dyn; + +		if (!_movement || _flags & 0x20) +			dyn = _statics; +		else +			dyn = _movement->_currDynamicPhase; + +		if (!dyn) { +			warning("HACK: StaticANIObject::draw(): dyn is missing"); +			return; +		} + +		if (dyn->getDynFlags() & 4) { +			rect = *dyn->_rect; + +			DynamicPhase *shd = g_fullpipe->_currentScene->_shadows->findSize(rect.width(), rect.height()); +			if (shd) { +				shd->getDimensions(&point); +				int midx = _ox - point.x / 2 - dyn->_someX; +				int midy = _oy - point.y / 2 - dyn->_someY + rect.bottom - 3; +				int shdw =  point.y; + +				int px; +				if (!_movement || (_flags & 0x20)) +					px = _statics->getCenter(&point)->x; +				else +					px = _movement->getCenter(&point)->x; + +				if (_shadowsOn != 1) +					midy = _shadowsOn - shdw / 2; + +				shd->draw(px + midx, midy, 0, 0); +			} +		} +	} + +	int angle = 0; +	if (_field_30 & 0xC000) { +		if (_field_30 & 0x8000) +			angle = -(_field_30 ^ 0x8000); +		else +			angle = _field_30 ^ 0x4000; +	} + +	if (!_movement || (_flags & 0x20)) { +		_statics->getSomeXY(point); +		_statics->_x = _ox - point.x; +		_statics->_y = _oy - point.y; +		_statics->draw(_statics->_x, _statics->_y, 0, angle); +	} else { +		_movement->draw(0, angle); +	} +} + +void StaticANIObject::draw2() { +	debug(0, "StatciANIObject::draw2(): id: (%s) %d [%d, %d]", transCyrillic((byte *)_objectName), _id, _ox, _oy); + +	if ((_flags & 4) && (_flags & 0x10)) { +		if (_movement) { +			_movement->draw(1, 0); +		} else { +			Common::Point point; + +			_statics->getSomeXY(point); + +			_statics->draw(_ox - point.x, _oy - point.y, 1, 0); +		} +	} +} + +MovTable *StaticANIObject::countMovements() { +	CGameVar *preloadSubVar = g_fullpipe->getGameLoaderGameVar()->getSubVarByName(getName())->getSubVarByName("PRELOAD"); + +	if (preloadSubVar || preloadSubVar->getSubVarsCount() == 0) +		return 0; + +	MovTable *movTable = new MovTable; + +	movTable->count = _movements.size(); +	movTable->movs = (int16 *)calloc(_movements.size(), sizeof(int16)); + +	for (uint i = 0; i < _movements.size(); i++) { +		GameObject *obj = (GameObject *)_movements[i]; +		movTable->movs[i] = 2; + +		for (CGameVar *sub = preloadSubVar->_subVars; sub; sub = sub->_nextVarObj) { +			if (scumm_stricmp(obj->getName(), sub->_varName) == 0) { +				movTable->movs[i] = 1; +				break; +			} +		} +	} + +	return movTable; +} + +void StaticANIObject::setSpeed(int speed) { +	CGameVar *var = g_fullpipe->getGameLoaderGameVar()->getSubVarByName(getName())->getSubVarByName("SpeedUp"); + +	if (!var) +		return; + +	for (var = var->_subVars; var; var = var->_nextVarObj) { +		Movement *mov = getMovementById(var->_value.intValue); + +		if (mov) { +			if (speed) { +				if (mov->_counterMax == 83) +					mov->_counterMax = 41; +			} else if (mov->_counterMax == 41) { +				mov->_counterMax = 83; +			} +		} +	} + +} + +void StaticANIObject::setAlpha(int alpha) { +	for (uint i = 0; i < _movements.size(); i++) +		((Movement *)_movements[i])->setAlpha(alpha); +	 +	for (uint i = 0; i < _staticsList.size(); i++) +		((Statics *)_staticsList[i])->setAlpha(alpha); +} + +void StaticANIObject::initMovements() { +	for (uint i = 0; i < _movements.size(); i++) +		((Movement *)_movements[i])->removeFirstPhase(); +} + +Common::Point *StaticANIObject::getCurrDimensions(Common::Point &p) { +	Picture *pic; + +	if (_movement) +		pic = _movement->_currDynamicPhase; +	else +		pic = _statics; + +	if (pic) { +		Common::Point point; + +		pic->getDimensions(&point); +		p.x = point.x; +		p.y = point.y; +	} else { +		p.x = 0; +		p.y = 0; +	} + +	return &p; +} + +void StaticANIObject::update(int counterdiff) { +	int mqid; + +	debug(6, "StaticANIObject::update() (%s) [%d] [%d, %d] fl: %x", transCyrillic((byte *)_objectName), _id, _ox, _oy, _flags); + +	if (_flags & 2) { +		_messageNum--; +		if (_messageNum) +			return; + +		mqid = _messageQueueId; +		_messageQueueId = 0; +		_flags ^= 2; + +		updateGlobalMessageQueue(mqid, _id); +		return; +	} + +	Common::Point point; +	ExCommand *ex, *newex; + +	if (_movement) { +		_movement->_counter += counterdiff; + +		if (_movement->_counter < _movement->_counterMax) +			return; + +		_movement->_counter = 0; + +		if (_flags & 1) { +			if (_counter) { +				_counter--; + +				return; +			} + +			DynamicPhase *dyn = _movement->_currDynamicPhase; +			if (dyn->_initialCountdown == dyn->_countdown) { + +				ex = dyn->getExCommand(); +				if (ex && ex->_messageKind != 35) { +					newex = new ExCommand(ex); +					newex->_excFlags |= 2; +					if (newex->_messageKind == 17) { +						newex->_parentId = _id; +						newex->_keyCode = _okeyCode; +					} +					newex->sendMessage(); + +					if (!_movement) +						return; +				} +			} + +			if (dyn->_initialCountdown != dyn->_countdown || dyn->_field_68 == 0) { +				newex = new ExCommand(_id, 17, dyn->_field_68, 0, 0, 0, 1, 0, 0, 0); +				newex->_excFlags = 2; +				newex->_keyCode = _okeyCode; +				newex->sendMessage(); + +				if (!_movement) +					return; +			} + +			if (!_movement->gotoNextFrame(_callback1, _callback2)) { +				stopAnim_maybe(); +			} else { +				setOXY(_movement->_ox, _movement->_oy); +				_counter = _initialCounter; + +				if (dyn->_initialCountdown == dyn->_countdown) { +					ex = dyn->getExCommand(); +					if (ex) { +						if (ex->_messageKind == 35) { +							newex = new ExCommand(ex); +							newex->_excFlags |= 2; +							newex->sendMessage(); +						} +					} +				} +				if (!_movement) +					return; + +				_stepArray.getCurrPoint(&point); +				setOXY(point.x + _ox, point.y + _oy); +				_stepArray.gotoNextPoint(); +				if (_someDynamicPhaseIndex == _movement->_currDynamicPhaseIndex) +					adjustSomeXY(); +			} +		} else if (_flags & 0x20) { +			_flags ^= 0x20; +			_flags |= 1; + +			_movement->gotoFirstFrame(); +			_movement->getCurrDynamicPhaseXY(point); + +			Common::Point pointS; +			_statics->getSomeXY(pointS); +			_movement->setOXY(_ox + point.x + _movement->_mx - pointS.x, +							  _oy + point.y + _movement->_my - pointS.y); +		} +	} else { +		if (_statics) { +			if (_messageQueueId) { +				if (_statics->_countdown) { +					_statics->_countdown--; +					return; +				} +				mqid = _messageQueueId; +				_messageQueueId = 0; +				updateGlobalMessageQueue(mqid, _id); +			} +		} +	} +} + +void StaticANIObject::stopAnim_maybe() { +	debug(6, "StaticANIObject::stopAnim_maybe()"); + +	if (!(_flags & 1)) +		return; + +	_flags ^= 1; + +	int oid = 0; +	int oldmqid = _messageQueueId; +	Common::Point point; + +	if (_movement) { +		setOXY(_movement->_ox, _movement->_oy); + +		if (_flags & 0x40) { +			if (!_movement->_currMovement && !_movement->_currDynamicPhaseIndex) { +				_statics = _movement->_staticsObj1; +				_movement->getCurrDynamicPhaseXY(point); +				_ox -= point.x; +				_oy -= point.y; + +				_ox -= _movement->_mx; +				_oy -= _movement->_my; + +				_statics->getSomeXY(point); +				if (_movement->_currMovement) { +					_oy += point.y; +					_ox -= point.x; +					_ox += _statics->getDimensions(&point)->x; +				} else { +					_ox += point.x; +					_oy += point.y; +				} +			} +		} + +		if (_movement->_currDynamicPhaseIndex || !(_flags & 0x40)) +			_statics = _movement->_staticsObj2; + +		_statics->getSomeXY(point); + +		_statics->_x = _ox - point.x; +		_statics->_y = _oy - point.y; +		oid = _movement->_id; +		_movement = 0; + +		ExCommand *ex = new ExCommand(_id, 17, 24, 0, 0, 0, 1, 0, 0, 0); +		ex->_keyCode = _okeyCode; +		ex->_excFlags = 2; +		ex->postMessage(); +	} + +	int mqid = _messageQueueId; + +	if (_animExFlag) { +		_messageQueueId = 0; +		startAnimEx(oid, mqid, -1, -1); +	} else { +		if (_messageQueueId == oldmqid) { +			_messageQueueId = 0; +			if (_field_34 == 1) +				updateGlobalMessageQueue(mqid, _id); +		} +	} +} + +void StaticANIObject::adjustSomeXY() { +	warning("STUB: StaticANIObject::adjustSomeXY()"); +} + +MessageQueue *StaticANIObject::changeStatics1(int msgNum) { +	warning("STUB: StaticANIObject::changeStatics1(%d)", msgNum); + +	return 0; +} + +void StaticANIObject::changeStatics2(int objId) { +	warning("STUB: StaticANIObject::changeStatics2(%d)", objId); +} + +void StaticANIObject::hide() { +	if (!_messageQueueId) { +		if (_flags & 4) +			_flags ^= 4; +	} +} + +void StaticANIObject::show1(int x, int y, int movId, int mqId) { +	debug(0, "StaticANIObject::show1(%d, %d, %d, %d)", x, y, movId, mqId); + +	if (_messageQueueId) +		return; + +	if (movId == -1) { +		_flags |= 4u; +		if (x != -1 && y != -1) { +			setOXY(x, y); +		} + +		return; +	} + +	Movement *mov = getMovementById(movId); +	if (!mov) +		return; + +	if (x != -1 && y != -1) { +		setOXY(x, y); +	} + +	_statics = mov->_staticsObj1; + +	Common::Point point; + +	mov->_staticsObj1->getSomeXY(point); +	_statics->_x = x - point.x; +	_statics->_y = y - point.y; + +	_statics->_countdown = _statics->_initialCountdown; + +	_flags |= 4; +	_ox = x; +	_oy = y; +	_movement = 0; + +	if (mov->_currMovement) +		_flags |= 8; +	else if (_flags & 8) +		_flags ^= 8; + +	if (_flags & 1) +		_flags ^= 1; + +	_messageQueueId = mqId; +} + +void StaticANIObject::show2(int x, int y, int movementId, int mqId) { +	warning("STUB: StaticANIObject::show2(%d, %d, %d, %d)", x, y, movementId, mqId); +} + +void StaticANIObject::playIdle() { +	if (isIdle()) +		adjustSomeXY(); +} + +void StaticANIObject::startAnimSteps(int movementId, int messageQueueId, int x, int y, Common::Point **points, int pointsCount, int someDynamicPhaseIndex) { +	warning("STUB: StaticANIObject::startAnimSteps()"); +} + +bool StaticANIObject::startAnimEx(int movid, int parId, int flag1, int flag2) { +	bool res = startAnim(movid, parId, -1); +	if (res) +		_animExFlag = 1; + +	_someDynamicPhaseIndex = -1; +	return res; +} + +bool StaticANIObject::startAnim(int movementId, int messageQueueId, int dynPhaseIdx) { +	if (_flags & 0x80) +		return false; + +	debug(0, "StaticANIObject::startAnim(%d, %d, %d) (%s [%d]) [%d, %d]", movementId, messageQueueId, dynPhaseIdx, transCyrillic((byte *)_objectName), _id, _ox, _oy); + +	if (_messageQueueId) { +		updateGlobalMessageQueue(messageQueueId, _id); +		return false; +	} + +	Movement *mov = 0; + +	for (uint i = 0; i < _movements.size(); i++) { + +		if (((Movement *)_movements[i])->_id == movementId) { +			mov = (Movement *)_movements[i]; +			break; +		} +	} + +	if (!mov) { +		updateGlobalMessageQueue(messageQueueId, _id); +		return false; +	} + +	if (mov == _movement) { +		_flags |= 1; +		_messageQueueId = messageQueueId; + +		return true; +	} + +	int newx = _ox; +	int newy = _oy; +	Common::Point point; + +	debug(0, "0 %d %d", newx, newy); +	if (_movement) { +		_movement->getCurrDynamicPhaseXY(point); + +		newx -= point.x; +		newy -= point.y; + +		debug(0, "1 %d %d", newx, newy); +	} else if (_statics) { +		_statics->getSomeXY(point); + +		newx -= point.x; +		newy -= point.y; +		debug(0, "2 %d %d - %d %d assa", newx, newy, point.x, point.y); +	} + +	_movement = mov; + +	_stepArray.clear(); + +	if (_flags & 0x40) +		_movement->gotoLastFrame(); +	else +		_movement->gotoFirstFrame(); + +	if (!(_flags & 0x40)) { +		if (!_movement->_currDynamicPhaseIndex) { +			_stepArray.getCurrPoint(&point); +			newx += point.x + _movement->_mx; +			newy += point.y + _movement->_my; + +			debug(0, "3 %d %d", newx, newy); +			_stepArray.gotoNextPoint(); + +			ExCommand *ex = _movement->_currDynamicPhase->getExCommand(); +			if (ex) { +				if (ex->_messageKind == 35) { +					ExCommand *newex = new ExCommand(ex); +					newex->_excFlags |= 2; +					newex->sendMessage(); +				} +			} +		} +	} + +	_movement->getCurrDynamicPhaseXY(point); +	setOXY(point.x + newx, point.y + newy); + +	if (_movement->_staticsObj2->_staticsId & 0x4000) +		_flags |= 8; +	else +		_flags &= 0xFFF7; + +	_flags |= 1; + +	_messageQueueId = messageQueueId; +	_movement->_currDynamicPhase->_countdown = _movement->_currDynamicPhase->_initialCountdown; +	_movement->_counter = 0; + +	_counter = _initialCounter; +	_someDynamicPhaseIndex = dynPhaseIdx; + +	_stepArray.clear(); + +	ExCommand *newex = new ExCommand(_id, 17, 23, 0, 0, movementId, 1, 0, 0, 0); + +	newex->_keyCode = _okeyCode; +	newex->_excFlags = 2; + +	newex->postMessage(); + +	return true; +} + +Statics::Statics() { +	_staticsId = 0; +	_picture = 0; +	_staticsName = 0; +} + +Statics::Statics(Statics *src, bool reverse) : DynamicPhase(src, reverse) { +	_staticsId = src->_staticsId; + +	if (reverse) { +		_staticsId ^= 0x4000; +		int newlen = strlen(src->_staticsName) + strlen(sO_MirroredTo) + 1; +		_staticsName = (char *)calloc(newlen, 1); + +		snprintf(_staticsName, newlen, "%s%s", sO_MirroredTo, src->_staticsName); +	} else { +		_staticsName = (char *)calloc(strlen(src->_staticsName) + 1, 1); +		strncpy(_staticsName, src->_staticsName, strlen(src->_staticsName) + 1); +	} + +	_memfilename = (char *)calloc(strlen(src->_memfilename) + 1, 1); +	strncpy(_memfilename, src->_memfilename, strlen(src->_memfilename) + 1); + +	_picture = new Picture(); +} + +bool Statics::load(MfcArchive &file) { +	debug(5, "Statics::load()"); + +	DynamicPhase::load(file); + +	_staticsId = file.readUint16LE(); + +	_staticsName = file.readPascalString(); +	debug(7, "statics: <%s> id: %d (%x)", transCyrillic((byte *)_staticsName), _staticsId, _staticsId); + +	_picture = new Picture(); +	_picture->load(file); + +	return true; +} + +Common::Point *Statics::getSomeXY(Common::Point &p) { +	p.x = _someX; +	p.y = _someY; + +	return &p; +} + +Common::Point *Statics::getCenter(Common::Point *p) { +	Common::Rect rect; + +	rect = *_rect; + +	if (_staticsId & 0x4000) { +		Common::Point point; + +		getDimensions(&point); +		rect.moveTo(point.x - _rect->right, _rect->top); +	} + +	p->x = rect.left + _rect->width() / 2; +	p->y = rect.top + _rect->height() / 2; + +	return p; +} + +Movement::Movement() { +	_lastFrameSpecialFlag = 0; +	_flipFlag = 0; +	_updateFlag1 = 0; +	_staticsObj1 = 0; +	_staticsObj2 = 0; +	_mx = 0; +	_my = 0; +	_m2x = 0; +	_m2y = 0; +	_field_50 = 1; +	_field_78 = 0; +	_framePosOffsets = 0; +	_field_84 = 0; +	_currDynamicPhase = 0; +	_field_8C = 0; +	_currDynamicPhaseIndex = 0; +	_field_94 = 0; +	_currMovement = 0; +	_counter = 0; +	_counterMax = 83; + +	_field_24 = 0; +	_field_28 = 0; +} + +Movement::Movement(Movement *src, StaticANIObject *ani) { +	_lastFrameSpecialFlag = 0; +	_flipFlag = src->_flipFlag; +	_updateFlag1 = src->_updateFlag1; +	_staticsObj1 = 0; +	_staticsObj2 = 0; +	_mx = 0; +	_my = 0; +	_m2x = 0; +	_m2y = 0; + +	_field_78 = 0; +	_framePosOffsets = 0; +	_field_84 = 0; +	_currDynamicPhase = 0; +	_field_8C = 0; +	_currDynamicPhaseIndex = src->_currDynamicPhaseIndex; +	_field_94 = 0; + +	_currMovement = src; +	_ox = src->_ox; +	_oy = src->_oy; + +	initStatics(ani); + +	_counterMax = src->_counterMax; +	_counter = src->_counter; +	_field_50 = src->_field_50; + +	updateCurrDynamicPhase(); +} + +Movement::Movement(Movement *src, int *flag1, int flag2, StaticANIObject *ani) { +	warning("STUB: Movement(src, %p, %d, ani)", (void *)flag1, flag2); +} + +bool Movement::load(MfcArchive &file) { +	warning("STUB: Movement::load"); +	return true; +} + +bool Movement::load(MfcArchive &file, StaticANIObject *ani) { +	GameObject::load(file); + +	int dynCount = file.readUint16LE(); + +	debug(7, "dynCount: %d  _id: %d", dynCount, _id); +	if (dynCount != 0xffff || _id == MV_MAN_TURN_LU) { +		_framePosOffsets = (Common::Point **)calloc(dynCount + 2, sizeof(Common::Point *)); + +		for (int i = 0; i < dynCount + 2; i++) +			_framePosOffsets[i] = new Common::Point(); + +		for (int i = 0; i < dynCount; i++) { +			DynamicPhase *ph = new DynamicPhase(); +			ph->load(file); + +			_dynamicPhases.push_back(ph); + +			_framePosOffsets[i]->x = ph->_x; +			_framePosOffsets[i]->y = ph->_y; +		} + +		int staticsid = file.readUint16LE(); + +		_staticsObj1 = ani->getStaticsById(staticsid); + +		if (!_staticsObj1 && (staticsid & 0x4000)) { +			Statics *s = ani->getStaticsById(staticsid ^ 0x4000); +			_staticsObj1 = ani->addReverseStatics(s); +		} + +		_mx = file.readUint32LE(); +		_my = file.readUint32LE(); + +		staticsid = file.readUint16LE(); + +		_staticsObj2 = ani->getStaticsById(staticsid); + +		if (!_staticsObj2 && (staticsid & 0x4000)) { +			Statics *s = ani->getStaticsById(staticsid ^ 0x4000); +			_staticsObj2 = ani->addReverseStatics(s); +		} + +		_m2x = file.readUint32LE(); +		_m2y = file.readUint32LE(); + +		if (_staticsObj2) { +			_dynamicPhases.push_back(_staticsObj2); + +			_framePosOffsets[_dynamicPhases.size() - 1]->x = _m2x; +			_framePosOffsets[_dynamicPhases.size() - 1]->y = _m2y; +		} + +	} else { +		int movid = file.readUint16LE(); + +		_currMovement = ani->getMovementById(movid); +		_staticsObj1 = 0; +		_staticsObj2 = 0; + +		initStatics(ani); +	} + +	if (_staticsObj1 && _staticsObj2) { +		if ((_staticsObj1->_staticsId ^ _staticsObj2->_staticsId) & 0x4000) +			_flipFlag = 1; +	} + +	if (g_fullpipe->_gameProjectVersion >= 8) +		_field_50 = file.readUint32LE(); + +	if (g_fullpipe->_gameProjectVersion < 12) +		_counterMax = 83; +	else +		_counterMax = file.readUint32LE(); + +	_counter = 0; +	updateCurrDynamicPhase(); + +	return true; +} + +Common::Point *Movement::getCurrDynamicPhaseXY(Common::Point &p) { +	p.x = _currDynamicPhase->_someX; +	p.y = _currDynamicPhase->_someY; + +	return &p; +} + +void Movement::setAlpha(int alpha) { +	if (_currMovement) +		for (uint i = 0; i < _currMovement->_dynamicPhases.size(); i++) { +			((DynamicPhase *)_currMovement->_dynamicPhases[i])->setAlpha(alpha); +		} +	else +		for (uint i = 0; i < _dynamicPhases.size(); i++) { +			((DynamicPhase *)_dynamicPhases[i])->setAlpha(alpha); +		} +} + +Common::Point *Movement::getDimensionsOfPhase(Common::Point *p, int phaseIndex) { +	int idx = phaseIndex; + +	if (idx == -1) +		idx = _currDynamicPhaseIndex; + +	DynamicPhase *dyn; + +	if (_currMovement) +		dyn = (DynamicPhase *)_currMovement->_dynamicPhases[idx]; +	else +		dyn = (DynamicPhase *)_dynamicPhases[idx]; + +	Common::Point point; + +	dyn->getDimensions(&point); + +	*p = point; + +	return p; +} + +void Movement::initStatics(StaticANIObject *ani) { +	if (!_currMovement) +		return; + +	debug(7, "Movement::initStatics()"); + +	_staticsObj2 = ani->addReverseStatics(_currMovement->_staticsObj2); +	_staticsObj1 = ani->addReverseStatics(_currMovement->_staticsObj1); +	 +	_mx = _currMovement->_mx; +	_my = _currMovement->_my; + +	_currMovement->setDynamicPhaseIndex(_currMovement->_updateFlag1 != 0 ? 1 : 0); + +	Common::Point point; + +	int x1 = _currMovement->_staticsObj1->getDimensions(&point)->x - _mx; + +	_mx = x1 - _currMovement->_currDynamicPhase->getDimensions(&point)->x; + +	_currMovement->setDynamicPhaseIndex(_currMovement->_currDynamicPhaseIndex); + +	_m2x = _currMovement->_m2x; +	_m2y = _currMovement->_m2y; +	_currMovement->gotoLastFrame(); + +	x1 = _currMovement->_staticsObj2->getDimensions(&point)->x; +	_m2x = _currMovement->_currDynamicPhase->getDimensions(&point)->x - _m2x - x1; +} + +void Movement::updateCurrDynamicPhase() { +	debug(7, "Movement::updateCurrDynamicPhase()"); + +	if (_currMovement) { +		if (_currMovement->_dynamicPhases.size() == 0 || (uint)_currDynamicPhaseIndex >= _currMovement->_dynamicPhases.size()) +			return; + +		if (_currMovement->_dynamicPhases[_currDynamicPhaseIndex]) +			_currDynamicPhase = (DynamicPhase *)_currMovement->_dynamicPhases[_currDynamicPhaseIndex]; +	} else { +		if (_dynamicPhases.size() == 0 || (uint)_currDynamicPhaseIndex >= _dynamicPhases.size()) +			return; + +		if (_dynamicPhases[_currDynamicPhaseIndex]) +			_currDynamicPhase = (DynamicPhase *)_dynamicPhases[_currDynamicPhaseIndex]; +	} +} + +int Movement::calcDuration() { +	int res = 0; + +	if (_currMovement) +		for (uint i = 0; i < _currMovement->_dynamicPhases.size(); i++) { +			res += ((DynamicPhase *)_currMovement->_dynamicPhases[i])->_initialCountdown; +		} +	else +		for (uint i = 0; i < _dynamicPhases.size(); i++) { +			res += ((DynamicPhase *)_dynamicPhases[i])->_initialCountdown; +		} + +	return res; +} + +void Movement::setDynamicPhaseIndex(int index) { +	debug(7, "Movement::setDynamicPhaseIndex(%d)", index); +	while (_currDynamicPhaseIndex < index) +		gotoNextFrame(0, 0); + +	while (_currDynamicPhaseIndex > index) +		gotoPrevFrame(); +} + +DynamicPhase *Movement::getDynamicPhaseByIndex(int idx) { +	debug(7, "Movement::updateCurrDynamicPhase()"); + +	if (_currMovement) { +		if (_currMovement->_dynamicPhases.size() == 0 || (uint)idx >= _currMovement->_dynamicPhases.size()) +			return 0; + +		return (DynamicPhase *)_currMovement->_dynamicPhases[idx]; +	} else { +		if (_dynamicPhases.size() == 0 || (uint)idx >= _dynamicPhases.size()) +			return 0; + +		return (DynamicPhase *)_dynamicPhases[idx]; +	} +} + +void Movement::loadPixelData() { +	Movement *mov = this; +	for (Movement *i = _currMovement; i; i = i->_currMovement) +		mov = i; + +	for (uint i = 0; i < _dynamicPhases.size(); i++) { +		if ((Statics *)_dynamicPhases[i] != mov->_staticsObj2 || !(mov->_staticsObj2->_staticsId & 0x4000)) +			((Statics *)_dynamicPhases[i])->getPixelData(); +	} + +	if (!(mov->_staticsObj1->_staticsId & 0x4000)) +		mov->_staticsObj1->getPixelData(); +} + +void Movement::removeFirstPhase() { +	if (_updateFlag1) { +		if (!_currDynamicPhaseIndex) +			gotoNextFrame(0, 0); + +		if (!_currMovement) { +			_dynamicPhases.remove_at(0); + +			for (uint i = 0; i < _dynamicPhases.size(); i++) { +				_framePosOffsets[i - 1]->x = _framePosOffsets[i]->x; +				_framePosOffsets[i - 1]->y = _framePosOffsets[i]->y; +			} +		} +		_currDynamicPhaseIndex--; +	} + +	updateCurrDynamicPhase(); +	_updateFlag1 = 0; +} + +bool Movement::gotoNextFrame(int callback1, void (*callback2)(int *)) { +	debug(8, "Movement::gotoNextFrame()"); + +	if (!callback2) { +		if (_currMovement) { +			if ((uint)_currDynamicPhaseIndex == _currMovement->_dynamicPhases.size() - 1 +				&& !(((DynamicPhase *)(_currMovement->_dynamicPhases.back()))->_countdown)) { +				return false; +			} +		} else if ((uint)_currDynamicPhaseIndex == _dynamicPhases.size() - 1 +				   && !(((DynamicPhase *)(_dynamicPhases.back()))->_countdown)) { +			return false; +		} +	} + +	if (_currDynamicPhase->_countdown) { +		_currDynamicPhase->_countdown--; +		return true; +	} + +	Common::Point point; + +	getCurrDynamicPhaseXY(point); +	_ox -= point.x; +	_oy -= point.y; + +	int deltax = 0; + +	if (_currMovement) +		deltax = _currMovement->getDimensionsOfPhase(&point, _currDynamicPhaseIndex)->x; + +	int oldDynIndex = _currDynamicPhaseIndex; + +	if (callback2) +		callback2(&_currDynamicPhaseIndex); +	else +		_currDynamicPhaseIndex++; + +	bool result = true; + +	if (_currMovement) { +		if (_currMovement->_dynamicPhases.size() <= (uint)_currDynamicPhaseIndex) { +			_currDynamicPhaseIndex = _currMovement->_dynamicPhases.size() - 1; +			result = (callback2 == 0); +		} +		if (_currDynamicPhaseIndex < 0) { +			_currDynamicPhaseIndex = 0; +			result = false; +		} +		if (_currMovement->_framePosOffsets) { +			if (callback1) { +				point = *_currMovement->_framePosOffsets[_currDynamicPhaseIndex]; +				//callback1(_currDynamicPhaseIndex, &point, _ox, _oy); + +				_ox += deltax - point.x; +				_oy += point.y; + +				_ox -= _currMovement->getDimensionsOfPhase(&point, _currDynamicPhaseIndex)->x; +			} else if (oldDynIndex >= _currDynamicPhaseIndex) { +				while (oldDynIndex > _currDynamicPhaseIndex) { +					_ox += deltax; +					deltax = _currMovement->getDimensionsOfPhase(&point, oldDynIndex)->x; + +					_ox += _currMovement->_framePosOffsets[oldDynIndex]->x; +					_oy -= _currMovement->_framePosOffsets[oldDynIndex]->y; +					oldDynIndex--; + +					_ox -= _currMovement->getDimensionsOfPhase(&point, oldDynIndex)->x; +				} +			} else { +				for (int i = oldDynIndex + 1; i <= _currDynamicPhaseIndex; i++) { +					_ox += deltax; +					deltax = _currMovement->getDimensionsOfPhase(&point, i)->x; +					_ox -= _currMovement->_framePosOffsets[i]->x; +					_oy += _currMovement->_framePosOffsets[i]->y; +					_ox -= _currMovement->getDimensionsOfPhase(&point, i)->x; +				} +			} +		} +	} else { +		if (_dynamicPhases.size() <= (uint)_currDynamicPhaseIndex) { +			_currDynamicPhaseIndex = _dynamicPhases.size() - 1; +			result = (callback2 == 0); +		} +		if (_currDynamicPhaseIndex < 0) { +			_currDynamicPhaseIndex = 0; +			result = false; +		} + +		if (_framePosOffsets) { +			if (callback1) { +				point.x = _framePosOffsets[_currDynamicPhaseIndex]->x; +				point.y = _framePosOffsets[_currDynamicPhaseIndex]->y; + +				//callback1(_currDynamicPhaseIndex, &point, _ox, _oy); +				_ox += point.x; +				_oy += point.y; +			} else if (oldDynIndex >= _currDynamicPhaseIndex) { +				for (int i = oldDynIndex; i > _currDynamicPhaseIndex; i--) { +					_ox -= _framePosOffsets[i]->x; +					_oy -= _framePosOffsets[i]->y; +				} +			} else { +				for (int i = oldDynIndex + 1; i <= _currDynamicPhaseIndex; i++) { +					_ox += _framePosOffsets[i]->x; +					_oy += _framePosOffsets[i]->y; +				} +			} +		} +	} + +	updateCurrDynamicPhase(); +	getCurrDynamicPhaseXY(point); +	_ox += point.x; +	_oy += point.y; + +	_currDynamicPhase->_countdown = _currDynamicPhase->_initialCountdown; + +	return result; +} + +bool Movement::gotoPrevFrame() { +	debug(8, "Movement::gotoPrevFrame()"); + +	if (!_currDynamicPhaseIndex) { +		gotoLastFrame(); +		return false; +	} + +	Common::Point point; + +	getCurrDynamicPhaseXY(point); + +	_ox -= point.x; +	_oy -= point.y; + +	if (_currMovement) { +		if (_currMovement->_framePosOffsets) { +			_ox += _currMovement->getDimensionsOfPhase(&point, _currDynamicPhaseIndex)->x; +			_ox += _currMovement->_framePosOffsets[_currDynamicPhaseIndex]->x; +			_oy -= _currMovement->_framePosOffsets[_currDynamicPhaseIndex]->y; +		} + +		_currDynamicPhaseIndex--; +		if (_currDynamicPhaseIndex < 0) +			_currDynamicPhaseIndex = _currMovement->_dynamicPhases.size() - 1; + +		_ox -= _currMovement->getDimensionsOfPhase(&point, _currDynamicPhaseIndex)->x; +	} else { +		if (_framePosOffsets) { +			_ox -= _framePosOffsets[_currDynamicPhaseIndex]->x; +			_oy -= _framePosOffsets[_currDynamicPhaseIndex]->y; +		} + +		_currDynamicPhaseIndex--; +		if (_currDynamicPhaseIndex < 0) +			_currDynamicPhaseIndex = _currMovement->_dynamicPhases.size() - 1; +	} + +	updateCurrDynamicPhase(); +	getCurrDynamicPhaseXY(point); + +	_ox += point.x; +	_oy += point.y; + +	return true; +} + +void Movement::gotoFirstFrame() { +	while (_currDynamicPhaseIndex) +			gotoPrevFrame(); +} + +void Movement::gotoLastFrame() { +	if (_currMovement) { +		while ((uint)_currDynamicPhaseIndex != _currMovement->_dynamicPhases.size() - 1) +			gotoNextFrame(0, 0); +	} else { +		while ((uint)_currDynamicPhaseIndex != _dynamicPhases.size() - 1) +			gotoNextFrame(0, 0); +	} +} + +Common::Point *Movement::getCenter(Common::Point *p) { +	Common::Rect rect; + +	rect = *_currDynamicPhase->_rect; + +	if (_currMovement) { +		Common::Point point; + +		_currMovement->getDimensionsOfPhase(&point, _currDynamicPhaseIndex); + +		rect.moveTo(point.x - _currDynamicPhase->_rect->right, _currDynamicPhase->_rect->top); +	} + +	p->x = rect.left + _currDynamicPhase->_rect->width() / 2; +	p->y = rect.top + _currDynamicPhase->_rect->height() / 2; + +	return p; +} + +DynamicPhase::DynamicPhase() { +	_someX = 0; +	_rect = 0; +	_field_7C = 0; +	_field_7E = 0; +	_dynFlags = 0; +	_someY = 0; +} + +DynamicPhase::DynamicPhase(DynamicPhase *src, bool reverse) { +	_field_7C = src->_field_7C; +	_field_7E = 0; +	_rect = new Common::Rect(); + +	debug(0, "DynamicPhase::DynamicPhase(src, %d)", reverse); + +	if (reverse) { +		if (!src->_bitmap) +			src->init(); + +		_bitmap = src->_bitmap->reverseImage(); +		_data = _bitmap->_pixels; +		_dataSize = src->_dataSize; + +		if (g_fullpipe->_currArchive) { +			_mfield_14 = 0; +			_libHandle = g_fullpipe->_currArchive; +		} + +		_mflags |= 1; + +		_someX = src->_someX; +		_someY = src->_someY; +	} else { +		_mfield_14 = src->_mfield_14; +		_mfield_8 = src->_mfield_8; +		_mflags = src->_mflags; + +		_memfilename = (char *)calloc(strlen(src->_memfilename) + 1, 1); +		strncpy(_memfilename, src->_memfilename, strlen(src->_memfilename) + 1); +		_dataSize = src->_dataSize; +		_mfield_10 = src->_mfield_10; +		_libHandle = src->_libHandle; + +		_bitmap = src->_bitmap; +		if (_bitmap) +			_field_54 = 1; + +		_someX = src->_someX; +		_someY = src->_someY; +	} + +	*_rect = *src->_rect; + +	_width = src->_width; +	_height = src->_height; +	_field_7C = src->_field_7C; + +	if (src->getExCommand()) +		_exCommand = new ExCommand(src->getExCommand()); +	else +		_exCommand = 0; + +	_initialCountdown = src->_initialCountdown; +	_field_6A = src->_field_6A; +	_dynFlags = src->_dynFlags; + +	setPaletteData(src->getPaletteData()); + +	copyMemoryObject2(src); +} + +bool DynamicPhase::load(MfcArchive &file) { +	debug(5, "DynamicPhase::load()"); + +	StaticPhase::load(file); + +	_field_7C = file.readUint16LE(); +	_rect = new Common::Rect(); +	_rect->left = file.readUint32LE(); +	_rect->top = file.readUint32LE(); +	_rect->right = file.readUint32LE(); +	_rect->bottom = file.readUint32LE(); + +	assert (g_fullpipe->_gameProjectVersion >= 1); + +	_someX = file.readUint32LE(); +	_someY = file.readUint32LE(); + +	assert (g_fullpipe->_gameProjectVersion >= 12); + +	_dynFlags = file.readUint32LE(); + +	return true; +} + +StaticPhase::StaticPhase() { +	_field_6A = 1; +	_initialCountdown = 0; +	_countdown = 0; +	_field_68 = 0; +	_exCommand = 0; +} + +bool StaticPhase::load(MfcArchive &file) { +	debug(5, "StaticPhase::load()"); + +	Picture::load(file); + +	_initialCountdown = file.readUint16LE(); +	_field_6A = file.readUint16LE(); +	 +	if (g_fullpipe->_gameProjectVersion >= 12) { +		_exCommand = (ExCommand *)file.readClass(); + +		return true; +	} + +	assert (g_fullpipe->_gameProjectVersion >= 12); + +	return true; +} + +} // End of namespace Fullpipe diff --git a/engines/fullpipe/statics.h b/engines/fullpipe/statics.h new file mode 100644 index 0000000000..3d45ac6623 --- /dev/null +++ b/engines/fullpipe/statics.h @@ -0,0 +1,247 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef FULLPIPE_STATICS_H +#define FULLPIPE_STATICS_H + +#include "fullpipe/gfx.h" + +namespace Fullpipe { + +class ExCommand; + +class CStepArray : public CObject { +	int _currPointIndex; +	Common::Point **_points; +	int _maxPointIndex; +	int _pointsCount; +	int _isEos; + +  public: +	CStepArray(); +	~CStepArray(); +	void clear(); + +	int getCurrPointIndex() { return _currPointIndex; } +	Common::Point *getCurrPoint(Common::Point *point); +	bool gotoNextPoint(); +}; + +class StaticPhase : public Picture { + public: +	int16 _initialCountdown; +	int16 _countdown; +	int16 _field_68; +	int16 _field_6A; +	ExCommand *_exCommand; + +  public: +	StaticPhase(); + +	virtual bool load(MfcArchive &file); + +	ExCommand *getExCommand() { return _exCommand; } +}; + +class DynamicPhase : public StaticPhase { + public: +	int _someX; +	int _someY; +	Common::Rect *_rect; +	int16 _field_7C; +	int16 _field_7E; +	int _dynFlags; + +  public: +	DynamicPhase(); +	DynamicPhase(DynamicPhase *src, bool reverse); + +	virtual bool load(MfcArchive &file); + +	int getDynFlags() { return _dynFlags; } +}; + +class Statics : public DynamicPhase { + public: + 	int16 _staticsId; +	char *_staticsName; +	Picture *_picture; + +  public: +	Statics(); +	Statics(Statics *src, bool reverse); + +	virtual bool load(MfcArchive &file); +	Statics *getStaticsById(int itemId); + +	Common::Point *getSomeXY(Common::Point &p); +	Common::Point *getCenter(Common::Point *p); +}; + +class StaticANIObject; + +class Movement : public GameObject { +  public: +	int _field_24; +	int _field_28; +	int _lastFrameSpecialFlag; +	int _flipFlag; +	int _updateFlag1; +	Statics *_staticsObj1; +	Statics *_staticsObj2; +	int _mx; +	int _my; +	int _m2x; +	int _m2y; +	int _field_50; +	int _counterMax; +	int _counter; +	CPtrList _dynamicPhases; +	int _field_78; +	Common::Point **_framePosOffsets; +	Movement *_currMovement; +	int _field_84; +	DynamicPhase *_currDynamicPhase; +	int _field_8C; +	int _currDynamicPhaseIndex; +	int _field_94; + +  public: +	Movement(); +	Movement(Movement *src, StaticANIObject *ani); +	Movement(Movement *src, int *flag1, int flag2, StaticANIObject *ani); + +	virtual bool load(MfcArchive &file); +	bool load(MfcArchive &file, StaticANIObject *ani); + +	Common::Point *getCurrDynamicPhaseXY(Common::Point &p); +	Common::Point *getCenter(Common::Point *p); +	Common::Point *getDimensionsOfPhase(Common::Point *p, int phaseIndex); + +	void initStatics(StaticANIObject *ani); +	void updateCurrDynamicPhase(); + +	void setAlpha(int alpha); + +	void setDynamicPhaseIndex(int index); +	DynamicPhase *getDynamicPhaseByIndex(int idx); + +	int calcDuration(); + +	void removeFirstPhase(); +	bool gotoNextFrame(int callback1, void (*callback2)(int *)); +	bool gotoPrevFrame(); +	void gotoFirstFrame(); +	void gotoLastFrame(); + +	void loadPixelData(); + +	void draw(bool flipFlag, int angle); +}; + +class StaticANIObject : public GameObject { + public: +	Movement *_movement; +	Statics *_statics; +	int _shadowsOn; +	int16 _field_30; +	int16 _field_32; +	int _field_34; +	int _initialCounter; +	int _callback1; +	void (*_callback2)(int *); +	CPtrList _movements; +	CPtrList _staticsList; +	CStepArray _stepArray; +	int16 _field_96; +	int _messageQueueId; +	int _messageNum; +	int _animExFlag; +	int _counter; +	int _someDynamicPhaseIndex; + +  public: +	int16 _sceneId; + +  public: +	StaticANIObject(); +	StaticANIObject(StaticANIObject *src); + +	virtual bool load(MfcArchive &file); + +	void setOXY(int x, int y); +	Statics *getStaticsById(int id); +	Statics *getStaticsByName(char *name); +	Movement *getMovementById(int id); +	int getMovementIdById(int itemId); +	Movement *getMovementByName(char *name); +	Common::Point *getCurrDimensions(Common::Point &p); + +	void clearFlags(); +	void setFlags40(bool state); +	bool isIdle(); +	void setAlpha(int alpha); + +	void deleteFromGlobalMessageQueue(); +	void queueMessageQueue(MessageQueue *msg); +	MessageQueue *getMessageQueue(); +	bool trySetMessageQueue(int msgNum, int qId); + +	void initMovements(); +	void loadMovementsPixelData(); + +	void setSomeDynamicPhaseIndex(int val) { _someDynamicPhaseIndex = val; } +	void adjustSomeXY(); + +	bool startAnim(int movementId, int messageQueueId, int dynPhaseIdx); +	bool startAnimEx(int movid, int parId, int flag1, int flag2); +	void startAnimSteps(int movementId, int messageQueueId, int x, int y, Common::Point **points, int pointsCount, int someDynamicPhaseIndex); + +	void hide(); +	void show1(int x, int y, int movementId, int mqId); +	void show2(int x, int y, int movementId, int mqId); +	void playIdle(); +	void update(int counterdiff); + +	Statics *addReverseStatics(Statics *ani); +	void draw(); +	void draw2(); + +	MovTable *countMovements(); +	void setSpeed(int speed); + +	void stopAnim_maybe(); + +	MessageQueue *changeStatics1(int msgNum); +	void changeStatics2(int objId); + +	bool getPixelAtPos(int x, int y, int *pixel); +}; + +struct MovTable { +	int count; +	int16 *movs; +}; + +} // End of namespace Fullpipe + +#endif /* FULLPIPE_STATICS_H */ diff --git a/engines/fullpipe/utils.cpp b/engines/fullpipe/utils.cpp new file mode 100644 index 0000000000..ee73aeaa64 --- /dev/null +++ b/engines/fullpipe/utils.cpp @@ -0,0 +1,484 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "fullpipe/fullpipe.h" + +#include "common/file.h" +#include "common/memstream.h" + +#include "fullpipe/objects.h" +#include "fullpipe/motion.h" +#include "fullpipe/ngiarchive.h" +#include "fullpipe/messages.h" +#include "fullpipe/interaction.h" + +namespace Fullpipe { + +bool CObject::loadFile(const char *fname) { +	Common::File file; + +	if (!file.open(fname)) +		return false; + +	MfcArchive archive(&file); + +	return load(archive); +} + +bool CObList::load(MfcArchive &file) { +	debug(5, "CObList::load()"); +	int count = file.readCount(); + +	debug(9, "CObList::count: %d:", count); + +	for (int i = 0; i < count; i++) { +		debug(9, "CObList::[%d]", i); +		CObject *t = file.readClass(); + +		push_back(t); +	} + +	return true; +} + +bool CObArray::load(MfcArchive &file) { +	debug(5, "CObArray::load()"); +	int count = file.readCount(); + +	resize(count); + +	for (int i = 0; i < count; i++) { +		CObject *t = file.readClass(); + +		push_back(*t); +	} + +	return true; +} + +bool CDWordArray::load(MfcArchive &file) { +	debug(5, "CWordArray::load()"); +	int count = file.readCount(); + +	debug(9, "CDWordArray::count: %d", count); + +	resize(count); + +	for (int i = 0; i < count; i++) { +		int32 t = file.readUint32LE(); + +		push_back(t); +	} + +	return true; +} + +char *MfcArchive::readPascalString(bool twoByte) { +	char *tmp; +	int len; + +	if (twoByte) +		len = readUint16LE(); +	else +		len = readByte(); + +	tmp = (char *)calloc(len + 1, 1); +	read(tmp, len); + +	debug(9, "readPascalString: %d <%s>", len, transCyrillic((byte *)tmp)); + +	return tmp; +} + +MemoryObject::MemoryObject() { +	_memfilename = 0; +	_mfield_8 = 0; +	_mfield_C = 0; +	_mfield_10 = -1; +	_mfield_14 = 1; +	_dataSize = 0; +	_mflags = 0; +	_libHandle = 0; +	_data = 0; +} + +MemoryObject::~MemoryObject() { +	freeData(); +	if (_memfilename) +		free(_memfilename); +} + +bool MemoryObject::load(MfcArchive &file) { +	debug(5, "MemoryObject::load()"); +	_memfilename = file.readPascalString(); + +	if (char *p = strchr(_memfilename, '\\')) { +		for (char *d = _memfilename; *p;) { +			p++; +			*d++ = *p; +		} +	} + +	if (g_fullpipe->_currArchive) { +		_mfield_14 = 0; +		_libHandle = g_fullpipe->_currArchive; +	} + +	return true; +} + +void MemoryObject::loadFile(char *filename) { +	debug(5, "MemoryObject::loadFile(<%s>)", filename); +	if (!_data) { +		Common::SeekableReadStream *s = g_fullpipe->_currArchive->createReadStreamForMember(filename); + +		if (s) { +			assert(s->size() > 0); + +			_dataSize = s->size(); + +			debug(5, "Loading %s (%d bytes)", filename, _dataSize); +			_data = (byte *)calloc(_dataSize, 1); +			s->read(_data, _dataSize); + +			delete s; +		} +	} +} + +byte *MemoryObject::getData() { +	load(); + +	if (_mfield_14 || _mflags & 1) { +		return _data; +	} else { +		error("Unhandled packed data"); +	} +} + +byte *MemoryObject::loadData() { +	load(); +	return _data; +} + +void MemoryObject::freeData() { +	if (_data) +		free(_data); + +	_data = 0; +} + +bool MemoryObject::testFlags() { +	if (_mfield_8) +		return false; + +	if (_mflags & 1) +		return true; + +	return false; +} + +MemoryObject2::MemoryObject2() { +	_rows = 0; +} + +MemoryObject2::~MemoryObject2() { +	if (_rows) +		free(_rows); +} + +bool MemoryObject2::load(MfcArchive &file) { +	debug(5, "MemoryObject2::load()"); +	MemoryObject::load(file); + +	_mflags |= 1; + +	debug(5, "MemoryObject2::load: <%s>", _memfilename); + +	if (_memfilename && *_memfilename) { +		MemoryObject::loadFile(_memfilename); +	} + +	return true; +} + +void MemoryObject2::copyData(byte *src, int dataSize) { +	if (_data) +		freeData(); + +	_dataSize = dataSize; +	_data = (byte *)malloc(dataSize); + +	memcpy(_data, src, _dataSize); +} + +int MfcArchive::readCount() { +	int count = readUint16LE(); + +	if (count == 0xffff) +		count = readUint32LE(); + +	return count; +} + +double MfcArchive::readDouble() { +	// FIXME: This is utterly cruel and unportable +	// Some articles on the matter: +	// http://randomascii.wordpress.com/2013/02/07/float-precision-revisited-nine-digit-float-portability/ +	// http://randomascii.wordpress.com/2012/01/11/tricks-with-the-floating-point-format/ + +	union { +		struct { +			int32 a; +			int32 b; +		} i; +		double d; +	} tmp; + +	tmp.i.a = readUint32LE(); +	tmp.i.b = readUint32LE(); + +	return tmp.d; +} + +enum { +	kNullObject, +	kCInteraction, +	kMessageQueue, +	kExCommand, +	kCObjstateCommand, +	kCGameVar, +	kCMctlCompound, +	kCMovGraph, +	kCMovGraphLink, +	kCMovGraphNode, +	kCReactParallel, +	kCReactPolygonal +}; + +const struct { +	const char *name; +	int id; +} classMap[] = { +	{ "CInteraction",	kCInteraction }, +	{ "MessageQueue",	kMessageQueue }, +	{ "ExCommand",		kExCommand }, +	{ "CObjstateCommand", kCObjstateCommand }, +	{ "CGameVar",		kCGameVar }, +	{ "CMctlCompound",	kCMctlCompound }, +	{ "CMovGraph",		kCMovGraph }, +	{ "CMovGraphLink",	kCMovGraphLink }, +	{ "CMovGraphNode",	kCMovGraphNode }, +	{ "CReactParallel", kCReactParallel }, +	{ "CReactPolygonal", kCReactPolygonal }, +	{ 0, 0 } +}; + +static const char *lookupObjectId(int id) { +	for (int i = 0; classMap[i].name; i++) { +		if (classMap[i].id == id) +			return classMap[i].name; +	} + +	return ""; +} + +static CObject *createObject(int objectId) { +	switch (objectId) { +	case kNullObject: +		return 0; +	case kCInteraction: +		return new CInteraction(); +	case kMessageQueue: +		return new MessageQueue(); +	case kExCommand: +		return new ExCommand(); +	case kCObjstateCommand: +		return new CObjstateCommand(); +	case kCGameVar: +		return new CGameVar(); +	case kCMctlCompound: +		return new CMctlCompound(); +	case kCMovGraph: +		return new CMovGraph(); +	case kCMovGraphLink: +		return new CMovGraphLink(); +	case kCMovGraphNode: +		return new CMovGraphNode(); +	case kCReactParallel: +		return new CReactParallel(); +	case kCReactPolygonal: +		return new CReactPolygonal(); +	default: +		error("Unknown objectId: %d", objectId); +	} + +	return 0; +} + +MfcArchive::MfcArchive(Common::SeekableReadStream *stream) { +	for (int i = 0; classMap[i].name; i++) { +		_classMap[classMap[i].name] = classMap[i].id; +	} + +	_lastIndex = 1; +	_level = 0; + +	_stream = stream; + +	_objectMap.push_back(0); +	_objectIdMap.push_back(kNullObject); +} + +CObject *MfcArchive::readClass() { +	bool isCopyReturned; +	CObject *res = parseClass(&isCopyReturned); + +	if (res && !isCopyReturned) +		res->load(*this); + +	return res; +} + +CObject *MfcArchive::parseClass(bool *isCopyReturned) { +	char *name; +	int objectId = 0; +	CObject *res = 0; + +	uint obTag = readUint16LE(); + +	debug(7, "parseClass::obTag = %d (%04x)  at 0x%08x", obTag, obTag, pos() - 2); + +	if (obTag == 0xffff) { +		int schema = readUint16LE(); + +		debug(7, "parseClass::schema = %d", schema); + +		name = readPascalString(true); +		debug(7, "parseClass::class <%s>", name); + +		if (!_classMap.contains(name)) { +			error("Unknown class in MfcArchive: <%s>", name); +		} + +		objectId = _classMap[name]; + +		debug(7, "tag: %d 0x%x (%x)", _objectMap.size() - 1, _objectMap.size() - 1, objectId); + +		res = createObject(objectId); +		_objectMap.push_back(res); +		_objectIdMap.push_back(objectId); + +		_objectMap.push_back(res); // Basically a hack, but behavior is all correct +		_objectIdMap.push_back(objectId); + +		*isCopyReturned = false; +	} else if ((obTag & 0x8000) == 0) { +		if (_objectMap.size() < obTag) { +			error("Object index too big: %d  at 0x%08x", obTag, pos() - 2); +		} +		res = _objectMap[obTag]; + +		*isCopyReturned = true; +	} else { + +		obTag &= ~0x8000; + +		if (_objectMap.size() < obTag) { +			error("Object index too big: %d  at 0x%08x", obTag, pos() - 2); +		} + +		debug(7, "parseClass::obTag <%s>", lookupObjectId(_objectIdMap[obTag])); + +		objectId = _objectIdMap[obTag]; + +		res = createObject(objectId); +		_objectMap.push_back(res); +		_objectIdMap.push_back(objectId); + +		*isCopyReturned = false; +	} + +	return res; +} + +char *genFileName(int superId, int sceneId, const char *ext) { +	char *s = (char *)calloc(256, 1); + +	if (superId) { +		snprintf(s, 255, "%04d%04d.%s", superId, sceneId, ext); +	} else { +		snprintf(s, 255, "%04d.%s", sceneId, ext); +	} + +	debug(7, "genFileName: %s", s); + +	return s; +} + +// Translates cp-1251..utf-8 +byte *transCyrillic(byte *s) { +	static byte tmp[1024]; + +	static int trans[] = { 0xa8, 0xd081, 0xb8, 0xd191, 0xc0, 0xd090, +		0xc1, 0xd091, 0xc2, 0xd092, 0xc3, 0xd093, 0xc4, 0xd094, +		0xc5, 0xd095, 0xc6, 0xd096, 0xc7, 0xd097, 0xc8, 0xd098, +		0xc9, 0xd099, 0xca, 0xd09a, 0xcb, 0xd09b, 0xcc, 0xd09c, +		0xcd, 0xd09d, 0xce, 0xd09e, 0xcf, 0xd09f, 0xd0, 0xd0a0, +		0xd1, 0xd0a1, 0xd2, 0xd0a2, 0xd3, 0xd0a3, 0xd4, 0xd0a4, +		0xd5, 0xd0a5, 0xd6, 0xd0a6, 0xd7, 0xd0a7, 0xd8, 0xd0a8, +		0xd9, 0xd0a9, 0xda, 0xd0aa, 0xdb, 0xd0ab, 0xdc, 0xd0ac, +		0xdd, 0xd0ad, 0xde, 0xd0ae, 0xdf, 0xd0af, 0xe0, 0xd0b0, +		0xe1, 0xd0b1, 0xe2, 0xd0b2, 0xe3, 0xd0b3, 0xe4, 0xd0b4, +		0xe5, 0xd0b5, 0xe6, 0xd0b6, 0xe7, 0xd0b7, 0xe8, 0xd0b8, +		0xe9, 0xd0b9, 0xea, 0xd0ba, 0xeb, 0xd0bb, 0xec, 0xd0bc, +		0xed, 0xd0bd, 0xee, 0xd0be, 0xef, 0xd0bf, 0xf0, 0xd180, +		0xf1, 0xd181, 0xf2, 0xd182, 0xf3, 0xd183, 0xf4, 0xd184, +		0xf5, 0xd185, 0xf6, 0xd186, 0xf7, 0xd187, 0xf8, 0xd188, +		0xf9, 0xd189, 0xfa, 0xd18a, 0xfb, 0xd18b, 0xfc, 0xd18c, +		0xfd, 0xd18d, 0xfe, 0xd18e, 0xff, 0xd18f }; + +	int i = 0; + +	for (byte *p = s; *p; p++) { +		if (*p < 128) { +			tmp[i++] = *p; +		} else { +			int j; +			for (j = 0; trans[j]; j += 2) { +				if (trans[j] == *p) { +					tmp[i++] = (trans[j + 1] >> 8) & 0xff; +					tmp[i++] = trans[j + 1] & 0xff; +					break; +				} +			} + +			assert(trans[j]); +		} +	} + +	tmp[i] = 0; + +	return tmp; +} + +} // End of namespace Fullpipe diff --git a/engines/fullpipe/utils.h b/engines/fullpipe/utils.h new file mode 100644 index 0000000000..76a1ae944c --- /dev/null +++ b/engines/fullpipe/utils.h @@ -0,0 +1,154 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef FULLPIPE_UTILS_H +#define FULLPIPE_UTILS_H + +#include "common/hash-str.h" +#include "common/array.h" +#include "common/file.h" + +namespace Fullpipe { + +class CObject; +class NGIArchive; + +typedef Common::HashMap<Common::String, int, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo> ClassMap; + +class MfcArchive : public Common::SeekableReadStream { +	ClassMap _classMap; +	Common::Array<CObject *> _objectMap; +	Common::Array<int> _objectIdMap; + +	int _lastIndex; +	int _level; + +	Common::SeekableReadStream *_stream; + + public: +	MfcArchive(Common::SeekableReadStream *file); + +	char *readPascalString(bool twoByte = false); +	int readCount(); +	double readDouble(); +	CObject *parseClass(bool *isCopyReturned); +	CObject *readClass(); + +	void incLevel() { _level++; } +	void decLevel() { _level--; } +	int getLevel() { return _level; } + +	virtual bool eos() const { return _stream->eos(); } +	virtual uint32 read(void *dataPtr, uint32 dataSize) { return _stream->read(dataPtr, dataSize); } +	virtual int32 pos() const { return _stream->pos(); } +	virtual int32 size() const { return _stream->size(); } +	virtual bool seek(int32 offset, int whence = SEEK_SET) { return _stream->seek(offset, whence); } +}; + +enum ObjType { +	kObjTypeDefault, +	kObjTypeObjstateCommand, +	kObjTypeStaticANIObject, +	kObjTypePictureObject +}; + +class CObject { + public: +	ObjType _objtype; + +	CObject() : _objtype(kObjTypeDefault) {} +	virtual bool load(MfcArchive &in) { return true; } +	virtual ~CObject() {} + +	bool loadFile(const char *fname); +}; + +class CObList : public Common::List<CObject *>, public CObject { + public: +	virtual bool load(MfcArchive &file); +}; + +class MemoryObject : CObject { +	friend class Picture; +	friend class Scene; + + protected: +	char *_memfilename; +	int _mfield_8; +	int _mfield_C; +	int _mfield_10; +	char _mfield_14; +	char _mfield_15; +	char _mfield_16; +	char _mfield_17; +	byte *_data; +	int _dataSize; +	int _mflags; +	NGIArchive *_libHandle; + + public: +	MemoryObject(); +	virtual ~MemoryObject(); + +	virtual bool load(MfcArchive &file); +	void loadFile(char *filename); +	void load() { loadFile(_memfilename); } +	byte *getData(); +	byte *loadData(); + +	bool testFlags(); + +	void freeData(); +}; + +class MemoryObject2 : public MemoryObject { +	friend class Picture; + + protected: +	byte **_rows; + + public: +	MemoryObject2(); +	virtual ~MemoryObject2(); +	virtual bool load(MfcArchive &file); + +	void copyData(byte *src, int dataSize); +}; + +class CObArray : public Common::Array<CObject>, public CObject { + public: +	virtual bool load(MfcArchive &file); +}; + +class CDWordArray : public Common::Array<int32>, public CObject { + public: +	virtual bool load(MfcArchive &file); +}; + +typedef Common::Array<void *> CPtrList; + +char *genFileName(int superId, int sceneId, const char *ext); +byte *transCyrillic(byte *s); + +} // End of namespace Fullpipe + +#endif /* FULLPIPE_UTILS_H */ diff --git a/engines/plugins_table.h b/engines/plugins_table.h index edc94eb0d3..ee7713bb76 100644 --- a/engines/plugins_table.h +++ b/engines/plugins_table.h @@ -29,6 +29,9 @@ LINK_PLUGIN(DRASCULA)  #if PLUGIN_ENABLED_STATIC(DREAMWEB)  LINK_PLUGIN(DREAMWEB)  #endif +#if PLUGIN_ENABLED_STATIC(FULLPIPE) +LINK_PLUGIN(FULLPIPE) +#endif  #if PLUGIN_ENABLED_STATIC(GOB)  LINK_PLUGIN(GOB)  #endif | 
