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 "made/made.h"
24 #include "made/console.h"
25 #include "made/pmvplayer.h"
26 #include "made/resource.h"
27 #include "made/screen.h"
28 #include "made/database.h"
29 #include "made/script.h"
30 #include "made/music.h"
31
32 #include "common/config-manager.h"
33 #include "common/events.h"
34 #include "common/system.h"
35 #include "common/error.h"
36
37 #include "engines/util.h"
38
39 #include "backends/audiocd/audiocd.h"
40
41 namespace Made {
42
43 struct GameSettings {
44 const char *gameid;
45 const char *description;
46 byte id;
47 uint32 features;
48 const char *detectname;
49 };
50
51 static const GameSettings madeSettings[] = {
52 {"made", "Made game", 0, 0, 0},
53
54 {NULL, NULL, 0, 0, NULL}
55 };
56
MadeEngine(OSystem * syst,const MadeGameDescription * gameDesc)57 MadeEngine::MadeEngine(OSystem *syst, const MadeGameDescription *gameDesc) : Engine(syst), _gameDescription(gameDesc) {
58
59 _eventNum = 0;
60 _eventMouseX = _eventMouseY = 0;
61 _eventKey = 0;
62 _autoStopSound = false;
63 _soundEnergyIndex = 0;
64 _soundEnergyArray = 0;
65 _musicBeatStart = 0;
66 _cdTimeStart = 0;
67
68 _rnd = new Common::RandomSource("made");
69
70 _console = new MadeConsole(this);
71
72 _system->getAudioCDManager()->open();
73
74 _pmvPlayer = new PmvPlayer(this, _mixer);
75 _res = new ResourceReader();
76 _screen = new Screen(this);
77
78 if (getGameID() == GID_LGOP2 || getGameID() == GID_MANHOLE || getGameID() == GID_RODNEY) {
79 _dat = new GameDatabaseV2(this);
80 } else if (getGameID() == GID_RTZ) {
81 _dat = new GameDatabaseV3(this);
82 } else {
83 error("Unknown GameID");
84 }
85
86 _script = new ScriptInterpreter(this);
87
88 _music = nullptr;
89
90 _soundRate = 0;
91
92 // Set default sound frequency
93 switch (getGameID()) {
94 case GID_RODNEY:
95 _soundRate = 11025;
96 break;
97 case GID_MANHOLE:
98 _soundRate = 11025;
99 break;
100 case GID_LGOP2:
101 _soundRate = 8000;
102 break;
103 case GID_RTZ:
104 // Return to Zork sets it itself via a script funtion
105 break;
106 }
107 }
108
~MadeEngine()109 MadeEngine::~MadeEngine() {
110 _system->getAudioCDManager()->stop();
111
112 delete _rnd;
113 delete _console;
114 delete _pmvPlayer;
115 delete _res;
116 delete _screen;
117 delete _dat;
118 delete _script;
119 delete _music;
120 }
121
syncSoundSettings()122 void MadeEngine::syncSoundSettings() {
123 Engine::syncSoundSettings();
124
125 bool mute = false;
126 if (ConfMan.hasKey("mute"))
127 mute = ConfMan.getBool("mute");
128
129 _music->setVolume(mute ? 0 : ConfMan.getInt("music_volume"));
130 _mixer->setVolumeForSoundType(Audio::Mixer::kPlainSoundType,
131 mute ? 0 : ConfMan.getInt("sfx_volume"));
132 }
133
getTicks()134 int16 MadeEngine::getTicks() {
135 return g_system->getMillis() * 30 / 1000;
136 }
137
getDebugger()138 GUI::Debugger *MadeEngine::getDebugger() {
139 return _console;
140 }
141
getTimer(int16 timerNum)142 int16 MadeEngine::getTimer(int16 timerNum) {
143 if (timerNum > 0 && timerNum <= ARRAYSIZE(_timers) && _timers[timerNum - 1] != -1)
144 return (getTicks() - _timers[timerNum - 1]);
145 else
146 return 32000;
147 }
148
setTimer(int16 timerNum,int16 value)149 void MadeEngine::setTimer(int16 timerNum, int16 value) {
150 if (timerNum > 0 && timerNum <= ARRAYSIZE(_timers))
151 _timers[timerNum - 1] = value;
152 }
153
resetTimer(int16 timerNum)154 void MadeEngine::resetTimer(int16 timerNum) {
155 if (timerNum > 0 && timerNum <= ARRAYSIZE(_timers))
156 _timers[timerNum - 1] = getTicks();
157 }
158
allocTimer()159 int16 MadeEngine::allocTimer() {
160 for (int i = 0; i < ARRAYSIZE(_timers); i++) {
161 if (_timers[i] == -1) {
162 _timers[i] = getTicks();
163 return i + 1;
164 }
165 }
166 return 0;
167 }
168
freeTimer(int16 timerNum)169 void MadeEngine::freeTimer(int16 timerNum) {
170 if (timerNum > 0 && timerNum <= ARRAYSIZE(_timers))
171 _timers[timerNum - 1] = -1;
172 }
173
resetAllTimers()174 void MadeEngine::resetAllTimers() {
175 for (int i = 0; i < ARRAYSIZE(_timers); i++)
176 _timers[i] = -1;
177 }
178
getSavegameFilename(int16 saveNum)179 Common::String MadeEngine::getSavegameFilename(int16 saveNum) {
180 return Common::String::format("%s.%03d", getTargetName().c_str(), saveNum);
181 }
182
handleEvents()183 void MadeEngine::handleEvents() {
184
185 Common::Event event;
186 Common::EventManager *eventMan = _system->getEventManager();
187
188 // NOTE: Don't reset _eventNum to 0 here or no events will get through to the scripts.
189
190 while (eventMan->pollEvent(event)) {
191 switch (event.type) {
192
193 case Common::EVENT_MOUSEMOVE:
194 _eventMouseX = event.mouse.x;
195 _eventMouseY = event.mouse.y;
196 break;
197
198 case Common::EVENT_LBUTTONDOWN:
199 _eventNum = 2;
200 break;
201
202 case Common::EVENT_LBUTTONUP:
203 _eventNum = 1;
204 break;
205
206 case Common::EVENT_RBUTTONDOWN:
207 _eventNum = 4;
208 break;
209
210 case Common::EVENT_RBUTTONUP:
211 _eventNum = 3;
212 break;
213
214 case Common::EVENT_KEYDOWN:
215 // Handle any special keys here
216 // Supported keys taken from http://www.allgame.com/game.php?id=13542&tab=controls
217
218 switch (event.kbd.keycode) {
219 case Common::KEYCODE_KP_PLUS: // action (same as left mouse click)
220 _eventNum = 1; // left mouse button up
221 break;
222 case Common::KEYCODE_KP_MINUS: // inventory (same as right mouse click)
223 _eventNum = 3; // right mouse button up
224 break;
225 case Common::KEYCODE_UP:
226 case Common::KEYCODE_KP8:
227 _eventMouseY = MAX<int16>(0, _eventMouseY - 1);
228 g_system->warpMouse(_eventMouseX, _eventMouseY);
229 break;
230 case Common::KEYCODE_DOWN:
231 case Common::KEYCODE_KP2:
232 _eventMouseY = MIN<int16>(199, _eventMouseY + 1);
233 g_system->warpMouse(_eventMouseX, _eventMouseY);
234 break;
235 case Common::KEYCODE_LEFT:
236 case Common::KEYCODE_KP4:
237 _eventMouseX = MAX<int16>(0, _eventMouseX - 1);
238 g_system->warpMouse(_eventMouseX, _eventMouseY);
239 break;
240 case Common::KEYCODE_RIGHT:
241 case Common::KEYCODE_KP6:
242 _eventMouseX = MIN<int16>(319, _eventMouseX + 1);
243 g_system->warpMouse(_eventMouseX, _eventMouseY);
244 break;
245 case Common::KEYCODE_F1: // menu
246 case Common::KEYCODE_F2: // save game
247 case Common::KEYCODE_F3: // load game
248 case Common::KEYCODE_F4: // repeat last message
249 _eventNum = 5;
250 _eventKey = (event.kbd.keycode - Common::KEYCODE_F1) + 21;
251 break;
252 case Common::KEYCODE_BACKSPACE:
253 _eventNum = 5;
254 _eventKey = 9;
255 break;
256 default:
257 _eventNum = 5;
258 _eventKey = event.kbd.ascii;
259 break;
260 }
261
262 // Check for Debugger Activation
263 if (event.kbd.hasFlags(Common::KBD_CTRL) && event.kbd.keycode == Common::KEYCODE_d) {
264 this->getDebugger()->attach();
265 this->getDebugger()->onFrame();
266 }
267 break;
268
269 default:
270 break;
271
272 }
273 }
274
275 _system->getAudioCDManager()->update();
276
277 }
278
run()279 Common::Error MadeEngine::run() {
280 _music = new MusicPlayer(getGameID() == GID_RTZ);
281 syncSoundSettings();
282
283 // Initialize backend
284 initGraphics(320, 200);
285
286 resetAllTimers();
287
288 if (getGameID() == GID_RTZ) {
289 if (getFeatures() & GF_DEMO) {
290 _dat->open("demo.dat");
291 _res->open("demo.prj");
292 } else if (getFeatures() & GF_CD) {
293 _dat->open("rtzcd.dat");
294 _res->open("rtzcd.prj");
295 } else if (getFeatures() & GF_CD_COMPRESSED) {
296 _dat->openFromRed("rtzcd.red", "rtzcd.dat");
297 _res->open("rtzcd.prj");
298 } else if (getFeatures() & GF_FLOPPY) {
299 _dat->open("rtz.dat");
300 _res->open("rtz.prj");
301 } else {
302 error("Unknown RTZ game features");
303 }
304 } else if (getGameID() == GID_MANHOLE) {
305 _dat->open("manhole.dat");
306
307 if (getVersion() == 2) {
308 _res->open("manhole.prj");
309 } else {
310 _res->openResourceBlocks();
311 }
312 } else if (getGameID() == GID_LGOP2) {
313 _dat->open("lgop2.dat");
314 _res->open("lgop2.prj");
315 } else if (getGameID() == GID_RODNEY) {
316 _dat->open("rodneys.dat");
317 _res->open("rodneys.prj");
318 } else {
319 error ("Unknown MADE game");
320 }
321
322 if ((getFeatures() & GF_CD) || (getFeatures() & GF_CD_COMPRESSED))
323 checkCD();
324
325 _autoStopSound = false;
326 _eventNum = _eventKey = _eventMouseX = _eventMouseY = 0;
327
328 #ifdef DUMP_SCRIPTS
329 _script->dumpAllScripts();
330 #else
331 _screen->setDefaultMouseCursor();
332 _script->runScript(_dat->getMainCodeObjectIndex());
333 #endif
334
335 return Common::kNoError;
336 }
337
338 } // End of namespace Made
339