/* ScummVM - Graphic Adventure Engine * * ScummVM is the legal property of its developers, whose names * are too numerous to list here. Please refer to the COPYRIGHT * file distributed with this source distribution. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * */ #include "twine/debugger/debug.h" #include "common/system.h" #include "twine/debugger/debug_grid.h" #include "twine/debugger/debug_scene.h" #include "twine/menu/interface.h" #include "twine/menu/menu.h" #include "twine/renderer/redraw.h" #include "twine/renderer/screens.h" #include "twine/scene/scene.h" #include "twine/scene/grid.h" #include "twine/text.h" #include "twine/twine.h" namespace TwinE { void Debug::debugFillButton(int32 x, int32 y, int32 width, int32 height, int8 color) { const Common::Rect rect(x, y, x + width, y + height); _engine->_interface->drawFilledRect(rect, color); } void Debug::debugDrawButton(const Common::Rect &rect, const char *text, int32 textLeft, int32 textTop, int32 isActive, int8 color) { debugFillButton(rect.left + 1, rect.top + 1, rect.right - rect.left - 1, rect.bottom - rect.top - 1, color); _engine->_menu->drawRectBorders(rect); _engine->drawText(textLeft, textTop, text, 0); _engine->copyBlockPhys(rect); } void Debug::debugDrawWindowButtons(int32 w) { DebugWindowStruct &window = _debugWindows[w]; for (int32 b = 0; b < window.numButtons; b++) { DebugButtonStruct &btn = window.debugButtons[b]; const char *text = btn.text; const int32 textLeft = btn.textLeft; const int32 textTop = btn.textTop; const int32 isActive = btn.isActive; int8 color = btn.color; if (isActive > 0) { color = btn.activeColor; } debugDrawButton(btn.rect, text, textLeft, textTop, isActive, color); } } void Debug::debugDrawWindow(int32 w) { DebugWindowStruct &window = _debugWindows[w]; const Common::Rect &rect = window.rect; const int32 alpha = window.alpha; _engine->_interface->drawTransparentBox(rect, alpha); _engine->_menu->drawRectBorders(rect); if (window.numLines > 0) { for (int32 l = 0; l < window.numLines; l++) { _engine->drawText(rect.left + 10, rect.top + l * 20 + 5, window.text[l], 0); } } debugDrawWindowButtons(w); } int32 Debug::debugTypeUseMenu(int32 type) { for (int32 w = 0; w < _numDebugWindows; w++) { DebugWindowStruct &window = _debugWindows[w]; if (window.isActive <= 0) { continue; } for (int32 b = 0; b < window.numButtons; b++) { DebugButtonStruct &btn = window.debugButtons[b]; if (btn.type != type) { continue; } const int submenu = btn.submenu; if (submenu > 0) { _debugWindows[submenu].isActive = !_debugWindows[submenu].isActive; } return submenu; } } return 0; } void Debug::debugResetButtonsState() { for (int32 w = 0; w < _numDebugWindows; w++) { DebugWindowStruct &window = _debugWindows[w]; if (window.isActive <= 0) { continue; } for (int32 b = 0; b < window.numButtons; b++) { DebugButtonStruct &btn = window.debugButtons[b]; if (btn.type > -1) { continue; } btn.isActive = 0; } } } void Debug::debugRefreshButtons(int32 type) { for (int32 w = 0; w < _numDebugWindows; w++) { DebugWindowStruct &window = _debugWindows[w]; if (window.isActive <= 0) { continue; } for (int32 b = 0; b < window.numButtons; b++) { DebugButtonStruct &btn = window.debugButtons[b]; if (btn.type != type) { continue; } const char *text = btn.text; const int32 textLeft = btn.textLeft; const int32 textTop = btn.textTop; int8 color = btn.color; const int32 isActive = btn.isActive = !btn.isActive; if (isActive > 0) { color = btn.activeColor; } debugDrawButton(btn.rect, text, textLeft, textTop, isActive, color); if (btn.submenu && isActive > 0) { debugDrawWindow(btn.submenu); } } } } void Debug::debugDrawWindows() { for (int32 w = 0; w < _numDebugWindows; w++) { DebugWindowStruct &window = _debugWindows[w]; if (window.isActive > 0) { debugDrawWindow(w); } } } void Debug::debugResetButton(int32 type) { for (int32 w = 0; w < _numDebugWindows; w++) { DebugWindowStruct &window = _debugWindows[w]; if (window.isActive <= 0) { continue; } for (int32 b = 0; b < window.numButtons; b++) { DebugButtonStruct &btn = window.debugButtons[b]; if (btn.type != type) { continue; } const int submenu = btn.submenu; btn.isActive = 0; if (submenu > 0) { _debugWindows[submenu].debugButtons[b].isActive = !_debugWindows[submenu].debugButtons[b].isActive; } break; } } } void Debug::debugRedrawScreen() { _engine->_redraw->redrawEngineActions(true); _engine->saveFrontBuffer(); debugDrawWindows(); } int32 Debug::debugGetActionsState(int32 type) { int32 state = 0; switch (type) { case FREE_CAMERA: state = _engine->_debugGrid->_useFreeCamera ? 1 : 0; break; case CHANGE_SCENE: state = _engine->_debugGrid->_canChangeScenes ? 1 : 0; break; case SHOW_ZONES: state = _engine->_debugScene->_showingZones ? 1 : 0; break; case SHOW_ZONE_CUBE: case SHOW_ZONE_CAMERA: case SHOW_ZONE_SCENARIC: case SHOW_ZONE_CELLINGGRID: case SHOW_ZONE_OBJECT: case SHOW_ZONE_TEXT: case SHOW_ZONE_LADDER: state = _engine->_debugScene->_typeZones; break; default: break; } return state; } void Debug::debugSetActions(int32 type) { switch (type) { case FREE_CAMERA: _engine->_debugGrid->_useFreeCamera = !_engine->_debugGrid->_useFreeCamera; break; case CHANGE_SCENE: _engine->_debugGrid->_canChangeScenes = !_engine->_debugGrid->_canChangeScenes; break; case SHOW_ZONES: _engine->_debugScene->_showingZones = !_engine->_debugScene->_showingZones; debugResetButton(-1); debugResetButton(-2); debugRedrawScreen(); break; case SHOW_ZONE_CUBE: if (_engine->_debugScene->_showingZones) { if (_engine->_debugScene->_typeZones & 0x01) _engine->_debugScene->_typeZones &= ~0x01; else _engine->_debugScene->_typeZones |= 0x01; debugRedrawScreen(); } break; case SHOW_ZONE_CAMERA: if (_engine->_debugScene->_showingZones) { if (_engine->_debugScene->_typeZones & 0x02) _engine->_debugScene->_typeZones &= ~0x02; else _engine->_debugScene->_typeZones |= 0x02; debugRedrawScreen(); } break; case SHOW_ZONE_SCENARIC: if (_engine->_debugScene->_showingZones) { if (_engine->_debugScene->_typeZones & 0x04) _engine->_debugScene->_typeZones &= ~0x04; else _engine->_debugScene->_typeZones |= 0x04; debugRedrawScreen(); } break; case SHOW_ZONE_CELLINGGRID: if (_engine->_debugScene->_showingZones) { if (_engine->_debugScene->_typeZones & 0x08) _engine->_debugScene->_typeZones &= ~0x08; else _engine->_debugScene->_typeZones |= 0x08; debugRedrawScreen(); debugRedrawScreen(); } break; case SHOW_ZONE_OBJECT: if (_engine->_debugScene->_showingZones) { if (_engine->_debugScene->_typeZones & 0x10) _engine->_debugScene->_typeZones &= ~0x10; else _engine->_debugScene->_typeZones |= 0x10; debugRedrawScreen(); debugRedrawScreen(); } break; case SHOW_ZONE_TEXT: if (_engine->_debugScene->_showingZones) { if (_engine->_debugScene->_typeZones & 0x20) _engine->_debugScene->_typeZones &= ~0x20; else _engine->_debugScene->_typeZones |= 0x20; debugRedrawScreen(); } break; case SHOW_ZONE_LADDER: if (_engine->_debugScene->_showingZones) { if (_engine->_debugScene->_typeZones & 0x40) _engine->_debugScene->_typeZones &= ~0x40; else _engine->_debugScene->_typeZones |= 0x40; debugRedrawScreen(); } break; case -1: debugResetButton(-2); debugRedrawScreen(); break; case -2: debugResetButton(-1); debugRedrawScreen(); break; default: break; } } void Debug::debugAddButton(int32 window, const Common::Rect &rect, const char *text, int32 textLeft, int32 textTop, int32 isActive, int32 color, int32 activeColor, int32 submenu, int32 type) { const int32 button = _debugWindows[window].numButtons; DebugButtonStruct &btn = _debugWindows[window].debugButtons[button]; btn.rect = rect; btn.text = text; btn.textLeft = textLeft; btn.textTop = textTop; btn.isActive = debugGetActionsState(type); btn.color = color; btn.activeColor = activeColor; btn.submenu = submenu; btn.type = type; _debugWindows[window].numButtons++; } void Debug::debugAddWindowText(int32 window, const char *text) { int32 line = _debugWindows[window].numLines; _debugWindows[window].text[line] = text; _debugWindows[window].numLines++; } void Debug::debugAddWindow(const Common::Rect &rect, int32 alpha, int32 isActive) { _debugWindows[_numDebugWindows].rect = rect; _debugWindows[_numDebugWindows].alpha = alpha; _debugWindows[_numDebugWindows].numButtons = 0; _debugWindows[_numDebugWindows].isActive = isActive; _numDebugWindows++; } void Debug::debugLeftMenu() { // left menu window debugAddWindow(Common::Rect(5, 60, 200, 474), 4, 1); debugAddButton(0, Common::Rect(5, 55, 160, 75), "Use free camera", 30, 60, 0, 87, 119, NO_MENU, FREE_CAMERA); debugAddButton(0, Common::Rect(161, 55, 200, 75), "info", 171, 60, 0, 87, 119, FREE_CAMERA_INFO_MENU, -1); debugAddButton(0, Common::Rect(5, 76, 160, 96), "Change scenes", 30, 81, 0, 87, 119, NO_MENU, CHANGE_SCENE); debugAddButton(0, Common::Rect(161, 76, 200, 96), "info", 171, 81, 0, 87, 119, CHANGE_SCENE_INFO_MENU, -2); debugAddButton(0, Common::Rect(5, 97, 200, 117), "Show celling grids", 30, 102, 0, 87, 119, NO_MENU, 3); debugAddButton(0, Common::Rect(5, 118, 200, 138), "Show zones", 30, 123, 0, 87, 119, ZONES_MENU, SHOW_ZONES); // add submenu windows // - free camera window debugAddWindow(Common::Rect(205, 55, 634, 160), 4, 0); debugAddWindowText(FREE_CAMERA_INFO_MENU, "When enable, use the following keys to browse through the scenes:"); debugAddWindowText(FREE_CAMERA_INFO_MENU, " - S to go North"); debugAddWindowText(FREE_CAMERA_INFO_MENU, " - X to go South"); debugAddWindowText(FREE_CAMERA_INFO_MENU, " - Z to go West"); debugAddWindowText(FREE_CAMERA_INFO_MENU, " - C to go East"); // - change scene window debugAddWindow(Common::Rect(205, 55, 634, 137), 4, 0); debugAddWindowText(CHANGE_SCENE_INFO_MENU, "When enable, use the following keys to change to another scene:"); debugAddWindowText(CHANGE_SCENE_INFO_MENU, " - R to go Next Scene"); debugAddWindowText(CHANGE_SCENE_INFO_MENU, " - F to go Previous Scene"); // - zones window debugAddWindow(Common::Rect(205, 55, 634, 97), 4, 0); debugAddWindowText(ZONES_MENU, "You can enable or disable each zone type:"); debugAddButton(ZONES_MENU, Common::Rect(205, 118, 350, 138), "Cube Zones", 215, 123, 1, 87, 119, 0, SHOW_ZONE_CUBE); debugAddButton(ZONES_MENU, Common::Rect(205, 139, 350, 159), "Camera Zones", 215, 144, 2, 87, 119, 0, SHOW_ZONE_CAMERA); debugAddButton(ZONES_MENU, Common::Rect(205, 160, 350, 180), "Scenaric Zones", 215, 165, 3, 87, 119, 0, SHOW_ZONE_SCENARIC); debugAddButton(ZONES_MENU, Common::Rect(205, 181, 350, 201), "Celling Grid Zones", 215, 186, 4, 87, 119, 0, SHOW_ZONE_CELLINGGRID); debugAddButton(ZONES_MENU, Common::Rect(205, 202, 350, 222), "Object Zones", 215, 207, 5, 87, 119, 0, SHOW_ZONE_OBJECT); debugAddButton(ZONES_MENU, Common::Rect(205, 223, 350, 243), "Text Zones", 215, 228, 6, 87, 119, 0, SHOW_ZONE_TEXT); debugAddButton(ZONES_MENU, Common::Rect(205, 244, 350, 264), "Ladder Zones", 215, 249, 7, 87, 119, 0, SHOW_ZONE_LADDER); } int32 Debug::debugProcessButton(int32 x, int32 y) { for (int32 i = 0; i < _numDebugWindows; i++) { for (int32 j = 0; j < _debugWindows[i].numButtons; j++) { const Common::Rect &rect = _debugWindows[i].debugButtons[j].rect; if (rect.contains(x, y)) { return _debugWindows[i].debugButtons[j].type; } } } return 0; } void Debug::debugPlasmaWindow(const char *text, int32 color) { _engine->_menu->processPlasmaEffect(Common::Rect(0, 0, PLASMA_WIDTH, PLASMA_HEIGHT), color); const int32 textSize = _engine->_text->getTextSize(text); _engine->_text->drawText((_engine->width() / 2) - (textSize / 2), 10, text); const Common::Rect rect(5, 5, _engine->width() - 5, 50); _engine->_menu->drawRectBorders(rect); _engine->copyBlockPhys(rect); } void Debug::debugProcessWindow() { if (!_engine->_input->toggleActionIfActive(TwinEActionType::DebugMenu)) { return; } const char *text = "Game Debug Window"; int32 colorIdx = 4; int32 count = 0; ScopedCursor cursor(_engine); _engine->saveFrontBuffer(); debugResetButtonsState(); if (_numDebugWindows == 0) { debugLeftMenu(); } debugDrawWindows(); for (;;) { FrameMarker frame(_engine, 25); _engine->readKeys(); if (_engine->shouldQuit()) { break; } const Common::Point &point = _engine->_input->getMousePositions(); if (_engine->_input->toggleActionIfActive(TwinEActionType::DebugMenuActivate)) { int type = 0; if ((type = debugProcessButton(point.x, point.y)) != NO_ACTION) { // process menu item if (debugTypeUseMenu(type)) { _engine->restoreFrontBuffer(); _engine->copyBlockPhys(205, 55, 634, 474); } debugRefreshButtons(type); debugSetActions(type); } } // draw window plasma effect if (count == 256) { colorIdx++; count = 0; } int32 color = colorIdx * 16; if (color >= 240) { color = 64; colorIdx = 4; } debugPlasmaWindow(text, color); if (_engine->_input->toggleActionIfActive(TwinEActionType::DebugMenu)) { break; } count++; } _engine->_redraw->_firstTime = true; } void Debug::processDebug() { if (!_engine->_cfgfile.Debug) { return; } Input *input = _engine->_input; if (input->isActionActive(TwinEActionType::DebugPlaceActorAtCenterOfScreen)) { ActorStruct *actor = _engine->_scene->getActor(OWN_ACTOR_SCENE_INDEX); actor->_pos = _engine->_grid->_camera; actor->_pos.y += 1000; } debugProcessWindow(); _engine->_debugGrid->changeGrid(); _engine->_debugGrid->changeGridCamera(); _engine->_debugGrid->applyCellingGrid(); } } // namespace TwinE