1
0
mirror of https://github.com/TerryCavanagh/VVVVVV.git synced 2024-06-25 22:18:30 +02:00
VVVVVV/desktop_version/src/LevelDebugger.cpp
AllyTally 91f87fa126 Add level debugger screen
The level debugger is toggleable in playtesting mode by pressing Y.
You can toggle whether or not the game is paused inside of the debugger
by pressing TAB. The debugger screen allows you to see entity and block
properties, and allows you to move them around.
2023-11-19 17:34:23 -08:00

307 lines
9.7 KiB
C++

#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));
}
}
}
};