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 "neverhood/console.h"
24 #include "gui/debugger.h"
25 #include "neverhood/neverhood.h"
26 #include "neverhood/gamemodule.h"
27 #include "neverhood/navigationscene.h"
28 #include "neverhood/scene.h"
29 #include "neverhood/smackerscene.h"
30 #include "neverhood/sound.h"
31 #include "neverhood/modules/module1600.h"
32 #include "neverhood/modules/module3000_sprites.h"
33
34 namespace Neverhood {
35
Console(NeverhoodEngine * vm)36 Console::Console(NeverhoodEngine *vm) : GUI::Debugger(), _vm(vm) {
37 registerCmd("cheat", WRAP_METHOD(Console, Cmd_Cheat));
38 registerCmd("checkresource", WRAP_METHOD(Console, Cmd_CheckResource));
39 registerCmd("dumpresource", WRAP_METHOD(Console, Cmd_DumpResource));
40 registerCmd("dumpvars", WRAP_METHOD(Console, Cmd_Dumpvars));
41 registerCmd("playsound", WRAP_METHOD(Console, Cmd_PlaySound));
42 registerCmd("scene", WRAP_METHOD(Console, Cmd_Scene));
43 registerCmd("surfaces", WRAP_METHOD(Console, Cmd_Surfaces));
44 }
45
~Console()46 Console::~Console() {
47 }
48
Cmd_Scene(int argc,const char ** argv)49 bool Console::Cmd_Scene(int argc, const char **argv) {
50 if (argc != 3) {
51 int currentModule = _vm->_gameModule->getCurrentModuleNum();
52 int previousModule = _vm->_gameModule->getPreviousModuleNum();
53 int scenenNum = _vm->gameState().sceneNum;
54 SceneType sceneType = ((GameModule *)_vm->_gameModule->_childObject)->getSceneType();
55
56 const char *sceneTypes[] = { "normal", "smacker", "navigation" };
57
58 debugPrintf("Current module: %d, previous module: %d, scene %d (%s scene)\n", currentModule, previousModule, scenenNum, sceneTypes[sceneType]);
59
60 if (sceneType == kSceneTypeNormal) {
61 Scene *scene = (Scene *)((GameModule *)_vm->_gameModule->_childObject)->_childObject;
62 // Normal scenes have a background and a cursor file hash
63 debugPrintf("Background hash: 0x%x, cursor hash: 0x%x\n", scene->getBackgroundFileHash(), scene->getCursorFileHash());
64 } else if (sceneType == kSceneTypeSmacker) {
65 SmackerScene *scene = (SmackerScene *)((GameModule *)_vm->_gameModule->_childObject)->_childObject;
66 // Smacker scenes have a file hash, or a list of hashes
67 // TODO: Only the first file hash is shown - any additional hashes, found in
68 // scenes with a list of hashes (two scenes in module 1100 and the making of
69 // video) aren't shown yet
70 debugPrintf("File hash: 0x%x\n", scene->getSmackerFileHash());
71 } else if (sceneType == kSceneTypeNavigation) {
72 NavigationScene *scene = (NavigationScene *)((GameModule *)_vm->_gameModule->_childObject)->_childObject;
73 // Navigation scenes have a navigation list and its index
74 NavigationList *navigationList = _vm->_staticData->getNavigationList(scene->getNavigationListId());
75 int navigationIndex = scene->getGlobalVar(V_NAVIGATION_INDEX);
76 NavigationItem curNavigation = (*navigationList)[navigationIndex];
77 debugPrintf("Navigation list ID: 0x%x, index: %d\n", scene->getNavigationListId(), navigationIndex);
78 debugPrintf("File hash: 0x%x, cursor hash: 0x%x, Smacker hashes: [left: 0x%x, middle: 0x%x, right: 0x%x\n",
79 curNavigation.fileHash, curNavigation.mouseCursorFileHash,
80 curNavigation.leftSmackerFileHash, curNavigation.middleSmackerFileHash, curNavigation.rightSmackerFileHash);
81 }
82
83 debugPrintf("Use %s <module> <scene> to change scenes\n", argv[0]);
84 debugPrintf("Modules are incremental by 100, from 1000 to 3000\n");
85 } else {
86 int newModule = atoi(argv[1]);
87 int newScene = atoi(argv[2]);
88
89 _vm->gameState().sceneNum = newScene;
90 _vm->_gameModule->createModule(newModule, -1);
91 }
92
93 return true;
94 }
95
Cmd_Surfaces(int argc,const char ** argv)96 bool Console::Cmd_Surfaces(int argc, const char **argv) {
97 if (_vm->_gameModule->_childObject) {
98 ((Scene *)((GameModule *)_vm->_gameModule->_childObject)->_childObject)->printSurfaces(this);
99 }
100 return true;
101 }
102
Cmd_Cheat(int argc,const char ** argv)103 bool Console::Cmd_Cheat(int argc, const char **argv) {
104 if (argc < 2) {
105 debugPrintf("Cheats for various puzzles in the game\n");
106 debugPrintf("Use %s <cheatname> to use a cheat.\n", argv[0]);
107 debugPrintf("Cheats:\n-------\n");
108 debugPrintf(" buttons - enables all 3 buttons on the door in the purple building, module 3000, scene 9\n");
109 debugPrintf(" cannon - sets the correct cannon combination in module 3000, scene 8\n");
110 debugPrintf(" dice - shows the correct dice combination in the teddy bear puzzle, module 1100, scene 6\n");
111 debugPrintf(" memory - solves the memory puzzle, module 1400, scene 4\n");
112 debugPrintf(" music - shows the correct index in the radio music puzzle, module 2800, scene 1\n");
113 debugPrintf(" radio - enables the radio, module 3000, scene 9 - same as pulling the rightmost cord in the flytrap room\n");
114 debugPrintf(" symbols - solves the symbols puzzle, module 1600, scene 8. Only available in that room\n");
115 debugPrintf(" tubes - shows the correct test tube combination in module 2800, scenes 7 and 10\n");
116 return true;
117 }
118
119 Common::String cheatName = argv[1];
120 int moduleNum = _vm->_gameModule->getCurrentModuleNum();
121 int sceneNum = _vm->gameState().sceneNum;
122
123 if (cheatName == "buttons") {
124 Scene *scene = (Scene *)((GameModule *)_vm->_gameModule->_childObject)->_childObject;
125
126 scene->setSubVar(VA_LOCKS_DISABLED, 0x304008D2, 1); // kScene3010ButtonNameHashes[0]
127 scene->setSubVar(VA_LOCKS_DISABLED, 0x40119852, 1); // kScene3010ButtonNameHashes[1]
128 scene->setSubVar(VA_LOCKS_DISABLED, 0x01180951, 1); // kScene3010ButtonNameHashes[2]
129
130 debugPrintf("All 3 door buttons have been enabled\n");
131 } else if (cheatName == "cannon") {
132 Scene *scene = (Scene *)((GameModule *)_vm->_gameModule->_childObject)->_childObject;
133
134 for (int i = 0; i < 3; i++)
135 scene->setSubVar(VA_CURR_CANNON_SYMBOLS, i, scene->getSubVar(VA_GOOD_CANNON_SYMBOLS_1, i));
136
137 for (int i = 3; i < 6; i++)
138 scene->setSubVar(VA_CURR_CANNON_SYMBOLS, i, scene->getSubVar(VA_GOOD_CANNON_SYMBOLS_2, i - 3));
139
140 debugPrintf("Puzzle solved\n");
141 } else if (cheatName == "dice") {
142 Scene *scene = (Scene *)((GameModule *)_vm->_gameModule->_childObject)->_childObject;
143 debugPrintf("Good: (%d %d %d), current: (%d %d %d)\n",
144 scene->getSubVar(VA_GOOD_DICE_NUMBERS, 0), scene->getSubVar(VA_GOOD_DICE_NUMBERS, 1), scene->getSubVar(VA_GOOD_DICE_NUMBERS, 2),
145 scene->getSubVar(VA_CURR_DICE_NUMBERS, 0), scene->getSubVar(VA_CURR_DICE_NUMBERS, 1), scene->getSubVar(VA_CURR_DICE_NUMBERS, 2)
146 );
147 } else if (cheatName == "memory") {
148 Scene *scene = (Scene *)((GameModule *)_vm->_gameModule->_childObject)->_childObject;
149
150 // Autosolve all tiles and leave only two matching tiles closed
151 for (int i = 0; i < 48; i++)
152 scene->setSubVar(VA_IS_TILE_MATCH, i, 1);
153
154 // Close the top left tile
155 scene->setSubVar(VA_IS_TILE_MATCH, 0, 0);
156
157 // Find and close the pair of the top left tile
158 for (int i = 0; i < 48; i++) {
159 if (i != 0 && scene->getSubVar(VA_TILE_SYMBOLS, i) == scene->getSubVar(VA_TILE_SYMBOLS, 0)) {
160 scene->setSubVar(VA_IS_TILE_MATCH, i, 0);
161 break;
162 }
163 }
164
165 debugPrintf("Puzzle solved\n");
166 } else if (cheatName == "music") {
167 Scene *scene = (Scene *)((GameModule *)_vm->_gameModule->_childObject)->_childObject;
168 debugPrintf("Good music index: %d, current radio music index: %d\n", scene->getGlobalVar(V_CURR_RADIO_MUSIC_INDEX), scene->getGlobalVar(V_GOOD_RADIO_MUSIC_INDEX));
169 } else if (cheatName == "radio") {
170 Scene *scene = (Scene *)((GameModule *)_vm->_gameModule->_childObject)->_childObject;
171 scene->setGlobalVar(V_RADIO_ENABLED, 1);
172
173 debugPrintf("The radio has been enabled\n");
174 } else if (cheatName == "symbols") {
175 if (moduleNum == 1600 && sceneNum == 8) {
176 Scene1609 *scene = ((Scene1609 *)((Module1600 *)_vm->_gameModule->_childObject)->_childObject);
177
178 for (int index = 0; index < 12; index++) {
179 scene->_asSymbols[index]->change((int)scene->getSubVar(VA_CODE_SYMBOLS, index) + 12, index == (int)scene->getSubVar(VA_CODE_SYMBOLS, scene->_noisySymbolIndex));
180 }
181
182 scene->_changeCurrentSymbol = false;
183 scene->_symbolPosition = 11;
184 scene->_countdown1 = 36;
185
186 debugPrintf("Puzzle solved\n");
187 } else {
188 debugPrintf("Only available in module 1600, scene 8\n");
189 }
190 } else if (cheatName == "tubes") {
191 Scene *scene = (Scene *)((GameModule *)_vm->_gameModule->_childObject)->_childObject;
192 debugPrintf("Tube set 1: %d %d %d\n", scene->getSubVar(VA_GOOD_TEST_TUBES_LEVEL_1, 0), scene->getSubVar(VA_GOOD_TEST_TUBES_LEVEL_1, 1), scene->getSubVar(VA_GOOD_TEST_TUBES_LEVEL_1, 2));
193 debugPrintf("Tube set 2: %d %d %d\n", scene->getSubVar(VA_GOOD_TEST_TUBES_LEVEL_2, 0), scene->getSubVar(VA_GOOD_TEST_TUBES_LEVEL_2, 1), scene->getSubVar(VA_GOOD_TEST_TUBES_LEVEL_2, 2));
194 }
195
196 return true;
197 }
198
Cmd_Dumpvars(int argc,const char ** argv)199 bool Console::Cmd_Dumpvars(int argc, const char **argv) {
200 _vm->_gameVars->dumpVars(this);
201
202 return true;
203 }
204
Cmd_PlaySound(int argc,const char ** argv)205 bool Console::Cmd_PlaySound(int argc, const char **argv) {
206 if (argc < 2) {
207 debugPrintf("Usage: %s <sound hash>\n", argv[0]);
208 } else {
209 uint32 soundHash = strtol(argv[1], NULL, 0);
210 AudioResourceManSoundItem *soundItem = new AudioResourceManSoundItem(_vm, soundHash);
211 soundItem->setVolume(100);
212 soundItem->playSound(false);
213 while (soundItem->isPlaying()) {
214 _vm->_system->delayMillis(10);
215 }
216 delete soundItem;
217 }
218
219 return true;
220 }
221
Cmd_CheckResource(int argc,const char ** argv)222 bool Console::Cmd_CheckResource(int argc, const char **argv) {
223 const char *resourceNames[] = { "unknown", "unknown", "bitmap", "palette", "animation", "data", "text", "sound", "music", "unknown", "video" };
224
225 if (argc < 2) {
226 debugPrintf("Gets information about a resource\n");
227 debugPrintf("Usage: %s <resource hash>\n", argv[0]);
228 } else {
229 uint32 resourceHash = strtol(argv[1], NULL, 0);
230 ResourceHandle handle;
231
232 _vm->_res->queryResource(resourceHash, handle);
233 if (!handle.isValid()) {
234 debugPrintf("Invalid resource hash\n");
235 } else {
236 debugPrintf("Resource type: %d (%s). Size: %d bytes\n", handle.type(), resourceNames[handle.type()], handle.size());
237 }
238 }
239
240 return true;
241 }
242
Cmd_DumpResource(int argc,const char ** argv)243 bool Console::Cmd_DumpResource(int argc, const char **argv) {
244 if (argc < 3) {
245 debugPrintf("Dumps a resource to disk\n");
246 debugPrintf("Usage: %s <resource hash> <output file>\n", argv[0]);
247 } else {
248 uint32 resourceHash = strtol(argv[1], NULL, 0);
249 const char *outFileName = argv[2];
250 ResourceHandle handle;
251
252 _vm->_res->queryResource(resourceHash, handle);
253 if (!handle.isValid()) {
254 debugPrintf("Invalid resource hash\n");
255 } else {
256 _vm->_res->loadResource(handle, _vm->applyResourceFixes());
257 Common::DumpFile outFile;
258 outFile.open(outFileName);
259 outFile.write(handle.data(), handle.size());
260 outFile.finalize();
261 outFile.close();
262 _vm->_res->unloadResource(handle);
263 }
264 }
265
266 return true;
267 }
268
269 } // End of namespace Neverhood
270