You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

322 lines
9.1 KiB

/**
* @file debug.cpp
*
* Implementation of debug functions.
*/
#ifdef _DEBUG
#include <cmath>
#include <cstdint>
#include <cstdio>
#include <ankerl/unordered_dense.h>
#include "debug.h"
#include "automap.h"
#include "cursor.h"
#include "engine/load_cel.hpp"
#include "engine/point.hpp"
#include "lighting.h"
#include "monster.h"
#include "plrmsg.h"
#include "utils/str_case.hpp"
#include "utils/str_cat.hpp"
namespace devilution {
std::string TestMapPath;
OptionalOwnedClxSpriteList pSquareCel;
5 years ago
bool DebugToggle = false;
bool DebugGodMode = false;
bool DebugVision = false;
bool DebugPath = false;
bool DebugGrid = false;
ankerl::unordered_dense::map<int, Point> DebugCoordsMap;
bool DebugScrollViewEnabled = false;
std::string debugTRN;
// Used for debugging level generation
uint32_t glMid1Seed[NUMLEVELS];
uint32_t glMid2Seed[NUMLEVELS];
uint32_t glMid3Seed[NUMLEVELS];
uint32_t glEndSeed[NUMLEVELS];
namespace {
DebugGridTextItem SelectedDebugGridTextItem;
int DebugMonsterId;
std::vector<std::string> SearchMonsters;
std::vector<std::string> SearchItems;
std::vector<std::string> SearchObjects;
void PrintDebugMonster(const Monster &monster)
{
EventPlrMsg(StrCat(
"Monster ", static_cast<int>(monster.getId()), " = ", monster.name(),
"\nX = ", monster.position.tile.x, ", Y = ", monster.position.tile.y,
"\nEnemy = ", monster.enemy, ", HP = ", monster.hitPoints,
"\nMode = ", static_cast<int>(monster.mode), ", Var1 = ", monster.var1),
UiFlags::ColorWhite);
bool bActive = false;
for (size_t i = 0; i < ActiveMonsterCount; i++) {
if (&Monsters[ActiveMonsters[i]] == &monster) {
bActive = true;
break;
}
}
EventPlrMsg(StrCat("Active List = ", bActive ? 1 : 0, ", Squelch = ", monster.activeForTicks), UiFlags::ColorWhite);
}
} // namespace
void LoadDebugGFX()
{
pSquareCel = LoadCel("data\\square", 64);
}
void FreeDebugGFX()
{
pSquareCel = std::nullopt;
}
void GetDebugMonster()
{
int monsterIndex = pcursmonst;
if (monsterIndex == -1)
monsterIndex = std::abs(dMonster[cursPosition.x][cursPosition.y]) - 1;
if (monsterIndex == -1)
monsterIndex = DebugMonsterId;
PrintDebugMonster(Monsters[monsterIndex]);
}
void NextDebugMonster()
{
DebugMonsterId++;
if (DebugMonsterId == MaxMonsters)
DebugMonsterId = 0;
EventPlrMsg(StrCat("Current debug monster = ", DebugMonsterId), UiFlags::ColorWhite);
}
void SetDebugLevelSeedInfos(uint32_t mid1Seed, uint32_t mid2Seed, uint32_t mid3Seed, uint32_t endSeed)
{
glMid1Seed[currlevel] = mid1Seed;
glMid2Seed[currlevel] = mid2Seed;
glMid3Seed[currlevel] = mid3Seed;
glEndSeed[currlevel] = endSeed;
}
bool IsDebugGridTextNeeded()
{
return SelectedDebugGridTextItem != DebugGridTextItem::None;
}
bool IsDebugGridInMegatiles()
{
switch (SelectedDebugGridTextItem) {
case DebugGridTextItem::AutomapView:
case DebugGridTextItem::dungeon:
case DebugGridTextItem::pdungeon:
case DebugGridTextItem::Protected:
return true;
default:
return false;
}
}
DebugGridTextItem GetDebugGridTextType()
{
return SelectedDebugGridTextItem;
}
void SetDebugGridTextType(DebugGridTextItem value)
{
SelectedDebugGridTextItem = value;
}
bool GetDebugGridText(Point dungeonCoords, char *debugGridTextBuffer)
{
int info = 0;
int blankValue = 0;
Point megaCoords = dungeonCoords.worldToMega();
switch (SelectedDebugGridTextItem) {
case DebugGridTextItem::coords:
*BufCopy(debugGridTextBuffer, dungeonCoords.x, ":", dungeonCoords.y) = '\0';
return true;
case DebugGridTextItem::cursorcoords:
if (dungeonCoords != cursPosition)
return false;
*BufCopy(debugGridTextBuffer, dungeonCoords.x, ":", dungeonCoords.y) = '\0';
return true;
case DebugGridTextItem::objectindex: {
info = 0;
Object *object = FindObjectAtPosition(dungeonCoords);
if (object != nullptr) {
info = static_cast<int>(object->_otype);
}
break;
}
case DebugGridTextItem::microTiles: {
std::string result;
const MICROS &micros = DPieceMicros[dPiece[dungeonCoords.x][dungeonCoords.y]];
for (const LevelCelBlock tile : micros.mt) {
if (!tile.hasValue()) break;
if (!result.empty()) result += '\n';
StrAppend(result, tile.frame(), " ");
switch (tile.type()) {
case TileType::Square: StrAppend(result, "S"); break;
case TileType::TransparentSquare: StrAppend(result, "T"); break;
case TileType::LeftTriangle: StrAppend(result, "<"); break;
case TileType::RightTriangle: StrAppend(result, ">"); break;
case TileType::LeftTrapezoid: StrAppend(result, "\\"); break;
case TileType::RightTrapezoid: StrAppend(result, "/"); break;
}
}
if (result.empty()) return false;
*BufCopy(debugGridTextBuffer, result) = '\0';
return true;
} break;
case DebugGridTextItem::dPiece:
info = dPiece[dungeonCoords.x][dungeonCoords.y];
break;
case DebugGridTextItem::dTransVal:
info = dTransVal[dungeonCoords.x][dungeonCoords.y];
break;
case DebugGridTextItem::dLight:
info = dLight[dungeonCoords.x][dungeonCoords.y];
blankValue = LightsMax;
break;
case DebugGridTextItem::dPreLight:
info = dPreLight[dungeonCoords.x][dungeonCoords.y];
blankValue = LightsMax;
break;
case DebugGridTextItem::dFlags:
info = static_cast<int>(dFlags[dungeonCoords.x][dungeonCoords.y]);
break;
case DebugGridTextItem::dPlayer:
info = dPlayer[dungeonCoords.x][dungeonCoords.y];
break;
case DebugGridTextItem::dMonster:
info = dMonster[dungeonCoords.x][dungeonCoords.y];
break;
case DebugGridTextItem::dCorpse:
info = dCorpse[dungeonCoords.x][dungeonCoords.y];
break;
case DebugGridTextItem::dItem:
info = dItem[dungeonCoords.x][dungeonCoords.y];
break;
case DebugGridTextItem::dSpecial:
info = dSpecial[dungeonCoords.x][dungeonCoords.y];
break;
case DebugGridTextItem::dObject:
info = dObject[dungeonCoords.x][dungeonCoords.y];
break;
case DebugGridTextItem::Solid:
info = TileHasAny(dungeonCoords, TileProperties::Solid) << 0 | TileHasAny(dungeonCoords, TileProperties::BlockLight) << 1 | TileHasAny(dungeonCoords, TileProperties::BlockMissile) << 2;
break;
case DebugGridTextItem::Transparent:
info = TileHasAny(dungeonCoords, TileProperties::Transparent) << 0 | TileHasAny(dungeonCoords, TileProperties::TransparentLeft) << 1 | TileHasAny(dungeonCoords, TileProperties::TransparentRight) << 2;
break;
case DebugGridTextItem::Trap:
info = TileHasAny(dungeonCoords, TileProperties::Trap);
break;
case DebugGridTextItem::AutomapView:
if (megaCoords.x >= 0 && megaCoords.x < DMAXX && megaCoords.y >= 0 && megaCoords.y < DMAXY)
info = AutomapView[megaCoords.x][megaCoords.y];
break;
case DebugGridTextItem::dungeon:
if (megaCoords.x >= 0 && megaCoords.x < DMAXX && megaCoords.y >= 0 && megaCoords.y < DMAXY)
info = dungeon[megaCoords.x][megaCoords.y];
break;
case DebugGridTextItem::pdungeon:
if (megaCoords.x >= 0 && megaCoords.x < DMAXX && megaCoords.y >= 0 && megaCoords.y < DMAXY)
info = pdungeon[megaCoords.x][megaCoords.y];
break;
case DebugGridTextItem::Protected:
if (megaCoords.x >= 0 && megaCoords.x < DMAXX && megaCoords.y >= 0 && megaCoords.y < DMAXY)
info = Protected.test(megaCoords.x, megaCoords.y);
break;
case DebugGridTextItem::None:
return false;
}
if (info == blankValue)
return false;
*BufCopy(debugGridTextBuffer, info) = '\0';
return true;
}
bool IsDebugAutomapHighlightNeeded()
{
return SearchMonsters.size() > 0 || SearchItems.size() > 0 || SearchObjects.size() > 0;
}
bool ShouldHighlightDebugAutomapTile(Point position)
{
auto matchesSearched = [](const std::string_view name, const std::vector<std::string> &searchedNames) {
const std::string lowercaseName = AsciiStrToLower(name);
for (const auto &searchedName : searchedNames) {
if (lowercaseName.find(searchedName) != std::string::npos) {
return true;
}
}
return false;
};
if (SearchMonsters.size() > 0 && dMonster[position.x][position.y] != 0) {
const int mi = std::abs(dMonster[position.x][position.y]) - 1;
const Monster &monster = Monsters[mi];
if (matchesSearched(monster.name(), SearchMonsters))
return true;
}
if (SearchItems.size() > 0 && dItem[position.x][position.y] != 0) {
const int itemId = std::abs(dItem[position.x][position.y]) - 1;
const Item &item = Items[itemId];
if (matchesSearched(item.getName(), SearchItems))
return true;
}
if (SearchObjects.size() > 0 && IsObjectAtPosition(position)) {
const Object &object = ObjectAtPosition(position);
if (matchesSearched(object.name(), SearchObjects))
return true;
}
return false;
}
void AddDebugAutomapMonsterHighlight(std::string_view name)
{
SearchMonsters.emplace_back(name);
}
void AddDebugAutomapItemHighlight(std::string_view name)
{
SearchItems.emplace_back(name);
}
void AddDebugAutomapObjectHighlight(std::string_view name)
{
SearchObjects.emplace_back(name);
}
void ClearDebugAutomapHighlights()
{
SearchMonsters.clear();
SearchItems.clear();
SearchObjects.clear();
}
} // namespace devilution
#endif