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 "scummvm_file.h"
24 #include "common/config-manager.h"
25 #include "common/language.h"
26 
27 namespace Lua {
28 
LuaFileProxy(const Common::String & filename,const Common::String & mode)29 LuaFileProxy::LuaFileProxy(const Common::String &filename, const Common::String &mode) : _readPos(0) {
30 	assert(filename.contains("config.lua"));
31 	if (mode == "r")
32 		setupConfigFile();
33 }
34 
formatDouble(double value)35 Common::String LuaFileProxy::formatDouble(double value) {
36 	// This is a bit hackish. The point of it is that it's important that
37 	// we ignore the locale decimal mark and force it to be a point. If it
38 	// would happen to be a comma instead, it seems that it's seen as two
39 	// comma-separated integers rather than one floating-point value. Or
40 	// something like that.
41 
42 	bool negative = value < 0.0;
43 	value = fabs(value);
44 	double integerPart = floor(value);
45 	double fractionalPart = (value - integerPart) * 1000000.0;
46 
47 	return Common::String::format("%s%.0f.%.0f", negative ? "-" : "", integerPart, fractionalPart);
48 }
49 
setupConfigFile()50 void LuaFileProxy::setupConfigFile() {
51 	double sfxVolume = !ConfMan.hasKey("sfx_volume") ? 1.0 : 1.0 * ConfMan.getInt("sfx_volume") / 255.0;
52 	double musicVolume = !ConfMan.hasKey("music_volume") ? 0.5 : 1.0 * ConfMan.getInt("music_volume") / 255.0;
53 	double speechVolume = !ConfMan.hasKey("speech_volume") ? 1.0 : 1.0 * ConfMan.getInt("speech_volume") / 255.0;
54 	bool subtitles = !ConfMan.hasKey("subtitles") ? true : ConfMan.getBool("subtitles");
55 
56 	_readData = Common::String::format(
57 "GAME_LANGUAGE = \"%s\"\r\n\
58 GAME_SUBTITLES = %s\r\n\
59 MAX_MEMORY_USAGE = 256000000\r\n\
60 GFX_VSYNC_ACTIVE = true\r\n\
61 SFX_SAMPLING_RATE = 44100\r\n\
62 SFX_CHANNEL_COUNT = 32\r\n\
63 SFX_SOUND_VOLUME = %s\r\n\
64 SFX_MUSIC_VOLUME = %s\r\n\
65 SFX_SPEECH_VOLUME = %s\r\n",
66 		getLanguage().c_str(), subtitles ? "true" : "false",
67 		formatDouble(sfxVolume).c_str(),
68 		formatDouble(musicVolume).c_str(),
69 		formatDouble(speechVolume).c_str());
70 
71 	_readPos = 0;
72 }
73 
~LuaFileProxy()74 LuaFileProxy::~LuaFileProxy() {
75 	if (!_settings.empty())
76 		writeSettings();
77 }
78 
read(void * ptr,size_t size,size_t count)79 size_t LuaFileProxy::read(void *ptr, size_t size, size_t count) {
80 	size_t bytesRead = MIN<size_t>(_readData.size() - _readPos, size * count);
81 	memmove(ptr, &_readData.c_str()[_readPos], bytesRead);
82 	_readPos += bytesRead;
83 	return bytesRead / size;
84 }
85 
write(const char * ptr,size_t count)86 size_t LuaFileProxy::write(const char *ptr, size_t count) {
87 	// Loop through the provided line(s)
88 	while (*ptr) {
89 		if ((*ptr == '-') && (*(ptr + 1) == '-')) {
90 			// Comment line to skip over
91 			while ((*ptr != '\r') && (*ptr != '\n'))
92 				++ptr;
93 		} else {
94 			// Legitimate data
95 			const char *p = strchr(ptr, '\n');
96 			if (!p) p = ptr + strlen(ptr);
97 			while ((*p == '\r') || (*p == '\n'))
98 				++p;
99 
100 			_settings += Common::String(ptr, p - ptr);
101 			ptr = p;
102 		}
103 
104 		while ((*ptr == '\r') || (*ptr == '\n'))
105 			++ptr;
106 	}
107 
108 	return count;
109 }
110 
writeSettings()111 void LuaFileProxy::writeSettings() {
112 	// Loop through the setting lines
113 	const char *pSrc = _settings.c_str();
114 	while (*pSrc) {
115 		if ((*pSrc != '\r') && (*pSrc != '\n')) {
116 			const char *p = strchr(pSrc, '=');
117 			assert(p);
118 
119 			// Get the setting name
120 			const char *pEnd = p - 1;
121 			while (*pEnd == ' ')
122 				--pEnd;
123 			Common::String settingName(pSrc, pEnd - pSrc + 1);
124 
125 			// Get the setting value
126 			const char *pStart = p + 1;
127 			while (*pStart == ' ')
128 				++pStart;
129 
130 			pEnd = pStart + 1;
131 			while ((*pEnd != '\r') && (*pEnd != '\n') && (*pEnd != '\0'))
132 				++pEnd;
133 			Common::String value(pStart + (*pStart == '"' ? 1 : 0), pEnd - pStart - (*pStart == '"' ? 2 : 0));
134 
135 			// Update the setting
136 			updateSetting(settingName, value);
137 			pSrc = pEnd;
138 		}
139 
140 		// Move to next line
141 		while ((*pSrc == '\r') || (*pSrc == '\n'))
142 			++pSrc;
143 	}
144 
145 	ConfMan.flushToDisk();
146 }
147 
updateSetting(const Common::String & setting,const Common::String & value)148 void LuaFileProxy::updateSetting(const Common::String &setting, const Common::String &value) {
149 	if (setting == "GAME_LANGUAGE")
150 		setLanguage(value);
151 	else if (setting == "GAME_SUBTITLES")
152 		ConfMan.setBool("subtitles", value == "true");
153 	else if (setting == "SFX_SOUND_VOLUME") {
154 		double v = strtod(value.c_str(), NULL);
155 		ConfMan.setInt("sfx_volume", (int)(v * 255));
156 	} else if (setting == "SFX_MUSIC_VOLUME") {
157 		double v = strtod(value.c_str(), NULL);
158 		ConfMan.setInt("music_volume", (int)(v * 255));
159 	} else if (setting == "SFX_SPEECH_VOLUME") {
160 		double v = strtod(value.c_str(), NULL);
161 		ConfMan.setInt("speech_volume", (int)(v * 255));
162 	} else {
163 		// All other settings are ignored
164 	}
165 }
166 
167 /**
168  * Get the language code used by the game for each language it supports
169  */
getLanguage()170 Common::String LuaFileProxy::getLanguage() {
171 	Common::Language lang = Common::parseLanguage(ConfMan.get("language"));
172 	switch (lang) {
173 	case Common::EN_ANY:
174 		return "en";
175 	case Common::DE_DEU:
176 		return "de";
177 	case Common::ES_ESP:
178 		return "es";
179 	case Common::FR_FRA:
180 		return "fr";
181 	case Common::HU_HUN:
182 		return "hu";
183 	case Common::IT_ITA:
184 		return "it";
185 	case Common::PL_POL:
186 		return "pl";
187 	case Common::PT_BRA:
188 		return "pt";
189 	case Common::RU_RUS:
190 		return "ru";
191 	default:
192 		error("Unknown language '%s' encountered", ConfMan.get("language").c_str());
193 		break;
194 	}
195 }
196 
197 /**
198  * Set the language code fro the game
199  */
setLanguage(const Common::String & lang)200 void LuaFileProxy::setLanguage(const Common::String &lang) {
201 	if (lang == "en")
202 		ConfMan.set("language", Common::getLanguageCode(Common::EN_ANY));
203 	else if (lang == "de")
204 		ConfMan.set("language", Common::getLanguageCode(Common::DE_DEU));
205 	else if (lang == "es")
206 		ConfMan.set("language", Common::getLanguageCode(Common::ES_ESP));
207 	else if (lang == "fr")
208 		ConfMan.set("language", Common::getLanguageCode(Common::FR_FRA));
209 	else if (lang == "hu")
210 		ConfMan.set("language", Common::getLanguageCode(Common::HU_HUN));
211 	else if (lang == "it")
212 		ConfMan.set("language", Common::getLanguageCode(Common::IT_ITA));
213 	else if (lang == "pl")
214 		ConfMan.set("language", Common::getLanguageCode(Common::PL_POL));
215 	else if (lang == "pt")
216 		ConfMan.set("language", Common::getLanguageCode(Common::PT_BRA));
217 	else if (lang == "ru")
218 		ConfMan.set("language", Common::getLanguageCode(Common::RU_RUS));
219 	else
220 		error("Unknown language encountered");
221 }
222 
223 } // End of namespace Lua
224