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 "gnap/gnap.h"
24 
25 #include "common/config-manager.h"
26 #include "engines/advancedDetector.h"
27 #include "common/savefile.h"
28 #include "common/system.h"
29 #include "base/plugins.h"
30 #include "graphics/thumbnail.h"
31 
32 static const PlainGameDescriptor gnapGames[] = {
33 	{ "gnap", "Gnap" },
34 	{ 0, 0 }
35 };
36 
37 namespace Gnap {
38 
39 static const ADGameDescription gameDescriptions[] = {
40 	{
41 		"gnap", "",
42 		{
43 			{"stock_n.dat", 0, "46819043d019a2f36b727cc2bdd6980f", 12515823},
44 			AD_LISTEND
45 		},
46 		Common::EN_ANY, Common::kPlatformWindows, ADGF_NO_FLAGS, GUIO0()
47 	},
48 	{
49 		"gnap", "",
50 		{
51 			{"stock_n.dat", 0, "46819043d019a2f36b727cc2bdd6980f", 13497301},
52 			AD_LISTEND
53 		},
54 		Common::EN_ANY, Common::kPlatformWindows, ADGF_NO_FLAGS, GUIO0()
55 	},
56 	{
57 		"gnap", "",
58 		{
59 			{"stock_n.dat", 0, "46819043d019a2f36b727cc2bdd6980f", 12995485},
60 			AD_LISTEND
61 		},
62 		Common::RU_RUS, Common::kPlatformWindows, ADGF_NO_FLAGS, GUIO0()
63 	},
64 	{
65 		"gnap", "Fargus",
66 		{
67 			{"stock_n.dat", 0, "46819043d019a2f36b727cc2bdd6980f", 12847726},
68 			AD_LISTEND
69 		},
70 		Common::RU_RUS, Common::kPlatformWindows, ADGF_NO_FLAGS, GUIO0()
71 	},
72 
73 	AD_TABLE_END_MARKER
74 };
75 
76 } // End of namespace Gnap
77 
78 class GnapMetaEngine : public AdvancedMetaEngine {
79 public:
GnapMetaEngine()80 	GnapMetaEngine() : AdvancedMetaEngine(Gnap::gameDescriptions, sizeof(ADGameDescription), gnapGames) {
81 		_singleId = "gnap";
82 		_maxScanDepth = 3;
83 	}
84 
getName() const85 	virtual const char *getName() const {
86 		return "Gnap";
87 	}
88 
getOriginalCopyright() const89 	virtual const char *getOriginalCopyright() const {
90 		return "Gnap (C) Artech Digital Entertainment 1997";
91 	}
92 
93 	virtual bool hasFeature(MetaEngineFeature f) const;
94 	virtual bool createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const;
95 	virtual int getMaximumSaveSlot() const;
96 	virtual SaveStateList listSaves(const char *target) const;
97 	SaveStateDescriptor querySaveMetaInfos(const char *target, int slot) const;
98 	virtual void removeSaveState(const char *target, int slot) const;
99 };
100 
hasFeature(MetaEngineFeature f) const101 bool GnapMetaEngine::hasFeature(MetaEngineFeature f) const {
102 	return
103 		(f == kSupportsListSaves) ||
104 		(f == kSupportsLoadingDuringStartup) ||
105 		(f == kSupportsDeleteSave) ||
106 		(f == kSavesSupportMetaInfo) ||
107 		(f == kSavesSupportThumbnail) ||
108 		(f == kSavesSupportCreationDate) ||
109 		(f == kSimpleSavesNames);
110 }
111 
hasFeature(EngineFeature f) const112 bool Gnap::GnapEngine::hasFeature(EngineFeature f) const {
113 	return
114 		(f == kSupportsRTL) ||
115 		(f == kSupportsLoadingDuringRuntime) ||
116 		(f == kSupportsSavingDuringRuntime);
117 }
118 
removeSaveState(const char * target,int slot) const119 void GnapMetaEngine::removeSaveState(const char *target, int slot) const {
120 	Common::String fileName = Common::String::format("%s.%03d", target, slot);
121 	g_system->getSavefileManager()->removeSavefile(fileName);
122 }
123 
getMaximumSaveSlot() const124 int GnapMetaEngine::getMaximumSaveSlot() const { return 99; }
125 
listSaves(const char * target) const126 SaveStateList GnapMetaEngine::listSaves(const char *target) const {
127 	Common::SaveFileManager *saveFileMan = g_system->getSavefileManager();
128 	Common::StringArray filenames;
129 	Common::String saveDesc;
130 	Common::String pattern = Common::String::format("%s.0##", target);
131 	Gnap::GnapSavegameHeader header;
132 
133 	filenames = saveFileMan->listSavefiles(pattern);
134 
135 	SaveStateList saveList;
136 	for (Common::StringArray::const_iterator file = filenames.begin(); file != filenames.end(); ++file) {
137 		const char *ext = strrchr(file->c_str(), '.');
138 		int slot = ext ? atoi(ext + 1) : -1;
139 
140 		if (slot >= 0 && slot < getMaximumSaveSlot()) {
141 			Common::InSaveFile *in = g_system->getSavefileManager()->openForLoading(*file);
142 
143 			if (in) {
144 				if (Gnap::GnapEngine::readSavegameHeader(in, header))
145 					saveList.push_back(SaveStateDescriptor(slot, header._saveName));
146 				delete in;
147 			}
148 		}
149 	}
150 
151 	// Sort saves based on slot number.
152 	Common::sort(saveList.begin(), saveList.end(), SaveStateDescriptorSlotComparator());
153 	return saveList;
154 }
155 
querySaveMetaInfos(const char * target,int slot) const156 SaveStateDescriptor GnapMetaEngine::querySaveMetaInfos(const char *target, int slot) const {
157 	Common::String fileName = Common::String::format("%s.%03d", target, slot);
158 	Common::InSaveFile *file = g_system->getSavefileManager()->openForLoading(fileName);
159 	if (file) {
160 		char saveIdentBuffer[5];
161 		file->read(saveIdentBuffer, 5);
162 
163 		int32 version = file->readByte();
164 		if (version > GNAP_SAVEGAME_VERSION) {
165 			delete file;
166 			return SaveStateDescriptor();
167 		}
168 
169 		Common::String saveName;
170 		char ch;
171 		while ((ch = (char)file->readByte()) != '\0')
172 			saveName += ch;
173 
174 		SaveStateDescriptor desc(slot, saveName);
175 
176 		if (version != 1) {
177 			Graphics::Surface *thumbnail;
178 			if (!Graphics::loadThumbnail(*file, thumbnail)) {
179 				delete file;
180 				return SaveStateDescriptor();
181 			}
182 			desc.setThumbnail(thumbnail);
183 		}
184 
185 		int year = file->readSint16LE();
186 		int month = file->readSint16LE();
187 		int day = file->readSint16LE();
188 		int hour = file->readSint16LE();
189 		int minutes = file->readSint16LE();
190 
191 		desc.setSaveDate(year, month, day);
192 		desc.setSaveTime(hour, minutes);
193 
194 		delete file;
195 		return desc;
196 	}
197 
198 	return SaveStateDescriptor();
199 }
200 
createInstance(OSystem * syst,Engine ** engine,const ADGameDescription * desc) const201 bool GnapMetaEngine::createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const {
202 	if (desc) {
203 		*engine = new Gnap::GnapEngine(syst, desc);
204 	}
205 	return desc != 0;
206 }
207 
208 #if PLUGIN_ENABLED_DYNAMIC(GNAP)
209 	REGISTER_PLUGIN_DYNAMIC(GNAP, PLUGIN_TYPE_ENGINE, GnapMetaEngine);
210 #else
211 	REGISTER_PLUGIN_STATIC(GNAP, PLUGIN_TYPE_ENGINE, GnapMetaEngine);
212 #endif
213