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  * CD/drive handling functions
22  */
23 
24 #include "common/textconsole.h"
25 #include "tinsel/drives.h"
26 #include "tinsel/scene.h"
27 #include "tinsel/tinsel.h"
28 #include "tinsel/sched.h"
29 #include "tinsel/strres.h"
30 
31 namespace Tinsel {
32 
33 // FIXME: Avoid non-const global vars
34 
35 char g_currentCD = '1';
36 
37 static bool g_bChangingCD = false;
38 static char g_nextCD = '\0';
39 
40 static uint32 g_lastTime = 0;
41 extern LANGUAGE g_sampleLanguage;
42 
43 
CdCD(CORO_PARAM)44 void CdCD(CORO_PARAM) {
45 	CORO_BEGIN_CONTEXT;
46 	CORO_END_CONTEXT(_ctx);
47 
48 	CORO_BEGIN_CODE(_ctx);
49 
50 	while (g_bChangingCD) {
51 		if (CoroScheduler.getCurrentProcess()) {
52 			// FIXME: CdCD gets passed a Common::nullContext in RegisterGlobals() and
53 			//        PrimeSceneHopper(), because I didn't know how to get a proper
54 			//        context without converting the whole calling stack to CORO'd
55 			//        functions. If these functions really get called while a CD
56 			//        change is requested, this needs to be resolved.
57 			if (coroParam == Common::nullContext)
58 				error("CdCD needs context");
59 			CORO_SLEEP(1);
60 		} else
61 			error("No current process in CdCD()");
62 	}
63 
64 	CORO_END_CODE;
65 }
66 
GetCurrentCD()67 int GetCurrentCD() {
68 	// count from 1
69 	return (g_currentCD - '1' + 1);
70 }
71 
72 static const uint32 cdFlags[] = { fCd1, fCd2, fCd3, fCd4, fCd5, fCd6, fCd7, fCd8 };
73 
SetCD(int flags)74 void SetCD(int flags) {
75 	if (flags & cdFlags[g_currentCD - '1'])
76 		return;
77 
78 	error("SetCD() problem");
79 }
80 
GetCD(int flags)81 int GetCD(int flags) {
82 	int i;
83 	char cd = '\0';
84 
85 	if (flags & cdFlags[g_currentCD - '1'])
86 		return GetCurrentCD();
87 
88 	for (i = 0; i < 8; i++) {
89 		if (flags & cdFlags[i]) {
90 			cd = (char)(i + '1');
91 			break;
92 		}
93 	}
94 	assert(i != 8);
95 
96 	g_nextCD = cd;
97 	return cd;
98 }
99 
DoCdChange()100 void DoCdChange() {
101 	if (g_bChangingCD && (g_system->getMillis() > (g_lastTime + 1000))) {
102 		g_lastTime = g_system->getMillis();
103 		_vm->_sound->closeSampleStream();
104 
105 		// Use the filesize of the sample file to determine, for Discworld 2, which CD it is
106 		if (TinselV2) {
107 			TinselFile f;
108 			if (!f.open(_vm->getSampleFile(g_sampleLanguage)))
109 				// No CD present
110 				return;
111 
112 			char sampleCdNumber = (f.size() >= (200 * 1024 * 1024)) ? '1' : '2';
113 
114 			f.close();
115 
116 			if (g_currentCD != sampleCdNumber)
117 				return;
118 		}
119 
120 		_vm->_sound->openSampleFiles();
121 		ChangeLanguage(TextLanguage());
122 		g_bChangingCD = false;
123 	}
124 }
125 
SetNextCD(int cdNumber)126 void SetNextCD(int cdNumber) {
127 	assert(cdNumber == 1 || cdNumber == 2);
128 
129 	g_nextCD = (char)(cdNumber + '1' - 1);
130 }
131 
GotoCD()132 bool GotoCD() {
133 	// WORKAROUND: Somehow, CdDoChange() is called twice... Hopefully, this guard helps
134 	if (g_currentCD == g_nextCD)
135 		return false;
136 
137 	g_currentCD = g_nextCD;
138 
139 /*	if (bNoCD)	{
140 		strcpy(cdDirectory, hdDirectory);
141 		cdLastBit[3] = currentCD;
142 		strcat(cdDirectory, cdLastBit);
143 	}
144 */
145 	g_bChangingCD = true;
146 
147 	return true;
148 }
149 
150 bool TinselFile::_warningShown = false;
151 
TinselFile()152 TinselFile::TinselFile() : ReadStreamEndian(TinselV1Mac) {
153 	_stream = NULL;
154 }
155 
~TinselFile()156 TinselFile::~TinselFile() {
157 	delete _stream;
158 }
159 
openInternal(const Common::String & filename)160 bool TinselFile::openInternal(const Common::String &filename) {
161 	_stream = SearchMan.createReadStreamForMember(filename);
162 	if (!_stream)
163 		_stream = SearchMan.createReadStreamForMember(filename + ".");
164 	return _stream != 0;
165 }
166 
open(const Common::String & filename)167 bool TinselFile::open(const Common::String &filename) {
168 	if (openInternal(filename))
169 		return true;
170 
171 	if (!TinselV2)
172 		return false;
173 
174 	// Check if the file being requested is the *1.* or *2.* files
175 	const char *fname = filename.c_str();
176 	const char *p = strchr(fname, '1');
177 	if (!p)
178 		p = strchr(fname, '2');
179 	if (!p || (*(p + 1) != '.'))
180 		return false;
181 
182 	// Form a filename without the CD number character
183 	char newFilename[50];
184 	strncpy(newFilename, fname, p - fname);
185 	strcpy(newFilename + (p - fname), p + 1);
186 
187 	return openInternal(newFilename);
188 }
189 
close()190 void TinselFile::close() {
191 	delete _stream;
192 	_stream = NULL;
193 }
194 
pos() const195 int32 TinselFile::pos() const {
196 	assert(_stream);
197 	return _stream->pos();
198 }
199 
size() const200 int32 TinselFile::size() const {
201 	assert(_stream);
202 	return _stream->size();
203 }
204 
seek(int32 offset,int whence)205 bool TinselFile::seek(int32 offset, int whence) {
206 	assert(_stream);
207 	return _stream->seek(offset, whence);
208 }
209 
eos() const210 bool TinselFile::eos() const {
211 	assert(_stream);
212 	return _stream->eos();
213 }
214 
err() const215 bool TinselFile::err() const {
216 	assert(_stream);
217 	return _stream->err();
218 }
219 
clearErr()220 void TinselFile::clearErr() {
221 	assert(_stream);
222 	_stream->clearErr();
223 }
224 
read(void * dataPtr,uint32 dataSize)225 uint32 TinselFile::read(void *dataPtr, uint32 dataSize) {
226 	assert(_stream);
227 	return _stream->read(dataPtr, dataSize);
228 }
229 
230 
231 
232 
233 } // End of namespace Tinsel
234