1 /* ScummVM - Graphic Adventure Engine
2  *
3  * ScummVM is the legal property of its developers, whose names
4  * are too numerous to list here. Please refer to the COPYRIGHT
5  * file distributed with this source distribution.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20  *
21  */
22 
23 #include "base/plugins.h"
24 
25 #include "engines/advancedDetector.h"
26 #include "common/file.h"
27 
28 #include "neverhood/neverhood.h"
29 #include "neverhood/detection.h"
30 
31 namespace Neverhood {
32 
getGameId() const33 const char *NeverhoodEngine::getGameId() const {
34 	return _gameDescription->gameId;
35 }
36 
getPlatform() const37 Common::Platform NeverhoodEngine::getPlatform() const {
38 	return _gameDescription->platform;
39 }
40 
getLanguage() const41 Common::Language NeverhoodEngine::getLanguage() const {
42 	return _gameDescription->language;
43 }
44 
isDemo() const45 bool NeverhoodEngine::isDemo() const {
46 	return _gameDescription->flags & ADGF_DEMO;
47 }
48 
isBigDemo() const49 bool NeverhoodEngine::isBigDemo() const {
50 	return _gameDescription->flags & GF_BIG_DEMO;
51 }
52 
applyResourceFixes() const53 bool NeverhoodEngine::applyResourceFixes() const {
54 	return getLanguage() == Common::RU_RUS;
55 }
56 
57 } // End of namespace Neverhood
58 
59 class NeverhoodMetaEngine : public AdvancedMetaEngine {
60 public:
getName() const61 	const char *getName() const override {
62 		return "neverhood";
63 	}
64 
65 	bool hasFeature(MetaEngineFeature f) const override;
66 	Common::Error createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const override;
67 
68 	SaveStateList listSaves(const char *target) const override;
69 	int getMaximumSaveSlot() const override;
70 	void removeSaveState(const char *target, int slot) const override;
71 	SaveStateDescriptor querySaveMetaInfos(const char *target, int slot) const override;
72 };
73 
hasFeature(MetaEngineFeature f) const74 bool NeverhoodMetaEngine::hasFeature(MetaEngineFeature f) const {
75 	return
76 		(f == kSupportsListSaves) ||
77 		(f == kSupportsLoadingDuringStartup) ||
78 		(f == kSupportsDeleteSave) ||
79 		(f == kSavesSupportMetaInfo) ||
80 		(f == kSavesSupportThumbnail) ||
81 		(f == kSavesSupportCreationDate) ||
82 		(f == kSavesSupportPlayTime) ||
83 		(f == kSimpleSavesNames);
84 }
85 
hasFeature(EngineFeature f) const86 bool Neverhood::NeverhoodEngine::hasFeature(EngineFeature f) const {
87 	return
88 		(f == kSupportsReturnToLauncher) ||
89 		(f == kSupportsLoadingDuringRuntime) ||
90 		(f == kSupportsSavingDuringRuntime);
91 }
92 
createInstance(OSystem * syst,Engine ** engine,const ADGameDescription * desc) const93 Common::Error NeverhoodMetaEngine::createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const {
94 	*engine = new Neverhood::NeverhoodEngine(syst, desc);
95 	return Common::kNoError;
96 }
97 
listSaves(const char * target) const98 SaveStateList NeverhoodMetaEngine::listSaves(const char *target) const {
99 	Common::SaveFileManager *saveFileMan = g_system->getSavefileManager();
100 	Neverhood::NeverhoodEngine::SaveHeader header;
101 	Common::String pattern = target;
102 	pattern += ".###";
103 
104 	Common::StringArray filenames;
105 	filenames = saveFileMan->listSavefiles(pattern.c_str());
106 
107 	SaveStateList saveList;
108 	for (Common::StringArray::const_iterator file = filenames.begin(); file != filenames.end(); file++) {
109 		// Obtain the last 3 digits of the filename, since they correspond to the save slot
110 		int slotNum = atoi(file->c_str() + file->size() - 3);
111 		if (slotNum >= 0 && slotNum <= 999) {
112 			Common::InSaveFile *in = saveFileMan->openForLoading(file->c_str());
113 			if (in) {
114 				if (Neverhood::NeverhoodEngine::readSaveHeader(in, header) == Neverhood::NeverhoodEngine::kRSHENoError) {
115 					saveList.push_back(SaveStateDescriptor(this, slotNum, header.description));
116 				}
117 				delete in;
118 			}
119 		}
120 	}
121 
122 	// Sort saves based on slot number.
123 	Common::sort(saveList.begin(), saveList.end(), SaveStateDescriptorSlotComparator());
124 	return saveList;
125 }
126 
getMaximumSaveSlot() const127 int NeverhoodMetaEngine::getMaximumSaveSlot() const {
128 	return 999;
129 }
130 
removeSaveState(const char * target,int slot) const131 void NeverhoodMetaEngine::removeSaveState(const char *target, int slot) const {
132 	Common::SaveFileManager *saveFileMan = g_system->getSavefileManager();
133 	Common::String filename = Neverhood::NeverhoodEngine::getSavegameFilename(target, slot);
134 	saveFileMan->removeSavefile(filename.c_str());
135 }
136 
querySaveMetaInfos(const char * target,int slot) const137 SaveStateDescriptor NeverhoodMetaEngine::querySaveMetaInfos(const char *target, int slot) const {
138 	Common::String filename = Neverhood::NeverhoodEngine::getSavegameFilename(target, slot);
139 	Common::InSaveFile *in = g_system->getSavefileManager()->openForLoading(filename.c_str());
140 
141 	if (in) {
142 		Neverhood::NeverhoodEngine::SaveHeader header;
143 		Neverhood::NeverhoodEngine::kReadSaveHeaderError error;
144 
145 		error = Neverhood::NeverhoodEngine::readSaveHeader(in, header, false);
146 		delete in;
147 
148 		if (error == Neverhood::NeverhoodEngine::kRSHENoError) {
149 			SaveStateDescriptor desc(this, slot, header.description);
150 
151 			desc.setThumbnail(header.thumbnail);
152 			int day = (header.saveDate >> 24) & 0xFF;
153 			int month = (header.saveDate >> 16) & 0xFF;
154 			int year = header.saveDate & 0xFFFF;
155 			desc.setSaveDate(year, month, day);
156 			int hour = (header.saveTime >> 16) & 0xFF;
157 			int minutes = (header.saveTime >> 8) & 0xFF;
158 			desc.setSaveTime(hour, minutes);
159 			desc.setPlayTime(header.playTime * 1000);
160 			return desc;
161 		}
162 	}
163 
164 	return SaveStateDescriptor();
165 }
166 
167 #if PLUGIN_ENABLED_DYNAMIC(NEVERHOOD)
168 	REGISTER_PLUGIN_DYNAMIC(NEVERHOOD, PLUGIN_TYPE_ENGINE, NeverhoodMetaEngine);
169 #else
170 	REGISTER_PLUGIN_STATIC(NEVERHOOD, PLUGIN_TYPE_ENGINE, NeverhoodMetaEngine);
171 #endif
172