diff --git a/desktop_version/CMakeLists.txt b/desktop_version/CMakeLists.txt index b2dfbf8d..41ec3396 100644 --- a/desktop_version/CMakeLists.txt +++ b/desktop_version/CMakeLists.txt @@ -84,6 +84,7 @@ set(VVV_SRC src/Input.cpp src/KeyPoll.cpp src/Labclass.cpp + src/LevelDebugger.cpp src/Localization.cpp src/LocalizationMaint.cpp src/LocalizationStorage.cpp diff --git a/desktop_version/src/Game.cpp b/desktop_version/src/Game.cpp index 552cb059..df506186 100644 --- a/desktop_version/src/Game.cpp +++ b/desktop_version/src/Game.cpp @@ -17,6 +17,7 @@ #include "Font.h" #include "GlitchrunnerMode.h" #include "Graphics.h" +#include "LevelDebugger.h" #include "Localization.h" #include "LocalizationStorage.h" #include "KeyPoll.h" @@ -7491,7 +7492,7 @@ int Game::get_timestep(void) bool Game::physics_frozen(void) { - return roomname_translator::is_pausing(); + return roomname_translator::is_pausing() || level_debugger::is_pausing(); } bool Game::incompetitive(void) diff --git a/desktop_version/src/Input.cpp b/desktop_version/src/Input.cpp index 55c8064e..dcb29828 100644 --- a/desktop_version/src/Input.cpp +++ b/desktop_version/src/Input.cpp @@ -13,6 +13,7 @@ #include "Graphics.h" #include "GraphicsUtil.h" #include "KeyPoll.h" +#include "LevelDebugger.h" #include "Localization.h" #include "LocalizationMaint.h" #include "LocalizationStorage.h" @@ -2436,6 +2437,12 @@ void gameinput(void) } } + level_debugger::input(); + if (level_debugger::is_pausing()) + { + return; + } + game.press_map = false; if (key.isDown(KEYBOARD_ENTER) || key.isDown(SDLK_KP_ENTER) || key.isDown(game.controllerButton_map) ) { diff --git a/desktop_version/src/LevelDebugger.cpp b/desktop_version/src/LevelDebugger.cpp new file mode 100644 index 00000000..b8f902b8 --- /dev/null +++ b/desktop_version/src/LevelDebugger.cpp @@ -0,0 +1,306 @@ +#include "LevelDebugger.h" + +#include "Constants.h" +#include "Entity.h" +#include "Font.h" +#include "Graphics.h" +#include "KeyPoll.h" +#include "Localization.h" +#include "Map.h" +#include "UtilityClass.h" +#include "VFormat.h" + +namespace level_debugger +{ + bool active = false; + bool should_pause = true; + bool tab_held = false; + bool debug_held = false; + + // Moving entities/blocks + bool mouse_held = false; + int held_entity = -1; + int held_block = -1; + int grabber_offset_x = 0; + int grabber_offset_y = 0; + + bool is_pausing(void) + { + return active && should_pause; + } + + bool is_active(void) + { + return active; + } + + void toggle_active(void) + { + active = !active; + } + + bool mouse_within(SDL_Rect* rect) + { + return key.mx >= rect->x && key.mx < rect->x + rect->w && + key.my >= rect->y && key.my < rect->y + rect->h; + } + + void input(void) + { + if (!map.custommode || map.custommodeforreal) + { + active = false; + return; + } + + if (key.isDown(SDLK_y)) + { + if (!debug_held) + { + debug_held = true; + active = !active; + } + } + else + { + debug_held = false; + } + + if (!active) + { + return; + } + + if (key.isDown(SDLK_TAB)) + { + if (!tab_held) + { + tab_held = true; + should_pause = !should_pause; + } + } + else + { + tab_held = false; + } + + for (int i = 0; i < obj.entities.size(); i++) + { + SDL_Rect bounding_box = { + obj.entities[i].xp + obj.entities[i].cx, + obj.entities[i].yp + obj.entities[i].cy, + obj.entities[i].w, + obj.entities[i].h + }; + + if (key.leftbutton) + { + if (mouse_within(&bounding_box)) + { + if (!mouse_held) + { + mouse_held = true; + held_entity = i; + grabber_offset_x = key.mx - obj.entities[i].xp; + grabber_offset_y = key.my - obj.entities[i].yp; + + if (!key.keymap[SDLK_LSHIFT] && !key.keymap[SDLK_RSHIFT]) + { + for (int j = 0; j < obj.blocks.size(); j++) + { + if (obj.entities[i].xp == obj.blocks[j].rect.x && obj.entities[i].yp == obj.blocks[j].rect.y) + { + held_block = j; + } + } + } + } + break; + } + } + else + { + mouse_held = false; + held_entity = -1; + held_block = -1; + } + } + + if (held_entity == -1) + { + for (int i = 0; i < obj.blocks.size(); i++) + { + SDL_Rect bounding_box = { + obj.blocks[i].rect.x, + obj.blocks[i].rect.y, + obj.blocks[i].rect.w, + obj.blocks[i].rect.h + }; + + if (key.leftbutton) + { + if (mouse_within(&bounding_box)) + { + if (!mouse_held) + { + mouse_held = true; + held_block = i; + grabber_offset_x = key.mx - obj.blocks[i].rect.x; + grabber_offset_y = key.my - obj.blocks[i].rect.y; + } + break; + } + } + else + { + held_entity = -1; + mouse_held = false; + held_block = -1; + } + } + } + + if (INBOUNDS_VEC(held_entity, obj.entities)) + { + obj.entities[held_entity].xp = key.mx - grabber_offset_x; + obj.entities[held_entity].yp = key.my - grabber_offset_y; + + if (key.isDown(SDLK_LSHIFT) || key.isDown(SDLK_RSHIFT)) + { + obj.entities[held_entity].xp -= obj.entities[held_entity].xp % 8; + obj.entities[held_entity].yp -= obj.entities[held_entity].yp % 8; + } + } + + if (INBOUNDS_VEC(held_block, obj.blocks)) + { + int new_xp = key.mx - grabber_offset_x; + int new_yp = key.my - grabber_offset_y; + + if (key.isDown(SDLK_LSHIFT) || key.isDown(SDLK_RSHIFT)) + { + new_xp -= new_xp % 8; + new_yp -= new_yp % 8; + } + + obj.blocks[held_block].xp = new_xp; + obj.blocks[held_block].yp = new_yp; + obj.blocks[held_block].rect.x = new_xp; + obj.blocks[held_block].rect.y = new_yp; + } + } + + void render_info(int y, const char* text, const char* value) + { + char buffer[SCREEN_WIDTH_CHARS + 1]; + vformat_buf(buffer, sizeof(buffer), text, "value:str", value); + font::print(PR_BOR | PR_FONT_8X8, 5, 32 + (10 * y), buffer, 220 - (help.glow), 220 - (help.glow), 255 - (help.glow / 2)); + } + + void render(void) + { + if (!active) + { + return; + } + + int hovered = -1; + bool hovered_entity = true; + SDL_Rect hover_box; + + for (int i = 0; i < obj.entities.size(); i++) + { + SDL_Rect bounding_box = { + obj.entities[i].xp + obj.entities[i].cx, + obj.entities[i].yp + obj.entities[i].cy, + obj.entities[i].w, + obj.entities[i].h + }; + + bool hovering = false; + + if (hovered == -1 && mouse_within(&bounding_box)) + { + hovering = true; + hovered = i; + hovered_entity = true; + hover_box = bounding_box; + } + + graphics.draw_rect(bounding_box.x, bounding_box.y, bounding_box.w, bounding_box.h, graphics.getRGB(15, 90, 90)); + } + + for (int i = 0; i < obj.blocks.size(); i++) + { + SDL_Rect bounding_box = { + obj.blocks[i].rect.x, + obj.blocks[i].rect.y, + obj.blocks[i].rect.w, + obj.blocks[i].rect.h + }; + + bool hovering = false; + + if (hovered == -1 && mouse_within(&bounding_box)) + { + hovering = true; + hovered = i; + hovered_entity = false; + hover_box = bounding_box; + } + + graphics.draw_rect(bounding_box.x, bounding_box.y, bounding_box.w, bounding_box.h, graphics.getRGB(90, 15, 15)); + } + + font::print(PR_BOR | PR_FONT_8X8, 5, 14, loc::gettext("[Press TAB to toggle movement]"), 220 - (help.glow), 220 - (help.glow), 255 - (help.glow / 2)); + + if (hovered != -1) + { + int line = 0; + if (hovered_entity) + { + entclass* entity = &obj.entities[hovered]; + render_info(line++, "Index: {value}", help.String(hovered).c_str()); + render_info(line++, "X: {value}", help.String(entity->xp).c_str()); + render_info(line++, "Y: {value}", help.String(entity->yp).c_str()); + render_info(line++, "Width: {value}", help.String(entity->w).c_str()); + render_info(line++, "Height: {value}", help.String(entity->h).c_str()); + line++; + render_info(line++, "Rule: {value}", help.String(entity->rule).c_str()); + render_info(line++, "Type: {value}", help.String(entity->type).c_str()); + render_info(line++, "Behave: {value}", help.String(entity->behave).c_str()); + render_info(line++, "Para: {value}", help.String(entity->para).c_str()); + line++; + render_info(line++, "Tile: {value}", help.String(entity->tile).c_str()); + render_info(line++, "Draw Frame: {value}", help.String(entity->drawframe).c_str()); + render_info(line++, "Size: {value}", help.String(entity->size).c_str()); + render_info(line++, "Direction: {value}", help.String(entity->dir).c_str()); + + graphics.draw_rect(hover_box.x, hover_box.y, hover_box.w, hover_box.h, graphics.getRGB(32, 255 - help.glow, 255 - help.glow)); + } + else + { + blockclass* block = &obj.blocks[hovered]; + render_info(line++, "Index: {value}", help.String(hovered).c_str()); + render_info(line++, "X: {value}", help.String(block->rect.x).c_str()); + render_info(line++, "Y: {value}", help.String(block->rect.y).c_str()); + render_info(line++, "Width: {value}", help.String(block->rect.w).c_str()); + render_info(line++, "Height: {value}", help.String(block->rect.h).c_str()); + + line++; + + if (block->type == TRIGGER || block->type == ACTIVITY) + { + render_info(line++, "Script: {value}", block->script.c_str()); + render_info(line++, "State: {value}", help.String(block->trigger).c_str()); + } + else if (block->type == DIRECTIONAL) + { + render_info(line++, "Direction: {value}", help.String(block->trigger).c_str()); + } + + graphics.draw_rect(hover_box.x, hover_box.y, hover_box.w, hover_box.h, graphics.getRGB(255 - help.glow, 32, 32)); + } + } + } +}; diff --git a/desktop_version/src/LevelDebugger.h b/desktop_version/src/LevelDebugger.h new file mode 100644 index 00000000..8f8b988a --- /dev/null +++ b/desktop_version/src/LevelDebugger.h @@ -0,0 +1,14 @@ +#ifndef LEVELDEBUGGER_H +#define LEVELDEBUGGER_H + +#include + +namespace level_debugger +{ + bool is_pausing(void); + bool is_active(void); + void input(void); + void render(void); +} + +#endif /* LEVELDEBUGGER_H */ diff --git a/desktop_version/src/Render.cpp b/desktop_version/src/Render.cpp index 7c6ca1ce..dc064642 100644 --- a/desktop_version/src/Render.cpp +++ b/desktop_version/src/Render.cpp @@ -14,6 +14,7 @@ #include "GraphicsUtil.h" #include "InterimVersion.h" #include "KeyPoll.h" +#include "LevelDebugger.h" #include "Localization.h" #include "LocalizationStorage.h" #include "MakeAndPlay.h" @@ -2472,6 +2473,7 @@ void gamerender(void) graphics.drawtrophytext(); } + level_debugger::render(); graphics.renderwithscreeneffects(); }